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