qemu/backends/cryptodev-builtin.c
<<
>>
Prefs
   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 "crypto/akcipher.h"
  30#include "qom/object.h"
  31
  32
  33/**
  34 * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
  35 * name of backend that uses QEMU cipher API
  36 */
  37#define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
  38
  39OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
  40
  41
  42typedef struct CryptoDevBackendBuiltinSession {
  43    QCryptoCipher *cipher;
  44    uint8_t direction; /* encryption or decryption */
  45    uint8_t type; /* cipher? hash? aead? */
  46    QCryptoAkCipher *akcipher;
  47    QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
  48} CryptoDevBackendBuiltinSession;
  49
  50/* Max number of symmetric/asymmetric sessions */
  51#define MAX_NUM_SESSIONS 256
  52
  53#define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512
  54#define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN  64
  55
  56struct CryptoDevBackendBuiltin {
  57    CryptoDevBackend parent_obj;
  58
  59    CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
  60};
  61
  62static void cryptodev_builtin_init(
  63             CryptoDevBackend *backend, Error **errp)
  64{
  65    /* Only support one queue */
  66    int queues = backend->conf.peers.queues;
  67    CryptoDevBackendClient *cc;
  68
  69    if (queues != 1) {
  70        error_setg(errp,
  71                  "Only support one queue in cryptdov-builtin backend");
  72        return;
  73    }
  74
  75    cc = cryptodev_backend_new_client(
  76              "cryptodev-builtin", NULL);
  77    cc->info_str = g_strdup_printf("cryptodev-builtin0");
  78    cc->queue_index = 0;
  79    cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN;
  80    backend->conf.peers.ccs[0] = cc;
  81
  82    backend->conf.crypto_services =
  83                         1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
  84                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
  85                         1u << VIRTIO_CRYPTO_SERVICE_MAC |
  86                         1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
  87    backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
  88    backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
  89    backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
  90    /*
  91     * Set the Maximum length of crypto request.
  92     * Why this value? Just avoid to overflow when
  93     * memory allocation for each crypto request.
  94     */
  95    backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
  96    backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
  97    backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
  98
  99    cryptodev_backend_set_ready(backend, true);
 100}
 101
 102static int
 103cryptodev_builtin_get_unused_session_index(
 104                 CryptoDevBackendBuiltin *builtin)
 105{
 106    size_t i;
 107
 108    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
 109        if (builtin->sessions[i] == NULL) {
 110            return i;
 111        }
 112    }
 113
 114    return -1;
 115}
 116
 117#define AES_KEYSIZE_128 16
 118#define AES_KEYSIZE_192 24
 119#define AES_KEYSIZE_256 32
 120#define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
 121#define AES_KEYSIZE_256_XTS 64
 122
 123static int
 124cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
 125{
 126    int algo;
 127
 128    if (key_len == AES_KEYSIZE_128) {
 129        algo = QCRYPTO_CIPHER_ALG_AES_128;
 130    } else if (key_len == AES_KEYSIZE_192) {
 131        algo = QCRYPTO_CIPHER_ALG_AES_192;
 132    } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
 133        if (mode == QCRYPTO_CIPHER_MODE_XTS) {
 134            algo = QCRYPTO_CIPHER_ALG_AES_128;
 135        } else {
 136            algo = QCRYPTO_CIPHER_ALG_AES_256;
 137        }
 138    } else if (key_len == AES_KEYSIZE_256_XTS) {
 139        if (mode == QCRYPTO_CIPHER_MODE_XTS) {
 140            algo = QCRYPTO_CIPHER_ALG_AES_256;
 141        } else {
 142            goto err;
 143        }
 144    } else {
 145        goto err;
 146    }
 147
 148    return algo;
 149
 150err:
 151   error_setg(errp, "Unsupported key length :%u", key_len);
 152   return -1;
 153}
 154
 155static int cryptodev_builtin_get_rsa_hash_algo(
 156    int virtio_rsa_hash, Error **errp)
 157{
 158    switch (virtio_rsa_hash) {
 159    case VIRTIO_CRYPTO_RSA_MD5:
 160        return QCRYPTO_HASH_ALG_MD5;
 161
 162    case VIRTIO_CRYPTO_RSA_SHA1:
 163        return QCRYPTO_HASH_ALG_SHA1;
 164
 165    case VIRTIO_CRYPTO_RSA_SHA256:
 166        return QCRYPTO_HASH_ALG_SHA256;
 167
 168    case VIRTIO_CRYPTO_RSA_SHA512:
 169        return QCRYPTO_HASH_ALG_SHA512;
 170
 171    default:
 172        error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
 173        return -1;
 174    }
 175}
 176
 177static int cryptodev_builtin_set_rsa_options(
 178                    int virtio_padding_algo,
 179                    int virtio_hash_algo,
 180                    QCryptoAkCipherOptionsRSA *opt,
 181                    Error **errp)
 182{
 183    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
 184        int hash_alg;
 185
 186        hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
 187        if (hash_alg < 0) {
 188            return -1;
 189        }
 190        opt->hash_alg = hash_alg;
 191        opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
 192        return 0;
 193    }
 194
 195    if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
 196        opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
 197        return 0;
 198    }
 199
 200    error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
 201    return -1;
 202}
 203
 204static int cryptodev_builtin_create_cipher_session(
 205                    CryptoDevBackendBuiltin *builtin,
 206                    CryptoDevBackendSymSessionInfo *sess_info,
 207                    Error **errp)
 208{
 209    int algo;
 210    int mode;
 211    QCryptoCipher *cipher;
 212    int index;
 213    CryptoDevBackendBuiltinSession *sess;
 214
 215    if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
 216        error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
 217        return -1;
 218    }
 219
 220    index = cryptodev_builtin_get_unused_session_index(builtin);
 221    if (index < 0) {
 222        error_setg(errp, "Total number of sessions created exceeds %u",
 223                  MAX_NUM_SESSIONS);
 224        return -1;
 225    }
 226
 227    switch (sess_info->cipher_alg) {
 228    case VIRTIO_CRYPTO_CIPHER_AES_ECB:
 229        mode = QCRYPTO_CIPHER_MODE_ECB;
 230        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
 231                                                    mode, errp);
 232        if (algo < 0)  {
 233            return -1;
 234        }
 235        break;
 236    case VIRTIO_CRYPTO_CIPHER_AES_CBC:
 237        mode = QCRYPTO_CIPHER_MODE_CBC;
 238        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
 239                                                    mode, errp);
 240        if (algo < 0)  {
 241            return -1;
 242        }
 243        break;
 244    case VIRTIO_CRYPTO_CIPHER_AES_CTR:
 245        mode = QCRYPTO_CIPHER_MODE_CTR;
 246        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
 247                                                    mode, errp);
 248        if (algo < 0)  {
 249            return -1;
 250        }
 251        break;
 252    case VIRTIO_CRYPTO_CIPHER_AES_XTS:
 253        mode = QCRYPTO_CIPHER_MODE_XTS;
 254        algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
 255                                                    mode, errp);
 256        if (algo < 0)  {
 257            return -1;
 258        }
 259        break;
 260    case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
 261        mode = QCRYPTO_CIPHER_MODE_ECB;
 262        algo = QCRYPTO_CIPHER_ALG_3DES;
 263        break;
 264    case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
 265        mode = QCRYPTO_CIPHER_MODE_CBC;
 266        algo = QCRYPTO_CIPHER_ALG_3DES;
 267        break;
 268    case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
 269        mode = QCRYPTO_CIPHER_MODE_CTR;
 270        algo = QCRYPTO_CIPHER_ALG_3DES;
 271        break;
 272    default:
 273        error_setg(errp, "Unsupported cipher alg :%u",
 274                   sess_info->cipher_alg);
 275        return -1;
 276    }
 277
 278    cipher = qcrypto_cipher_new(algo, mode,
 279                               sess_info->cipher_key,
 280                               sess_info->key_len,
 281                               errp);
 282    if (!cipher) {
 283        return -1;
 284    }
 285
 286    sess = g_new0(CryptoDevBackendBuiltinSession, 1);
 287    sess->cipher = cipher;
 288    sess->direction = sess_info->direction;
 289    sess->type = sess_info->op_type;
 290
 291    builtin->sessions[index] = sess;
 292
 293    return index;
 294}
 295
 296static int cryptodev_builtin_create_akcipher_session(
 297                    CryptoDevBackendBuiltin *builtin,
 298                    CryptoDevBackendAsymSessionInfo *sess_info,
 299                    Error **errp)
 300{
 301    CryptoDevBackendBuiltinSession *sess;
 302    QCryptoAkCipher *akcipher;
 303    int index;
 304    QCryptoAkCipherKeyType type;
 305    QCryptoAkCipherOptions opts;
 306
 307    switch (sess_info->algo) {
 308    case VIRTIO_CRYPTO_AKCIPHER_RSA:
 309        opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
 310        if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
 311            sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) {
 312            return -1;
 313        }
 314        break;
 315
 316    /* TODO support DSA&ECDSA until qemu crypto framework support these */
 317
 318    default:
 319        error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
 320        return -1;
 321    }
 322
 323    switch (sess_info->keytype) {
 324    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
 325        type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
 326        break;
 327
 328    case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
 329        type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
 330        break;
 331
 332    default:
 333        error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
 334        return -1;
 335    }
 336
 337    index = cryptodev_builtin_get_unused_session_index(builtin);
 338    if (index < 0) {
 339        error_setg(errp, "Total number of sessions created exceeds %u",
 340                   MAX_NUM_SESSIONS);
 341        return -1;
 342    }
 343
 344    akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key,
 345                                    sess_info->keylen, errp);
 346    if (!akcipher) {
 347        return -1;
 348    }
 349
 350    sess = g_new0(CryptoDevBackendBuiltinSession, 1);
 351    sess->akcipher = akcipher;
 352
 353    builtin->sessions[index] = sess;
 354
 355    return index;
 356}
 357
 358static int64_t cryptodev_builtin_create_session(
 359           CryptoDevBackend *backend,
 360           CryptoDevBackendSessionInfo *sess_info,
 361           uint32_t queue_index, Error **errp)
 362{
 363    CryptoDevBackendBuiltin *builtin =
 364                      CRYPTODEV_BACKEND_BUILTIN(backend);
 365    CryptoDevBackendSymSessionInfo *sym_sess_info;
 366    CryptoDevBackendAsymSessionInfo *asym_sess_info;
 367
 368    switch (sess_info->op_code) {
 369    case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
 370        sym_sess_info = &sess_info->u.sym_sess_info;
 371        return cryptodev_builtin_create_cipher_session(
 372                           builtin, sym_sess_info, errp);
 373
 374    case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
 375        asym_sess_info = &sess_info->u.asym_sess_info;
 376        return cryptodev_builtin_create_akcipher_session(
 377                           builtin, asym_sess_info, errp);
 378
 379    case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
 380    case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
 381    default:
 382        error_setg(errp, "Unsupported opcode :%" PRIu32 "",
 383                   sess_info->op_code);
 384        return -1;
 385    }
 386
 387    return -1;
 388}
 389
 390static int cryptodev_builtin_close_session(
 391           CryptoDevBackend *backend,
 392           uint64_t session_id,
 393           uint32_t queue_index, Error **errp)
 394{
 395    CryptoDevBackendBuiltin *builtin =
 396                      CRYPTODEV_BACKEND_BUILTIN(backend);
 397    CryptoDevBackendBuiltinSession *session;
 398
 399    assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
 400
 401    session = builtin->sessions[session_id];
 402    if (session->cipher) {
 403        qcrypto_cipher_free(session->cipher);
 404    } else if (session->akcipher) {
 405        qcrypto_akcipher_free(session->akcipher);
 406    }
 407
 408    g_free(session);
 409    builtin->sessions[session_id] = NULL;
 410    return 0;
 411}
 412
 413static int cryptodev_builtin_sym_operation(
 414                 CryptoDevBackendBuiltinSession *sess,
 415                 CryptoDevBackendSymOpInfo *op_info, Error **errp)
 416{
 417    int ret;
 418
 419    if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
 420        error_setg(errp,
 421               "Algorithm chain is unsupported for cryptdoev-builtin");
 422        return -VIRTIO_CRYPTO_NOTSUPP;
 423    }
 424
 425    if (op_info->iv_len > 0) {
 426        ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
 427                                   op_info->iv_len, errp);
 428        if (ret < 0) {
 429            return -VIRTIO_CRYPTO_ERR;
 430        }
 431    }
 432
 433    if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) {
 434        ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src,
 435                                     op_info->dst, op_info->src_len, errp);
 436        if (ret < 0) {
 437            return -VIRTIO_CRYPTO_ERR;
 438        }
 439    } else {
 440        ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
 441                                     op_info->dst, op_info->src_len, errp);
 442        if (ret < 0) {
 443            return -VIRTIO_CRYPTO_ERR;
 444        }
 445    }
 446
 447    return VIRTIO_CRYPTO_OK;
 448}
 449
 450static int cryptodev_builtin_asym_operation(
 451                 CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
 452                 CryptoDevBackendAsymOpInfo *op_info, Error **errp)
 453{
 454    int ret;
 455
 456    switch (op_code) {
 457    case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
 458        ret = qcrypto_akcipher_encrypt(sess->akcipher,
 459                                       op_info->src, op_info->src_len,
 460                                       op_info->dst, op_info->dst_len, errp);
 461        break;
 462
 463    case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
 464        ret = qcrypto_akcipher_decrypt(sess->akcipher,
 465                                       op_info->src, op_info->src_len,
 466                                       op_info->dst, op_info->dst_len, errp);
 467        break;
 468
 469    case VIRTIO_CRYPTO_AKCIPHER_SIGN:
 470        ret = qcrypto_akcipher_sign(sess->akcipher,
 471                                    op_info->src, op_info->src_len,
 472                                    op_info->dst, op_info->dst_len, errp);
 473        break;
 474
 475    case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
 476        ret = qcrypto_akcipher_verify(sess->akcipher,
 477                                      op_info->src, op_info->src_len,
 478                                      op_info->dst, op_info->dst_len, errp);
 479        break;
 480
 481    default:
 482        return -VIRTIO_CRYPTO_ERR;
 483    }
 484
 485    if (ret < 0) {
 486        if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
 487            return -VIRTIO_CRYPTO_KEY_REJECTED;
 488        }
 489        return -VIRTIO_CRYPTO_ERR;
 490    }
 491
 492    /* Buffer is too short, typically the driver should handle this case */
 493    if (unlikely(ret > op_info->dst_len)) {
 494        if (errp && !*errp) {
 495            error_setg(errp, "dst buffer too short");
 496        }
 497
 498        return -VIRTIO_CRYPTO_ERR;
 499    }
 500
 501    op_info->dst_len = ret;
 502
 503    return VIRTIO_CRYPTO_OK;
 504}
 505
 506static int cryptodev_builtin_operation(
 507                 CryptoDevBackend *backend,
 508                 CryptoDevBackendOpInfo *op_info,
 509                 uint32_t queue_index, Error **errp)
 510{
 511    CryptoDevBackendBuiltin *builtin =
 512                      CRYPTODEV_BACKEND_BUILTIN(backend);
 513    CryptoDevBackendBuiltinSession *sess;
 514    CryptoDevBackendSymOpInfo *sym_op_info;
 515    CryptoDevBackendAsymOpInfo *asym_op_info;
 516    enum CryptoDevBackendAlgType algtype = op_info->algtype;
 517    int ret = -VIRTIO_CRYPTO_ERR;
 518
 519    if (op_info->session_id >= MAX_NUM_SESSIONS ||
 520              builtin->sessions[op_info->session_id] == NULL) {
 521        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
 522                   op_info->session_id);
 523        return -VIRTIO_CRYPTO_INVSESS;
 524    }
 525
 526    sess = builtin->sessions[op_info->session_id];
 527    if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
 528        sym_op_info = op_info->u.sym_op_info;
 529        ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
 530    } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
 531        asym_op_info = op_info->u.asym_op_info;
 532        ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
 533                                               asym_op_info, errp);
 534    }
 535
 536    return ret;
 537}
 538
 539static void cryptodev_builtin_cleanup(
 540             CryptoDevBackend *backend,
 541             Error **errp)
 542{
 543    CryptoDevBackendBuiltin *builtin =
 544                      CRYPTODEV_BACKEND_BUILTIN(backend);
 545    size_t i;
 546    int queues = backend->conf.peers.queues;
 547    CryptoDevBackendClient *cc;
 548
 549    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
 550        if (builtin->sessions[i] != NULL) {
 551            cryptodev_builtin_close_session(backend, i, 0, &error_abort);
 552        }
 553    }
 554
 555    for (i = 0; i < queues; i++) {
 556        cc = backend->conf.peers.ccs[i];
 557        if (cc) {
 558            cryptodev_backend_free_client(cc);
 559            backend->conf.peers.ccs[i] = NULL;
 560        }
 561    }
 562
 563    cryptodev_backend_set_ready(backend, false);
 564}
 565
 566static void
 567cryptodev_builtin_class_init(ObjectClass *oc, void *data)
 568{
 569    CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
 570
 571    bc->init = cryptodev_builtin_init;
 572    bc->cleanup = cryptodev_builtin_cleanup;
 573    bc->create_session = cryptodev_builtin_create_session;
 574    bc->close_session = cryptodev_builtin_close_session;
 575    bc->do_op = cryptodev_builtin_operation;
 576}
 577
 578static const TypeInfo cryptodev_builtin_info = {
 579    .name = TYPE_CRYPTODEV_BACKEND_BUILTIN,
 580    .parent = TYPE_CRYPTODEV_BACKEND,
 581    .class_init = cryptodev_builtin_class_init,
 582    .instance_size = sizeof(CryptoDevBackendBuiltin),
 583};
 584
 585static void
 586cryptodev_builtin_register_types(void)
 587{
 588    type_register_static(&cryptodev_builtin_info);
 589}
 590
 591type_init(cryptodev_builtin_register_types);
 592