139fff6f3SLei He /* 239fff6f3SLei He * QEMU Cryptodev backend for QEMU cipher APIs 339fff6f3SLei He * 439fff6f3SLei He * Copyright (c) 2022 Bytedance.Inc 539fff6f3SLei He * 639fff6f3SLei He * Authors: 739fff6f3SLei He * lei he <helei.sig11@bytedance.com> 839fff6f3SLei He * 939fff6f3SLei He * This library is free software; you can redistribute it and/or 1039fff6f3SLei He * modify it under the terms of the GNU Lesser General Public 1139fff6f3SLei He * License as published by the Free Software Foundation; either 1239fff6f3SLei He * version 2.1 of the License, or (at your option) any later version. 1339fff6f3SLei He * 1439fff6f3SLei He * This library is distributed in the hope that it will be useful, 1539fff6f3SLei He * but WITHOUT ANY WARRANTY; without even the implied warranty of 1639fff6f3SLei He * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1739fff6f3SLei He * Lesser General Public License for more details. 1839fff6f3SLei He * 1939fff6f3SLei He * You should have received a copy of the GNU Lesser General Public 2039fff6f3SLei He * License along with this library; if not, see <http://www.gnu.org/licenses/>. 2139fff6f3SLei He * 2239fff6f3SLei He */ 2339fff6f3SLei He 2439fff6f3SLei He #include "qemu/osdep.h" 2539fff6f3SLei He #include "crypto/cipher.h" 2639fff6f3SLei He #include "crypto/akcipher.h" 2739fff6f3SLei He #include "qapi/error.h" 2839fff6f3SLei He #include "qemu/main-loop.h" 2939fff6f3SLei He #include "qemu/thread.h" 3039fff6f3SLei He #include "qemu/error-report.h" 3139fff6f3SLei He #include "qemu/queue.h" 3239fff6f3SLei He #include "qom/object.h" 3339fff6f3SLei He #include "sysemu/cryptodev.h" 3439fff6f3SLei He #include "standard-headers/linux/virtio_crypto.h" 3539fff6f3SLei He 3639fff6f3SLei He #include <keyutils.h> 3739fff6f3SLei He #include <sys/eventfd.h> 3839fff6f3SLei He 3939fff6f3SLei He /** 4039fff6f3SLei He * @TYPE_CRYPTODEV_BACKEND_LKCF: 4139fff6f3SLei He * name of backend that uses linux kernel crypto framework 4239fff6f3SLei He */ 4339fff6f3SLei He #define TYPE_CRYPTODEV_BACKEND_LKCF "cryptodev-backend-lkcf" 4439fff6f3SLei He 4539fff6f3SLei He OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendLKCF, CRYPTODEV_BACKEND_LKCF) 4639fff6f3SLei He 4739fff6f3SLei He #define INVALID_KEY_ID -1 4839fff6f3SLei He #define MAX_SESSIONS 256 4939fff6f3SLei He #define NR_WORKER_THREAD 64 5039fff6f3SLei He 5139fff6f3SLei He #define KCTL_KEY_TYPE_PKEY "asymmetric" 5239fff6f3SLei He /** 5339fff6f3SLei He * Here the key is uploaded to the thread-keyring of worker thread, at least 5439fff6f3SLei He * util linux-6.0: 5539fff6f3SLei He * 1. process keyring seems to behave unexpectedly if main-thread does not 5639fff6f3SLei He * create the keyring before creating any other thread. 5739fff6f3SLei He * 2. at present, the guest kernel never perform multiple operations on a 5839fff6f3SLei He * session. 5939fff6f3SLei He * 3. it can reduce the load of the main-loop because the key passed by the 6039fff6f3SLei He * guest kernel has been already checked. 6139fff6f3SLei He */ 6239fff6f3SLei He #define KCTL_KEY_RING KEY_SPEC_THREAD_KEYRING 6339fff6f3SLei He 6439fff6f3SLei He typedef struct CryptoDevBackendLKCFSession { 6539fff6f3SLei He uint8_t *key; 6639fff6f3SLei He size_t keylen; 6739fff6f3SLei He QCryptoAkCipherKeyType keytype; 6839fff6f3SLei He QCryptoAkCipherOptions akcipher_opts; 6939fff6f3SLei He } CryptoDevBackendLKCFSession; 7039fff6f3SLei He 7139fff6f3SLei He typedef struct CryptoDevBackendLKCF CryptoDevBackendLKCF; 7239fff6f3SLei He typedef struct CryptoDevLKCFTask CryptoDevLKCFTask; 7339fff6f3SLei He struct CryptoDevLKCFTask { 7439fff6f3SLei He CryptoDevBackendLKCFSession *sess; 7539fff6f3SLei He CryptoDevBackendOpInfo *op_info; 7639fff6f3SLei He CryptoDevCompletionFunc cb; 7739fff6f3SLei He void *opaque; 7839fff6f3SLei He int status; 7939fff6f3SLei He CryptoDevBackendLKCF *lkcf; 8039fff6f3SLei He QSIMPLEQ_ENTRY(CryptoDevLKCFTask) queue; 8139fff6f3SLei He }; 8239fff6f3SLei He 8339fff6f3SLei He typedef struct CryptoDevBackendLKCF { 8439fff6f3SLei He CryptoDevBackend parent_obj; 8539fff6f3SLei He CryptoDevBackendLKCFSession *sess[MAX_SESSIONS]; 8639fff6f3SLei He QSIMPLEQ_HEAD(, CryptoDevLKCFTask) requests; 8739fff6f3SLei He QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses; 8839fff6f3SLei He QemuMutex mutex; 8939fff6f3SLei He QemuCond cond; 9039fff6f3SLei He QemuMutex rsp_mutex; 9139fff6f3SLei He 9239fff6f3SLei He /** 9339fff6f3SLei He * There is no async interface for asymmetric keys like AF_ALG sockets, 9439fff6f3SLei He * we don't seem to have better way than create a lots of thread. 9539fff6f3SLei He */ 9639fff6f3SLei He QemuThread worker_threads[NR_WORKER_THREAD]; 9739fff6f3SLei He bool running; 9839fff6f3SLei He int eventfd; 9939fff6f3SLei He } CryptoDevBackendLKCF; 10039fff6f3SLei He 10139fff6f3SLei He static void *cryptodev_lkcf_worker(void *arg); 10239fff6f3SLei He static int cryptodev_lkcf_close_session(CryptoDevBackend *backend, 10339fff6f3SLei He uint64_t session_id, 10439fff6f3SLei He uint32_t queue_index, 10539fff6f3SLei He CryptoDevCompletionFunc cb, 10639fff6f3SLei He void *opaque); 10739fff6f3SLei He 10839fff6f3SLei He static void cryptodev_lkcf_handle_response(void *opaque) 10939fff6f3SLei He { 11039fff6f3SLei He CryptoDevBackendLKCF *lkcf = (CryptoDevBackendLKCF *)opaque; 11139fff6f3SLei He QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses; 11239fff6f3SLei He CryptoDevLKCFTask *task, *next; 11339fff6f3SLei He eventfd_t nevent; 11439fff6f3SLei He 11539fff6f3SLei He QSIMPLEQ_INIT(&responses); 11639fff6f3SLei He eventfd_read(lkcf->eventfd, &nevent); 11739fff6f3SLei He 11839fff6f3SLei He qemu_mutex_lock(&lkcf->rsp_mutex); 11939fff6f3SLei He QSIMPLEQ_PREPEND(&responses, &lkcf->responses); 12039fff6f3SLei He qemu_mutex_unlock(&lkcf->rsp_mutex); 12139fff6f3SLei He 12239fff6f3SLei He QSIMPLEQ_FOREACH_SAFE(task, &responses, queue, next) { 12339fff6f3SLei He if (task->cb) { 12439fff6f3SLei He task->cb(task->opaque, task->status); 12539fff6f3SLei He } 12639fff6f3SLei He g_free(task); 12739fff6f3SLei He } 12839fff6f3SLei He } 12939fff6f3SLei He 13039fff6f3SLei He static int cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions *opts, 13139fff6f3SLei He char *key_desc, 13239fff6f3SLei He size_t desc_len, 13339fff6f3SLei He Error **errp) 13439fff6f3SLei He { 13539fff6f3SLei He QCryptoAkCipherOptionsRSA *rsa_opt; 13639fff6f3SLei He if (opts->alg != QCRYPTO_AKCIPHER_ALG_RSA) { 13739fff6f3SLei He error_setg(errp, "Unsupported alg: %u", opts->alg); 13839fff6f3SLei He return -1; 13939fff6f3SLei He } 14039fff6f3SLei He 14139fff6f3SLei He rsa_opt = &opts->u.rsa; 14239fff6f3SLei He if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALG_PKCS1) { 14339fff6f3SLei He snprintf(key_desc, desc_len, "enc=%s hash=%s", 14439fff6f3SLei He QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg), 14539fff6f3SLei He QCryptoHashAlgorithm_str(rsa_opt->hash_alg)); 14639fff6f3SLei He 14739fff6f3SLei He } else { 14839fff6f3SLei He snprintf(key_desc, desc_len, "enc=%s", 14939fff6f3SLei He QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg)); 15039fff6f3SLei He } 15139fff6f3SLei He return 0; 15239fff6f3SLei He } 15339fff6f3SLei He 15439fff6f3SLei He static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg, 15539fff6f3SLei He int virtio_hash_alg, 15639fff6f3SLei He QCryptoAkCipherOptionsRSA *opt, 15739fff6f3SLei He Error **errp) 15839fff6f3SLei He { 15939fff6f3SLei He if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) { 16039fff6f3SLei He opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1; 16139fff6f3SLei He 16239fff6f3SLei He switch (virtio_hash_alg) { 16339fff6f3SLei He case VIRTIO_CRYPTO_RSA_MD5: 16439fff6f3SLei He opt->hash_alg = QCRYPTO_HASH_ALG_MD5; 16539fff6f3SLei He break; 16639fff6f3SLei He 16739fff6f3SLei He case VIRTIO_CRYPTO_RSA_SHA1: 16839fff6f3SLei He opt->hash_alg = QCRYPTO_HASH_ALG_SHA1; 16939fff6f3SLei He break; 17039fff6f3SLei He 17139fff6f3SLei He case VIRTIO_CRYPTO_RSA_SHA256: 17239fff6f3SLei He opt->hash_alg = QCRYPTO_HASH_ALG_SHA256; 17339fff6f3SLei He break; 17439fff6f3SLei He 17539fff6f3SLei He case VIRTIO_CRYPTO_RSA_SHA512: 17639fff6f3SLei He opt->hash_alg = QCRYPTO_HASH_ALG_SHA512; 17739fff6f3SLei He break; 17839fff6f3SLei He 17939fff6f3SLei He default: 18039fff6f3SLei He error_setg(errp, "Unsupported rsa hash algo: %d", virtio_hash_alg); 18139fff6f3SLei He return -1; 18239fff6f3SLei He } 18339fff6f3SLei He return 0; 18439fff6f3SLei He } 18539fff6f3SLei He 18639fff6f3SLei He if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_RAW_PADDING) { 18739fff6f3SLei He opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW; 18839fff6f3SLei He return 0; 18939fff6f3SLei He } 19039fff6f3SLei He 19139fff6f3SLei He error_setg(errp, "Unsupported rsa padding algo: %u", virtio_padding_alg); 19239fff6f3SLei He return -1; 19339fff6f3SLei He } 19439fff6f3SLei He 19539fff6f3SLei He static int cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF *lkcf) 19639fff6f3SLei He { 19739fff6f3SLei He size_t i; 19839fff6f3SLei He 19939fff6f3SLei He for (i = 0; i < MAX_SESSIONS; i++) { 20039fff6f3SLei He if (lkcf->sess[i] == NULL) { 20139fff6f3SLei He return i; 20239fff6f3SLei He } 20339fff6f3SLei He } 20439fff6f3SLei He return -1; 20539fff6f3SLei He } 20639fff6f3SLei He 20739fff6f3SLei He static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp) 20839fff6f3SLei He { 20939fff6f3SLei He /* Only support one queue */ 21039fff6f3SLei He int queues = backend->conf.peers.queues, i; 21139fff6f3SLei He CryptoDevBackendClient *cc; 21239fff6f3SLei He CryptoDevBackendLKCF *lkcf = 21339fff6f3SLei He CRYPTODEV_BACKEND_LKCF(backend); 21439fff6f3SLei He 21539fff6f3SLei He if (queues != 1) { 21639fff6f3SLei He error_setg(errp, 21739fff6f3SLei He "Only support one queue in cryptodev-builtin backend"); 21839fff6f3SLei He return; 21939fff6f3SLei He } 22039fff6f3SLei He lkcf->eventfd = eventfd(0, 0); 22139fff6f3SLei He if (lkcf->eventfd < 0) { 22239fff6f3SLei He error_setg(errp, "Failed to create eventfd: %d", errno); 22339fff6f3SLei He return; 22439fff6f3SLei He } 22539fff6f3SLei He 2263f478371Szhenwei pi cc = cryptodev_backend_new_client(); 22739fff6f3SLei He cc->info_str = g_strdup_printf("cryptodev-lkcf0"); 22839fff6f3SLei He cc->queue_index = 0; 22914c9fd16Szhenwei pi cc->type = QCRYPTODEV_BACKEND_TYPE_LKCF; 23039fff6f3SLei He backend->conf.peers.ccs[0] = cc; 23139fff6f3SLei He 23239fff6f3SLei He backend->conf.crypto_services = 233bc304a64Szhenwei pi 1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER; 23439fff6f3SLei He backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA; 23539fff6f3SLei He lkcf->running = true; 23639fff6f3SLei He 23739fff6f3SLei He QSIMPLEQ_INIT(&lkcf->requests); 23839fff6f3SLei He QSIMPLEQ_INIT(&lkcf->responses); 23939fff6f3SLei He qemu_mutex_init(&lkcf->mutex); 24039fff6f3SLei He qemu_mutex_init(&lkcf->rsp_mutex); 24139fff6f3SLei He qemu_cond_init(&lkcf->cond); 24239fff6f3SLei He for (i = 0; i < NR_WORKER_THREAD; i++) { 24339fff6f3SLei He qemu_thread_create(&lkcf->worker_threads[i], "lkcf-worker", 24439fff6f3SLei He cryptodev_lkcf_worker, lkcf, 0); 24539fff6f3SLei He } 24639fff6f3SLei He qemu_set_fd_handler( 24739fff6f3SLei He lkcf->eventfd, cryptodev_lkcf_handle_response, NULL, lkcf); 24839fff6f3SLei He cryptodev_backend_set_ready(backend, true); 24939fff6f3SLei He } 25039fff6f3SLei He 25139fff6f3SLei He static void cryptodev_lkcf_cleanup(CryptoDevBackend *backend, Error **errp) 25239fff6f3SLei He { 25339fff6f3SLei He CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend); 25439fff6f3SLei He size_t i; 25539fff6f3SLei He int queues = backend->conf.peers.queues; 25639fff6f3SLei He CryptoDevBackendClient *cc; 25739fff6f3SLei He CryptoDevLKCFTask *task, *next; 25839fff6f3SLei He 25939fff6f3SLei He qemu_mutex_lock(&lkcf->mutex); 26039fff6f3SLei He lkcf->running = false; 26139fff6f3SLei He qemu_mutex_unlock(&lkcf->mutex); 26239fff6f3SLei He qemu_cond_broadcast(&lkcf->cond); 26339fff6f3SLei He 26439fff6f3SLei He close(lkcf->eventfd); 26539fff6f3SLei He for (i = 0; i < NR_WORKER_THREAD; i++) { 26639fff6f3SLei He qemu_thread_join(&lkcf->worker_threads[i]); 26739fff6f3SLei He } 26839fff6f3SLei He 26939fff6f3SLei He QSIMPLEQ_FOREACH_SAFE(task, &lkcf->requests, queue, next) { 27039fff6f3SLei He if (task->cb) { 27139fff6f3SLei He task->cb(task->opaque, task->status); 27239fff6f3SLei He } 27339fff6f3SLei He g_free(task); 27439fff6f3SLei He } 27539fff6f3SLei He 27639fff6f3SLei He QSIMPLEQ_FOREACH_SAFE(task, &lkcf->responses, queue, next) { 27739fff6f3SLei He if (task->cb) { 27839fff6f3SLei He task->cb(task->opaque, task->status); 27939fff6f3SLei He } 28039fff6f3SLei He g_free(task); 28139fff6f3SLei He } 28239fff6f3SLei He 28339fff6f3SLei He qemu_mutex_destroy(&lkcf->mutex); 28439fff6f3SLei He qemu_cond_destroy(&lkcf->cond); 28539fff6f3SLei He qemu_mutex_destroy(&lkcf->rsp_mutex); 28639fff6f3SLei He 28739fff6f3SLei He for (i = 0; i < MAX_SESSIONS; i++) { 28839fff6f3SLei He if (lkcf->sess[i] != NULL) { 28939fff6f3SLei He cryptodev_lkcf_close_session(backend, i, 0, NULL, NULL); 29039fff6f3SLei He } 29139fff6f3SLei He } 29239fff6f3SLei He 29339fff6f3SLei He for (i = 0; i < queues; i++) { 29439fff6f3SLei He cc = backend->conf.peers.ccs[i]; 29539fff6f3SLei He if (cc) { 29639fff6f3SLei He cryptodev_backend_free_client(cc); 29739fff6f3SLei He backend->conf.peers.ccs[i] = NULL; 29839fff6f3SLei He } 29939fff6f3SLei He } 30039fff6f3SLei He 30139fff6f3SLei He cryptodev_backend_set_ready(backend, false); 30239fff6f3SLei He } 30339fff6f3SLei He 30439fff6f3SLei He static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task) 30539fff6f3SLei He { 30639fff6f3SLei He CryptoDevBackendLKCFSession *session = task->sess; 30739fff6f3SLei He CryptoDevBackendAsymOpInfo *asym_op_info; 30839fff6f3SLei He bool kick = false; 30939fff6f3SLei He int ret, status, op_code = task->op_info->op_code; 31039fff6f3SLei He size_t p8info_len; 31139fff6f3SLei He g_autofree uint8_t *p8info = NULL; 31239fff6f3SLei He Error *local_error = NULL; 31339fff6f3SLei He key_serial_t key_id = INVALID_KEY_ID; 31439fff6f3SLei He char op_desc[64]; 31539fff6f3SLei He g_autoptr(QCryptoAkCipher) akcipher = NULL; 31639fff6f3SLei He 31739fff6f3SLei He /** 31839fff6f3SLei He * We only offload private key session: 31939fff6f3SLei He * 1. currently, the Linux kernel can only accept public key wrapped 32039fff6f3SLei He * with X.509 certificates, but unfortunately the cost of making a 32139fff6f3SLei He * ceritificate with public key is too expensive. 32239fff6f3SLei He * 2. generally, public key related compution is fast, just compute it with 32339fff6f3SLei He * thread-pool. 32439fff6f3SLei He */ 325*5f4059efSMarkus Armbruster if (session->keytype == QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE) { 32639fff6f3SLei He if (qcrypto_akcipher_export_p8info(&session->akcipher_opts, 32739fff6f3SLei He session->key, session->keylen, 32839fff6f3SLei He &p8info, &p8info_len, 32939fff6f3SLei He &local_error) != 0 || 33039fff6f3SLei He cryptodev_lkcf_set_op_desc(&session->akcipher_opts, op_desc, 33139fff6f3SLei He sizeof(op_desc), &local_error) != 0) { 33239fff6f3SLei He error_report_err(local_error); 33339fff6f3SLei He } else { 33439fff6f3SLei He key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key", 33539fff6f3SLei He p8info, p8info_len, KCTL_KEY_RING); 33639fff6f3SLei He } 33739fff6f3SLei He } 33839fff6f3SLei He 33939fff6f3SLei He if (key_id < 0) { 34039fff6f3SLei He if (!qcrypto_akcipher_supports(&session->akcipher_opts)) { 34139fff6f3SLei He status = -VIRTIO_CRYPTO_NOTSUPP; 34239fff6f3SLei He goto out; 34339fff6f3SLei He } 34439fff6f3SLei He akcipher = qcrypto_akcipher_new(&session->akcipher_opts, 34539fff6f3SLei He session->keytype, 34639fff6f3SLei He session->key, session->keylen, 34739fff6f3SLei He &local_error); 34839fff6f3SLei He if (!akcipher) { 34939fff6f3SLei He status = -VIRTIO_CRYPTO_ERR; 35039fff6f3SLei He goto out; 35139fff6f3SLei He } 35239fff6f3SLei He } 35339fff6f3SLei He 35439fff6f3SLei He asym_op_info = task->op_info->u.asym_op_info; 35539fff6f3SLei He switch (op_code) { 35639fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: 35739fff6f3SLei He if (key_id >= 0) { 35839fff6f3SLei He ret = keyctl_pkey_encrypt(key_id, op_desc, 35939fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 36039fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len); 36139fff6f3SLei He } else { 36239fff6f3SLei He ret = qcrypto_akcipher_encrypt(akcipher, 36339fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 36439fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len, &local_error); 36539fff6f3SLei He } 36639fff6f3SLei He break; 36739fff6f3SLei He 36839fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: 36939fff6f3SLei He if (key_id >= 0) { 37039fff6f3SLei He ret = keyctl_pkey_decrypt(key_id, op_desc, 37139fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 37239fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len); 37339fff6f3SLei He } else { 37439fff6f3SLei He ret = qcrypto_akcipher_decrypt(akcipher, 37539fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 37639fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len, &local_error); 37739fff6f3SLei He } 37839fff6f3SLei He break; 37939fff6f3SLei He 38039fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_SIGN: 38139fff6f3SLei He if (key_id >= 0) { 38239fff6f3SLei He ret = keyctl_pkey_sign(key_id, op_desc, 38339fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 38439fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len); 38539fff6f3SLei He } else { 38639fff6f3SLei He ret = qcrypto_akcipher_sign(akcipher, 38739fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 38839fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len, &local_error); 38939fff6f3SLei He } 39039fff6f3SLei He break; 39139fff6f3SLei He 39239fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_VERIFY: 39339fff6f3SLei He if (key_id >= 0) { 39439fff6f3SLei He ret = keyctl_pkey_verify(key_id, op_desc, 39539fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 39639fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len); 39739fff6f3SLei He } else { 39839fff6f3SLei He ret = qcrypto_akcipher_verify(akcipher, 39939fff6f3SLei He asym_op_info->src, asym_op_info->src_len, 40039fff6f3SLei He asym_op_info->dst, asym_op_info->dst_len, &local_error); 40139fff6f3SLei He } 40239fff6f3SLei He break; 40339fff6f3SLei He 40439fff6f3SLei He default: 40539fff6f3SLei He error_setg(&local_error, "Unknown opcode: %u", op_code); 40639fff6f3SLei He status = -VIRTIO_CRYPTO_ERR; 40739fff6f3SLei He goto out; 40839fff6f3SLei He } 40939fff6f3SLei He 41039fff6f3SLei He if (ret < 0) { 41139fff6f3SLei He if (!local_error) { 41239fff6f3SLei He if (errno != EKEYREJECTED) { 41339fff6f3SLei He error_report("Failed do operation with keyctl: %d", errno); 41439fff6f3SLei He } 41539fff6f3SLei He } else { 41639fff6f3SLei He error_report_err(local_error); 41739fff6f3SLei He } 41839fff6f3SLei He status = op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY ? 41939fff6f3SLei He -VIRTIO_CRYPTO_KEY_REJECTED : -VIRTIO_CRYPTO_ERR; 42039fff6f3SLei He } else { 42139fff6f3SLei He status = VIRTIO_CRYPTO_OK; 42239fff6f3SLei He asym_op_info->dst_len = ret; 42339fff6f3SLei He } 42439fff6f3SLei He 42539fff6f3SLei He out: 42639fff6f3SLei He if (key_id >= 0) { 42739fff6f3SLei He keyctl_unlink(key_id, KCTL_KEY_RING); 42839fff6f3SLei He } 42939fff6f3SLei He task->status = status; 43039fff6f3SLei He 43139fff6f3SLei He qemu_mutex_lock(&task->lkcf->rsp_mutex); 43239fff6f3SLei He if (QSIMPLEQ_EMPTY(&task->lkcf->responses)) { 43339fff6f3SLei He kick = true; 43439fff6f3SLei He } 43539fff6f3SLei He QSIMPLEQ_INSERT_TAIL(&task->lkcf->responses, task, queue); 43639fff6f3SLei He qemu_mutex_unlock(&task->lkcf->rsp_mutex); 43739fff6f3SLei He 43839fff6f3SLei He if (kick) { 43939fff6f3SLei He eventfd_write(task->lkcf->eventfd, 1); 44039fff6f3SLei He } 44139fff6f3SLei He } 44239fff6f3SLei He 44339fff6f3SLei He static void *cryptodev_lkcf_worker(void *arg) 44439fff6f3SLei He { 44539fff6f3SLei He CryptoDevBackendLKCF *backend = (CryptoDevBackendLKCF *)arg; 44639fff6f3SLei He CryptoDevLKCFTask *task; 44739fff6f3SLei He 44839fff6f3SLei He for (;;) { 44939fff6f3SLei He task = NULL; 45039fff6f3SLei He qemu_mutex_lock(&backend->mutex); 45139fff6f3SLei He while (backend->running && QSIMPLEQ_EMPTY(&backend->requests)) { 45239fff6f3SLei He qemu_cond_wait(&backend->cond, &backend->mutex); 45339fff6f3SLei He } 45439fff6f3SLei He if (backend->running) { 45539fff6f3SLei He task = QSIMPLEQ_FIRST(&backend->requests); 45639fff6f3SLei He QSIMPLEQ_REMOVE_HEAD(&backend->requests, queue); 45739fff6f3SLei He } 45839fff6f3SLei He qemu_mutex_unlock(&backend->mutex); 45939fff6f3SLei He 46039fff6f3SLei He /* stopped */ 46139fff6f3SLei He if (!task) { 46239fff6f3SLei He break; 46339fff6f3SLei He } 46439fff6f3SLei He cryptodev_lkcf_execute_task(task); 46539fff6f3SLei He } 46639fff6f3SLei He 46739fff6f3SLei He return NULL; 46839fff6f3SLei He } 46939fff6f3SLei He 47039fff6f3SLei He static int cryptodev_lkcf_operation( 47139fff6f3SLei He CryptoDevBackend *backend, 4722cb06927Szhenwei pi CryptoDevBackendOpInfo *op_info) 47339fff6f3SLei He { 47439fff6f3SLei He CryptoDevBackendLKCF *lkcf = 47539fff6f3SLei He CRYPTODEV_BACKEND_LKCF(backend); 47639fff6f3SLei He CryptoDevBackendLKCFSession *sess; 477999c789fSzhenwei pi QCryptodevBackendAlgType algtype = op_info->algtype; 47839fff6f3SLei He CryptoDevLKCFTask *task; 47939fff6f3SLei He 48039fff6f3SLei He if (op_info->session_id >= MAX_SESSIONS || 48139fff6f3SLei He lkcf->sess[op_info->session_id] == NULL) { 48239fff6f3SLei He error_report("Cannot find a valid session id: %" PRIu64 "", 48339fff6f3SLei He op_info->session_id); 48439fff6f3SLei He return -VIRTIO_CRYPTO_INVSESS; 48539fff6f3SLei He } 48639fff6f3SLei He 48739fff6f3SLei He sess = lkcf->sess[op_info->session_id]; 488999c789fSzhenwei pi if (algtype != QCRYPTODEV_BACKEND_ALG_ASYM) { 48939fff6f3SLei He error_report("algtype not supported: %u", algtype); 49039fff6f3SLei He return -VIRTIO_CRYPTO_NOTSUPP; 49139fff6f3SLei He } 49239fff6f3SLei He 49339fff6f3SLei He task = g_new0(CryptoDevLKCFTask, 1); 49439fff6f3SLei He task->op_info = op_info; 4952cb06927Szhenwei pi task->cb = op_info->cb; 4962cb06927Szhenwei pi task->opaque = op_info->opaque; 49739fff6f3SLei He task->sess = sess; 49839fff6f3SLei He task->lkcf = lkcf; 49939fff6f3SLei He task->status = -VIRTIO_CRYPTO_ERR; 50039fff6f3SLei He 50139fff6f3SLei He qemu_mutex_lock(&lkcf->mutex); 50239fff6f3SLei He QSIMPLEQ_INSERT_TAIL(&lkcf->requests, task, queue); 50339fff6f3SLei He qemu_mutex_unlock(&lkcf->mutex); 50439fff6f3SLei He qemu_cond_signal(&lkcf->cond); 50539fff6f3SLei He 50639fff6f3SLei He return VIRTIO_CRYPTO_OK; 50739fff6f3SLei He } 50839fff6f3SLei He 50939fff6f3SLei He static int cryptodev_lkcf_create_asym_session( 51039fff6f3SLei He CryptoDevBackendLKCF *lkcf, 51139fff6f3SLei He CryptoDevBackendAsymSessionInfo *sess_info, 51239fff6f3SLei He uint64_t *session_id) 51339fff6f3SLei He { 51439fff6f3SLei He Error *local_error = NULL; 51539fff6f3SLei He int index; 51639fff6f3SLei He g_autofree CryptoDevBackendLKCFSession *sess = 51739fff6f3SLei He g_new0(CryptoDevBackendLKCFSession, 1); 51839fff6f3SLei He 51939fff6f3SLei He switch (sess_info->algo) { 52039fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_RSA: 52139fff6f3SLei He sess->akcipher_opts.alg = QCRYPTO_AKCIPHER_ALG_RSA; 52239fff6f3SLei He if (cryptodev_lkcf_set_rsa_opt( 52339fff6f3SLei He sess_info->u.rsa.padding_algo, sess_info->u.rsa.hash_algo, 52439fff6f3SLei He &sess->akcipher_opts.u.rsa, &local_error) != 0) { 52539fff6f3SLei He error_report_err(local_error); 52639fff6f3SLei He return -VIRTIO_CRYPTO_ERR; 52739fff6f3SLei He } 52839fff6f3SLei He break; 52939fff6f3SLei He 53039fff6f3SLei He default: 53139fff6f3SLei He error_report("Unsupported asym alg %u", sess_info->algo); 53239fff6f3SLei He return -VIRTIO_CRYPTO_NOTSUPP; 53339fff6f3SLei He } 53439fff6f3SLei He 53539fff6f3SLei He switch (sess_info->keytype) { 53639fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: 537*5f4059efSMarkus Armbruster sess->keytype = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC; 53839fff6f3SLei He break; 53939fff6f3SLei He 54039fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: 541*5f4059efSMarkus Armbruster sess->keytype = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE; 54239fff6f3SLei He break; 54339fff6f3SLei He 54439fff6f3SLei He default: 54539fff6f3SLei He error_report("Unknown akcipher keytype: %u", sess_info->keytype); 54639fff6f3SLei He return -VIRTIO_CRYPTO_ERR; 54739fff6f3SLei He } 54839fff6f3SLei He 54939fff6f3SLei He index = cryptodev_lkcf_get_unused_session_index(lkcf); 55039fff6f3SLei He if (index < 0) { 55139fff6f3SLei He error_report("Total number of sessions created exceeds %u", 55239fff6f3SLei He MAX_SESSIONS); 55339fff6f3SLei He return -VIRTIO_CRYPTO_ERR; 55439fff6f3SLei He } 55539fff6f3SLei He 55639fff6f3SLei He sess->keylen = sess_info->keylen; 55739fff6f3SLei He sess->key = g_malloc(sess_info->keylen); 55839fff6f3SLei He memcpy(sess->key, sess_info->key, sess_info->keylen); 55939fff6f3SLei He 56039fff6f3SLei He lkcf->sess[index] = g_steal_pointer(&sess); 56139fff6f3SLei He *session_id = index; 56239fff6f3SLei He 56339fff6f3SLei He return VIRTIO_CRYPTO_OK; 56439fff6f3SLei He } 56539fff6f3SLei He 56639fff6f3SLei He static int cryptodev_lkcf_create_session( 56739fff6f3SLei He CryptoDevBackend *backend, 56839fff6f3SLei He CryptoDevBackendSessionInfo *sess_info, 56939fff6f3SLei He uint32_t queue_index, 57039fff6f3SLei He CryptoDevCompletionFunc cb, 57139fff6f3SLei He void *opaque) 57239fff6f3SLei He { 57339fff6f3SLei He CryptoDevBackendAsymSessionInfo *asym_sess_info; 57439fff6f3SLei He CryptoDevBackendLKCF *lkcf = 57539fff6f3SLei He CRYPTODEV_BACKEND_LKCF(backend); 57639fff6f3SLei He int ret; 57739fff6f3SLei He 57839fff6f3SLei He switch (sess_info->op_code) { 57939fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: 58039fff6f3SLei He asym_sess_info = &sess_info->u.asym_sess_info; 58139fff6f3SLei He ret = cryptodev_lkcf_create_asym_session( 58239fff6f3SLei He lkcf, asym_sess_info, &sess_info->session_id); 58339fff6f3SLei He break; 58439fff6f3SLei He 58539fff6f3SLei He default: 58639fff6f3SLei He ret = -VIRTIO_CRYPTO_NOTSUPP; 58739fff6f3SLei He error_report("Unsupported opcode: %" PRIu32 "", 58839fff6f3SLei He sess_info->op_code); 58939fff6f3SLei He break; 59039fff6f3SLei He } 59139fff6f3SLei He if (cb) { 59239fff6f3SLei He cb(opaque, ret); 59339fff6f3SLei He } 59439fff6f3SLei He return 0; 59539fff6f3SLei He } 59639fff6f3SLei He 59739fff6f3SLei He static int cryptodev_lkcf_close_session(CryptoDevBackend *backend, 59839fff6f3SLei He uint64_t session_id, 59939fff6f3SLei He uint32_t queue_index, 60039fff6f3SLei He CryptoDevCompletionFunc cb, 60139fff6f3SLei He void *opaque) 60239fff6f3SLei He { 60339fff6f3SLei He CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend); 60439fff6f3SLei He CryptoDevBackendLKCFSession *session; 60539fff6f3SLei He 60639fff6f3SLei He assert(session_id < MAX_SESSIONS && lkcf->sess[session_id]); 60739fff6f3SLei He session = lkcf->sess[session_id]; 60839fff6f3SLei He lkcf->sess[session_id] = NULL; 60939fff6f3SLei He 61039fff6f3SLei He g_free(session->key); 61139fff6f3SLei He g_free(session); 61239fff6f3SLei He 61339fff6f3SLei He if (cb) { 61439fff6f3SLei He cb(opaque, VIRTIO_CRYPTO_OK); 61539fff6f3SLei He } 61639fff6f3SLei He return 0; 61739fff6f3SLei He } 61839fff6f3SLei He 61939fff6f3SLei He static void cryptodev_lkcf_class_init(ObjectClass *oc, void *data) 62039fff6f3SLei He { 62139fff6f3SLei He CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); 62239fff6f3SLei He 62339fff6f3SLei He bc->init = cryptodev_lkcf_init; 62439fff6f3SLei He bc->cleanup = cryptodev_lkcf_cleanup; 62539fff6f3SLei He bc->create_session = cryptodev_lkcf_create_session; 62639fff6f3SLei He bc->close_session = cryptodev_lkcf_close_session; 62739fff6f3SLei He bc->do_op = cryptodev_lkcf_operation; 62839fff6f3SLei He } 62939fff6f3SLei He 63039fff6f3SLei He static const TypeInfo cryptodev_builtin_info = { 63139fff6f3SLei He .name = TYPE_CRYPTODEV_BACKEND_LKCF, 63239fff6f3SLei He .parent = TYPE_CRYPTODEV_BACKEND, 63339fff6f3SLei He .class_init = cryptodev_lkcf_class_init, 63439fff6f3SLei He .instance_size = sizeof(CryptoDevBackendLKCF), 63539fff6f3SLei He }; 63639fff6f3SLei He 63739fff6f3SLei He static void cryptodev_lkcf_register_types(void) 63839fff6f3SLei He { 63939fff6f3SLei He type_register_static(&cryptodev_builtin_info); 64039fff6f3SLei He } 64139fff6f3SLei He 64239fff6f3SLei He type_init(cryptodev_lkcf_register_types); 643