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
cryptodev_lkcf_handle_response(void * opaque)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
cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions * opts,char * key_desc,size_t desc_len,Error ** errp)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;
136cd48d82aSMarkus Armbruster if (opts->alg != QCRYPTO_AK_CIPHER_ALGO_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;
142c96050f4SMarkus Armbruster if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALGO_PKCS1) {
14339fff6f3SLei He snprintf(key_desc, desc_len, "enc=%s hash=%s",
144c96050f4SMarkus Armbruster QCryptoRSAPaddingAlgo_str(rsa_opt->padding_alg),
145ef834aa2SMarkus Armbruster QCryptoHashAlgo_str(rsa_opt->hash_alg));
14639fff6f3SLei He
14739fff6f3SLei He } else {
14839fff6f3SLei He snprintf(key_desc, desc_len, "enc=%s",
149c96050f4SMarkus Armbruster QCryptoRSAPaddingAlgo_str(rsa_opt->padding_alg));
15039fff6f3SLei He }
15139fff6f3SLei He return 0;
15239fff6f3SLei He }
15339fff6f3SLei He
cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,int virtio_hash_alg,QCryptoAkCipherOptionsRSA * opt,Error ** errp)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) {
160c96050f4SMarkus Armbruster opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1;
16139fff6f3SLei He
16239fff6f3SLei He switch (virtio_hash_alg) {
16339fff6f3SLei He case VIRTIO_CRYPTO_RSA_MD5:
164ef834aa2SMarkus Armbruster opt->hash_alg = QCRYPTO_HASH_ALGO_MD5;
16539fff6f3SLei He break;
16639fff6f3SLei He
16739fff6f3SLei He case VIRTIO_CRYPTO_RSA_SHA1:
168ef834aa2SMarkus Armbruster opt->hash_alg = QCRYPTO_HASH_ALGO_SHA1;
16939fff6f3SLei He break;
17039fff6f3SLei He
17139fff6f3SLei He case VIRTIO_CRYPTO_RSA_SHA256:
172ef834aa2SMarkus Armbruster opt->hash_alg = QCRYPTO_HASH_ALGO_SHA256;
17339fff6f3SLei He break;
17439fff6f3SLei He
17539fff6f3SLei He case VIRTIO_CRYPTO_RSA_SHA512:
176ef834aa2SMarkus Armbruster opt->hash_alg = QCRYPTO_HASH_ALGO_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) {
187c96050f4SMarkus Armbruster opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_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
cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF * lkcf)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
cryptodev_lkcf_init(CryptoDevBackend * backend,Error ** errp)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 =
233d0917d79SMarkus Armbruster 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_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
cryptodev_lkcf_cleanup(CryptoDevBackend * backend,Error ** errp)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
cryptodev_lkcf_execute_task(CryptoDevLKCFTask * task)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 */
3255f4059efSMarkus 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
cryptodev_lkcf_worker(void * arg)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
cryptodev_lkcf_operation(CryptoDevBackend * backend,CryptoDevBackendOpInfo * op_info)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;
477*b1019999SMarkus Armbruster QCryptodevBackendAlgoType 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];
488*b1019999SMarkus Armbruster if (algtype != QCRYPTODEV_BACKEND_ALGO_TYPE_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
cryptodev_lkcf_create_asym_session(CryptoDevBackendLKCF * lkcf,CryptoDevBackendAsymSessionInfo * sess_info,uint64_t * session_id)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:
521cd48d82aSMarkus Armbruster sess->akcipher_opts.alg = QCRYPTO_AK_CIPHER_ALGO_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:
5375f4059efSMarkus Armbruster sess->keytype = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC;
53839fff6f3SLei He break;
53939fff6f3SLei He
54039fff6f3SLei He case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
5415f4059efSMarkus 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
cryptodev_lkcf_create_session(CryptoDevBackend * backend,CryptoDevBackendSessionInfo * sess_info,uint32_t queue_index,CryptoDevCompletionFunc cb,void * opaque)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
cryptodev_lkcf_close_session(CryptoDevBackend * backend,uint64_t session_id,uint32_t queue_index,CryptoDevCompletionFunc cb,void * opaque)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
cryptodev_lkcf_class_init(ObjectClass * oc,void * data)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
cryptodev_lkcf_register_types(void)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