]> git.proxmox.com Git - mirror_qemu.git/blob - backends/cryptodev-builtin.c
cryptodev: introduce a new cryptodev backend
[mirror_qemu.git] / backends / cryptodev-builtin.c
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);