summaryrefslogtreecommitdiffstats
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-rw-r--r--backends/cryptodev-builtin.c69
-rw-r--r--backends/cryptodev-lkcf.c645
-rw-r--r--backends/cryptodev-vhost-user.c51
-rw-r--r--backends/cryptodev.c44
-rw-r--r--backends/meson.build3
5 files changed, 761 insertions, 51 deletions
diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 125cbad1d3..cda6ca3b71 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -355,42 +355,62 @@ static int cryptodev_builtin_create_akcipher_session(
return index;
}
-static int64_t cryptodev_builtin_create_session(
+static int cryptodev_builtin_create_session(
CryptoDevBackend *backend,
CryptoDevBackendSessionInfo *sess_info,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendBuiltin *builtin =
CRYPTODEV_BACKEND_BUILTIN(backend);
CryptoDevBackendSymSessionInfo *sym_sess_info;
CryptoDevBackendAsymSessionInfo *asym_sess_info;
+ int ret, status;
+ Error *local_error = NULL;
switch (sess_info->op_code) {
case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
sym_sess_info = &sess_info->u.sym_sess_info;
- return cryptodev_builtin_create_cipher_session(
- builtin, sym_sess_info, errp);
+ ret = cryptodev_builtin_create_cipher_session(
+ builtin, sym_sess_info, &local_error);
+ break;
case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
asym_sess_info = &sess_info->u.asym_sess_info;
- return cryptodev_builtin_create_akcipher_session(
- builtin, asym_sess_info, errp);
+ ret = cryptodev_builtin_create_akcipher_session(
+ builtin, asym_sess_info, &local_error);
+ break;
case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
default:
- error_setg(errp, "Unsupported opcode :%" PRIu32 "",
+ error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
sess_info->op_code);
- return -1;
+ return -VIRTIO_CRYPTO_NOTSUPP;
}
- return -1;
+ if (local_error) {
+ error_report_err(local_error);
+ }
+ if (ret < 0) {
+ status = -VIRTIO_CRYPTO_ERR;
+ } else {
+ sess_info->session_id = ret;
+ status = VIRTIO_CRYPTO_OK;
+ }
+ if (cb) {
+ cb(opaque, status);
+ }
+ return 0;
}
static int cryptodev_builtin_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendBuiltin *builtin =
CRYPTODEV_BACKEND_BUILTIN(backend);
@@ -407,6 +427,9 @@ static int cryptodev_builtin_close_session(
g_free(session);
builtin->sessions[session_id] = NULL;
+ if (cb) {
+ cb(opaque, VIRTIO_CRYPTO_OK);
+ }
return 0;
}
@@ -506,7 +529,9 @@ static int cryptodev_builtin_asym_operation(
static int cryptodev_builtin_operation(
CryptoDevBackend *backend,
CryptoDevBackendOpInfo *op_info,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendBuiltin *builtin =
CRYPTODEV_BACKEND_BUILTIN(backend);
@@ -514,11 +539,12 @@ static int cryptodev_builtin_operation(
CryptoDevBackendSymOpInfo *sym_op_info;
CryptoDevBackendAsymOpInfo *asym_op_info;
enum CryptoDevBackendAlgType algtype = op_info->algtype;
- int ret = -VIRTIO_CRYPTO_ERR;
+ int status = -VIRTIO_CRYPTO_ERR;
+ Error *local_error = NULL;
if (op_info->session_id >= MAX_NUM_SESSIONS ||
builtin->sessions[op_info->session_id] == NULL) {
- error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
+ error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "",
op_info->session_id);
return -VIRTIO_CRYPTO_INVSESS;
}
@@ -526,14 +552,21 @@ static int cryptodev_builtin_operation(
sess = builtin->sessions[op_info->session_id];
if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
sym_op_info = op_info->u.sym_op_info;
- ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
+ status = cryptodev_builtin_sym_operation(sess, sym_op_info,
+ &local_error);
} else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
asym_op_info = op_info->u.asym_op_info;
- ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
- asym_op_info, errp);
+ status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
+ asym_op_info, &local_error);
}
- return ret;
+ if (local_error) {
+ error_report_err(local_error);
+ }
+ if (cb) {
+ cb(opaque, status);
+ }
+ return 0;
}
static void cryptodev_builtin_cleanup(
@@ -548,7 +581,7 @@ static void cryptodev_builtin_cleanup(
for (i = 0; i < MAX_NUM_SESSIONS; i++) {
if (builtin->sessions[i] != NULL) {
- cryptodev_builtin_close_session(backend, i, 0, &error_abort);
+ cryptodev_builtin_close_session(backend, i, 0, NULL, NULL);
}
}
diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c
new file mode 100644
index 0000000000..133bd706a4
--- /dev/null
+++ b/backends/cryptodev-lkcf.c
@@ -0,0 +1,645 @@
+/*
+ * QEMU Cryptodev backend for QEMU cipher APIs
+ *
+ * Copyright (c) 2022 Bytedance.Inc
+ *
+ * Authors:
+ * lei he <helei.sig11@bytedance.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/cipher.h"
+#include "crypto/akcipher.h"
+#include "qapi/error.h"
+#include "qemu/main-loop.h"
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+#include "qemu/queue.h"
+#include "qom/object.h"
+#include "sysemu/cryptodev.h"
+#include "standard-headers/linux/virtio_crypto.h"
+
+#include <keyutils.h>
+#include <sys/eventfd.h>
+
+/**
+ * @TYPE_CRYPTODEV_BACKEND_LKCF:
+ * name of backend that uses linux kernel crypto framework
+ */
+#define TYPE_CRYPTODEV_BACKEND_LKCF "cryptodev-backend-lkcf"
+
+OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendLKCF, CRYPTODEV_BACKEND_LKCF)
+
+#define INVALID_KEY_ID -1
+#define MAX_SESSIONS 256
+#define NR_WORKER_THREAD 64
+
+#define KCTL_KEY_TYPE_PKEY "asymmetric"
+/**
+ * Here the key is uploaded to the thread-keyring of worker thread, at least
+ * util linux-6.0:
+ * 1. process keyring seems to behave unexpectedly if main-thread does not
+ * create the keyring before creating any other thread.
+ * 2. at present, the guest kernel never perform multiple operations on a
+ * session.
+ * 3. it can reduce the load of the main-loop because the key passed by the
+ * guest kernel has been already checked.
+ */
+#define KCTL_KEY_RING KEY_SPEC_THREAD_KEYRING
+
+typedef struct CryptoDevBackendLKCFSession {
+ uint8_t *key;
+ size_t keylen;
+ QCryptoAkCipherKeyType keytype;
+ QCryptoAkCipherOptions akcipher_opts;
+} CryptoDevBackendLKCFSession;
+
+typedef struct CryptoDevBackendLKCF CryptoDevBackendLKCF;
+typedef struct CryptoDevLKCFTask CryptoDevLKCFTask;
+struct CryptoDevLKCFTask {
+ CryptoDevBackendLKCFSession *sess;
+ CryptoDevBackendOpInfo *op_info;
+ CryptoDevCompletionFunc cb;
+ void *opaque;
+ int status;
+ CryptoDevBackendLKCF *lkcf;
+ QSIMPLEQ_ENTRY(CryptoDevLKCFTask) queue;
+};
+
+typedef struct CryptoDevBackendLKCF {
+ CryptoDevBackend parent_obj;
+ CryptoDevBackendLKCFSession *sess[MAX_SESSIONS];
+ QSIMPLEQ_HEAD(, CryptoDevLKCFTask) requests;
+ QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses;
+ QemuMutex mutex;
+ QemuCond cond;
+ QemuMutex rsp_mutex;
+
+ /**
+ * There is no async interface for asymmetric keys like AF_ALG sockets,
+ * we don't seem to have better way than create a lots of thread.
+ */
+ QemuThread worker_threads[NR_WORKER_THREAD];
+ bool running;
+ int eventfd;
+} CryptoDevBackendLKCF;
+
+static void *cryptodev_lkcf_worker(void *arg);
+static int cryptodev_lkcf_close_session(CryptoDevBackend *backend,
+ uint64_t session_id,
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque);
+
+static void cryptodev_lkcf_handle_response(void *opaque)
+{
+ CryptoDevBackendLKCF *lkcf = (CryptoDevBackendLKCF *)opaque;
+ QSIMPLEQ_HEAD(, CryptoDevLKCFTask) responses;
+ CryptoDevLKCFTask *task, *next;
+ eventfd_t nevent;
+
+ QSIMPLEQ_INIT(&responses);
+ eventfd_read(lkcf->eventfd, &nevent);
+
+ qemu_mutex_lock(&lkcf->rsp_mutex);
+ QSIMPLEQ_PREPEND(&responses, &lkcf->responses);
+ qemu_mutex_unlock(&lkcf->rsp_mutex);
+
+ QSIMPLEQ_FOREACH_SAFE(task, &responses, queue, next) {
+ if (task->cb) {
+ task->cb(task->opaque, task->status);
+ }
+ g_free(task);
+ }
+}
+
+static int cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions *opts,
+ char *key_desc,
+ size_t desc_len,
+ Error **errp)
+{
+ QCryptoAkCipherOptionsRSA *rsa_opt;
+ if (opts->alg != QCRYPTO_AKCIPHER_ALG_RSA) {
+ error_setg(errp, "Unsupported alg: %u", opts->alg);
+ return -1;
+ }
+
+ rsa_opt = &opts->u.rsa;
+ if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALG_PKCS1) {
+ snprintf(key_desc, desc_len, "enc=%s hash=%s",
+ QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg),
+ QCryptoHashAlgorithm_str(rsa_opt->hash_alg));
+
+ } else {
+ snprintf(key_desc, desc_len, "enc=%s",
+ QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg));
+ }
+ return 0;
+}
+
+static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,
+ int virtio_hash_alg,
+ QCryptoAkCipherOptionsRSA *opt,
+ Error **errp)
+{
+ if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
+ opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+
+ switch (virtio_hash_alg) {
+ case VIRTIO_CRYPTO_RSA_MD5:
+ opt->hash_alg = QCRYPTO_HASH_ALG_MD5;
+ break;
+
+ case VIRTIO_CRYPTO_RSA_SHA1:
+ opt->hash_alg = QCRYPTO_HASH_ALG_SHA1;
+ break;
+
+ case VIRTIO_CRYPTO_RSA_SHA256:
+ opt->hash_alg = QCRYPTO_HASH_ALG_SHA256;
+ break;
+
+ case VIRTIO_CRYPTO_RSA_SHA512:
+ opt->hash_alg = QCRYPTO_HASH_ALG_SHA512;
+ break;
+
+ default:
+ error_setg(errp, "Unsupported rsa hash algo: %d", virtio_hash_alg);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
+ opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
+ return 0;
+ }
+
+ error_setg(errp, "Unsupported rsa padding algo: %u", virtio_padding_alg);
+ return -1;
+}
+
+static int cryptodev_lkcf_get_unused_session_index(CryptoDevBackendLKCF *lkcf)
+{
+ size_t i;
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ if (lkcf->sess[i] == NULL) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
+{
+ /* Only support one queue */
+ int queues = backend->conf.peers.queues, i;
+ CryptoDevBackendClient *cc;
+ CryptoDevBackendLKCF *lkcf =
+ CRYPTODEV_BACKEND_LKCF(backend);
+
+ if (queues != 1) {
+ error_setg(errp,
+ "Only support one queue in cryptodev-builtin backend");
+ return;
+ }
+ lkcf->eventfd = eventfd(0, 0);
+ if (lkcf->eventfd < 0) {
+ error_setg(errp, "Failed to create eventfd: %d", errno);
+ return;
+ }
+
+ cc = cryptodev_backend_new_client("cryptodev-lkcf", NULL);
+ cc->info_str = g_strdup_printf("cryptodev-lkcf0");
+ cc->queue_index = 0;
+ cc->type = CRYPTODEV_BACKEND_TYPE_LKCF;
+ backend->conf.peers.ccs[0] = cc;
+
+ backend->conf.crypto_services =
+ 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
+ backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
+ lkcf->running = true;
+
+ QSIMPLEQ_INIT(&lkcf->requests);
+ QSIMPLEQ_INIT(&lkcf->responses);
+ qemu_mutex_init(&lkcf->mutex);
+ qemu_mutex_init(&lkcf->rsp_mutex);
+ qemu_cond_init(&lkcf->cond);
+ for (i = 0; i < NR_WORKER_THREAD; i++) {
+ qemu_thread_create(&lkcf->worker_threads[i], "lkcf-worker",
+ cryptodev_lkcf_worker, lkcf, 0);
+ }
+ qemu_set_fd_handler(
+ lkcf->eventfd, cryptodev_lkcf_handle_response, NULL, lkcf);
+ cryptodev_backend_set_ready(backend, true);
+}
+
+static void cryptodev_lkcf_cleanup(CryptoDevBackend *backend, Error **errp)
+{
+ CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend);
+ size_t i;
+ int queues = backend->conf.peers.queues;
+ CryptoDevBackendClient *cc;
+ CryptoDevLKCFTask *task, *next;
+
+ qemu_mutex_lock(&lkcf->mutex);
+ lkcf->running = false;
+ qemu_mutex_unlock(&lkcf->mutex);
+ qemu_cond_broadcast(&lkcf->cond);
+
+ close(lkcf->eventfd);
+ for (i = 0; i < NR_WORKER_THREAD; i++) {
+ qemu_thread_join(&lkcf->worker_threads[i]);
+ }
+
+ QSIMPLEQ_FOREACH_SAFE(task, &lkcf->requests, queue, next) {
+ if (task->cb) {
+ task->cb(task->opaque, task->status);
+ }
+ g_free(task);
+ }
+
+ QSIMPLEQ_FOREACH_SAFE(task, &lkcf->responses, queue, next) {
+ if (task->cb) {
+ task->cb(task->opaque, task->status);
+ }
+ g_free(task);
+ }
+
+ qemu_mutex_destroy(&lkcf->mutex);
+ qemu_cond_destroy(&lkcf->cond);
+ qemu_mutex_destroy(&lkcf->rsp_mutex);
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ if (lkcf->sess[i] != NULL) {
+ cryptodev_lkcf_close_session(backend, i, 0, NULL, NULL);
+ }
+ }
+
+ for (i = 0; i < queues; i++) {
+ cc = backend->conf.peers.ccs[i];
+ if (cc) {
+ cryptodev_backend_free_client(cc);
+ backend->conf.peers.ccs[i] = NULL;
+ }
+ }
+
+ cryptodev_backend_set_ready(backend, false);
+}
+
+static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task)
+{
+ CryptoDevBackendLKCFSession *session = task->sess;
+ CryptoDevBackendAsymOpInfo *asym_op_info;
+ bool kick = false;
+ int ret, status, op_code = task->op_info->op_code;
+ size_t p8info_len;
+ g_autofree uint8_t *p8info = NULL;
+ Error *local_error = NULL;
+ key_serial_t key_id = INVALID_KEY_ID;
+ char op_desc[64];
+ g_autoptr(QCryptoAkCipher) akcipher = NULL;
+
+ /**
+ * We only offload private key session:
+ * 1. currently, the Linux kernel can only accept public key wrapped
+ * with X.509 certificates, but unfortunately the cost of making a
+ * ceritificate with public key is too expensive.
+ * 2. generally, public key related compution is fast, just compute it with
+ * thread-pool.
+ */
+ if (session->keytype == QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE) {
+ if (qcrypto_akcipher_export_p8info(&session->akcipher_opts,
+ session->key, session->keylen,
+ &p8info, &p8info_len,
+ &local_error) != 0 ||
+ cryptodev_lkcf_set_op_desc(&session->akcipher_opts, op_desc,
+ sizeof(op_desc), &local_error) != 0) {
+ error_report_err(local_error);
+ } else {
+ key_id = add_key(KCTL_KEY_TYPE_PKEY, "lkcf-backend-priv-key",
+ p8info, p8info_len, KCTL_KEY_RING);
+ }
+ }
+
+ if (key_id < 0) {
+ if (!qcrypto_akcipher_supports(&session->akcipher_opts)) {
+ status = -VIRTIO_CRYPTO_NOTSUPP;
+ goto out;
+ }
+ akcipher = qcrypto_akcipher_new(&session->akcipher_opts,
+ session->keytype,
+ session->key, session->keylen,
+ &local_error);
+ if (!akcipher) {
+ status = -VIRTIO_CRYPTO_ERR;
+ goto out;
+ }
+ }
+
+ asym_op_info = task->op_info->u.asym_op_info;
+ switch (op_code) {
+ case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+ if (key_id >= 0) {
+ ret = keyctl_pkey_encrypt(key_id, op_desc,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len);
+ } else {
+ ret = qcrypto_akcipher_encrypt(akcipher,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len, &local_error);
+ }
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+ if (key_id >= 0) {
+ ret = keyctl_pkey_decrypt(key_id, op_desc,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len);
+ } else {
+ ret = qcrypto_akcipher_decrypt(akcipher,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len, &local_error);
+ }
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+ if (key_id >= 0) {
+ ret = keyctl_pkey_sign(key_id, op_desc,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len);
+ } else {
+ ret = qcrypto_akcipher_sign(akcipher,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len, &local_error);
+ }
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+ if (key_id >= 0) {
+ ret = keyctl_pkey_verify(key_id, op_desc,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len);
+ } else {
+ ret = qcrypto_akcipher_verify(akcipher,
+ asym_op_info->src, asym_op_info->src_len,
+ asym_op_info->dst, asym_op_info->dst_len, &local_error);
+ }
+ break;
+
+ default:
+ error_setg(&local_error, "Unknown opcode: %u", op_code);
+ status = -VIRTIO_CRYPTO_ERR;
+ goto out;
+ }
+
+ if (ret < 0) {
+ if (!local_error) {
+ if (errno != EKEYREJECTED) {
+ error_report("Failed do operation with keyctl: %d", errno);
+ }
+ } else {
+ error_report_err(local_error);
+ }
+ status = op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY ?
+ -VIRTIO_CRYPTO_KEY_REJECTED : -VIRTIO_CRYPTO_ERR;
+ } else {
+ status = VIRTIO_CRYPTO_OK;
+ asym_op_info->dst_len = ret;
+ }
+
+out:
+ if (key_id >= 0) {
+ keyctl_unlink(key_id, KCTL_KEY_RING);
+ }
+ task->status = status;
+
+ qemu_mutex_lock(&task->lkcf->rsp_mutex);
+ if (QSIMPLEQ_EMPTY(&task->lkcf->responses)) {
+ kick = true;
+ }
+ QSIMPLEQ_INSERT_TAIL(&task->lkcf->responses, task, queue);
+ qemu_mutex_unlock(&task->lkcf->rsp_mutex);
+
+ if (kick) {
+ eventfd_write(task->lkcf->eventfd, 1);
+ }
+}
+
+static void *cryptodev_lkcf_worker(void *arg)
+{
+ CryptoDevBackendLKCF *backend = (CryptoDevBackendLKCF *)arg;
+ CryptoDevLKCFTask *task;
+
+ for (;;) {
+ task = NULL;
+ qemu_mutex_lock(&backend->mutex);
+ while (backend->running && QSIMPLEQ_EMPTY(&backend->requests)) {
+ qemu_cond_wait(&backend->cond, &backend->mutex);
+ }
+ if (backend->running) {
+ task = QSIMPLEQ_FIRST(&backend->requests);
+ QSIMPLEQ_REMOVE_HEAD(&backend->requests, queue);
+ }
+ qemu_mutex_unlock(&backend->mutex);
+
+ /* stopped */
+ if (!task) {
+ break;
+ }
+ cryptodev_lkcf_execute_task(task);
+ }
+
+ return NULL;
+}
+
+static int cryptodev_lkcf_operation(
+ CryptoDevBackend *backend,
+ CryptoDevBackendOpInfo *op_info,
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
+{
+ CryptoDevBackendLKCF *lkcf =
+ CRYPTODEV_BACKEND_LKCF(backend);
+ CryptoDevBackendLKCFSession *sess;
+ enum CryptoDevBackendAlgType algtype = op_info->algtype;
+ CryptoDevLKCFTask *task;
+
+ if (op_info->session_id >= MAX_SESSIONS ||
+ lkcf->sess[op_info->session_id] == NULL) {
+ error_report("Cannot find a valid session id: %" PRIu64 "",
+ op_info->session_id);
+ return -VIRTIO_CRYPTO_INVSESS;
+ }
+
+ sess = lkcf->sess[op_info->session_id];
+ if (algtype != CRYPTODEV_BACKEND_ALG_ASYM) {
+ error_report("algtype not supported: %u", algtype);
+ return -VIRTIO_CRYPTO_NOTSUPP;
+ }
+
+ task = g_new0(CryptoDevLKCFTask, 1);
+ task->op_info = op_info;
+ task->cb = cb;
+ task->opaque = opaque;
+ task->sess = sess;
+ task->lkcf = lkcf;
+ task->status = -VIRTIO_CRYPTO_ERR;
+
+ qemu_mutex_lock(&lkcf->mutex);
+ QSIMPLEQ_INSERT_TAIL(&lkcf->requests, task, queue);
+ qemu_mutex_unlock(&lkcf->mutex);
+ qemu_cond_signal(&lkcf->cond);
+
+ return VIRTIO_CRYPTO_OK;
+}
+
+static int cryptodev_lkcf_create_asym_session(
+ CryptoDevBackendLKCF *lkcf,
+ CryptoDevBackendAsymSessionInfo *sess_info,
+ uint64_t *session_id)
+{
+ Error *local_error = NULL;
+ int index;
+ g_autofree CryptoDevBackendLKCFSession *sess =
+ g_new0(CryptoDevBackendLKCFSession, 1);
+
+ switch (sess_info->algo) {
+ case VIRTIO_CRYPTO_AKCIPHER_RSA:
+ sess->akcipher_opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ if (cryptodev_lkcf_set_rsa_opt(
+ sess_info->u.rsa.padding_algo, sess_info->u.rsa.hash_algo,
+ &sess->akcipher_opts.u.rsa, &local_error) != 0) {
+ error_report_err(local_error);
+ return -VIRTIO_CRYPTO_ERR;
+ }
+ break;
+
+ default:
+ error_report("Unsupported asym alg %u", sess_info->algo);
+ return -VIRTIO_CRYPTO_NOTSUPP;
+ }
+
+ switch (sess_info->keytype) {
+ case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+ break;
+
+ default:
+ error_report("Unknown akcipher keytype: %u", sess_info->keytype);
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ index = cryptodev_lkcf_get_unused_session_index(lkcf);
+ if (index < 0) {
+ error_report("Total number of sessions created exceeds %u",
+ MAX_SESSIONS);
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ sess->keylen = sess_info->keylen;
+ sess->key = g_malloc(sess_info->keylen);
+ memcpy(sess->key, sess_info->key, sess_info->keylen);
+
+ lkcf->sess[index] = g_steal_pointer(&sess);
+ *session_id = index;
+
+ return VIRTIO_CRYPTO_OK;
+}
+
+static int cryptodev_lkcf_create_session(
+ CryptoDevBackend *backend,
+ CryptoDevBackendSessionInfo *sess_info,
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
+{
+ CryptoDevBackendAsymSessionInfo *asym_sess_info;
+ CryptoDevBackendLKCF *lkcf =
+ CRYPTODEV_BACKEND_LKCF(backend);
+ int ret;
+
+ switch (sess_info->op_code) {
+ case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+ asym_sess_info = &sess_info->u.asym_sess_info;
+ ret = cryptodev_lkcf_create_asym_session(
+ lkcf, asym_sess_info, &sess_info->session_id);
+ break;
+
+ default:
+ ret = -VIRTIO_CRYPTO_NOTSUPP;
+ error_report("Unsupported opcode: %" PRIu32 "",
+ sess_info->op_code);
+ break;
+ }
+ if (cb) {
+ cb(opaque, ret);
+ }
+ return 0;
+}
+
+static int cryptodev_lkcf_close_session(CryptoDevBackend *backend,
+ uint64_t session_id,
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
+{
+ CryptoDevBackendLKCF *lkcf = CRYPTODEV_BACKEND_LKCF(backend);
+ CryptoDevBackendLKCFSession *session;
+
+ assert(session_id < MAX_SESSIONS && lkcf->sess[session_id]);
+ session = lkcf->sess[session_id];
+ lkcf->sess[session_id] = NULL;
+
+ g_free(session->key);
+ g_free(session);
+
+ if (cb) {
+ cb(opaque, VIRTIO_CRYPTO_OK);
+ }
+ return 0;
+}
+
+static void cryptodev_lkcf_class_init(ObjectClass *oc, void *data)
+{
+ CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
+
+ bc->init = cryptodev_lkcf_init;
+ bc->cleanup = cryptodev_lkcf_cleanup;
+ bc->create_session = cryptodev_lkcf_create_session;
+ bc->close_session = cryptodev_lkcf_close_session;
+ bc->do_op = cryptodev_lkcf_operation;
+}
+
+static const TypeInfo cryptodev_builtin_info = {
+ .name = TYPE_CRYPTODEV_BACKEND_LKCF,
+ .parent = TYPE_CRYPTODEV_BACKEND,
+ .class_init = cryptodev_lkcf_class_init,
+ .instance_size = sizeof(CryptoDevBackendLKCF),
+};
+
+static void cryptodev_lkcf_register_types(void)
+{
+ type_register_static(&cryptodev_builtin_info);
+}
+
+type_init(cryptodev_lkcf_register_types);
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index f9c5867e38..ab3028e045 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -259,13 +259,18 @@ static int64_t cryptodev_vhost_user_sym_create_session(
return -1;
}
-static int64_t cryptodev_vhost_user_create_session(
+static int cryptodev_vhost_user_create_session(
CryptoDevBackend *backend,
CryptoDevBackendSessionInfo *sess_info,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
uint32_t op_code = sess_info->op_code;
CryptoDevBackendSymSessionInfo *sym_sess_info;
+ int64_t ret;
+ Error *local_error = NULL;
+ int status;
switch (op_code) {
case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
@@ -273,27 +278,42 @@ static int64_t cryptodev_vhost_user_create_session(
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
sym_sess_info = &sess_info->u.sym_sess_info;
- return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
- queue_index, errp);
+ ret = cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
+ queue_index, &local_error);
+ break;
+
default:
- error_setg(errp, "Unsupported opcode :%" PRIu32 "",
+ error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
sess_info->op_code);
- return -1;
-
+ return -VIRTIO_CRYPTO_NOTSUPP;
}
- return -1;
+ if (local_error) {
+ error_report_err(local_error);
+ }
+ if (ret < 0) {
+ status = -VIRTIO_CRYPTO_ERR;
+ } else {
+ sess_info->session_id = ret;
+ status = VIRTIO_CRYPTO_OK;
+ }
+ if (cb) {
+ cb(opaque, status);
+ }
+ return 0;
}
static int cryptodev_vhost_user_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendClient *cc =
backend->conf.peers.ccs[queue_index];
CryptoDevBackendVhost *vhost_crypto;
- int ret;
+ int ret = -1, status;
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, backend, queue_index);
if (vhost_crypto) {
@@ -301,12 +321,17 @@ static int cryptodev_vhost_user_close_session(
ret = dev->vhost_ops->vhost_crypto_close_session(dev,
session_id);
if (ret < 0) {
- return -1;
+ status = -VIRTIO_CRYPTO_ERR;
} else {
- return 0;
+ status = VIRTIO_CRYPTO_OK;
}
+ } else {
+ status = -VIRTIO_CRYPTO_NOTSUPP;
}
- return -1;
+ if (cb) {
+ cb(opaque, status);
+ }
+ return 0;
}
static void cryptodev_vhost_user_cleanup(
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 33eb4e1a70..54ee8c81f5 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/config-file.h"
+#include "qemu/error-report.h"
#include "qom/object_interfaces.h"
#include "hw/virtio/virtio-crypto.h"
@@ -72,69 +73,72 @@ void cryptodev_backend_cleanup(
}
}
-int64_t cryptodev_backend_create_session(
+int cryptodev_backend_create_session(
CryptoDevBackend *backend,
CryptoDevBackendSessionInfo *sess_info,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendClass *bc =
CRYPTODEV_BACKEND_GET_CLASS(backend);
if (bc->create_session) {
- return bc->create_session(backend, sess_info, queue_index, errp);
+ return bc->create_session(backend, sess_info, queue_index, cb, opaque);
}
-
- return -1;
+ return -VIRTIO_CRYPTO_NOTSUPP;
}
int cryptodev_backend_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendClass *bc =
CRYPTODEV_BACKEND_GET_CLASS(backend);
if (bc->close_session) {
- return bc->close_session(backend, session_id, queue_index, errp);
+ return bc->close_session(backend, session_id, queue_index, cb, opaque);
}
-
- return -1;
+ return -VIRTIO_CRYPTO_NOTSUPP;
}
static int cryptodev_backend_operation(
CryptoDevBackend *backend,
CryptoDevBackendOpInfo *op_info,
- uint32_t queue_index, Error **errp)
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb,
+ void *opaque)
{
CryptoDevBackendClass *bc =
CRYPTODEV_BACKEND_GET_CLASS(backend);
if (bc->do_op) {
- return bc->do_op(backend, op_info, queue_index, errp);
+ return bc->do_op(backend, op_info, queue_index, cb, opaque);
}
-
- return -VIRTIO_CRYPTO_ERR;
+ return -VIRTIO_CRYPTO_NOTSUPP;
}
int cryptodev_backend_crypto_operation(
CryptoDevBackend *backend,
- void *opaque,
- uint32_t queue_index, Error **errp)
+ void *opaque1,
+ uint32_t queue_index,
+ CryptoDevCompletionFunc cb, void *opaque2)
{
- VirtIOCryptoReq *req = opaque;
+ VirtIOCryptoReq *req = opaque1;
CryptoDevBackendOpInfo *op_info = &req->op_info;
enum CryptoDevBackendAlgType algtype = req->flags;
if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
&& (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
- error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
- algtype);
-
+ error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
return -VIRTIO_CRYPTO_NOTSUPP;
}
- return cryptodev_backend_operation(backend, op_info, queue_index, errp);
+ return cryptodev_backend_operation(backend, op_info, queue_index,
+ cb, opaque2);
}
static void
diff --git a/backends/meson.build b/backends/meson.build
index b1884a88ec..954e658b25 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -12,6 +12,9 @@ softmmu_ss.add([files(
softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('rng-random.c'))
softmmu_ss.add(when: 'CONFIG_POSIX', if_true: files('hostmem-file.c'))
softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('hostmem-memfd.c'))
+if keyutils.found()
+ softmmu_ss.add(keyutils, files('cryptodev-lkcf.c'))
+endif
if have_vhost_user
softmmu_ss.add(when: 'CONFIG_VIRTIO', if_true: files('vhost-user.c'))
endif