cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cryptodev-builtin.c (11924B)


      1/*
      2 * QEMU Cryptodev backend for QEMU cipher APIs
      3 *
      4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
      5 *
      6 * Authors:
      7 *    Gonglei <arei.gonglei@huawei.com>
      8 *
      9 * This library is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU Lesser General Public
     11 * License as published by the Free Software Foundation; either
     12 * version 2.1 of the License, or (at your option) any later version.
     13 *
     14 * This library is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17 * Lesser General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU Lesser General Public
     20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     21 *
     22 */
     23
     24#include "qemu/osdep.h"
     25#include "sysemu/cryptodev.h"
     26#include "qapi/error.h"
     27#include "standard-headers/linux/virtio_crypto.h"
     28#include "crypto/cipher.h"
     29#include "qom/object.h"
     30
     31
     32/**
     33 * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
     34 * name of backend that uses QEMU cipher API
     35 */
     36#define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
     37
     38OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
     39
     40
     41typedef struct CryptoDevBackendBuiltinSession {
     42    QCryptoCipher *cipher;
     43    uint8_t direction; /* encryption or decryption */
     44    uint8_t type; /* cipher? hash? aead? */
     45    QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
     46} CryptoDevBackendBuiltinSession;
     47
     48/* Max number of symmetric sessions */
     49#define MAX_NUM_SESSIONS 256
     50
     51#define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512
     52#define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN  64
     53
     54struct CryptoDevBackendBuiltin {
     55    CryptoDevBackend parent_obj;
     56
     57    CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
     58};
     59
     60static void cryptodev_builtin_init(
     61             CryptoDevBackend *backend, Error **errp)
     62{
     63    /* Only support one queue */
     64    int queues = backend->conf.peers.queues;
     65    CryptoDevBackendClient *cc;
     66
     67    if (queues != 1) {
     68        error_setg(errp,
     69                  "Only support one queue in cryptdov-builtin backend");
     70        return;
     71    }
     72
     73    cc = cryptodev_backend_new_client(
     74              "cryptodev-builtin", NULL);
     75    cc->info_str = g_strdup_printf("cryptodev-builtin0");
     76    cc->queue_index = 0;
     77    cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN;
     78    backend->conf.peers.ccs[0] = cc;
     79
     80    backend->conf.crypto_services =
     81                         1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
     82                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
     83                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
     84    backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
     85    backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
     86    /*
     87     * Set the Maximum length of crypto request.
     88     * Why this value? Just avoid to overflow when
     89     * memory allocation for each crypto request.
     90     */
     91    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
     92    backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
     93    backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
     94
     95    cryptodev_backend_set_ready(backend, true);
     96}
     97
     98static int
     99cryptodev_builtin_get_unused_session_index(
    100                 CryptoDevBackendBuiltin *builtin)
    101{
    102    size_t i;
    103
    104    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
    105        if (builtin->sessions[i] == NULL) {
    106            return i;
    107        }
    108    }
    109
    110    return -1;
    111}
    112
    113#define AES_KEYSIZE_128 16
    114#define AES_KEYSIZE_192 24
    115#define AES_KEYSIZE_256 32
    116#define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
    117#define AES_KEYSIZE_256_XTS 64
    118
    119static int
    120cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
    121{
    122    int algo;
    123
    124    if (key_len == AES_KEYSIZE_128) {
    125        algo = QCRYPTO_CIPHER_ALG_AES_128;
    126    } else if (key_len == AES_KEYSIZE_192) {
    127        algo = QCRYPTO_CIPHER_ALG_AES_192;
    128    } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
    129        if (mode == QCRYPTO_CIPHER_MODE_XTS) {
    130            algo = QCRYPTO_CIPHER_ALG_AES_128;
    131        } else {
    132            algo = QCRYPTO_CIPHER_ALG_AES_256;
    133        }
    134    } else if (key_len == AES_KEYSIZE_256_XTS) {
    135        if (mode == QCRYPTO_CIPHER_MODE_XTS) {
    136            algo = QCRYPTO_CIPHER_ALG_AES_256;
    137        } else {
    138            goto err;
    139        }
    140    } else {
    141        goto err;
    142    }
    143
    144    return algo;
    145
    146err:
    147   error_setg(errp, "Unsupported key length :%u", key_len);
    148   return -1;
    149}
    150
    151static int cryptodev_builtin_create_cipher_session(
    152                    CryptoDevBackendBuiltin *builtin,
    153                    CryptoDevBackendSymSessionInfo *sess_info,
    154                    Error **errp)
    155{
    156    int algo;
    157    int mode;
    158    QCryptoCipher *cipher;
    159    int index;
    160    CryptoDevBackendBuiltinSession *sess;
    161
    162    if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
    163        error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
    164        return -1;
    165    }
    166
    167    index = cryptodev_builtin_get_unused_session_index(builtin);
    168    if (index < 0) {
    169        error_setg(errp, "Total number of sessions created exceeds %u",
    170                  MAX_NUM_SESSIONS);
    171        return -1;
    172    }
    173
    174    switch (sess_info->cipher_alg) {
    175    case VIRTIO_CRYPTO_CIPHER_AES_ECB:
    176        mode = QCRYPTO_CIPHER_MODE_ECB;
    177        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
    178                                                    mode, errp);
    179        if (algo < 0)  {
    180            return -1;
    181        }
    182        break;
    183    case VIRTIO_CRYPTO_CIPHER_AES_CBC:
    184        mode = QCRYPTO_CIPHER_MODE_CBC;
    185        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
    186                                                    mode, errp);
    187        if (algo < 0)  {
    188            return -1;
    189        }
    190        break;
    191    case VIRTIO_CRYPTO_CIPHER_AES_CTR:
    192        mode = QCRYPTO_CIPHER_MODE_CTR;
    193        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
    194                                                    mode, errp);
    195        if (algo < 0)  {
    196            return -1;
    197        }
    198        break;
    199    case VIRTIO_CRYPTO_CIPHER_AES_XTS:
    200        mode = QCRYPTO_CIPHER_MODE_XTS;
    201        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
    202                                                    mode, errp);
    203        if (algo < 0)  {
    204            return -1;
    205        }
    206        break;
    207    case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
    208        mode = QCRYPTO_CIPHER_MODE_ECB;
    209        algo = QCRYPTO_CIPHER_ALG_3DES;
    210        break;
    211    case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
    212        mode = QCRYPTO_CIPHER_MODE_CBC;
    213        algo = QCRYPTO_CIPHER_ALG_3DES;
    214        break;
    215    case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
    216        mode = QCRYPTO_CIPHER_MODE_CTR;
    217        algo = QCRYPTO_CIPHER_ALG_3DES;
    218        break;
    219    default:
    220        error_setg(errp, "Unsupported cipher alg :%u",
    221                   sess_info->cipher_alg);
    222        return -1;
    223    }
    224
    225    cipher = qcrypto_cipher_new(algo, mode,
    226                               sess_info->cipher_key,
    227                               sess_info->key_len,
    228                               errp);
    229    if (!cipher) {
    230        return -1;
    231    }
    232
    233    sess = g_new0(CryptoDevBackendBuiltinSession, 1);
    234    sess->cipher = cipher;
    235    sess->direction = sess_info->direction;
    236    sess->type = sess_info->op_type;
    237
    238    builtin->sessions[index] = sess;
    239
    240    return index;
    241}
    242
    243static int64_t cryptodev_builtin_sym_create_session(
    244           CryptoDevBackend *backend,
    245           CryptoDevBackendSymSessionInfo *sess_info,
    246           uint32_t queue_index, Error **errp)
    247{
    248    CryptoDevBackendBuiltin *builtin =
    249                      CRYPTODEV_BACKEND_BUILTIN(backend);
    250    int64_t session_id = -1;
    251    int ret;
    252
    253    switch (sess_info->op_code) {
    254    case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
    255        ret = cryptodev_builtin_create_cipher_session(
    256                           builtin, sess_info, errp);
    257        if (ret < 0) {
    258            return ret;
    259        } else {
    260            session_id = ret;
    261        }
    262        break;
    263    case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
    264    case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
    265    default:
    266        error_setg(errp, "Unsupported opcode :%" PRIu32 "",
    267                   sess_info->op_code);
    268        return -1;
    269    }
    270
    271    return session_id;
    272}
    273
    274static int cryptodev_builtin_sym_close_session(
    275           CryptoDevBackend *backend,
    276           uint64_t session_id,
    277           uint32_t queue_index, Error **errp)
    278{
    279    CryptoDevBackendBuiltin *builtin =
    280                      CRYPTODEV_BACKEND_BUILTIN(backend);
    281
    282    assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
    283
    284    qcrypto_cipher_free(builtin->sessions[session_id]->cipher);
    285    g_free(builtin->sessions[session_id]);
    286    builtin->sessions[session_id] = NULL;
    287    return 0;
    288}
    289
    290static int cryptodev_builtin_sym_operation(
    291                 CryptoDevBackend *backend,
    292                 CryptoDevBackendSymOpInfo *op_info,
    293                 uint32_t queue_index, Error **errp)
    294{
    295    CryptoDevBackendBuiltin *builtin =
    296                      CRYPTODEV_BACKEND_BUILTIN(backend);
    297    CryptoDevBackendBuiltinSession *sess;
    298    int ret;
    299
    300    if (op_info->session_id >= MAX_NUM_SESSIONS ||
    301              builtin->sessions[op_info->session_id] == NULL) {
    302        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
    303                   op_info->session_id);
    304        return -VIRTIO_CRYPTO_INVSESS;
    305    }
    306
    307    if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
    308        error_setg(errp,
    309               "Algorithm chain is unsupported for cryptdoev-builtin");
    310        return -VIRTIO_CRYPTO_NOTSUPP;
    311    }
    312
    313    sess = builtin->sessions[op_info->session_id];
    314
    315    if (op_info->iv_len > 0) {
    316        ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
    317                                   op_info->iv_len, errp);
    318        if (ret < 0) {
    319            return -VIRTIO_CRYPTO_ERR;
    320        }
    321    }
    322
    323    if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) {
    324        ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src,
    325                                     op_info->dst, op_info->src_len, errp);
    326        if (ret < 0) {
    327            return -VIRTIO_CRYPTO_ERR;
    328        }
    329    } else {
    330        ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
    331                                     op_info->dst, op_info->src_len, errp);
    332        if (ret < 0) {
    333            return -VIRTIO_CRYPTO_ERR;
    334        }
    335    }
    336    return VIRTIO_CRYPTO_OK;
    337}
    338
    339static void cryptodev_builtin_cleanup(
    340             CryptoDevBackend *backend,
    341             Error **errp)
    342{
    343    CryptoDevBackendBuiltin *builtin =
    344                      CRYPTODEV_BACKEND_BUILTIN(backend);
    345    size_t i;
    346    int queues = backend->conf.peers.queues;
    347    CryptoDevBackendClient *cc;
    348
    349    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
    350        if (builtin->sessions[i] != NULL) {
    351            cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
    352        }
    353    }
    354
    355    for (i = 0; i < queues; i++) {
    356        cc = backend->conf.peers.ccs[i];
    357        if (cc) {
    358            cryptodev_backend_free_client(cc);
    359            backend->conf.peers.ccs[i] = NULL;
    360        }
    361    }
    362
    363    cryptodev_backend_set_ready(backend, false);
    364}
    365
    366static void
    367cryptodev_builtin_class_init(ObjectClass *oc, void *data)
    368{
    369    CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
    370
    371    bc->init = cryptodev_builtin_init;
    372    bc->cleanup = cryptodev_builtin_cleanup;
    373    bc->create_session = cryptodev_builtin_sym_create_session;
    374    bc->close_session = cryptodev_builtin_sym_close_session;
    375    bc->do_sym_op = cryptodev_builtin_sym_operation;
    376}
    377
    378static const TypeInfo cryptodev_builtin_info = {
    379    .name = TYPE_CRYPTODEV_BACKEND_BUILTIN,
    380    .parent = TYPE_CRYPTODEV_BACKEND,
    381    .class_init = cryptodev_builtin_class_init,
    382    .instance_size = sizeof(CryptoDevBackendBuiltin),
    383};
    384
    385static void
    386cryptodev_builtin_register_types(void)
    387{
    388    type_register_static(&cryptodev_builtin_info);
    389}
    390
    391type_init(cryptodev_builtin_register_types);