xref: /openbmc/qemu/backends/cryptodev-builtin.c (revision f6a51c84)
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 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 "hw/boards.h"
27 #include "qapi/error.h"
28 #include "standard-headers/linux/virtio_crypto.h"
29 #include "crypto/cipher.h"
30 
31 
32 /**
33  * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
34  * name of backend that uses QEMU cipher API
35  */
36 #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
37 
38 #define CRYPTODEV_BACKEND_BUILTIN(obj) \
39     OBJECT_CHECK(CryptoDevBackendBuiltin, \
40                  (obj), TYPE_CRYPTODEV_BACKEND_BUILTIN)
41 
42 typedef struct CryptoDevBackendBuiltin
43                          CryptoDevBackendBuiltin;
44 
45 typedef struct CryptoDevBackendBuiltinSession {
46     QCryptoCipher *cipher;
47     uint8_t direction; /* encryption or decryption */
48     uint8_t type; /* cipher? hash? aead? */
49     QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
50 } CryptoDevBackendBuiltinSession;
51 
52 /* Max number of symmetric sessions */
53 #define MAX_NUM_SESSIONS 256
54 
55 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN    512
56 #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN  64
57 
58 struct CryptoDevBackendBuiltin {
59     CryptoDevBackend parent_obj;
60 
61     CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
62 };
63 
64 static void cryptodev_builtin_init(
65              CryptoDevBackend *backend, Error **errp)
66 {
67     /* Only support one queue */
68     int queues = backend->conf.peers.queues;
69     CryptoDevBackendClient *cc;
70 
71     if (queues != 1) {
72         error_setg(errp,
73                   "Only support one queue in cryptdov-builtin backend");
74         return;
75     }
76 
77     cc = cryptodev_backend_new_client(
78               "cryptodev-builtin", NULL);
79     cc->info_str = g_strdup_printf("cryptodev-builtin0");
80     cc->queue_index = 0;
81     backend->conf.peers.ccs[0] = cc;
82 
83     backend->conf.crypto_services =
84                          1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
85                          1u << VIRTIO_CRYPTO_SERVICE_HASH |
86                          1u << VIRTIO_CRYPTO_SERVICE_MAC;
87     backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
88     backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
89     /*
90      * Set the Maximum length of crypto request.
91      * Why this value? Just avoid to overflow when
92      * memory allocation for each crypto request.
93      */
94     backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
95     backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
96     backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
97 }
98 
99 static int
100 cryptodev_builtin_get_unused_session_index(
101                  CryptoDevBackendBuiltin *builtin)
102 {
103     size_t i;
104 
105     for (i = 0; i < MAX_NUM_SESSIONS; i++) {
106         if (builtin->sessions[i] == NULL) {
107             return i;
108         }
109     }
110 
111     return -1;
112 }
113 
114 static int
115 cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp)
116 {
117     int algo;
118 
119     if (key_len == 128 / 8) {
120         algo = QCRYPTO_CIPHER_ALG_AES_128;
121     } else if (key_len == 192 / 8) {
122         algo = QCRYPTO_CIPHER_ALG_AES_192;
123     } else if (key_len == 256 / 8) {
124         algo = QCRYPTO_CIPHER_ALG_AES_256;
125     } else {
126         error_setg(errp, "Unsupported key length :%u", key_len);
127         return -1;
128     }
129 
130     return algo;
131 }
132 
133 static int cryptodev_builtin_create_cipher_session(
134                     CryptoDevBackendBuiltin *builtin,
135                     CryptoDevBackendSymSessionInfo *sess_info,
136                     Error **errp)
137 {
138     int algo;
139     int mode;
140     QCryptoCipher *cipher;
141     int index;
142     CryptoDevBackendBuiltinSession *sess;
143 
144     if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
145         error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
146         return -1;
147     }
148 
149     index = cryptodev_builtin_get_unused_session_index(builtin);
150     if (index < 0) {
151         error_setg(errp, "Total number of sessions created exceeds %u",
152                   MAX_NUM_SESSIONS);
153         return -1;
154     }
155 
156     switch (sess_info->cipher_alg) {
157     case VIRTIO_CRYPTO_CIPHER_AES_ECB:
158         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
159                                                           errp);
160         if (algo < 0)  {
161             return -1;
162         }
163         mode = QCRYPTO_CIPHER_MODE_ECB;
164         break;
165     case VIRTIO_CRYPTO_CIPHER_AES_CBC:
166         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
167                                                           errp);
168         if (algo < 0)  {
169             return -1;
170         }
171         mode = QCRYPTO_CIPHER_MODE_CBC;
172         break;
173     case VIRTIO_CRYPTO_CIPHER_AES_CTR:
174         algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
175                                                           errp);
176         if (algo < 0)  {
177             return -1;
178         }
179         mode = QCRYPTO_CIPHER_MODE_CTR;
180         break;
181     case VIRTIO_CRYPTO_CIPHER_DES_ECB:
182         algo = QCRYPTO_CIPHER_ALG_DES_RFB;
183         mode = QCRYPTO_CIPHER_MODE_ECB;
184         break;
185     default:
186         error_setg(errp, "Unsupported cipher alg :%u",
187                    sess_info->cipher_alg);
188         return -1;
189     }
190 
191     cipher = qcrypto_cipher_new(algo, mode,
192                                sess_info->cipher_key,
193                                sess_info->key_len,
194                                errp);
195     if (!cipher) {
196         return -1;
197     }
198 
199     sess = g_new0(CryptoDevBackendBuiltinSession, 1);
200     sess->cipher = cipher;
201     sess->direction = sess_info->direction;
202     sess->type = sess_info->op_type;
203 
204     builtin->sessions[index] = sess;
205 
206     return index;
207 }
208 
209 static int64_t cryptodev_builtin_sym_create_session(
210            CryptoDevBackend *backend,
211            CryptoDevBackendSymSessionInfo *sess_info,
212            uint32_t queue_index, Error **errp)
213 {
214     CryptoDevBackendBuiltin *builtin =
215                       CRYPTODEV_BACKEND_BUILTIN(backend);
216     int64_t session_id = -1;
217     int ret;
218 
219     switch (sess_info->op_code) {
220     case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
221         ret = cryptodev_builtin_create_cipher_session(
222                            builtin, sess_info, errp);
223         if (ret < 0) {
224             return ret;
225         } else {
226             session_id = ret;
227         }
228         break;
229     case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
230     case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
231     default:
232         error_setg(errp, "Unsupported opcode :%" PRIu32 "",
233                    sess_info->op_code);
234         return -1;
235     }
236 
237     return session_id;
238 }
239 
240 static int cryptodev_builtin_sym_close_session(
241            CryptoDevBackend *backend,
242            uint64_t session_id,
243            uint32_t queue_index, Error **errp)
244 {
245     CryptoDevBackendBuiltin *builtin =
246                       CRYPTODEV_BACKEND_BUILTIN(backend);
247 
248     if (session_id >= MAX_NUM_SESSIONS ||
249               builtin->sessions[session_id] == NULL) {
250         error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
251                       session_id);
252         return -1;
253     }
254 
255     qcrypto_cipher_free(builtin->sessions[session_id]->cipher);
256     g_free(builtin->sessions[session_id]);
257     builtin->sessions[session_id] = NULL;
258     return 0;
259 }
260 
261 static int cryptodev_builtin_sym_operation(
262                  CryptoDevBackend *backend,
263                  CryptoDevBackendSymOpInfo *op_info,
264                  uint32_t queue_index, Error **errp)
265 {
266     CryptoDevBackendBuiltin *builtin =
267                       CRYPTODEV_BACKEND_BUILTIN(backend);
268     CryptoDevBackendBuiltinSession *sess;
269     int ret;
270 
271     if (op_info->session_id >= MAX_NUM_SESSIONS ||
272               builtin->sessions[op_info->session_id] == NULL) {
273         error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
274                    op_info->session_id);
275         return -VIRTIO_CRYPTO_INVSESS;
276     }
277 
278     if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
279         error_setg(errp,
280                "Algorithm chain is unsupported for cryptdoev-builtin");
281         return -VIRTIO_CRYPTO_NOTSUPP;
282     }
283 
284     sess = builtin->sessions[op_info->session_id];
285 
286     ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
287                                op_info->iv_len, errp);
288     if (ret < 0) {
289         return -VIRTIO_CRYPTO_ERR;
290     }
291 
292     if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) {
293         ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src,
294                                      op_info->dst, op_info->src_len, errp);
295         if (ret < 0) {
296             return -VIRTIO_CRYPTO_ERR;
297         }
298     } else {
299         ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
300                                      op_info->dst, op_info->src_len, errp);
301         if (ret < 0) {
302             return -VIRTIO_CRYPTO_ERR;
303         }
304     }
305     return VIRTIO_CRYPTO_OK;
306 }
307 
308 static void cryptodev_builtin_cleanup(
309              CryptoDevBackend *backend,
310              Error **errp)
311 {
312     CryptoDevBackendBuiltin *builtin =
313                       CRYPTODEV_BACKEND_BUILTIN(backend);
314     size_t i;
315     int queues = backend->conf.peers.queues;
316     CryptoDevBackendClient *cc;
317 
318     for (i = 0; i < MAX_NUM_SESSIONS; i++) {
319         if (builtin->sessions[i] != NULL) {
320             cryptodev_builtin_sym_close_session(
321                     backend, i, 0, errp);
322         }
323     }
324 
325     assert(queues == 1);
326 
327     for (i = 0; i < queues; i++) {
328         cc = backend->conf.peers.ccs[i];
329         if (cc) {
330             cryptodev_backend_free_client(cc);
331             backend->conf.peers.ccs[i] = NULL;
332         }
333     }
334 }
335 
336 static void
337 cryptodev_builtin_class_init(ObjectClass *oc, void *data)
338 {
339     CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
340 
341     bc->init = cryptodev_builtin_init;
342     bc->cleanup = cryptodev_builtin_cleanup;
343     bc->create_session = cryptodev_builtin_sym_create_session;
344     bc->close_session = cryptodev_builtin_sym_close_session;
345     bc->do_sym_op = cryptodev_builtin_sym_operation;
346 }
347 
348 static const TypeInfo cryptodev_builtin_info = {
349     .name = TYPE_CRYPTODEV_BACKEND_BUILTIN,
350     .parent = TYPE_CRYPTODEV_BACKEND,
351     .class_init = cryptodev_builtin_class_init,
352     .instance_size = sizeof(CryptoDevBackendBuiltin),
353 };
354 
355 static void
356 cryptodev_builtin_register_types(void)
357 {
358     type_register_static(&cryptodev_builtin_info);
359 }
360 
361 type_init(cryptodev_builtin_register_types);
362