Merge tag 'pull-request-2024-06-12' of https://gitlab.com/thuth/qemu into staging
[qemu/kevin.git] / backends / cryptodev-builtin.c
blob940104ee55222337b577ee23944a63c3c25d46bf
1 /*
2 * QEMU Cryptodev backend for QEMU cipher APIs
4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
6 * Authors:
7 * Gonglei <arei.gonglei@huawei.com>
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.
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.
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/>.
24 #include "qemu/osdep.h"
25 #include "sysemu/cryptodev.h"
26 #include "qemu/error-report.h"
27 #include "qapi/error.h"
28 #include "standard-headers/linux/virtio_crypto.h"
29 #include "crypto/cipher.h"
30 #include "crypto/akcipher.h"
31 #include "qom/object.h"
34 /**
35 * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
36 * name of backend that uses QEMU cipher API
38 #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
40 OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
43 typedef struct CryptoDevBackendBuiltinSession {
44 QCryptoCipher *cipher;
45 uint8_t direction; /* encryption or decryption */
46 uint8_t type; /* cipher? hash? aead? */
47 QCryptoAkCipher *akcipher;
48 QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
49 } CryptoDevBackendBuiltinSession;
51 /* Max number of symmetric/asymmetric sessions */
52 #define MAX_NUM_SESSIONS 256
54 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512
55 #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN 64
57 struct CryptoDevBackendBuiltin {
58 CryptoDevBackend parent_obj;
60 CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
63 static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
65 QCryptoAkCipherOptions opts;
67 opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
68 opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
69 if (qcrypto_akcipher_supports(&opts)) {
70 backend->conf.crypto_services |=
71 (1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER);
72 backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
76 static void cryptodev_builtin_init(
77 CryptoDevBackend *backend, Error **errp)
79 /* Only support one queue */
80 int queues = backend->conf.peers.queues;
81 CryptoDevBackendClient *cc;
83 if (queues != 1) {
84 error_setg(errp,
85 "Only support one queue in cryptdov-builtin backend");
86 return;
89 cc = cryptodev_backend_new_client();
90 cc->info_str = g_strdup_printf("cryptodev-builtin0");
91 cc->queue_index = 0;
92 cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN;
93 backend->conf.peers.ccs[0] = cc;
95 backend->conf.crypto_services =
96 1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
97 1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
98 1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
99 backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
100 backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
102 * Set the Maximum length of crypto request.
103 * Why this value? Just avoid to overflow when
104 * memory allocation for each crypto request.
106 backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
107 backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
108 backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
109 cryptodev_builtin_init_akcipher(backend);
111 cryptodev_backend_set_ready(backend, true);
114 static int
115 cryptodev_builtin_get_unused_session_index(
116 CryptoDevBackendBuiltin *builtin)
118 size_t i;
120 for (i = 0; i < MAX_NUM_SESSIONS; i++) {
121 if (builtin->sessions[i] == NULL) {
122 return i;
126 return -1;
129 #define AES_KEYSIZE_128 16
130 #define AES_KEYSIZE_192 24
131 #define AES_KEYSIZE_256 32
132 #define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
133 #define AES_KEYSIZE_256_XTS 64
135 static int
136 cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
138 int algo;
140 if (key_len == AES_KEYSIZE_128) {
141 algo = QCRYPTO_CIPHER_ALG_AES_128;
142 } else if (key_len == AES_KEYSIZE_192) {
143 algo = QCRYPTO_CIPHER_ALG_AES_192;
144 } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
145 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
146 algo = QCRYPTO_CIPHER_ALG_AES_128;
147 } else {
148 algo = QCRYPTO_CIPHER_ALG_AES_256;
150 } else if (key_len == AES_KEYSIZE_256_XTS) {
151 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
152 algo = QCRYPTO_CIPHER_ALG_AES_256;
153 } else {
154 goto err;
156 } else {
157 goto err;
160 return algo;
162 err:
163 error_setg(errp, "Unsupported key length :%u", key_len);
164 return -1;
167 static int cryptodev_builtin_get_rsa_hash_algo(
168 int virtio_rsa_hash, Error **errp)
170 switch (virtio_rsa_hash) {
171 case VIRTIO_CRYPTO_RSA_MD5:
172 return QCRYPTO_HASH_ALG_MD5;
174 case VIRTIO_CRYPTO_RSA_SHA1:
175 return QCRYPTO_HASH_ALG_SHA1;
177 case VIRTIO_CRYPTO_RSA_SHA256:
178 return QCRYPTO_HASH_ALG_SHA256;
180 case VIRTIO_CRYPTO_RSA_SHA512:
181 return QCRYPTO_HASH_ALG_SHA512;
183 default:
184 error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
185 return -1;
189 static int cryptodev_builtin_set_rsa_options(
190 int virtio_padding_algo,
191 int virtio_hash_algo,
192 QCryptoAkCipherOptionsRSA *opt,
193 Error **errp)
195 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
196 int hash_alg;
198 hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
199 if (hash_alg < 0) {
200 return -1;
202 opt->hash_alg = hash_alg;
203 opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
204 return 0;
207 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
208 opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
209 return 0;
212 error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
213 return -1;
216 static int cryptodev_builtin_create_cipher_session(
217 CryptoDevBackendBuiltin *builtin,
218 CryptoDevBackendSymSessionInfo *sess_info,
219 Error **errp)
221 int algo;
222 int mode;
223 QCryptoCipher *cipher;
224 int index;
225 CryptoDevBackendBuiltinSession *sess;
227 if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
228 error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
229 return -1;
232 index = cryptodev_builtin_get_unused_session_index(builtin);
233 if (index < 0) {
234 error_setg(errp, "Total number of sessions created exceeds %u",
235 MAX_NUM_SESSIONS);
236 return -1;
239 switch (sess_info->cipher_alg) {
240 case VIRTIO_CRYPTO_CIPHER_AES_ECB:
241 mode = QCRYPTO_CIPHER_MODE_ECB;
242 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
243 mode, errp);
244 if (algo < 0) {
245 return -1;
247 break;
248 case VIRTIO_CRYPTO_CIPHER_AES_CBC:
249 mode = QCRYPTO_CIPHER_MODE_CBC;
250 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
251 mode, errp);
252 if (algo < 0) {
253 return -1;
255 break;
256 case VIRTIO_CRYPTO_CIPHER_AES_CTR:
257 mode = QCRYPTO_CIPHER_MODE_CTR;
258 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
259 mode, errp);
260 if (algo < 0) {
261 return -1;
263 break;
264 case VIRTIO_CRYPTO_CIPHER_AES_XTS:
265 mode = QCRYPTO_CIPHER_MODE_XTS;
266 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
267 mode, errp);
268 if (algo < 0) {
269 return -1;
271 break;
272 case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
273 mode = QCRYPTO_CIPHER_MODE_ECB;
274 algo = QCRYPTO_CIPHER_ALG_3DES;
275 break;
276 case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
277 mode = QCRYPTO_CIPHER_MODE_CBC;
278 algo = QCRYPTO_CIPHER_ALG_3DES;
279 break;
280 case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
281 mode = QCRYPTO_CIPHER_MODE_CTR;
282 algo = QCRYPTO_CIPHER_ALG_3DES;
283 break;
284 default:
285 error_setg(errp, "Unsupported cipher alg :%u",
286 sess_info->cipher_alg);
287 return -1;
290 cipher = qcrypto_cipher_new(algo, mode,
291 sess_info->cipher_key,
292 sess_info->key_len,
293 errp);
294 if (!cipher) {
295 return -1;
298 sess = g_new0(CryptoDevBackendBuiltinSession, 1);
299 sess->cipher = cipher;
300 sess->direction = sess_info->direction;
301 sess->type = sess_info->op_type;
303 builtin->sessions[index] = sess;
305 return index;
308 static int cryptodev_builtin_create_akcipher_session(
309 CryptoDevBackendBuiltin *builtin,
310 CryptoDevBackendAsymSessionInfo *sess_info,
311 Error **errp)
313 CryptoDevBackendBuiltinSession *sess;
314 QCryptoAkCipher *akcipher;
315 int index;
316 QCryptoAkCipherKeyType type;
317 QCryptoAkCipherOptions opts;
319 switch (sess_info->algo) {
320 case VIRTIO_CRYPTO_AKCIPHER_RSA:
321 opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
322 if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
323 sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) {
324 return -1;
326 break;
328 /* TODO support DSA&ECDSA until qemu crypto framework support these */
330 default:
331 error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
332 return -1;
335 switch (sess_info->keytype) {
336 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
337 type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
338 break;
340 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
341 type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
342 break;
344 default:
345 error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
346 return -1;
349 index = cryptodev_builtin_get_unused_session_index(builtin);
350 if (index < 0) {
351 error_setg(errp, "Total number of sessions created exceeds %u",
352 MAX_NUM_SESSIONS);
353 return -1;
356 akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key,
357 sess_info->keylen, errp);
358 if (!akcipher) {
359 return -1;
362 sess = g_new0(CryptoDevBackendBuiltinSession, 1);
363 sess->akcipher = akcipher;
365 builtin->sessions[index] = sess;
367 return index;
370 static int cryptodev_builtin_create_session(
371 CryptoDevBackend *backend,
372 CryptoDevBackendSessionInfo *sess_info,
373 uint32_t queue_index,
374 CryptoDevCompletionFunc cb,
375 void *opaque)
377 CryptoDevBackendBuiltin *builtin =
378 CRYPTODEV_BACKEND_BUILTIN(backend);
379 CryptoDevBackendSymSessionInfo *sym_sess_info;
380 CryptoDevBackendAsymSessionInfo *asym_sess_info;
381 int ret, status;
382 Error *local_error = NULL;
384 switch (sess_info->op_code) {
385 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
386 sym_sess_info = &sess_info->u.sym_sess_info;
387 ret = cryptodev_builtin_create_cipher_session(
388 builtin, sym_sess_info, &local_error);
389 break;
391 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
392 asym_sess_info = &sess_info->u.asym_sess_info;
393 ret = cryptodev_builtin_create_akcipher_session(
394 builtin, asym_sess_info, &local_error);
395 break;
397 case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
398 case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
399 default:
400 error_report("Unsupported opcode :%" PRIu32 "",
401 sess_info->op_code);
402 return -VIRTIO_CRYPTO_NOTSUPP;
405 if (local_error) {
406 error_report_err(local_error);
408 if (ret < 0) {
409 status = -VIRTIO_CRYPTO_ERR;
410 } else {
411 sess_info->session_id = ret;
412 status = VIRTIO_CRYPTO_OK;
414 if (cb) {
415 cb(opaque, status);
417 return 0;
420 static int cryptodev_builtin_close_session(
421 CryptoDevBackend *backend,
422 uint64_t session_id,
423 uint32_t queue_index,
424 CryptoDevCompletionFunc cb,
425 void *opaque)
427 CryptoDevBackendBuiltin *builtin =
428 CRYPTODEV_BACKEND_BUILTIN(backend);
429 CryptoDevBackendBuiltinSession *session;
431 if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
432 return -VIRTIO_CRYPTO_INVSESS;
435 session = builtin->sessions[session_id];
436 if (session->cipher) {
437 qcrypto_cipher_free(session->cipher);
438 } else if (session->akcipher) {
439 qcrypto_akcipher_free(session->akcipher);
442 g_free(session);
443 builtin->sessions[session_id] = NULL;
444 if (cb) {
445 cb(opaque, VIRTIO_CRYPTO_OK);
447 return 0;
450 static int cryptodev_builtin_sym_operation(
451 CryptoDevBackendBuiltinSession *sess,
452 CryptoDevBackendSymOpInfo *op_info, Error **errp)
454 int ret;
456 if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
457 error_setg(errp,
458 "Algorithm chain is unsupported for cryptdoev-builtin");
459 return -VIRTIO_CRYPTO_NOTSUPP;
462 if (op_info->iv_len > 0) {
463 ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
464 op_info->iv_len, errp);
465 if (ret < 0) {
466 return -VIRTIO_CRYPTO_ERR;
470 if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) {
471 ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src,
472 op_info->dst, op_info->src_len, errp);
473 if (ret < 0) {
474 return -VIRTIO_CRYPTO_ERR;
476 } else {
477 ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
478 op_info->dst, op_info->src_len, errp);
479 if (ret < 0) {
480 return -VIRTIO_CRYPTO_ERR;
484 return VIRTIO_CRYPTO_OK;
487 static int cryptodev_builtin_asym_operation(
488 CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
489 CryptoDevBackendAsymOpInfo *op_info, Error **errp)
491 int ret;
493 switch (op_code) {
494 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
495 ret = qcrypto_akcipher_encrypt(sess->akcipher,
496 op_info->src, op_info->src_len,
497 op_info->dst, op_info->dst_len, errp);
498 break;
500 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
501 ret = qcrypto_akcipher_decrypt(sess->akcipher,
502 op_info->src, op_info->src_len,
503 op_info->dst, op_info->dst_len, errp);
504 break;
506 case VIRTIO_CRYPTO_AKCIPHER_SIGN:
507 ret = qcrypto_akcipher_sign(sess->akcipher,
508 op_info->src, op_info->src_len,
509 op_info->dst, op_info->dst_len, errp);
510 break;
512 case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
513 ret = qcrypto_akcipher_verify(sess->akcipher,
514 op_info->src, op_info->src_len,
515 op_info->dst, op_info->dst_len, errp);
516 break;
518 default:
519 return -VIRTIO_CRYPTO_ERR;
522 if (ret < 0) {
523 if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
524 return -VIRTIO_CRYPTO_KEY_REJECTED;
526 return -VIRTIO_CRYPTO_ERR;
529 /* Buffer is too short, typically the driver should handle this case */
530 if (unlikely(ret > op_info->dst_len)) {
531 if (errp && !*errp) {
532 error_setg(errp, "dst buffer too short");
535 return -VIRTIO_CRYPTO_ERR;
538 op_info->dst_len = ret;
540 return VIRTIO_CRYPTO_OK;
543 static int cryptodev_builtin_operation(
544 CryptoDevBackend *backend,
545 CryptoDevBackendOpInfo *op_info)
547 CryptoDevBackendBuiltin *builtin =
548 CRYPTODEV_BACKEND_BUILTIN(backend);
549 CryptoDevBackendBuiltinSession *sess;
550 CryptoDevBackendSymOpInfo *sym_op_info;
551 CryptoDevBackendAsymOpInfo *asym_op_info;
552 QCryptodevBackendAlgType algtype = op_info->algtype;
553 int status = -VIRTIO_CRYPTO_ERR;
554 Error *local_error = NULL;
556 if (op_info->session_id >= MAX_NUM_SESSIONS ||
557 builtin->sessions[op_info->session_id] == NULL) {
558 error_report("Cannot find a valid session id: %" PRIu64 "",
559 op_info->session_id);
560 return -VIRTIO_CRYPTO_INVSESS;
563 sess = builtin->sessions[op_info->session_id];
564 if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
565 sym_op_info = op_info->u.sym_op_info;
566 status = cryptodev_builtin_sym_operation(sess, sym_op_info,
567 &local_error);
568 } else if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
569 asym_op_info = op_info->u.asym_op_info;
570 status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
571 asym_op_info, &local_error);
574 if (local_error) {
575 error_report_err(local_error);
577 if (op_info->cb) {
578 op_info->cb(op_info->opaque, status);
580 return 0;
583 static void cryptodev_builtin_cleanup(
584 CryptoDevBackend *backend,
585 Error **errp)
587 CryptoDevBackendBuiltin *builtin =
588 CRYPTODEV_BACKEND_BUILTIN(backend);
589 size_t i;
590 int queues = backend->conf.peers.queues;
591 CryptoDevBackendClient *cc;
593 for (i = 0; i < MAX_NUM_SESSIONS; i++) {
594 if (builtin->sessions[i] != NULL) {
595 cryptodev_builtin_close_session(backend, i, 0, NULL, NULL);
599 for (i = 0; i < queues; i++) {
600 cc = backend->conf.peers.ccs[i];
601 if (cc) {
602 cryptodev_backend_free_client(cc);
603 backend->conf.peers.ccs[i] = NULL;
607 cryptodev_backend_set_ready(backend, false);
610 static void
611 cryptodev_builtin_class_init(ObjectClass *oc, void *data)
613 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
615 bc->init = cryptodev_builtin_init;
616 bc->cleanup = cryptodev_builtin_cleanup;
617 bc->create_session = cryptodev_builtin_create_session;
618 bc->close_session = cryptodev_builtin_close_session;
619 bc->do_op = cryptodev_builtin_operation;
622 static const TypeInfo cryptodev_builtin_info = {
623 .name = TYPE_CRYPTODEV_BACKEND_BUILTIN,
624 .parent = TYPE_CRYPTODEV_BACKEND,
625 .class_init = cryptodev_builtin_class_init,
626 .instance_size = sizeof(CryptoDevBackendBuiltin),
629 static void
630 cryptodev_builtin_register_types(void)
632 type_register_static(&cryptodev_builtin_info);
635 type_init(cryptodev_builtin_register_types);