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 int64_t cryptodev_builtin_create_session(
359 CryptoDevBackend
*backend
,
360 CryptoDevBackendSessionInfo
*sess_info
,
361 uint32_t queue_index
, Error
**errp
)
363 CryptoDevBackendBuiltin
*builtin
=
364 CRYPTODEV_BACKEND_BUILTIN(backend
);
365 CryptoDevBackendSymSessionInfo
*sym_sess_info
;
366 CryptoDevBackendAsymSessionInfo
*asym_sess_info
;
368 switch (sess_info
->op_code
) {
369 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION
:
370 sym_sess_info
= &sess_info
->u
.sym_sess_info
;
371 return cryptodev_builtin_create_cipher_session(
372 builtin
, sym_sess_info
, errp
);
374 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION
:
375 asym_sess_info
= &sess_info
->u
.asym_sess_info
;
376 return cryptodev_builtin_create_akcipher_session(
377 builtin
, asym_sess_info
, errp
);
379 case VIRTIO_CRYPTO_HASH_CREATE_SESSION
:
380 case VIRTIO_CRYPTO_MAC_CREATE_SESSION
:
382 error_setg(errp
, "Unsupported opcode :%" PRIu32
"",
390 static int cryptodev_builtin_close_session(
391 CryptoDevBackend
*backend
,
393 uint32_t queue_index
, Error
**errp
)
395 CryptoDevBackendBuiltin
*builtin
=
396 CRYPTODEV_BACKEND_BUILTIN(backend
);
397 CryptoDevBackendBuiltinSession
*session
;
399 assert(session_id
< MAX_NUM_SESSIONS
&& builtin
->sessions
[session_id
]);
401 session
= builtin
->sessions
[session_id
];
402 if (session
->cipher
) {
403 qcrypto_cipher_free(session
->cipher
);
404 } else if (session
->akcipher
) {
405 qcrypto_akcipher_free(session
->akcipher
);
409 builtin
->sessions
[session_id
] = NULL
;
413 static int cryptodev_builtin_sym_operation(
414 CryptoDevBackendBuiltinSession
*sess
,
415 CryptoDevBackendSymOpInfo
*op_info
, Error
**errp
)
419 if (op_info
->op_type
== VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING
) {
421 "Algorithm chain is unsupported for cryptdoev-builtin");
422 return -VIRTIO_CRYPTO_NOTSUPP
;
425 if (op_info
->iv_len
> 0) {
426 ret
= qcrypto_cipher_setiv(sess
->cipher
, op_info
->iv
,
427 op_info
->iv_len
, errp
);
429 return -VIRTIO_CRYPTO_ERR
;
433 if (sess
->direction
== VIRTIO_CRYPTO_OP_ENCRYPT
) {
434 ret
= qcrypto_cipher_encrypt(sess
->cipher
, op_info
->src
,
435 op_info
->dst
, op_info
->src_len
, errp
);
437 return -VIRTIO_CRYPTO_ERR
;
440 ret
= qcrypto_cipher_decrypt(sess
->cipher
, op_info
->src
,
441 op_info
->dst
, op_info
->src_len
, errp
);
443 return -VIRTIO_CRYPTO_ERR
;
447 return VIRTIO_CRYPTO_OK
;
450 static int cryptodev_builtin_asym_operation(
451 CryptoDevBackendBuiltinSession
*sess
, uint32_t op_code
,
452 CryptoDevBackendAsymOpInfo
*op_info
, Error
**errp
)
457 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT
:
458 ret
= qcrypto_akcipher_encrypt(sess
->akcipher
,
459 op_info
->src
, op_info
->src_len
,
460 op_info
->dst
, op_info
->dst_len
, errp
);
463 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT
:
464 ret
= qcrypto_akcipher_decrypt(sess
->akcipher
,
465 op_info
->src
, op_info
->src_len
,
466 op_info
->dst
, op_info
->dst_len
, errp
);
469 case VIRTIO_CRYPTO_AKCIPHER_SIGN
:
470 ret
= qcrypto_akcipher_sign(sess
->akcipher
,
471 op_info
->src
, op_info
->src_len
,
472 op_info
->dst
, op_info
->dst_len
, errp
);
475 case VIRTIO_CRYPTO_AKCIPHER_VERIFY
:
476 ret
= qcrypto_akcipher_verify(sess
->akcipher
,
477 op_info
->src
, op_info
->src_len
,
478 op_info
->dst
, op_info
->dst_len
, errp
);
482 return -VIRTIO_CRYPTO_ERR
;
486 if (op_code
== VIRTIO_CRYPTO_AKCIPHER_VERIFY
) {
487 return -VIRTIO_CRYPTO_KEY_REJECTED
;
489 return -VIRTIO_CRYPTO_ERR
;
492 /* Buffer is too short, typically the driver should handle this case */
493 if (unlikely(ret
> op_info
->dst_len
)) {
494 if (errp
&& !*errp
) {
495 error_setg(errp
, "dst buffer too short");
498 return -VIRTIO_CRYPTO_ERR
;
501 op_info
->dst_len
= ret
;
503 return VIRTIO_CRYPTO_OK
;
506 static int cryptodev_builtin_operation(
507 CryptoDevBackend
*backend
,
508 CryptoDevBackendOpInfo
*op_info
,
509 uint32_t queue_index
, Error
**errp
)
511 CryptoDevBackendBuiltin
*builtin
=
512 CRYPTODEV_BACKEND_BUILTIN(backend
);
513 CryptoDevBackendBuiltinSession
*sess
;
514 CryptoDevBackendSymOpInfo
*sym_op_info
;
515 CryptoDevBackendAsymOpInfo
*asym_op_info
;
516 enum CryptoDevBackendAlgType algtype
= op_info
->algtype
;
517 int ret
= -VIRTIO_CRYPTO_ERR
;
519 if (op_info
->session_id
>= MAX_NUM_SESSIONS
||
520 builtin
->sessions
[op_info
->session_id
] == NULL
) {
521 error_setg(errp
, "Cannot find a valid session id: %" PRIu64
"",
522 op_info
->session_id
);
523 return -VIRTIO_CRYPTO_INVSESS
;
526 sess
= builtin
->sessions
[op_info
->session_id
];
527 if (algtype
== CRYPTODEV_BACKEND_ALG_SYM
) {
528 sym_op_info
= op_info
->u
.sym_op_info
;
529 ret
= cryptodev_builtin_sym_operation(sess
, sym_op_info
, errp
);
530 } else if (algtype
== CRYPTODEV_BACKEND_ALG_ASYM
) {
531 asym_op_info
= op_info
->u
.asym_op_info
;
532 ret
= cryptodev_builtin_asym_operation(sess
, op_info
->op_code
,
539 static void cryptodev_builtin_cleanup(
540 CryptoDevBackend
*backend
,
543 CryptoDevBackendBuiltin
*builtin
=
544 CRYPTODEV_BACKEND_BUILTIN(backend
);
546 int queues
= backend
->conf
.peers
.queues
;
547 CryptoDevBackendClient
*cc
;
549 for (i
= 0; i
< MAX_NUM_SESSIONS
; i
++) {
550 if (builtin
->sessions
[i
] != NULL
) {
551 cryptodev_builtin_close_session(backend
, i
, 0, &error_abort
);
555 for (i
= 0; i
< queues
; i
++) {
556 cc
= backend
->conf
.peers
.ccs
[i
];
558 cryptodev_backend_free_client(cc
);
559 backend
->conf
.peers
.ccs
[i
] = NULL
;
563 cryptodev_backend_set_ready(backend
, false);
567 cryptodev_builtin_class_init(ObjectClass
*oc
, void *data
)
569 CryptoDevBackendClass
*bc
= CRYPTODEV_BACKEND_CLASS(oc
);
571 bc
->init
= cryptodev_builtin_init
;
572 bc
->cleanup
= cryptodev_builtin_cleanup
;
573 bc
->create_session
= cryptodev_builtin_create_session
;
574 bc
->close_session
= cryptodev_builtin_close_session
;
575 bc
->do_op
= cryptodev_builtin_operation
;
578 static const TypeInfo cryptodev_builtin_info
= {
579 .name
= TYPE_CRYPTODEV_BACKEND_BUILTIN
,
580 .parent
= TYPE_CRYPTODEV_BACKEND
,
581 .class_init
= cryptodev_builtin_class_init
,
582 .instance_size
= sizeof(CryptoDevBackendBuiltin
),
586 cryptodev_builtin_register_types(void)
588 type_register_static(&cryptodev_builtin_info
);
591 type_init(cryptodev_builtin_register_types
);