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 "qapi/error.h"
27 #include "standard-headers/linux/virtio_crypto.h"
28 #include "crypto/cipher.h"
29 #include "crypto/akcipher.h"
30 #include "qom/object.h"
34 * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
35 * name of backend that uses QEMU cipher API
37 #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
39 OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin
, CRYPTODEV_BACKEND_BUILTIN
)
42 typedef struct CryptoDevBackendBuiltinSession
{
43 QCryptoCipher
*cipher
;
44 uint8_t direction
; /* encryption or decryption */
45 uint8_t type
; /* cipher? hash? aead? */
46 QCryptoAkCipher
*akcipher
;
47 QTAILQ_ENTRY(CryptoDevBackendBuiltinSession
) next
;
48 } CryptoDevBackendBuiltinSession
;
50 /* Max number of symmetric/asymmetric sessions */
51 #define MAX_NUM_SESSIONS 256
53 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512
54 #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN 64
56 struct CryptoDevBackendBuiltin
{
57 CryptoDevBackend parent_obj
;
59 CryptoDevBackendBuiltinSession
*sessions
[MAX_NUM_SESSIONS
];
62 static void cryptodev_builtin_init(
63 CryptoDevBackend
*backend
, Error
**errp
)
65 /* Only support one queue */
66 int queues
= backend
->conf
.peers
.queues
;
67 CryptoDevBackendClient
*cc
;
71 "Only support one queue in cryptdov-builtin backend");
75 cc
= cryptodev_backend_new_client(
76 "cryptodev-builtin", NULL
);
77 cc
->info_str
= g_strdup_printf("cryptodev-builtin0");
79 cc
->type
= CRYPTODEV_BACKEND_TYPE_BUILTIN
;
80 backend
->conf
.peers
.ccs
[0] = cc
;
82 backend
->conf
.crypto_services
=
83 1u << VIRTIO_CRYPTO_SERVICE_CIPHER
|
84 1u << VIRTIO_CRYPTO_SERVICE_HASH
|
85 1u << VIRTIO_CRYPTO_SERVICE_MAC
|
86 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER
;
87 backend
->conf
.cipher_algo_l
= 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC
;
88 backend
->conf
.hash_algo
= 1u << VIRTIO_CRYPTO_HASH_SHA1
;
89 backend
->conf
.akcipher_algo
= 1u << VIRTIO_CRYPTO_AKCIPHER_RSA
;
91 * Set the Maximum length of crypto request.
92 * Why this value? Just avoid to overflow when
93 * memory allocation for each crypto request.
95 backend
->conf
.max_size
= LONG_MAX
- sizeof(CryptoDevBackendOpInfo
);
96 backend
->conf
.max_cipher_key_len
= CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN
;
97 backend
->conf
.max_auth_key_len
= CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN
;
99 cryptodev_backend_set_ready(backend
, true);
103 cryptodev_builtin_get_unused_session_index(
104 CryptoDevBackendBuiltin
*builtin
)
108 for (i
= 0; i
< MAX_NUM_SESSIONS
; i
++) {
109 if (builtin
->sessions
[i
] == NULL
) {
117 #define AES_KEYSIZE_128 16
118 #define AES_KEYSIZE_192 24
119 #define AES_KEYSIZE_256 32
120 #define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
121 #define AES_KEYSIZE_256_XTS 64
124 cryptodev_builtin_get_aes_algo(uint32_t key_len
, int mode
, Error
**errp
)
128 if (key_len
== AES_KEYSIZE_128
) {
129 algo
= QCRYPTO_CIPHER_ALG_AES_128
;
130 } else if (key_len
== AES_KEYSIZE_192
) {
131 algo
= QCRYPTO_CIPHER_ALG_AES_192
;
132 } else if (key_len
== AES_KEYSIZE_256
) { /* equals AES_KEYSIZE_128_XTS */
133 if (mode
== QCRYPTO_CIPHER_MODE_XTS
) {
134 algo
= QCRYPTO_CIPHER_ALG_AES_128
;
136 algo
= QCRYPTO_CIPHER_ALG_AES_256
;
138 } else if (key_len
== AES_KEYSIZE_256_XTS
) {
139 if (mode
== QCRYPTO_CIPHER_MODE_XTS
) {
140 algo
= QCRYPTO_CIPHER_ALG_AES_256
;
151 error_setg(errp
, "Unsupported key length :%u", key_len
);
155 static int cryptodev_builtin_get_rsa_hash_algo(
156 int virtio_rsa_hash
, Error
**errp
)
158 switch (virtio_rsa_hash
) {
159 case VIRTIO_CRYPTO_RSA_MD5
:
160 return QCRYPTO_HASH_ALG_MD5
;
162 case VIRTIO_CRYPTO_RSA_SHA1
:
163 return QCRYPTO_HASH_ALG_SHA1
;
165 case VIRTIO_CRYPTO_RSA_SHA256
:
166 return QCRYPTO_HASH_ALG_SHA256
;
168 case VIRTIO_CRYPTO_RSA_SHA512
:
169 return QCRYPTO_HASH_ALG_SHA512
;
172 error_setg(errp
, "Unsupported rsa hash algo: %d", virtio_rsa_hash
);
177 static int cryptodev_builtin_set_rsa_options(
178 int virtio_padding_algo
,
179 int virtio_hash_algo
,
180 QCryptoAkCipherOptionsRSA
*opt
,
183 if (virtio_padding_algo
== VIRTIO_CRYPTO_RSA_PKCS1_PADDING
) {
186 hash_alg
= cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo
, errp
);
190 opt
->hash_alg
= hash_alg
;
191 opt
->padding_alg
= QCRYPTO_RSA_PADDING_ALG_PKCS1
;
195 if (virtio_padding_algo
== VIRTIO_CRYPTO_RSA_RAW_PADDING
) {
196 opt
->padding_alg
= QCRYPTO_RSA_PADDING_ALG_RAW
;
200 error_setg(errp
, "Unsupported rsa padding algo: %d", virtio_padding_algo
);
204 static int cryptodev_builtin_create_cipher_session(
205 CryptoDevBackendBuiltin
*builtin
,
206 CryptoDevBackendSymSessionInfo
*sess_info
,
211 QCryptoCipher
*cipher
;
213 CryptoDevBackendBuiltinSession
*sess
;
215 if (sess_info
->op_type
!= VIRTIO_CRYPTO_SYM_OP_CIPHER
) {
216 error_setg(errp
, "Unsupported optype :%u", sess_info
->op_type
);
220 index
= cryptodev_builtin_get_unused_session_index(builtin
);
222 error_setg(errp
, "Total number of sessions created exceeds %u",
227 switch (sess_info
->cipher_alg
) {
228 case VIRTIO_CRYPTO_CIPHER_AES_ECB
:
229 mode
= QCRYPTO_CIPHER_MODE_ECB
;
230 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
236 case VIRTIO_CRYPTO_CIPHER_AES_CBC
:
237 mode
= QCRYPTO_CIPHER_MODE_CBC
;
238 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
244 case VIRTIO_CRYPTO_CIPHER_AES_CTR
:
245 mode
= QCRYPTO_CIPHER_MODE_CTR
;
246 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
252 case VIRTIO_CRYPTO_CIPHER_AES_XTS
:
253 mode
= QCRYPTO_CIPHER_MODE_XTS
;
254 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
260 case VIRTIO_CRYPTO_CIPHER_3DES_ECB
:
261 mode
= QCRYPTO_CIPHER_MODE_ECB
;
262 algo
= QCRYPTO_CIPHER_ALG_3DES
;
264 case VIRTIO_CRYPTO_CIPHER_3DES_CBC
:
265 mode
= QCRYPTO_CIPHER_MODE_CBC
;
266 algo
= QCRYPTO_CIPHER_ALG_3DES
;
268 case VIRTIO_CRYPTO_CIPHER_3DES_CTR
:
269 mode
= QCRYPTO_CIPHER_MODE_CTR
;
270 algo
= QCRYPTO_CIPHER_ALG_3DES
;
273 error_setg(errp
, "Unsupported cipher alg :%u",
274 sess_info
->cipher_alg
);
278 cipher
= qcrypto_cipher_new(algo
, mode
,
279 sess_info
->cipher_key
,
286 sess
= g_new0(CryptoDevBackendBuiltinSession
, 1);
287 sess
->cipher
= cipher
;
288 sess
->direction
= sess_info
->direction
;
289 sess
->type
= sess_info
->op_type
;
291 builtin
->sessions
[index
] = sess
;
296 static int cryptodev_builtin_create_akcipher_session(
297 CryptoDevBackendBuiltin
*builtin
,
298 CryptoDevBackendAsymSessionInfo
*sess_info
,
301 CryptoDevBackendBuiltinSession
*sess
;
302 QCryptoAkCipher
*akcipher
;
304 QCryptoAkCipherKeyType type
;
305 QCryptoAkCipherOptions opts
;
307 switch (sess_info
->algo
) {
308 case VIRTIO_CRYPTO_AKCIPHER_RSA
:
309 opts
.alg
= QCRYPTO_AKCIPHER_ALG_RSA
;
310 if (cryptodev_builtin_set_rsa_options(sess_info
->u
.rsa
.padding_algo
,
311 sess_info
->u
.rsa
.hash_algo
, &opts
.u
.rsa
, errp
) != 0) {
316 /* TODO support DSA&ECDSA until qemu crypto framework support these */
319 error_setg(errp
, "Unsupported akcipher alg %u", sess_info
->algo
);
323 switch (sess_info
->keytype
) {
324 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC
:
325 type
= QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC
;
328 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE
:
329 type
= QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE
;
333 error_setg(errp
, "Unsupported akcipher keytype %u", sess_info
->keytype
);
337 index
= cryptodev_builtin_get_unused_session_index(builtin
);
339 error_setg(errp
, "Total number of sessions created exceeds %u",
344 akcipher
= qcrypto_akcipher_new(&opts
, type
, sess_info
->key
,
345 sess_info
->keylen
, errp
);
350 sess
= g_new0(CryptoDevBackendBuiltinSession
, 1);
351 sess
->akcipher
= akcipher
;
353 builtin
->sessions
[index
] = sess
;
358 static int cryptodev_builtin_create_session(
359 CryptoDevBackend
*backend
,
360 CryptoDevBackendSessionInfo
*sess_info
,
361 uint32_t queue_index
,
362 CryptoDevCompletionFunc cb
,
365 CryptoDevBackendBuiltin
*builtin
=
366 CRYPTODEV_BACKEND_BUILTIN(backend
);
367 CryptoDevBackendSymSessionInfo
*sym_sess_info
;
368 CryptoDevBackendAsymSessionInfo
*asym_sess_info
;
370 Error
*local_error
= NULL
;
372 switch (sess_info
->op_code
) {
373 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION
:
374 sym_sess_info
= &sess_info
->u
.sym_sess_info
;
375 ret
= cryptodev_builtin_create_cipher_session(
376 builtin
, sym_sess_info
, &local_error
);
379 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION
:
380 asym_sess_info
= &sess_info
->u
.asym_sess_info
;
381 ret
= cryptodev_builtin_create_akcipher_session(
382 builtin
, asym_sess_info
, &local_error
);
385 case VIRTIO_CRYPTO_HASH_CREATE_SESSION
:
386 case VIRTIO_CRYPTO_MAC_CREATE_SESSION
:
388 error_setg(&local_error
, "Unsupported opcode :%" PRIu32
"",
390 return -VIRTIO_CRYPTO_NOTSUPP
;
394 error_report_err(local_error
);
397 status
= -VIRTIO_CRYPTO_ERR
;
399 sess_info
->session_id
= ret
;
400 status
= VIRTIO_CRYPTO_OK
;
408 static int cryptodev_builtin_close_session(
409 CryptoDevBackend
*backend
,
411 uint32_t queue_index
,
412 CryptoDevCompletionFunc cb
,
415 CryptoDevBackendBuiltin
*builtin
=
416 CRYPTODEV_BACKEND_BUILTIN(backend
);
417 CryptoDevBackendBuiltinSession
*session
;
419 assert(session_id
< MAX_NUM_SESSIONS
&& builtin
->sessions
[session_id
]);
421 session
= builtin
->sessions
[session_id
];
422 if (session
->cipher
) {
423 qcrypto_cipher_free(session
->cipher
);
424 } else if (session
->akcipher
) {
425 qcrypto_akcipher_free(session
->akcipher
);
429 builtin
->sessions
[session_id
] = NULL
;
431 cb(opaque
, VIRTIO_CRYPTO_OK
);
436 static int cryptodev_builtin_sym_operation(
437 CryptoDevBackendBuiltinSession
*sess
,
438 CryptoDevBackendSymOpInfo
*op_info
, Error
**errp
)
442 if (op_info
->op_type
== VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING
) {
444 "Algorithm chain is unsupported for cryptdoev-builtin");
445 return -VIRTIO_CRYPTO_NOTSUPP
;
448 if (op_info
->iv_len
> 0) {
449 ret
= qcrypto_cipher_setiv(sess
->cipher
, op_info
->iv
,
450 op_info
->iv_len
, errp
);
452 return -VIRTIO_CRYPTO_ERR
;
456 if (sess
->direction
== VIRTIO_CRYPTO_OP_ENCRYPT
) {
457 ret
= qcrypto_cipher_encrypt(sess
->cipher
, op_info
->src
,
458 op_info
->dst
, op_info
->src_len
, errp
);
460 return -VIRTIO_CRYPTO_ERR
;
463 ret
= qcrypto_cipher_decrypt(sess
->cipher
, op_info
->src
,
464 op_info
->dst
, op_info
->src_len
, errp
);
466 return -VIRTIO_CRYPTO_ERR
;
470 return VIRTIO_CRYPTO_OK
;
473 static int cryptodev_builtin_asym_operation(
474 CryptoDevBackendBuiltinSession
*sess
, uint32_t op_code
,
475 CryptoDevBackendAsymOpInfo
*op_info
, Error
**errp
)
480 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT
:
481 ret
= qcrypto_akcipher_encrypt(sess
->akcipher
,
482 op_info
->src
, op_info
->src_len
,
483 op_info
->dst
, op_info
->dst_len
, errp
);
486 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT
:
487 ret
= qcrypto_akcipher_decrypt(sess
->akcipher
,
488 op_info
->src
, op_info
->src_len
,
489 op_info
->dst
, op_info
->dst_len
, errp
);
492 case VIRTIO_CRYPTO_AKCIPHER_SIGN
:
493 ret
= qcrypto_akcipher_sign(sess
->akcipher
,
494 op_info
->src
, op_info
->src_len
,
495 op_info
->dst
, op_info
->dst_len
, errp
);
498 case VIRTIO_CRYPTO_AKCIPHER_VERIFY
:
499 ret
= qcrypto_akcipher_verify(sess
->akcipher
,
500 op_info
->src
, op_info
->src_len
,
501 op_info
->dst
, op_info
->dst_len
, errp
);
505 return -VIRTIO_CRYPTO_ERR
;
509 if (op_code
== VIRTIO_CRYPTO_AKCIPHER_VERIFY
) {
510 return -VIRTIO_CRYPTO_KEY_REJECTED
;
512 return -VIRTIO_CRYPTO_ERR
;
515 /* Buffer is too short, typically the driver should handle this case */
516 if (unlikely(ret
> op_info
->dst_len
)) {
517 if (errp
&& !*errp
) {
518 error_setg(errp
, "dst buffer too short");
521 return -VIRTIO_CRYPTO_ERR
;
524 op_info
->dst_len
= ret
;
526 return VIRTIO_CRYPTO_OK
;
529 static int cryptodev_builtin_operation(
530 CryptoDevBackend
*backend
,
531 CryptoDevBackendOpInfo
*op_info
,
532 uint32_t queue_index
,
533 CryptoDevCompletionFunc cb
,
536 CryptoDevBackendBuiltin
*builtin
=
537 CRYPTODEV_BACKEND_BUILTIN(backend
);
538 CryptoDevBackendBuiltinSession
*sess
;
539 CryptoDevBackendSymOpInfo
*sym_op_info
;
540 CryptoDevBackendAsymOpInfo
*asym_op_info
;
541 enum CryptoDevBackendAlgType algtype
= op_info
->algtype
;
542 int status
= -VIRTIO_CRYPTO_ERR
;
543 Error
*local_error
= NULL
;
545 if (op_info
->session_id
>= MAX_NUM_SESSIONS
||
546 builtin
->sessions
[op_info
->session_id
] == NULL
) {
547 error_setg(&local_error
, "Cannot find a valid session id: %" PRIu64
"",
548 op_info
->session_id
);
549 return -VIRTIO_CRYPTO_INVSESS
;
552 sess
= builtin
->sessions
[op_info
->session_id
];
553 if (algtype
== CRYPTODEV_BACKEND_ALG_SYM
) {
554 sym_op_info
= op_info
->u
.sym_op_info
;
555 status
= cryptodev_builtin_sym_operation(sess
, sym_op_info
,
557 } else if (algtype
== CRYPTODEV_BACKEND_ALG_ASYM
) {
558 asym_op_info
= op_info
->u
.asym_op_info
;
559 status
= cryptodev_builtin_asym_operation(sess
, op_info
->op_code
,
560 asym_op_info
, &local_error
);
564 error_report_err(local_error
);
572 static void cryptodev_builtin_cleanup(
573 CryptoDevBackend
*backend
,
576 CryptoDevBackendBuiltin
*builtin
=
577 CRYPTODEV_BACKEND_BUILTIN(backend
);
579 int queues
= backend
->conf
.peers
.queues
;
580 CryptoDevBackendClient
*cc
;
582 for (i
= 0; i
< MAX_NUM_SESSIONS
; i
++) {
583 if (builtin
->sessions
[i
] != NULL
) {
584 cryptodev_builtin_close_session(backend
, i
, 0, NULL
, NULL
);
588 for (i
= 0; i
< queues
; i
++) {
589 cc
= backend
->conf
.peers
.ccs
[i
];
591 cryptodev_backend_free_client(cc
);
592 backend
->conf
.peers
.ccs
[i
] = NULL
;
596 cryptodev_backend_set_ready(backend
, false);
600 cryptodev_builtin_class_init(ObjectClass
*oc
, void *data
)
602 CryptoDevBackendClass
*bc
= CRYPTODEV_BACKEND_CLASS(oc
);
604 bc
->init
= cryptodev_builtin_init
;
605 bc
->cleanup
= cryptodev_builtin_cleanup
;
606 bc
->create_session
= cryptodev_builtin_create_session
;
607 bc
->close_session
= cryptodev_builtin_close_session
;
608 bc
->do_op
= cryptodev_builtin_operation
;
611 static const TypeInfo cryptodev_builtin_info
= {
612 .name
= TYPE_CRYPTODEV_BACKEND_BUILTIN
,
613 .parent
= TYPE_CRYPTODEV_BACKEND
,
614 .class_init
= cryptodev_builtin_class_init
,
615 .instance_size
= sizeof(CryptoDevBackendBuiltin
),
619 cryptodev_builtin_register_types(void)
621 type_register_static(&cryptodev_builtin_info
);
624 type_init(cryptodev_builtin_register_types
);