master
c 632 lines 18.9 KB
Raw
1 /*
2 * QEMU Cryptodev backend for QEMU cipher APIs
3 *
4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
5 *
6 * Authors:
7 * Gonglei <arei.gonglei@huawei.com>
8 *
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.
13 *
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.
18 *
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/>.
21 *
22 */
23
24 #include "qemu/osdep.h"
25 #include "system/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"
32
33
34 /**
35 * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
36 * name of backend that uses QEMU cipher API
37 */
38 #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
39
40 OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
41
42
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;
50
51 /* Max number of symmetric/asymmetric sessions */
52 #define MAX_NUM_SESSIONS 256
53
54 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512
55 #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN 64
56 /* demonstration purposes only, use a limited size to avoid QEMU OOM */
57 #define CRYPTODEV_BUITLIN_MAX_REQUEST_SIZE (1024 * 1024)
58
59 struct CryptoDevBackendBuiltin {
60 CryptoDevBackend parent_obj;
61
62 CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
63 };
64
65 static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
66 {
67 QCryptoAkCipherOptions opts;
68
69 opts.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
70 opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW;
71 if (qcrypto_akcipher_supports(&opts)) {
72 backend->conf.crypto_services |=
73 (1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER);
74 backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
75 }
76 }
77
78 static void cryptodev_builtin_init(
79 CryptoDevBackend *backend, Error **errp)
80 {
81 /* Only support one queue */
82 int queues = backend->conf.peers.queues;
83 CryptoDevBackendClient *cc;
84
85 if (queues != 1) {
86 error_setg(errp,
87 "Only support one queue in cryptdov-builtin backend");
88 return;
89 }
90
91 cc = cryptodev_backend_new_client();
92 cc->info_str = g_strdup_printf("cryptodev-builtin0");
93 cc->queue_index = 0;
94 cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN;
95 backend->conf.peers.ccs[0] = cc;
96
97 backend->conf.crypto_services =
98 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER |
99 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_HASH |
100 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_MAC;
101 backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
102 backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
103 backend->conf.max_size = CRYPTODEV_BUITLIN_MAX_REQUEST_SIZE;
104 backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
105 backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
106 cryptodev_builtin_init_akcipher(backend);
107
108 cryptodev_backend_set_ready(backend, true);
109 }
110
111 static int
112 cryptodev_builtin_get_unused_session_index(
113 CryptoDevBackendBuiltin *builtin)
114 {
115 size_t i;
116
117 for (i = 0; i < MAX_NUM_SESSIONS; i++) {
118 if (builtin->sessions[i] == NULL) {
119 return i;
120 }
121 }
122
123 return -1;
124 }
125
126 #define AES_KEYSIZE_128 16
127 #define AES_KEYSIZE_192 24
128 #define AES_KEYSIZE_256 32
129 #define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
130 #define AES_KEYSIZE_256_XTS 64
131
132 static int
133 cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
134 {
135 int algo;
136
137 if (key_len == AES_KEYSIZE_128) {
138 algo = QCRYPTO_CIPHER_ALGO_AES_128;
139 } else if (key_len == AES_KEYSIZE_192) {
140 algo = QCRYPTO_CIPHER_ALGO_AES_192;
141 } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
142 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
143 algo = QCRYPTO_CIPHER_ALGO_AES_128;
144 } else {
145 algo = QCRYPTO_CIPHER_ALGO_AES_256;
146 }
147 } else if (key_len == AES_KEYSIZE_256_XTS) {
148 if (mode == QCRYPTO_CIPHER_MODE_XTS) {
149 algo = QCRYPTO_CIPHER_ALGO_AES_256;
150 } else {
151 goto err;
152 }
153 } else {
154 goto err;
155 }
156
157 return algo;
158
159 err:
160 error_setg(errp, "Unsupported key length :%u", key_len);
161 return -1;
162 }
163
164 static int cryptodev_builtin_get_rsa_hash_algo(
165 int virtio_rsa_hash, Error **errp)
166 {
167 switch (virtio_rsa_hash) {
168 case VIRTIO_CRYPTO_RSA_MD5:
169 return QCRYPTO_HASH_ALGO_MD5;
170
171 case VIRTIO_CRYPTO_RSA_SHA1:
172 return QCRYPTO_HASH_ALGO_SHA1;
173
174 case VIRTIO_CRYPTO_RSA_SHA256:
175 return QCRYPTO_HASH_ALGO_SHA256;
176
177 case VIRTIO_CRYPTO_RSA_SHA512:
178 return QCRYPTO_HASH_ALGO_SHA512;
179
180 default:
181 error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
182 return -1;
183 }
184 }
185
186 static int cryptodev_builtin_set_rsa_options(
187 int virtio_padding_algo,
188 int virtio_hash_algo,
189 QCryptoAkCipherOptionsRSA *opt,
190 Error **errp)
191 {
192 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
193 int hash_alg;
194
195 hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
196 if (hash_alg < 0) {
197 return -1;
198 }
199 opt->hash_alg = hash_alg;
200 opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1;
201 return 0;
202 }
203
204 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
205 opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW;
206 return 0;
207 }
208
209 error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
210 return -1;
211 }
212
213 static int cryptodev_builtin_create_cipher_session(
214 CryptoDevBackendBuiltin *builtin,
215 CryptoDevBackendSymSessionInfo *sess_info,
216 Error **errp)
217 {
218 int algo;
219 int mode;
220 QCryptoCipher *cipher;
221 int index;
222 CryptoDevBackendBuiltinSession *sess;
223
224 if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
225 error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
226 return -1;
227 }
228
229 index = cryptodev_builtin_get_unused_session_index(builtin);
230 if (index < 0) {
231 error_setg(errp, "Total number of sessions created exceeds %u",
232 MAX_NUM_SESSIONS);
233 return -1;
234 }
235
236 switch (sess_info->cipher_alg) {
237 case VIRTIO_CRYPTO_CIPHER_AES_ECB:
238 mode = QCRYPTO_CIPHER_MODE_ECB;
239 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
240 mode, errp);
241 if (algo < 0) {
242 return -1;
243 }
244 break;
245 case VIRTIO_CRYPTO_CIPHER_AES_CBC:
246 mode = QCRYPTO_CIPHER_MODE_CBC;
247 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
248 mode, errp);
249 if (algo < 0) {
250 return -1;
251 }
252 break;
253 case VIRTIO_CRYPTO_CIPHER_AES_CTR:
254 mode = QCRYPTO_CIPHER_MODE_CTR;
255 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
256 mode, errp);
257 if (algo < 0) {
258 return -1;
259 }
260 break;
261 case VIRTIO_CRYPTO_CIPHER_AES_XTS:
262 mode = QCRYPTO_CIPHER_MODE_XTS;
263 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
264 mode, errp);
265 if (algo < 0) {
266 return -1;
267 }
268 break;
269 case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
270 mode = QCRYPTO_CIPHER_MODE_ECB;
271 algo = QCRYPTO_CIPHER_ALGO_3DES;
272 break;
273 case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
274 mode = QCRYPTO_CIPHER_MODE_CBC;
275 algo = QCRYPTO_CIPHER_ALGO_3DES;
276 break;
277 case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
278 mode = QCRYPTO_CIPHER_MODE_CTR;
279 algo = QCRYPTO_CIPHER_ALGO_3DES;
280 break;
281 default:
282 error_setg(errp, "Unsupported cipher alg :%u",
283 sess_info->cipher_alg);
284 return -1;
285 }
286
287 cipher = qcrypto_cipher_new(algo, mode,
288 sess_info->cipher_key,
289 sess_info->key_len,
290 errp);
291 if (!cipher) {
292 return -1;
293 }
294
295 sess = g_new0(CryptoDevBackendBuiltinSession, 1);
296 sess->cipher = cipher;
297 sess->direction = sess_info->direction;
298 sess->type = sess_info->op_type;
299
300 builtin->sessions[index] = sess;
301
302 return index;
303 }
304
305 static int cryptodev_builtin_create_akcipher_session(
306 CryptoDevBackendBuiltin *builtin,
307 CryptoDevBackendAsymSessionInfo *sess_info,
308 Error **errp)
309 {
310 CryptoDevBackendBuiltinSession *sess;
311 QCryptoAkCipher *akcipher;
312 int index;
313 QCryptoAkCipherKeyType type;
314 QCryptoAkCipherOptions opts;
315
316 switch (sess_info->algo) {
317 case VIRTIO_CRYPTO_AKCIPHER_RSA:
318 opts.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
319 if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
320 sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) {
321 return -1;
322 }
323 break;
324
325 /* TODO support DSA&ECDSA until qemu crypto framework support these */
326
327 default:
328 error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
329 return -1;
330 }
331
332 switch (sess_info->keytype) {
333 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
334 type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC;
335 break;
336
337 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
338 type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE;
339 break;
340
341 default:
342 error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
343 return -1;
344 }
345
346 index = cryptodev_builtin_get_unused_session_index(builtin);
347 if (index < 0) {
348 error_setg(errp, "Total number of sessions created exceeds %u",
349 MAX_NUM_SESSIONS);
350 return -1;
351 }
352
353 akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key,
354 sess_info->keylen, errp);
355 if (!akcipher) {
356 return -1;
357 }
358
359 sess = g_new0(CryptoDevBackendBuiltinSession, 1);
360 sess->akcipher = akcipher;
361
362 builtin->sessions[index] = sess;
363
364 return index;
365 }
366
367 static int cryptodev_builtin_create_session(
368 CryptoDevBackend *backend,
369 CryptoDevBackendSessionInfo *sess_info,
370 uint32_t queue_index,
371 CryptoDevCompletionFunc cb,
372 void *opaque)
373 {
374 CryptoDevBackendBuiltin *builtin =
375 CRYPTODEV_BACKEND_BUILTIN(backend);
376 CryptoDevBackendSymSessionInfo *sym_sess_info;
377 CryptoDevBackendAsymSessionInfo *asym_sess_info;
378 int ret, status;
379 Error *local_error = NULL;
380
381 switch (sess_info->op_code) {
382 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
383 sym_sess_info = &sess_info->u.sym_sess_info;
384 ret = cryptodev_builtin_create_cipher_session(
385 builtin, sym_sess_info, &local_error);
386 break;
387
388 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
389 asym_sess_info = &sess_info->u.asym_sess_info;
390 ret = cryptodev_builtin_create_akcipher_session(
391 builtin, asym_sess_info, &local_error);
392 break;
393
394 case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
395 case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
396 default:
397 error_report("Unsupported opcode :%" PRIu32 "",
398 sess_info->op_code);
399 return -VIRTIO_CRYPTO_NOTSUPP;
400 }
401
402 if (local_error) {
403 error_report_err(local_error);
404 }
405 if (ret < 0) {
406 status = -VIRTIO_CRYPTO_ERR;
407 } else {
408 sess_info->session_id = ret;
409 status = VIRTIO_CRYPTO_OK;
410 }
411 if (cb) {
412 cb(opaque, status);
413 }
414 return 0;
415 }
416
417 static int cryptodev_builtin_close_session(
418 CryptoDevBackend *backend,
419 uint64_t session_id,
420 uint32_t queue_index,
421 CryptoDevCompletionFunc cb,
422 void *opaque)
423 {
424 CryptoDevBackendBuiltin *builtin =
425 CRYPTODEV_BACKEND_BUILTIN(backend);
426 CryptoDevBackendBuiltinSession *session;
427
428 if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
429 return -VIRTIO_CRYPTO_INVSESS;
430 }
431
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);
437 }
438
439 g_free(session);
440 builtin->sessions[session_id] = NULL;
441 if (cb) {
442 cb(opaque, VIRTIO_CRYPTO_OK);
443 }
444 return 0;
445 }
446
447 static int cryptodev_builtin_sym_operation(
448 CryptoDevBackendBuiltinSession *sess,
449 CryptoDevBackendSymOpInfo *op_info, Error **errp)
450 {
451 int ret;
452
453 if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
454 error_setg(errp,
455 "Algorithm chain is unsupported for cryptdoev-builtin");
456 return -VIRTIO_CRYPTO_NOTSUPP;
457 }
458
459 if (op_info->iv_len > 0) {
460 ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
461 op_info->iv_len, errp);
462 if (ret < 0) {
463 return -VIRTIO_CRYPTO_ERR;
464 }
465 }
466
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);
470 if (ret < 0) {
471 return -VIRTIO_CRYPTO_ERR;
472 }
473 } else {
474 ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
475 op_info->dst, op_info->src_len, errp);
476 if (ret < 0) {
477 return -VIRTIO_CRYPTO_ERR;
478 }
479 }
480
481 return VIRTIO_CRYPTO_OK;
482 }
483
484 static int cryptodev_builtin_asym_operation(
485 CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
486 CryptoDevBackendAsymOpInfo *op_info, Error **errp)
487 {
488 int ret;
489
490 switch (op_code) {
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);
495 break;
496
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);
501 break;
502
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);
507 break;
508
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);
513 break;
514
515 default:
516 return -VIRTIO_CRYPTO_ERR;
517 }
518
519 if (ret < 0) {
520 if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
521 return -VIRTIO_CRYPTO_KEY_REJECTED;
522 }
523 return -VIRTIO_CRYPTO_ERR;
524 }
525
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");
530 }
531
532 return -VIRTIO_CRYPTO_ERR;
533 }
534
535 op_info->dst_len = ret;
536
537 return VIRTIO_CRYPTO_OK;
538 }
539
540 static int cryptodev_builtin_operation(
541 CryptoDevBackend *backend,
542 CryptoDevBackendOpInfo *op_info)
543 {
544 CryptoDevBackendBuiltin *builtin =
545 CRYPTODEV_BACKEND_BUILTIN(backend);
546 CryptoDevBackendBuiltinSession *sess;
547 CryptoDevBackendSymOpInfo *sym_op_info;
548 CryptoDevBackendAsymOpInfo *asym_op_info;
549 QCryptodevBackendAlgoType algtype = op_info->algtype;
550 int status = -VIRTIO_CRYPTO_ERR;
551 Error *local_error = NULL;
552
553 if (op_info->session_id >= MAX_NUM_SESSIONS ||
554 builtin->sessions[op_info->session_id] == NULL) {
555 error_report("Cannot find a valid session id: %" PRIu64 "",
556 op_info->session_id);
557 return -VIRTIO_CRYPTO_INVSESS;
558 }
559
560 sess = builtin->sessions[op_info->session_id];
561 if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
562 sym_op_info = op_info->u.sym_op_info;
563 status = cryptodev_builtin_sym_operation(sess, sym_op_info,
564 &local_error);
565 } else if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_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);
569 }
570
571 if (local_error) {
572 error_report_err(local_error);
573 }
574 if (op_info->cb) {
575 op_info->cb(op_info->opaque, status);
576 }
577 return 0;
578 }
579
580 static void cryptodev_builtin_cleanup(
581 CryptoDevBackend *backend,
582 Error **errp)
583 {
584 CryptoDevBackendBuiltin *builtin =
585 CRYPTODEV_BACKEND_BUILTIN(backend);
586 size_t i;
587 int queues = backend->conf.peers.queues;
588 CryptoDevBackendClient *cc;
589
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);
593 }
594 }
595
596 for (i = 0; i < queues; i++) {
597 cc = backend->conf.peers.ccs[i];
598 if (cc) {
599 cryptodev_backend_free_client(cc);
600 backend->conf.peers.ccs[i] = NULL;
601 }
602 }
603
604 cryptodev_backend_set_ready(backend, false);
605 }
606
607 static void
608 cryptodev_builtin_class_init(ObjectClass *oc, const void *data)
609 {
610 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
611
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;
617 }
618
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),
624 };
625
626 static void
627 cryptodev_builtin_register_types(void)
628 {
629 type_register_static(&cryptodev_builtin_info);
630 }
631
632 type_init(cryptodev_builtin_register_types);