qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cryptodev-lkcf.c (20225B)


      1 /*
      2  * QEMU Cryptodev backend for QEMU cipher APIs
      3  *
      4  * Copyright (c) 2022 Bytedance.Inc
      5  *
      6  * Authors:
      7  *    lei he <helei.sig11@bytedance.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 "crypto/cipher.h"
     26 #include "crypto/akcipher.h"
     27 #include "qapi/error.h"
     28 #include "qemu/main-loop.h"
     29 #include "qemu/thread.h"
     30 #include "qemu/error-report.h"
     31 #include "qemu/queue.h"
     32 #include "qom/object.h"
     33 #include "sysemu/cryptodev.h"
     34 #include "standard-headers/linux/virtio_crypto.h"
     35 
     36 #include <keyutils.h>
     37 #include <sys/eventfd.h>
     38 
     39 /**
     40  * @TYPE_CRYPTODEV_BACKEND_LKCF:
     41  * name of backend that uses linux kernel crypto framework
     42  */
     43 #define TYPE_CRYPTODEV_BACKEND_LKCF "cryptodev-backend-lkcf"
     44 
     45 OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendLKCF, CRYPTODEV_BACKEND_LKCF)
     46 
     47 #define INVALID_KEY_ID -1
     48 #define MAX_SESSIONS 256
     49 #define NR_WORKER_THREAD 64
     50 
     51 #define KCTL_KEY_TYPE_PKEY "asymmetric"
     52 /**
     53  * Here the key is uploaded to the thread-keyring of worker thread, at least
     54  * util linux-6.0:
     55  * 1. process keyring seems to behave unexpectedly if main-thread does not
     56  * create the keyring before creating any other thread.
     57  * 2. at present, the guest kernel never perform multiple operations on a
     58  * session.
     59  * 3. it can reduce the load of the main-loop because the key passed by the
     60  * guest kernel has been already checked.
     61  */
     62 #define KCTL_KEY_RING KEY_SPEC_THREAD_KEYRING
     63 
     64 typedef struct CryptoDevBackendLKCFSession {
     65     uint8_t *key;
     66     size_t keylen;
     67     QCryptoAkCipherKeyType keytype;
     68     QCryptoAkCipherOptions akcipher_opts;
     69 } CryptoDevBackendLKCFSession;
     70 
     71 typedef struct CryptoDevBackendLKCF CryptoDevBackendLKCF;
     72 typedef struct CryptoDevLKCFTask CryptoDevLKCFTask;
     73 struct CryptoDevLKCFTask {
     74     CryptoDevBackendLKCFSession *sess;
     75     CryptoDevBackendOpInfo *op_info;
     76     CryptoDevCompletionFunc cb;
     77     void *opaque;
     78     int status;
     79     CryptoDevBackendLKCF *lkcf;
     80     QSIMPLEQ_ENTRY(CryptoDevLKCFTask) queue;
     81 };
     82 
     83 typedef struct CryptoDevBackendLKCF {
     84     CryptoDevBackend parent_obj;
     85     CryptoDevBackendLKCFSession *sess[MAX_SESSIONS];
     86     QSIMPLEQ_HEAD(, CryptoDevLKCFTask) requests;
     87     QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses;
     88     QemuMutex mutex;
     89     QemuCond cond;
     90     QemuMutex rsp_mutex;
     91 
     92     /**
     93      * There is no async interface for asymmetric keys like AF_ALG sockets,
     94      * we don't seem to have better way than create a lots of thread.
     95      */
     96     QemuThread worker_threads[NR_WORKER_THREAD];
     97     bool running;
     98     int eventfd;
     99 } CryptoDevBackendLKCF;
    100 
    101 static void *cryptodev_lkcf_worker(void *arg);
    102 static int cryptodev_lkcf_close_session(CryptoDevBackend *backend,
    103                                         uint64_t session_id,
    104                                         uint32_t queue_index,
    105                                         CryptoDevCompletionFunc cb,
    106                                         void *opaque);
    107 
    108 static void cryptodev_lkcf_handle_response(void *opaque)
    109 {
    110     CryptoDevBackendLKCF *lkcf = (CryptoDevBackendLKCF *)opaque;
    111     QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses;
    112     CryptoDevLKCFTask *task, *next;
    113     eventfd_t nevent;
    114 
    115     QSIMPLEQ_INIT(&responses);
    116     eventfd_read(lkcf->eventfd, &nevent);
    117 
    118     qemu_mutex_lock(&lkcf->rsp_mutex);
    119     QSIMPLEQ_PREPEND(&responses, &lkcf->responses);
    120     qemu_mutex_unlock(&lkcf->rsp_mutex);
    121 
    122     QSIMPLEQ_FOREACH_SAFE(task, &responses, queue, next) {
    123         if (task->cb) {
    124             task->cb(task->opaque, task->status);
    125         }
    126         g_free(task);
    127     }
    128 }
    129 
    130 static int cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions *opts,
    131                                       char *key_desc,
    132                                       size_t desc_len,
    133                                       Error **errp)
    134 {
    135     QCryptoAkCipherOptionsRSA *rsa_opt;
    136     if (opts->alg != QCRYPTO_AKCIPHER_ALG_RSA) {
    137         error_setg(errp, "Unsupported alg: %u", opts->alg);
    138         return -1;
    139     }
    140 
    141     rsa_opt = &opts->u.rsa;
    142     if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALG_PKCS1) {
    143         snprintf(key_desc, desc_len, "enc=%s hash=%s",
    144                  QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg),
    145                  QCryptoHashAlgorithm_str(rsa_opt->hash_alg));
    146 
    147     } else {
    148         snprintf(key_desc, desc_len, "enc=%s",
    149                  QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg));
    150     }
    151     return 0;
    152 }
    153 
    154 static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,
    155                                       int virtio_hash_alg,
    156                                       QCryptoAkCipherOptionsRSA *opt,
    157                                       Error **errp)
    158 {
    159     if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
    160         opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
    161 
    162         switch (virtio_hash_alg) {
    163         case VIRTIO_CRYPTO_RSA_MD5:
    164             opt->hash_alg = QCRYPTO_HASH_ALG_MD5;
    165             break;
    166 
    167         case VIRTIO_CRYPTO_RSA_SHA1:
    168             opt->hash_alg = QCRYPTO_HASH_ALG_SHA1;
    169             break;
    170 
    171         case VIRTIO_CRYPTO_RSA_SHA256:
    172             opt->hash_alg = QCRYPTO_HASH_ALG_SHA256;
    173             break;
    174 
    175         case VIRTIO_CRYPTO_RSA_SHA512:
    176             opt->hash_alg = QCRYPTO_HASH_ALG_SHA512;
    177             break;
    178 
    179         default:
    180             error_setg(errp, "Unsupported rsa hash algo: %d", virtio_hash_alg);
    181             return -1;
    182         }
    183         return 0;
    184     }
    185 
    186     if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
    187         opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
    188         return 0;
    189     }
    190 
    191     error_setg(errp, "Unsupported rsa padding algo: %u", virtio_padding_alg);
    192     return -1;
    193 }
    194 
    195 static int cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF *lkcf)
    196 {
    197     size_t i;
    198 
    199     for (i = 0; i < MAX_SESSIONS; i++) {
    200         if (lkcf->sess[i] == NULL) {
    201             return i;
    202         }
    203     }
    204     return -1;
    205 }
    206 
    207 static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
    208 {
    209     /* Only support one queue */
    210     int queues = backend->conf.peers.queues, i;
    211     CryptoDevBackendClient *cc;
    212     CryptoDevBackendLKCF *lkcf =
    213         CRYPTODEV_BACKEND_LKCF(backend);
    214 
    215     if (queues != 1) {
    216         error_setg(errp,
    217                    "Only support one queue in cryptodev-builtin backend");
    218         return;
    219     }
    220     lkcf->eventfd = eventfd(0, 0);
    221     if (lkcf->eventfd < 0) {
    222         error_setg(errp, "Failed to create eventfd: %d", errno);
    223         return;
    224     }
    225 
    226     cc = cryptodev_backend_new_client("cryptodev-lkcf", NULL);
    227     cc->info_str = g_strdup_printf("cryptodev-lkcf0");
    228     cc->queue_index = 0;
    229     cc->type = CRYPTODEV_BACKEND_TYPE_LKCF;
    230     backend->conf.peers.ccs[0] = cc;
    231 
    232     backend->conf.crypto_services =
    233         1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
    234     backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
    235     lkcf->running = true;
    236 
    237     QSIMPLEQ_INIT(&lkcf->requests);
    238     QSIMPLEQ_INIT(&lkcf->responses);
    239     qemu_mutex_init(&lkcf->mutex);
    240     qemu_mutex_init(&lkcf->rsp_mutex);
    241     qemu_cond_init(&lkcf->cond);
    242     for (i = 0; i < NR_WORKER_THREAD; i++) {
    243         qemu_thread_create(&lkcf->worker_threads[i], "lkcf-worker",
    244                            cryptodev_lkcf_worker, lkcf, 0);
    245     }
    246     qemu_set_fd_handler(
    247         lkcf->eventfd, cryptodev_lkcf_handle_response, NULL, lkcf);
    248     cryptodev_backend_set_ready(backend, true);
    249 }
    250 
    251 static void cryptodev_lkcf_cleanup(CryptoDevBackend *backend, Error **errp)
    252 {
    253     CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend);
    254     size_t i;
    255     int queues = backend->conf.peers.queues;
    256     CryptoDevBackendClient *cc;
    257     CryptoDevLKCFTask *task, *next;
    258 
    259     qemu_mutex_lock(&lkcf->mutex);
    260     lkcf->running = false;
    261     qemu_mutex_unlock(&lkcf->mutex);
    262     qemu_cond_broadcast(&lkcf->cond);
    263 
    264     close(lkcf->eventfd);
    265     for (i = 0; i < NR_WORKER_THREAD; i++) {
    266         qemu_thread_join(&lkcf->worker_threads[i]);
    267     }
    268 
    269     QSIMPLEQ_FOREACH_SAFE(task, &lkcf->requests, queue, next) {
    270         if (task->cb) {
    271             task->cb(task->opaque, task->status);
    272         }
    273         g_free(task);
    274     }
    275 
    276     QSIMPLEQ_FOREACH_SAFE(task, &lkcf->responses, queue, next) {
    277         if (task->cb) {
    278             task->cb(task->opaque, task->status);
    279         }
    280         g_free(task);
    281     }
    282 
    283     qemu_mutex_destroy(&lkcf->mutex);
    284     qemu_cond_destroy(&lkcf->cond);
    285     qemu_mutex_destroy(&lkcf->rsp_mutex);
    286 
    287     for (i = 0; i < MAX_SESSIONS; i++) {
    288         if (lkcf->sess[i] != NULL) {
    289             cryptodev_lkcf_close_session(backend, i, 0, NULL, NULL);
    290         }
    291     }
    292 
    293     for (i = 0; i < queues; i++) {
    294         cc = backend->conf.peers.ccs[i];
    295         if (cc) {
    296             cryptodev_backend_free_client(cc);
    297             backend->conf.peers.ccs[i] = NULL;
    298         }
    299     }
    300 
    301     cryptodev_backend_set_ready(backend, false);
    302 }
    303 
    304 static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task)
    305 {
    306     CryptoDevBackendLKCFSession *session = task->sess;
    307     CryptoDevBackendAsymOpInfo *asym_op_info;
    308     bool kick = false;
    309     int ret, status, op_code = task->op_info->op_code;
    310     size_t p8info_len;
    311     g_autofree uint8_t *p8info = NULL;
    312     Error *local_error = NULL;
    313     key_serial_t key_id = INVALID_KEY_ID;
    314     char op_desc[64];
    315     g_autoptr(QCryptoAkCipher) akcipher = NULL;
    316 
    317     /**
    318      * We only offload private key session:
    319      * 1. currently, the Linux kernel can only accept public key wrapped
    320      * with X.509 certificates, but unfortunately the cost of making a
    321      * ceritificate with public key is too expensive.
    322      * 2. generally, public key related compution is fast, just compute it with
    323      * thread-pool.
    324      */
    325     if (session->keytype == QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE) {
    326         if (qcrypto_akcipher_export_p8info(&session->akcipher_opts,
    327                                            session->key, session->keylen,
    328                                            &p8info, &p8info_len,
    329                                            &local_error) != 0 ||
    330             cryptodev_lkcf_set_op_desc(&session->akcipher_opts, op_desc,
    331                                        sizeof(op_desc), &local_error) != 0) {
    332             error_report_err(local_error);
    333         } else {
    334             key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key",
    335                              p8info, p8info_len, KCTL_KEY_RING);
    336         }
    337     }
    338 
    339     if (key_id < 0) {
    340         if (!qcrypto_akcipher_supports(&session->akcipher_opts)) {
    341             status = -VIRTIO_CRYPTO_NOTSUPP;
    342             goto out;
    343         }
    344         akcipher = qcrypto_akcipher_new(&session->akcipher_opts,
    345                                         session->keytype,
    346                                         session->key, session->keylen,
    347                                         &local_error);
    348         if (!akcipher) {
    349             status = -VIRTIO_CRYPTO_ERR;
    350             goto out;
    351         }
    352     }
    353 
    354     asym_op_info = task->op_info->u.asym_op_info;
    355     switch (op_code) {
    356     case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
    357         if (key_id >= 0) {
    358             ret = keyctl_pkey_encrypt(key_id, op_desc,
    359                 asym_op_info->src, asym_op_info->src_len,
    360                 asym_op_info->dst, asym_op_info->dst_len);
    361         } else {
    362             ret = qcrypto_akcipher_encrypt(akcipher,
    363                 asym_op_info->src, asym_op_info->src_len,
    364                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
    365         }
    366         break;
    367 
    368     case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
    369         if (key_id >= 0) {
    370             ret = keyctl_pkey_decrypt(key_id, op_desc,
    371                 asym_op_info->src, asym_op_info->src_len,
    372                 asym_op_info->dst, asym_op_info->dst_len);
    373         } else {
    374             ret = qcrypto_akcipher_decrypt(akcipher,
    375                 asym_op_info->src, asym_op_info->src_len,
    376                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
    377         }
    378         break;
    379 
    380     case VIRTIO_CRYPTO_AKCIPHER_SIGN:
    381         if (key_id >= 0) {
    382             ret = keyctl_pkey_sign(key_id, op_desc,
    383                 asym_op_info->src, asym_op_info->src_len,
    384                 asym_op_info->dst, asym_op_info->dst_len);
    385         } else {
    386             ret = qcrypto_akcipher_sign(akcipher,
    387                 asym_op_info->src, asym_op_info->src_len,
    388                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
    389         }
    390         break;
    391 
    392     case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
    393         if (key_id >= 0) {
    394             ret = keyctl_pkey_verify(key_id, op_desc,
    395                 asym_op_info->src, asym_op_info->src_len,
    396                 asym_op_info->dst, asym_op_info->dst_len);
    397         } else {
    398             ret = qcrypto_akcipher_verify(akcipher,
    399                 asym_op_info->src, asym_op_info->src_len,
    400                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
    401         }
    402         break;
    403 
    404     default:
    405         error_setg(&local_error, "Unknown opcode: %u", op_code);
    406         status = -VIRTIO_CRYPTO_ERR;
    407         goto out;
    408     }
    409 
    410     if (ret < 0) {
    411         if (!local_error) {
    412             if (errno != EKEYREJECTED) {
    413                 error_report("Failed do operation with keyctl: %d", errno);
    414             }
    415         } else {
    416             error_report_err(local_error);
    417         }
    418         status = op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY ?
    419             -VIRTIO_CRYPTO_KEY_REJECTED : -VIRTIO_CRYPTO_ERR;
    420     } else {
    421         status = VIRTIO_CRYPTO_OK;
    422         asym_op_info->dst_len = ret;
    423     }
    424 
    425 out:
    426     if (key_id >= 0) {
    427         keyctl_unlink(key_id, KCTL_KEY_RING);
    428     }
    429     task->status = status;
    430 
    431     qemu_mutex_lock(&task->lkcf->rsp_mutex);
    432     if (QSIMPLEQ_EMPTY(&task->lkcf->responses)) {
    433         kick = true;
    434     }
    435     QSIMPLEQ_INSERT_TAIL(&task->lkcf->responses, task, queue);
    436     qemu_mutex_unlock(&task->lkcf->rsp_mutex);
    437 
    438     if (kick) {
    439         eventfd_write(task->lkcf->eventfd, 1);
    440     }
    441 }
    442 
    443 static void *cryptodev_lkcf_worker(void *arg)
    444 {
    445     CryptoDevBackendLKCF *backend = (CryptoDevBackendLKCF *)arg;
    446     CryptoDevLKCFTask *task;
    447 
    448     for (;;) {
    449         task = NULL;
    450         qemu_mutex_lock(&backend->mutex);
    451         while (backend->running && QSIMPLEQ_EMPTY(&backend->requests)) {
    452             qemu_cond_wait(&backend->cond, &backend->mutex);
    453         }
    454         if (backend->running) {
    455             task = QSIMPLEQ_FIRST(&backend->requests);
    456             QSIMPLEQ_REMOVE_HEAD(&backend->requests, queue);
    457         }
    458         qemu_mutex_unlock(&backend->mutex);
    459 
    460         /* stopped */
    461         if (!task) {
    462             break;
    463         }
    464         cryptodev_lkcf_execute_task(task);
    465    }
    466 
    467    return NULL;
    468 }
    469 
    470 static int cryptodev_lkcf_operation(
    471     CryptoDevBackend *backend,
    472     CryptoDevBackendOpInfo *op_info,
    473     uint32_t queue_index,
    474     CryptoDevCompletionFunc cb,
    475     void *opaque)
    476 {
    477     CryptoDevBackendLKCF *lkcf =
    478         CRYPTODEV_BACKEND_LKCF(backend);
    479     CryptoDevBackendLKCFSession *sess;
    480     enum CryptoDevBackendAlgType algtype = op_info->algtype;
    481     CryptoDevLKCFTask *task;
    482 
    483     if (op_info->session_id >= MAX_SESSIONS ||
    484         lkcf->sess[op_info->session_id] == NULL) {
    485         error_report("Cannot find a valid session id: %" PRIu64 "",
    486                      op_info->session_id);
    487         return -VIRTIO_CRYPTO_INVSESS;
    488     }
    489 
    490     sess = lkcf->sess[op_info->session_id];
    491     if (algtype != CRYPTODEV_BACKEND_ALG_ASYM) {
    492         error_report("algtype not supported: %u", algtype);
    493         return -VIRTIO_CRYPTO_NOTSUPP;
    494     }
    495 
    496     task = g_new0(CryptoDevLKCFTask, 1);
    497     task->op_info = op_info;
    498     task->cb = cb;
    499     task->opaque = opaque;
    500     task->sess = sess;
    501     task->lkcf = lkcf;
    502     task->status = -VIRTIO_CRYPTO_ERR;
    503 
    504     qemu_mutex_lock(&lkcf->mutex);
    505     QSIMPLEQ_INSERT_TAIL(&lkcf->requests, task, queue);
    506     qemu_mutex_unlock(&lkcf->mutex);
    507     qemu_cond_signal(&lkcf->cond);
    508 
    509     return VIRTIO_CRYPTO_OK;
    510 }
    511 
    512 static int cryptodev_lkcf_create_asym_session(
    513     CryptoDevBackendLKCF *lkcf,
    514     CryptoDevBackendAsymSessionInfo *sess_info,
    515     uint64_t *session_id)
    516 {
    517     Error *local_error = NULL;
    518     int index;
    519     g_autofree CryptoDevBackendLKCFSession *sess =
    520         g_new0(CryptoDevBackendLKCFSession, 1);
    521 
    522     switch (sess_info->algo) {
    523     case VIRTIO_CRYPTO_AKCIPHER_RSA:
    524         sess->akcipher_opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
    525         if (cryptodev_lkcf_set_rsa_opt(
    526             sess_info->u.rsa.padding_algo, sess_info->u.rsa.hash_algo,
    527             &sess->akcipher_opts.u.rsa, &local_error) != 0) {
    528             error_report_err(local_error);
    529             return -VIRTIO_CRYPTO_ERR;
    530         }
    531         break;
    532 
    533     default:
    534         error_report("Unsupported asym alg %u", sess_info->algo);
    535         return -VIRTIO_CRYPTO_NOTSUPP;
    536     }
    537 
    538     switch (sess_info->keytype) {
    539     case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
    540         sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
    541         break;
    542 
    543     case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
    544         sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
    545         break;
    546 
    547     default:
    548         error_report("Unknown akcipher keytype: %u", sess_info->keytype);
    549         return -VIRTIO_CRYPTO_ERR;
    550     }
    551 
    552     index = cryptodev_lkcf_get_unused_session_index(lkcf);
    553     if (index < 0) {
    554         error_report("Total number of sessions created exceeds %u",
    555                      MAX_SESSIONS);
    556         return -VIRTIO_CRYPTO_ERR;
    557     }
    558 
    559     sess->keylen = sess_info->keylen;
    560     sess->key = g_malloc(sess_info->keylen);
    561     memcpy(sess->key, sess_info->key, sess_info->keylen);
    562 
    563     lkcf->sess[index] = g_steal_pointer(&sess);
    564     *session_id = index;
    565 
    566     return VIRTIO_CRYPTO_OK;
    567 }
    568 
    569 static int cryptodev_lkcf_create_session(
    570     CryptoDevBackend *backend,
    571     CryptoDevBackendSessionInfo *sess_info,
    572     uint32_t queue_index,
    573     CryptoDevCompletionFunc cb,
    574     void *opaque)
    575 {
    576     CryptoDevBackendAsymSessionInfo *asym_sess_info;
    577     CryptoDevBackendLKCF *lkcf =
    578         CRYPTODEV_BACKEND_LKCF(backend);
    579     int ret;
    580 
    581     switch (sess_info->op_code) {
    582     case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
    583         asym_sess_info = &sess_info->u.asym_sess_info;
    584         ret = cryptodev_lkcf_create_asym_session(
    585             lkcf, asym_sess_info, &sess_info->session_id);
    586         break;
    587 
    588     default:
    589         ret = -VIRTIO_CRYPTO_NOTSUPP;
    590         error_report("Unsupported opcode: %" PRIu32 "",
    591                      sess_info->op_code);
    592         break;
    593     }
    594     if (cb) {
    595         cb(opaque, ret);
    596     }
    597     return 0;
    598 }
    599 
    600 static int cryptodev_lkcf_close_session(CryptoDevBackend *backend,
    601                                         uint64_t session_id,
    602                                         uint32_t queue_index,
    603                                         CryptoDevCompletionFunc cb,
    604                                         void *opaque)
    605 {
    606     CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend);
    607     CryptoDevBackendLKCFSession *session;
    608 
    609     assert(session_id < MAX_SESSIONS && lkcf->sess[session_id]);
    610     session = lkcf->sess[session_id];
    611     lkcf->sess[session_id] = NULL;
    612 
    613     g_free(session->key);
    614     g_free(session);
    615 
    616     if (cb) {
    617         cb(opaque, VIRTIO_CRYPTO_OK);
    618     }
    619     return 0;
    620 }
    621 
    622 static void cryptodev_lkcf_class_init(ObjectClass *oc, void *data)
    623 {
    624     CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
    625 
    626     bc->init = cryptodev_lkcf_init;
    627     bc->cleanup = cryptodev_lkcf_cleanup;
    628     bc->create_session = cryptodev_lkcf_create_session;
    629     bc->close_session = cryptodev_lkcf_close_session;
    630     bc->do_op = cryptodev_lkcf_operation;
    631 }
    632 
    633 static const TypeInfo cryptodev_builtin_info = {
    634     .name = TYPE_CRYPTODEV_BACKEND_LKCF,
    635     .parent = TYPE_CRYPTODEV_BACKEND,
    636     .class_init = cryptodev_lkcf_class_init,
    637     .instance_size = sizeof(CryptoDevBackendLKCF),
    638 };
    639 
    640 static void cryptodev_lkcf_register_types(void)
    641 {
    642     type_register_static(&cryptodev_builtin_info);
    643 }
    644 
    645 type_init(cryptodev_lkcf_register_types);