xref: /openbmc/qemu/backends/cryptodev-builtin.c (revision 1935b7ea)
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 "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"
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 
57 struct CryptoDevBackendBuiltin {
58     CryptoDevBackend parent_obj;
59 
60     CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
61 };
62 
63 static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
64 {
65     QCryptoAkCipherOptions opts;
66 
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;
73     }
74 }
75 
76 static void cryptodev_builtin_init(
77              CryptoDevBackend *backend, Error **errp)
78 {
79     /* Only support one queue */
80     int queues = backend->conf.peers.queues;
81     CryptoDevBackendClient *cc;
82 
83     if (queues != 1) {
84         error_setg(errp,
85                   "Only support one queue in cryptdov-builtin backend");
86         return;
87     }
88 
89     cc = cryptodev_backend_new_client();
90     cc->info_str = g_strdup_printf("cryptodev-builtin0");
91     cc->queue_index = 0;
92     cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN;
93     backend->conf.peers.ccs[0] = cc;
94 
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;
101     /*
102      * Set the Maximum length of crypto request.
103      * Why this value? Just avoid to overflow when
104      * memory allocation for each crypto request.
105      */
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);
110 
111     cryptodev_backend_set_ready(backend, true);
112 }
113 
114 static int
115 cryptodev_builtin_get_unused_session_index(
116                  CryptoDevBackendBuiltin *builtin)
117 {
118     size_t i;
119 
120     for (i = 0; i < MAX_NUM_SESSIONS; i++) {
121         if (builtin->sessions[i] == NULL) {
122             return i;
123         }
124     }
125 
126     return -1;
127 }
128 
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
134 
135 static int
136 cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
137 {
138     int algo;
139 
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;
147         } else {
148             algo = QCRYPTO_CIPHER_ALG_AES_256;
149         }
150     } else if (key_len == AES_KEYSIZE_256_XTS) {
151         if (mode == QCRYPTO_CIPHER_MODE_XTS) {
152             algo = QCRYPTO_CIPHER_ALG_AES_256;
153         } else {
154             goto err;
155         }
156     } else {
157         goto err;
158     }
159 
160     return algo;
161 
162 err:
163    error_setg(errp, "Unsupported key length :%u", key_len);
164    return -1;
165 }
166 
167 static int cryptodev_builtin_get_rsa_hash_algo(
168     int virtio_rsa_hash, Error **errp)
169 {
170     switch (virtio_rsa_hash) {
171     case VIRTIO_CRYPTO_RSA_MD5:
172         return QCRYPTO_HASH_ALG_MD5;
173 
174     case VIRTIO_CRYPTO_RSA_SHA1:
175         return QCRYPTO_HASH_ALG_SHA1;
176 
177     case VIRTIO_CRYPTO_RSA_SHA256:
178         return QCRYPTO_HASH_ALG_SHA256;
179 
180     case VIRTIO_CRYPTO_RSA_SHA512:
181         return QCRYPTO_HASH_ALG_SHA512;
182 
183     default:
184         error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
185         return -1;
186     }
187 }
188 
189 static int cryptodev_builtin_set_rsa_options(
190                     int virtio_padding_algo,
191                     int virtio_hash_algo,
192                     QCryptoAkCipherOptionsRSA *opt,
193                     Error **errp)
194 {
195     if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
196         int hash_alg;
197 
198         hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
199         if (hash_alg < 0) {
200             return -1;
201         }
202         opt->hash_alg = hash_alg;
203         opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
204         return 0;
205     }
206 
207     if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
208         opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
209         return 0;
210     }
211 
212     error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
213     return -1;
214 }
215 
216 static int cryptodev_builtin_create_cipher_session(
217                     CryptoDevBackendBuiltin *builtin,
218                     CryptoDevBackendSymSessionInfo *sess_info,
219                     Error **errp)
220 {
221     int algo;
222     int mode;
223     QCryptoCipher *cipher;
224     int index;
225     CryptoDevBackendBuiltinSession *sess;
226 
227     if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
228         error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
229         return -1;
230     }
231 
232     index = cryptodev_builtin_get_unused_session_index(builtin);
233     if (index < 0) {
234         error_setg(errp, "Total number of sessions created exceeds %u",
235                   MAX_NUM_SESSIONS);
236         return -1;
237     }
238 
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,
243                                                     mode, errp);
244         if (algo < 0)  {
245             return -1;
246         }
247         break;
248     case VIRTIO_CRYPTO_CIPHER_AES_CBC:
249         mode = QCRYPTO_CIPHER_MODE_CBC;
250         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
251                                                     mode, errp);
252         if (algo < 0)  {
253             return -1;
254         }
255         break;
256     case VIRTIO_CRYPTO_CIPHER_AES_CTR:
257         mode = QCRYPTO_CIPHER_MODE_CTR;
258         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
259                                                     mode, errp);
260         if (algo < 0)  {
261             return -1;
262         }
263         break;
264     case VIRTIO_CRYPTO_CIPHER_AES_XTS:
265         mode = QCRYPTO_CIPHER_MODE_XTS;
266         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
267                                                     mode, errp);
268         if (algo < 0)  {
269             return -1;
270         }
271         break;
272     case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
273         mode = QCRYPTO_CIPHER_MODE_ECB;
274         algo = QCRYPTO_CIPHER_ALG_3DES;
275         break;
276     case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
277         mode = QCRYPTO_CIPHER_MODE_CBC;
278         algo = QCRYPTO_CIPHER_ALG_3DES;
279         break;
280     case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
281         mode = QCRYPTO_CIPHER_MODE_CTR;
282         algo = QCRYPTO_CIPHER_ALG_3DES;
283         break;
284     default:
285         error_setg(errp, "Unsupported cipher alg :%u",
286                    sess_info->cipher_alg);
287         return -1;
288     }
289 
290     cipher = qcrypto_cipher_new(algo, mode,
291                                sess_info->cipher_key,
292                                sess_info->key_len,
293                                errp);
294     if (!cipher) {
295         return -1;
296     }
297 
298     sess = g_new0(CryptoDevBackendBuiltinSession, 1);
299     sess->cipher = cipher;
300     sess->direction = sess_info->direction;
301     sess->type = sess_info->op_type;
302 
303     builtin->sessions[index] = sess;
304 
305     return index;
306 }
307 
308 static int cryptodev_builtin_create_akcipher_session(
309                     CryptoDevBackendBuiltin *builtin,
310                     CryptoDevBackendAsymSessionInfo *sess_info,
311                     Error **errp)
312 {
313     CryptoDevBackendBuiltinSession *sess;
314     QCryptoAkCipher *akcipher;
315     int index;
316     QCryptoAkCipherKeyType type;
317     QCryptoAkCipherOptions opts;
318 
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) {
324             return -1;
325         }
326         break;
327 
328     /* TODO support DSA&ECDSA until qemu crypto framework support these */
329 
330     default:
331         error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
332         return -1;
333     }
334 
335     switch (sess_info->keytype) {
336     case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
337         type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
338         break;
339 
340     case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
341         type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
342         break;
343 
344     default:
345         error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
346         return -1;
347     }
348 
349     index = cryptodev_builtin_get_unused_session_index(builtin);
350     if (index < 0) {
351         error_setg(errp, "Total number of sessions created exceeds %u",
352                    MAX_NUM_SESSIONS);
353         return -1;
354     }
355 
356     akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key,
357                                     sess_info->keylen, errp);
358     if (!akcipher) {
359         return -1;
360     }
361 
362     sess = g_new0(CryptoDevBackendBuiltinSession, 1);
363     sess->akcipher = akcipher;
364 
365     builtin->sessions[index] = sess;
366 
367     return index;
368 }
369 
370 static int cryptodev_builtin_create_session(
371            CryptoDevBackend *backend,
372            CryptoDevBackendSessionInfo *sess_info,
373            uint32_t queue_index,
374            CryptoDevCompletionFunc cb,
375            void *opaque)
376 {
377     CryptoDevBackendBuiltin *builtin =
378                       CRYPTODEV_BACKEND_BUILTIN(backend);
379     CryptoDevBackendSymSessionInfo *sym_sess_info;
380     CryptoDevBackendAsymSessionInfo *asym_sess_info;
381     int ret, status;
382     Error *local_error = NULL;
383 
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);
389         break;
390 
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);
395         break;
396 
397     case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
398     case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
399     default:
400         error_report("Unsupported opcode :%" PRIu32 "",
401                      sess_info->op_code);
402         return -VIRTIO_CRYPTO_NOTSUPP;
403     }
404 
405     if (local_error) {
406         error_report_err(local_error);
407     }
408     if (ret < 0) {
409         status = -VIRTIO_CRYPTO_ERR;
410     } else {
411         sess_info->session_id = ret;
412         status = VIRTIO_CRYPTO_OK;
413     }
414     if (cb) {
415         cb(opaque, status);
416     }
417     return 0;
418 }
419 
420 static int cryptodev_builtin_close_session(
421            CryptoDevBackend *backend,
422            uint64_t session_id,
423            uint32_t queue_index,
424            CryptoDevCompletionFunc cb,
425            void *opaque)
426 {
427     CryptoDevBackendBuiltin *builtin =
428                       CRYPTODEV_BACKEND_BUILTIN(backend);
429     CryptoDevBackendBuiltinSession *session;
430 
431     if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
432         return -VIRTIO_CRYPTO_INVSESS;
433     }
434 
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);
440     }
441 
442     g_free(session);
443     builtin->sessions[session_id] = NULL;
444     if (cb) {
445         cb(opaque, VIRTIO_CRYPTO_OK);
446     }
447     return 0;
448 }
449 
450 static int cryptodev_builtin_sym_operation(
451                  CryptoDevBackendBuiltinSession *sess,
452                  CryptoDevBackendSymOpInfo *op_info, Error **errp)
453 {
454     int ret;
455 
456     if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
457         error_setg(errp,
458                "Algorithm chain is unsupported for cryptdoev-builtin");
459         return -VIRTIO_CRYPTO_NOTSUPP;
460     }
461 
462     if (op_info->iv_len > 0) {
463         ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
464                                    op_info->iv_len, errp);
465         if (ret < 0) {
466             return -VIRTIO_CRYPTO_ERR;
467         }
468     }
469 
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);
473         if (ret < 0) {
474             return -VIRTIO_CRYPTO_ERR;
475         }
476     } else {
477         ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
478                                      op_info->dst, op_info->src_len, errp);
479         if (ret < 0) {
480             return -VIRTIO_CRYPTO_ERR;
481         }
482     }
483 
484     return VIRTIO_CRYPTO_OK;
485 }
486 
487 static int cryptodev_builtin_asym_operation(
488                  CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
489                  CryptoDevBackendAsymOpInfo *op_info, Error **errp)
490 {
491     int ret;
492 
493     switch (op_code) {
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);
498         break;
499 
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);
504         break;
505 
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);
510         break;
511 
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);
516         break;
517 
518     default:
519         return -VIRTIO_CRYPTO_ERR;
520     }
521 
522     if (ret < 0) {
523         if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
524             return -VIRTIO_CRYPTO_KEY_REJECTED;
525         }
526         return -VIRTIO_CRYPTO_ERR;
527     }
528 
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");
533         }
534 
535         return -VIRTIO_CRYPTO_ERR;
536     }
537 
538     op_info->dst_len = ret;
539 
540     return VIRTIO_CRYPTO_OK;
541 }
542 
543 static int cryptodev_builtin_operation(
544                  CryptoDevBackend *backend,
545                  CryptoDevBackendOpInfo *op_info)
546 {
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;
555 
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;
561     }
562 
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,
567                                                  &local_error);
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);
572     }
573 
574     if (local_error) {
575         error_report_err(local_error);
576     }
577     if (op_info->cb) {
578         op_info->cb(op_info->opaque, status);
579     }
580     return 0;
581 }
582 
583 static void cryptodev_builtin_cleanup(
584              CryptoDevBackend *backend,
585              Error **errp)
586 {
587     CryptoDevBackendBuiltin *builtin =
588                       CRYPTODEV_BACKEND_BUILTIN(backend);
589     size_t i;
590     int queues = backend->conf.peers.queues;
591     CryptoDevBackendClient *cc;
592 
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);
596         }
597     }
598 
599     for (i = 0; i < queues; i++) {
600         cc = backend->conf.peers.ccs[i];
601         if (cc) {
602             cryptodev_backend_free_client(cc);
603             backend->conf.peers.ccs[i] = NULL;
604         }
605     }
606 
607     cryptodev_backend_set_ready(backend, false);
608 }
609 
610 static void
611 cryptodev_builtin_class_init(ObjectClass *oc, void *data)
612 {
613     CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
614 
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;
620 }
621 
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),
627 };
628 
629 static void
630 cryptodev_builtin_register_types(void)
631 {
632     type_register_static(&cryptodev_builtin_info);
633 }
634 
635 type_init(cryptodev_builtin_register_types);
636