2 * QEMU Cryptodev backend for QEMU cipher APIs
4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
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"
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
;
85 "Only support one queue in cryptdov-builtin backend");
89 cc
= cryptodev_backend_new_client();
90 cc
->info_str
= g_strdup_printf("cryptodev-builtin0");
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);
115 cryptodev_builtin_get_unused_session_index(
116 CryptoDevBackendBuiltin
*builtin
)
120 for (i
= 0; i
< MAX_NUM_SESSIONS
; i
++) {
121 if (builtin
->sessions
[i
] == NULL
) {
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
136 cryptodev_builtin_get_aes_algo(uint32_t key_len
, int mode
, Error
**errp
)
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
;
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
;
163 error_setg(errp
, "Unsupported key length :%u", key_len
);
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
;
184 error_setg(errp
, "Unsupported rsa hash algo: %d", virtio_rsa_hash
);
189 static int cryptodev_builtin_set_rsa_options(
190 int virtio_padding_algo
,
191 int virtio_hash_algo
,
192 QCryptoAkCipherOptionsRSA
*opt
,
195 if (virtio_padding_algo
== VIRTIO_CRYPTO_RSA_PKCS1_PADDING
) {
198 hash_alg
= cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo
, errp
);
202 opt
->hash_alg
= hash_alg
;
203 opt
->padding_alg
= QCRYPTO_RSA_PADDING_ALG_PKCS1
;
207 if (virtio_padding_algo
== VIRTIO_CRYPTO_RSA_RAW_PADDING
) {
208 opt
->padding_alg
= QCRYPTO_RSA_PADDING_ALG_RAW
;
212 error_setg(errp
, "Unsupported rsa padding algo: %d", virtio_padding_algo
);
216 static int cryptodev_builtin_create_cipher_session(
217 CryptoDevBackendBuiltin
*builtin
,
218 CryptoDevBackendSymSessionInfo
*sess_info
,
223 QCryptoCipher
*cipher
;
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
);
232 index
= cryptodev_builtin_get_unused_session_index(builtin
);
234 error_setg(errp
, "Total number of sessions created exceeds %u",
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
,
248 case VIRTIO_CRYPTO_CIPHER_AES_CBC
:
249 mode
= QCRYPTO_CIPHER_MODE_CBC
;
250 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
256 case VIRTIO_CRYPTO_CIPHER_AES_CTR
:
257 mode
= QCRYPTO_CIPHER_MODE_CTR
;
258 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
264 case VIRTIO_CRYPTO_CIPHER_AES_XTS
:
265 mode
= QCRYPTO_CIPHER_MODE_XTS
;
266 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
272 case VIRTIO_CRYPTO_CIPHER_3DES_ECB
:
273 mode
= QCRYPTO_CIPHER_MODE_ECB
;
274 algo
= QCRYPTO_CIPHER_ALG_3DES
;
276 case VIRTIO_CRYPTO_CIPHER_3DES_CBC
:
277 mode
= QCRYPTO_CIPHER_MODE_CBC
;
278 algo
= QCRYPTO_CIPHER_ALG_3DES
;
280 case VIRTIO_CRYPTO_CIPHER_3DES_CTR
:
281 mode
= QCRYPTO_CIPHER_MODE_CTR
;
282 algo
= QCRYPTO_CIPHER_ALG_3DES
;
285 error_setg(errp
, "Unsupported cipher alg :%u",
286 sess_info
->cipher_alg
);
290 cipher
= qcrypto_cipher_new(algo
, mode
,
291 sess_info
->cipher_key
,
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
;
308 static int cryptodev_builtin_create_akcipher_session(
309 CryptoDevBackendBuiltin
*builtin
,
310 CryptoDevBackendAsymSessionInfo
*sess_info
,
313 CryptoDevBackendBuiltinSession
*sess
;
314 QCryptoAkCipher
*akcipher
;
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) {
328 /* TODO support DSA&ECDSA until qemu crypto framework support these */
331 error_setg(errp
, "Unsupported akcipher alg %u", sess_info
->algo
);
335 switch (sess_info
->keytype
) {
336 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC
:
337 type
= QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC
;
340 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE
:
341 type
= QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE
;
345 error_setg(errp
, "Unsupported akcipher keytype %u", sess_info
->keytype
);
349 index
= cryptodev_builtin_get_unused_session_index(builtin
);
351 error_setg(errp
, "Total number of sessions created exceeds %u",
356 akcipher
= qcrypto_akcipher_new(&opts
, type
, sess_info
->key
,
357 sess_info
->keylen
, errp
);
362 sess
= g_new0(CryptoDevBackendBuiltinSession
, 1);
363 sess
->akcipher
= akcipher
;
365 builtin
->sessions
[index
] = sess
;
370 static int cryptodev_builtin_create_session(
371 CryptoDevBackend
*backend
,
372 CryptoDevBackendSessionInfo
*sess_info
,
373 uint32_t queue_index
,
374 CryptoDevCompletionFunc cb
,
377 CryptoDevBackendBuiltin
*builtin
=
378 CRYPTODEV_BACKEND_BUILTIN(backend
);
379 CryptoDevBackendSymSessionInfo
*sym_sess_info
;
380 CryptoDevBackendAsymSessionInfo
*asym_sess_info
;
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
);
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
);
397 case VIRTIO_CRYPTO_HASH_CREATE_SESSION
:
398 case VIRTIO_CRYPTO_MAC_CREATE_SESSION
:
400 error_report("Unsupported opcode :%" PRIu32
"",
402 return -VIRTIO_CRYPTO_NOTSUPP
;
406 error_report_err(local_error
);
409 status
= -VIRTIO_CRYPTO_ERR
;
411 sess_info
->session_id
= ret
;
412 status
= VIRTIO_CRYPTO_OK
;
420 static int cryptodev_builtin_close_session(
421 CryptoDevBackend
*backend
,
423 uint32_t queue_index
,
424 CryptoDevCompletionFunc cb
,
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
);
443 builtin
->sessions
[session_id
] = NULL
;
445 cb(opaque
, VIRTIO_CRYPTO_OK
);
450 static int cryptodev_builtin_sym_operation(
451 CryptoDevBackendBuiltinSession
*sess
,
452 CryptoDevBackendSymOpInfo
*op_info
, Error
**errp
)
456 if (op_info
->op_type
== VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING
) {
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
);
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
);
474 return -VIRTIO_CRYPTO_ERR
;
477 ret
= qcrypto_cipher_decrypt(sess
->cipher
, op_info
->src
,
478 op_info
->dst
, op_info
->src_len
, errp
);
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
)
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
);
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
);
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
);
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
);
519 return -VIRTIO_CRYPTO_ERR
;
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
,
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
);
575 error_report_err(local_error
);
578 op_info
->cb(op_info
->opaque
, status
);
583 static void cryptodev_builtin_cleanup(
584 CryptoDevBackend
*backend
,
587 CryptoDevBackendBuiltin
*builtin
=
588 CRYPTODEV_BACKEND_BUILTIN(backend
);
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
];
602 cryptodev_backend_free_client(cc
);
603 backend
->conf
.peers
.ccs
[i
] = NULL
;
607 cryptodev_backend_set_ready(backend
, false);
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
),
630 cryptodev_builtin_register_types(void)
632 type_register_static(&cryptodev_builtin_info
);
635 type_init(cryptodev_builtin_register_types
);