xref: /qemu/backends/cryptodev-lkcf.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 "system/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 
cryptodev_lkcf_handle_response(void * opaque)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 
cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions * opts,char * key_desc,size_t desc_len,Error ** errp)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_AK_CIPHER_ALGO_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_ALGO_PKCS1) {
143         snprintf(key_desc, desc_len, "enc=%s hash=%s",
144                  QCryptoRSAPaddingAlgo_str(rsa_opt->padding_alg),
145                  QCryptoHashAlgo_str(rsa_opt->hash_alg));
146 
147     } else {
148         snprintf(key_desc, desc_len, "enc=%s",
149                  QCryptoRSAPaddingAlgo_str(rsa_opt->padding_alg));
150     }
151     return 0;
152 }
153 
cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,int virtio_hash_alg,QCryptoAkCipherOptionsRSA * opt,Error ** errp)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_ALGO_PKCS1;
161 
162         switch (virtio_hash_alg) {
163         case VIRTIO_CRYPTO_RSA_MD5:
164             opt->hash_alg = QCRYPTO_HASH_ALGO_MD5;
165             break;
166 
167         case VIRTIO_CRYPTO_RSA_SHA1:
168             opt->hash_alg = QCRYPTO_HASH_ALGO_SHA1;
169             break;
170 
171         case VIRTIO_CRYPTO_RSA_SHA256:
172             opt->hash_alg = QCRYPTO_HASH_ALGO_SHA256;
173             break;
174 
175         case VIRTIO_CRYPTO_RSA_SHA512:
176             opt->hash_alg = QCRYPTO_HASH_ALGO_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_ALGO_RAW;
188         return 0;
189     }
190 
191     error_setg(errp, "Unsupported rsa padding algo: %u", virtio_padding_alg);
192     return -1;
193 }
194 
cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF * lkcf)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 
cryptodev_lkcf_init(CryptoDevBackend * backend,Error ** errp)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();
227     cc->info_str = g_strdup_printf("cryptodev-lkcf0");
228     cc->queue_index = 0;
229     cc->type = QCRYPTODEV_BACKEND_TYPE_LKCF;
230     backend->conf.peers.ccs[0] = cc;
231 
232     backend->conf.crypto_services =
233         1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_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 
cryptodev_lkcf_cleanup(CryptoDevBackend * backend,Error ** errp)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 
cryptodev_lkcf_execute_task(CryptoDevLKCFTask * task)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_AK_CIPHER_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             status = -VIRTIO_CRYPTO_ERR;
334             goto out;
335         } else {
336             key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key",
337                              p8info, p8info_len, KCTL_KEY_RING);
338         }
339     }
340 
341     if (key_id < 0) {
342         if (!qcrypto_akcipher_supports(&session->akcipher_opts)) {
343             status = -VIRTIO_CRYPTO_NOTSUPP;
344             goto out;
345         }
346         akcipher = qcrypto_akcipher_new(&session->akcipher_opts,
347                                         session->keytype,
348                                         session->key, session->keylen,
349                                         &local_error);
350         if (!akcipher) {
351             error_report_err(local_error);
352             status = -VIRTIO_CRYPTO_ERR;
353             goto out;
354         }
355     }
356 
357     asym_op_info = task->op_info->u.asym_op_info;
358     switch (op_code) {
359     case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
360         if (key_id >= 0) {
361             ret = keyctl_pkey_encrypt(key_id, op_desc,
362                 asym_op_info->src, asym_op_info->src_len,
363                 asym_op_info->dst, asym_op_info->dst_len);
364         } else {
365             ret = qcrypto_akcipher_encrypt(akcipher,
366                 asym_op_info->src, asym_op_info->src_len,
367                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
368         }
369         break;
370 
371     case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
372         if (key_id >= 0) {
373             ret = keyctl_pkey_decrypt(key_id, op_desc,
374                 asym_op_info->src, asym_op_info->src_len,
375                 asym_op_info->dst, asym_op_info->dst_len);
376         } else {
377             ret = qcrypto_akcipher_decrypt(akcipher,
378                 asym_op_info->src, asym_op_info->src_len,
379                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
380         }
381         break;
382 
383     case VIRTIO_CRYPTO_AKCIPHER_SIGN:
384         if (key_id >= 0) {
385             ret = keyctl_pkey_sign(key_id, op_desc,
386                 asym_op_info->src, asym_op_info->src_len,
387                 asym_op_info->dst, asym_op_info->dst_len);
388         } else {
389             ret = qcrypto_akcipher_sign(akcipher,
390                 asym_op_info->src, asym_op_info->src_len,
391                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
392         }
393         break;
394 
395     case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
396         if (key_id >= 0) {
397             ret = keyctl_pkey_verify(key_id, op_desc,
398                 asym_op_info->src, asym_op_info->src_len,
399                 asym_op_info->dst, asym_op_info->dst_len);
400         } else {
401             ret = qcrypto_akcipher_verify(akcipher,
402                 asym_op_info->src, asym_op_info->src_len,
403                 asym_op_info->dst, asym_op_info->dst_len, &local_error);
404         }
405         break;
406 
407     default:
408         error_setg(&local_error, "Unknown opcode: %u", op_code);
409         status = -VIRTIO_CRYPTO_ERR;
410         goto out;
411     }
412 
413     if (ret < 0) {
414         if (!local_error) {
415             if (errno != EKEYREJECTED) {
416                 error_report("Failed do operation with keyctl: %d", errno);
417             }
418         } else {
419             error_report_err(local_error);
420         }
421         status = op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY ?
422             -VIRTIO_CRYPTO_KEY_REJECTED : -VIRTIO_CRYPTO_ERR;
423     } else {
424         status = VIRTIO_CRYPTO_OK;
425         asym_op_info->dst_len = ret;
426     }
427 
428 out:
429     if (key_id >= 0) {
430         keyctl_unlink(key_id, KCTL_KEY_RING);
431     }
432     task->status = status;
433 
434     qemu_mutex_lock(&task->lkcf->rsp_mutex);
435     if (QSIMPLEQ_EMPTY(&task->lkcf->responses)) {
436         kick = true;
437     }
438     QSIMPLEQ_INSERT_TAIL(&task->lkcf->responses, task, queue);
439     qemu_mutex_unlock(&task->lkcf->rsp_mutex);
440 
441     if (kick) {
442         eventfd_write(task->lkcf->eventfd, 1);
443     }
444 }
445 
cryptodev_lkcf_worker(void * arg)446 static void *cryptodev_lkcf_worker(void *arg)
447 {
448     CryptoDevBackendLKCF *backend = (CryptoDevBackendLKCF *)arg;
449     CryptoDevLKCFTask *task;
450 
451     for (;;) {
452         task = NULL;
453         qemu_mutex_lock(&backend->mutex);
454         while (backend->running && QSIMPLEQ_EMPTY(&backend->requests)) {
455             qemu_cond_wait(&backend->cond, &backend->mutex);
456         }
457         if (backend->running) {
458             task = QSIMPLEQ_FIRST(&backend->requests);
459             QSIMPLEQ_REMOVE_HEAD(&backend->requests, queue);
460         }
461         qemu_mutex_unlock(&backend->mutex);
462 
463         /* stopped */
464         if (!task) {
465             break;
466         }
467         cryptodev_lkcf_execute_task(task);
468    }
469 
470    return NULL;
471 }
472 
cryptodev_lkcf_operation(CryptoDevBackend * backend,CryptoDevBackendOpInfo * op_info)473 static int cryptodev_lkcf_operation(
474     CryptoDevBackend *backend,
475     CryptoDevBackendOpInfo *op_info)
476 {
477     CryptoDevBackendLKCF *lkcf =
478         CRYPTODEV_BACKEND_LKCF(backend);
479     CryptoDevBackendLKCFSession *sess;
480     QCryptodevBackendAlgoType 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 != QCRYPTODEV_BACKEND_ALGO_TYPE_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 = op_info->cb;
499     task->opaque = op_info->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 
cryptodev_lkcf_create_asym_session(CryptoDevBackendLKCF * lkcf,CryptoDevBackendAsymSessionInfo * sess_info,uint64_t * session_id)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_AK_CIPHER_ALGO_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_AK_CIPHER_KEY_TYPE_PUBLIC;
541         break;
542 
543     case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
544         sess->keytype = QCRYPTO_AK_CIPHER_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 
cryptodev_lkcf_create_session(CryptoDevBackend * backend,CryptoDevBackendSessionInfo * sess_info,uint32_t queue_index,CryptoDevCompletionFunc cb,void * opaque)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 
cryptodev_lkcf_close_session(CryptoDevBackend * backend,uint64_t session_id,uint32_t queue_index,CryptoDevCompletionFunc cb,void * opaque)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 
cryptodev_lkcf_class_init(ObjectClass * oc,const void * data)622 static void cryptodev_lkcf_class_init(ObjectClass *oc, const 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 
cryptodev_lkcf_register_types(void)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);
646