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_akcipher(CryptoDevBackend
*backend
)
64 QCryptoAkCipherOptions opts
;
66 opts
.alg
= QCRYPTO_AKCIPHER_ALG_RSA
;
67 opts
.u
.rsa
.padding_alg
= QCRYPTO_RSA_PADDING_ALG_RAW
;
68 if (qcrypto_akcipher_supports(&opts
)) {
69 backend
->conf
.crypto_services
|=
70 (1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER
);
71 backend
->conf
.akcipher_algo
= 1u << VIRTIO_CRYPTO_AKCIPHER_RSA
;
75 static void cryptodev_builtin_init(
76 CryptoDevBackend
*backend
, Error
**errp
)
78 /* Only support one queue */
79 int queues
= backend
->conf
.peers
.queues
;
80 CryptoDevBackendClient
*cc
;
84 "Only support one queue in cryptdov-builtin backend");
88 cc
= cryptodev_backend_new_client();
89 cc
->info_str
= g_strdup_printf("cryptodev-builtin0");
91 cc
->type
= QCRYPTODEV_BACKEND_TYPE_BUILTIN
;
92 backend
->conf
.peers
.ccs
[0] = cc
;
94 backend
->conf
.crypto_services
=
95 1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER
|
96 1u << QCRYPTODEV_BACKEND_SERVICE_HASH
|
97 1u << QCRYPTODEV_BACKEND_SERVICE_MAC
;
98 backend
->conf
.cipher_algo_l
= 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC
;
99 backend
->conf
.hash_algo
= 1u << VIRTIO_CRYPTO_HASH_SHA1
;
101 * Set the Maximum length of crypto request.
102 * Why this value? Just avoid to overflow when
103 * memory allocation for each crypto request.
105 backend
->conf
.max_size
= LONG_MAX
- sizeof(CryptoDevBackendOpInfo
);
106 backend
->conf
.max_cipher_key_len
= CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN
;
107 backend
->conf
.max_auth_key_len
= CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN
;
108 cryptodev_builtin_init_akcipher(backend
);
110 cryptodev_backend_set_ready(backend
, true);
114 cryptodev_builtin_get_unused_session_index(
115 CryptoDevBackendBuiltin
*builtin
)
119 for (i
= 0; i
< MAX_NUM_SESSIONS
; i
++) {
120 if (builtin
->sessions
[i
] == NULL
) {
128 #define AES_KEYSIZE_128 16
129 #define AES_KEYSIZE_192 24
130 #define AES_KEYSIZE_256 32
131 #define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
132 #define AES_KEYSIZE_256_XTS 64
135 cryptodev_builtin_get_aes_algo(uint32_t key_len
, int mode
, Error
**errp
)
139 if (key_len
== AES_KEYSIZE_128
) {
140 algo
= QCRYPTO_CIPHER_ALG_AES_128
;
141 } else if (key_len
== AES_KEYSIZE_192
) {
142 algo
= QCRYPTO_CIPHER_ALG_AES_192
;
143 } else if (key_len
== AES_KEYSIZE_256
) { /* equals AES_KEYSIZE_128_XTS */
144 if (mode
== QCRYPTO_CIPHER_MODE_XTS
) {
145 algo
= QCRYPTO_CIPHER_ALG_AES_128
;
147 algo
= QCRYPTO_CIPHER_ALG_AES_256
;
149 } else if (key_len
== AES_KEYSIZE_256_XTS
) {
150 if (mode
== QCRYPTO_CIPHER_MODE_XTS
) {
151 algo
= QCRYPTO_CIPHER_ALG_AES_256
;
162 error_setg(errp
, "Unsupported key length :%u", key_len
);
166 static int cryptodev_builtin_get_rsa_hash_algo(
167 int virtio_rsa_hash
, Error
**errp
)
169 switch (virtio_rsa_hash
) {
170 case VIRTIO_CRYPTO_RSA_MD5
:
171 return QCRYPTO_HASH_ALG_MD5
;
173 case VIRTIO_CRYPTO_RSA_SHA1
:
174 return QCRYPTO_HASH_ALG_SHA1
;
176 case VIRTIO_CRYPTO_RSA_SHA256
:
177 return QCRYPTO_HASH_ALG_SHA256
;
179 case VIRTIO_CRYPTO_RSA_SHA512
:
180 return QCRYPTO_HASH_ALG_SHA512
;
183 error_setg(errp
, "Unsupported rsa hash algo: %d", virtio_rsa_hash
);
188 static int cryptodev_builtin_set_rsa_options(
189 int virtio_padding_algo
,
190 int virtio_hash_algo
,
191 QCryptoAkCipherOptionsRSA
*opt
,
194 if (virtio_padding_algo
== VIRTIO_CRYPTO_RSA_PKCS1_PADDING
) {
197 hash_alg
= cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo
, errp
);
201 opt
->hash_alg
= hash_alg
;
202 opt
->padding_alg
= QCRYPTO_RSA_PADDING_ALG_PKCS1
;
206 if (virtio_padding_algo
== VIRTIO_CRYPTO_RSA_RAW_PADDING
) {
207 opt
->padding_alg
= QCRYPTO_RSA_PADDING_ALG_RAW
;
211 error_setg(errp
, "Unsupported rsa padding algo: %d", virtio_padding_algo
);
215 static int cryptodev_builtin_create_cipher_session(
216 CryptoDevBackendBuiltin
*builtin
,
217 CryptoDevBackendSymSessionInfo
*sess_info
,
222 QCryptoCipher
*cipher
;
224 CryptoDevBackendBuiltinSession
*sess
;
226 if (sess_info
->op_type
!= VIRTIO_CRYPTO_SYM_OP_CIPHER
) {
227 error_setg(errp
, "Unsupported optype :%u", sess_info
->op_type
);
231 index
= cryptodev_builtin_get_unused_session_index(builtin
);
233 error_setg(errp
, "Total number of sessions created exceeds %u",
238 switch (sess_info
->cipher_alg
) {
239 case VIRTIO_CRYPTO_CIPHER_AES_ECB
:
240 mode
= QCRYPTO_CIPHER_MODE_ECB
;
241 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
247 case VIRTIO_CRYPTO_CIPHER_AES_CBC
:
248 mode
= QCRYPTO_CIPHER_MODE_CBC
;
249 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
255 case VIRTIO_CRYPTO_CIPHER_AES_CTR
:
256 mode
= QCRYPTO_CIPHER_MODE_CTR
;
257 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
263 case VIRTIO_CRYPTO_CIPHER_AES_XTS
:
264 mode
= QCRYPTO_CIPHER_MODE_XTS
;
265 algo
= cryptodev_builtin_get_aes_algo(sess_info
->key_len
,
271 case VIRTIO_CRYPTO_CIPHER_3DES_ECB
:
272 mode
= QCRYPTO_CIPHER_MODE_ECB
;
273 algo
= QCRYPTO_CIPHER_ALG_3DES
;
275 case VIRTIO_CRYPTO_CIPHER_3DES_CBC
:
276 mode
= QCRYPTO_CIPHER_MODE_CBC
;
277 algo
= QCRYPTO_CIPHER_ALG_3DES
;
279 case VIRTIO_CRYPTO_CIPHER_3DES_CTR
:
280 mode
= QCRYPTO_CIPHER_MODE_CTR
;
281 algo
= QCRYPTO_CIPHER_ALG_3DES
;
284 error_setg(errp
, "Unsupported cipher alg :%u",
285 sess_info
->cipher_alg
);
289 cipher
= qcrypto_cipher_new(algo
, mode
,
290 sess_info
->cipher_key
,
297 sess
= g_new0(CryptoDevBackendBuiltinSession
, 1);
298 sess
->cipher
= cipher
;
299 sess
->direction
= sess_info
->direction
;
300 sess
->type
= sess_info
->op_type
;
302 builtin
->sessions
[index
] = sess
;
307 static int cryptodev_builtin_create_akcipher_session(
308 CryptoDevBackendBuiltin
*builtin
,
309 CryptoDevBackendAsymSessionInfo
*sess_info
,
312 CryptoDevBackendBuiltinSession
*sess
;
313 QCryptoAkCipher
*akcipher
;
315 QCryptoAkCipherKeyType type
;
316 QCryptoAkCipherOptions opts
;
318 switch (sess_info
->algo
) {
319 case VIRTIO_CRYPTO_AKCIPHER_RSA
:
320 opts
.alg
= QCRYPTO_AKCIPHER_ALG_RSA
;
321 if (cryptodev_builtin_set_rsa_options(sess_info
->u
.rsa
.padding_algo
,
322 sess_info
->u
.rsa
.hash_algo
, &opts
.u
.rsa
, errp
) != 0) {
327 /* TODO support DSA&ECDSA until qemu crypto framework support these */
330 error_setg(errp
, "Unsupported akcipher alg %u", sess_info
->algo
);
334 switch (sess_info
->keytype
) {
335 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC
:
336 type
= QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC
;
339 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE
:
340 type
= QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE
;
344 error_setg(errp
, "Unsupported akcipher keytype %u", sess_info
->keytype
);
348 index
= cryptodev_builtin_get_unused_session_index(builtin
);
350 error_setg(errp
, "Total number of sessions created exceeds %u",
355 akcipher
= qcrypto_akcipher_new(&opts
, type
, sess_info
->key
,
356 sess_info
->keylen
, errp
);
361 sess
= g_new0(CryptoDevBackendBuiltinSession
, 1);
362 sess
->akcipher
= akcipher
;
364 builtin
->sessions
[index
] = sess
;
369 static int cryptodev_builtin_create_session(
370 CryptoDevBackend
*backend
,
371 CryptoDevBackendSessionInfo
*sess_info
,
372 uint32_t queue_index
,
373 CryptoDevCompletionFunc cb
,
376 CryptoDevBackendBuiltin
*builtin
=
377 CRYPTODEV_BACKEND_BUILTIN(backend
);
378 CryptoDevBackendSymSessionInfo
*sym_sess_info
;
379 CryptoDevBackendAsymSessionInfo
*asym_sess_info
;
381 Error
*local_error
= NULL
;
383 switch (sess_info
->op_code
) {
384 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION
:
385 sym_sess_info
= &sess_info
->u
.sym_sess_info
;
386 ret
= cryptodev_builtin_create_cipher_session(
387 builtin
, sym_sess_info
, &local_error
);
390 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION
:
391 asym_sess_info
= &sess_info
->u
.asym_sess_info
;
392 ret
= cryptodev_builtin_create_akcipher_session(
393 builtin
, asym_sess_info
, &local_error
);
396 case VIRTIO_CRYPTO_HASH_CREATE_SESSION
:
397 case VIRTIO_CRYPTO_MAC_CREATE_SESSION
:
399 error_setg(&local_error
, "Unsupported opcode :%" PRIu32
"",
401 return -VIRTIO_CRYPTO_NOTSUPP
;
405 error_report_err(local_error
);
408 status
= -VIRTIO_CRYPTO_ERR
;
410 sess_info
->session_id
= ret
;
411 status
= VIRTIO_CRYPTO_OK
;
419 static int cryptodev_builtin_close_session(
420 CryptoDevBackend
*backend
,
422 uint32_t queue_index
,
423 CryptoDevCompletionFunc cb
,
426 CryptoDevBackendBuiltin
*builtin
=
427 CRYPTODEV_BACKEND_BUILTIN(backend
);
428 CryptoDevBackendBuiltinSession
*session
;
430 assert(session_id
< MAX_NUM_SESSIONS
&& builtin
->sessions
[session_id
]);
432 session
= builtin
->sessions
[session_id
];
433 if (session
->cipher
) {
434 qcrypto_cipher_free(session
->cipher
);
435 } else if (session
->akcipher
) {
436 qcrypto_akcipher_free(session
->akcipher
);
440 builtin
->sessions
[session_id
] = NULL
;
442 cb(opaque
, VIRTIO_CRYPTO_OK
);
447 static int cryptodev_builtin_sym_operation(
448 CryptoDevBackendBuiltinSession
*sess
,
449 CryptoDevBackendSymOpInfo
*op_info
, Error
**errp
)
453 if (op_info
->op_type
== VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING
) {
455 "Algorithm chain is unsupported for cryptdoev-builtin");
456 return -VIRTIO_CRYPTO_NOTSUPP
;
459 if (op_info
->iv_len
> 0) {
460 ret
= qcrypto_cipher_setiv(sess
->cipher
, op_info
->iv
,
461 op_info
->iv_len
, errp
);
463 return -VIRTIO_CRYPTO_ERR
;
467 if (sess
->direction
== VIRTIO_CRYPTO_OP_ENCRYPT
) {
468 ret
= qcrypto_cipher_encrypt(sess
->cipher
, op_info
->src
,
469 op_info
->dst
, op_info
->src_len
, errp
);
471 return -VIRTIO_CRYPTO_ERR
;
474 ret
= qcrypto_cipher_decrypt(sess
->cipher
, op_info
->src
,
475 op_info
->dst
, op_info
->src_len
, errp
);
477 return -VIRTIO_CRYPTO_ERR
;
481 return VIRTIO_CRYPTO_OK
;
484 static int cryptodev_builtin_asym_operation(
485 CryptoDevBackendBuiltinSession
*sess
, uint32_t op_code
,
486 CryptoDevBackendAsymOpInfo
*op_info
, Error
**errp
)
491 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT
:
492 ret
= qcrypto_akcipher_encrypt(sess
->akcipher
,
493 op_info
->src
, op_info
->src_len
,
494 op_info
->dst
, op_info
->dst_len
, errp
);
497 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT
:
498 ret
= qcrypto_akcipher_decrypt(sess
->akcipher
,
499 op_info
->src
, op_info
->src_len
,
500 op_info
->dst
, op_info
->dst_len
, errp
);
503 case VIRTIO_CRYPTO_AKCIPHER_SIGN
:
504 ret
= qcrypto_akcipher_sign(sess
->akcipher
,
505 op_info
->src
, op_info
->src_len
,
506 op_info
->dst
, op_info
->dst_len
, errp
);
509 case VIRTIO_CRYPTO_AKCIPHER_VERIFY
:
510 ret
= qcrypto_akcipher_verify(sess
->akcipher
,
511 op_info
->src
, op_info
->src_len
,
512 op_info
->dst
, op_info
->dst_len
, errp
);
516 return -VIRTIO_CRYPTO_ERR
;
520 if (op_code
== VIRTIO_CRYPTO_AKCIPHER_VERIFY
) {
521 return -VIRTIO_CRYPTO_KEY_REJECTED
;
523 return -VIRTIO_CRYPTO_ERR
;
526 /* Buffer is too short, typically the driver should handle this case */
527 if (unlikely(ret
> op_info
->dst_len
)) {
528 if (errp
&& !*errp
) {
529 error_setg(errp
, "dst buffer too short");
532 return -VIRTIO_CRYPTO_ERR
;
535 op_info
->dst_len
= ret
;
537 return VIRTIO_CRYPTO_OK
;
540 static int cryptodev_builtin_operation(
541 CryptoDevBackend
*backend
,
542 CryptoDevBackendOpInfo
*op_info
)
544 CryptoDevBackendBuiltin
*builtin
=
545 CRYPTODEV_BACKEND_BUILTIN(backend
);
546 CryptoDevBackendBuiltinSession
*sess
;
547 CryptoDevBackendSymOpInfo
*sym_op_info
;
548 CryptoDevBackendAsymOpInfo
*asym_op_info
;
549 QCryptodevBackendAlgType algtype
= op_info
->algtype
;
550 int status
= -VIRTIO_CRYPTO_ERR
;
551 Error
*local_error
= NULL
;
553 if (op_info
->session_id
>= MAX_NUM_SESSIONS
||
554 builtin
->sessions
[op_info
->session_id
] == NULL
) {
555 error_setg(&local_error
, "Cannot find a valid session id: %" PRIu64
"",
556 op_info
->session_id
);
557 return -VIRTIO_CRYPTO_INVSESS
;
560 sess
= builtin
->sessions
[op_info
->session_id
];
561 if (algtype
== QCRYPTODEV_BACKEND_ALG_SYM
) {
562 sym_op_info
= op_info
->u
.sym_op_info
;
563 status
= cryptodev_builtin_sym_operation(sess
, sym_op_info
,
565 } else if (algtype
== QCRYPTODEV_BACKEND_ALG_ASYM
) {
566 asym_op_info
= op_info
->u
.asym_op_info
;
567 status
= cryptodev_builtin_asym_operation(sess
, op_info
->op_code
,
568 asym_op_info
, &local_error
);
572 error_report_err(local_error
);
575 op_info
->cb(op_info
->opaque
, status
);
580 static void cryptodev_builtin_cleanup(
581 CryptoDevBackend
*backend
,
584 CryptoDevBackendBuiltin
*builtin
=
585 CRYPTODEV_BACKEND_BUILTIN(backend
);
587 int queues
= backend
->conf
.peers
.queues
;
588 CryptoDevBackendClient
*cc
;
590 for (i
= 0; i
< MAX_NUM_SESSIONS
; i
++) {
591 if (builtin
->sessions
[i
] != NULL
) {
592 cryptodev_builtin_close_session(backend
, i
, 0, NULL
, NULL
);
596 for (i
= 0; i
< queues
; i
++) {
597 cc
= backend
->conf
.peers
.ccs
[i
];
599 cryptodev_backend_free_client(cc
);
600 backend
->conf
.peers
.ccs
[i
] = NULL
;
604 cryptodev_backend_set_ready(backend
, false);
608 cryptodev_builtin_class_init(ObjectClass
*oc
, void *data
)
610 CryptoDevBackendClass
*bc
= CRYPTODEV_BACKEND_CLASS(oc
);
612 bc
->init
= cryptodev_builtin_init
;
613 bc
->cleanup
= cryptodev_builtin_cleanup
;
614 bc
->create_session
= cryptodev_builtin_create_session
;
615 bc
->close_session
= cryptodev_builtin_close_session
;
616 bc
->do_op
= cryptodev_builtin_operation
;
619 static const TypeInfo cryptodev_builtin_info
= {
620 .name
= TYPE_CRYPTODEV_BACKEND_BUILTIN
,
621 .parent
= TYPE_CRYPTODEV_BACKEND
,
622 .class_init
= cryptodev_builtin_class_init
,
623 .instance_size
= sizeof(CryptoDevBackendBuiltin
),
627 cryptodev_builtin_register_types(void)
629 type_register_static(&cryptodev_builtin_info
);
632 type_init(cryptodev_builtin_register_types
);