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