intel_iommu: fix several incorrect endianess and bit fields
[qemu/ar7.git] / backends / cryptodev-builtin.c
blobeda954b2a21ccdbf68bab1cf278b6e3f9acad871
1 /*
2 * QEMU Cryptodev backend for QEMU cipher APIs
4 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
6 * Authors:
7 * Gonglei <arei.gonglei@huawei.com>
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.
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.
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/>.
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"
32 /**
33 * @TYPE_CRYPTODEV_BACKEND_BUILTIN:
34 * name of backend that uses QEMU cipher API
36 #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
38 #define CRYPTODEV_BACKEND_BUILTIN(obj) \
39 OBJECT_CHECK(CryptoDevBackendBuiltin, \
40 (obj), TYPE_CRYPTODEV_BACKEND_BUILTIN)
42 typedef struct CryptoDevBackendBuiltin
43 CryptoDevBackendBuiltin;
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;
52 /* Max number of symmetric sessions */
53 #define MAX_NUM_SESSIONS 256
55 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512
56 #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN 64
58 struct CryptoDevBackendBuiltin {
59 CryptoDevBackend parent_obj;
61 CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
64 static void cryptodev_builtin_init(
65 CryptoDevBackend *backend, Error **errp)
67 /* Only support one queue */
68 int queues = backend->conf.peers.queues;
69 CryptoDevBackendClient *cc;
71 if (queues != 1) {
72 error_setg(errp,
73 "Only support one queue in cryptdov-builtin backend");
74 return;
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;
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;
90 * Set the Maximum length of crypto request.
91 * Why this value? Just avoid to overflow when
92 * memory allocation for each crypto request.
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;
99 static int
100 cryptodev_builtin_get_unused_session_index(
101 CryptoDevBackendBuiltin *builtin)
103 size_t i;
105 for (i = 0; i < MAX_NUM_SESSIONS; i++) {
106 if (builtin->sessions[i] == NULL) {
107 return i;
111 return -1;
114 static int
115 cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp)
117 int algo;
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;
130 return algo;
133 static int cryptodev_builtin_create_cipher_session(
134 CryptoDevBackendBuiltin *builtin,
135 CryptoDevBackendSymSessionInfo *sess_info,
136 Error **errp)
138 int algo;
139 int mode;
140 QCryptoCipher *cipher;
141 int index;
142 CryptoDevBackendBuiltinSession *sess;
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;
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;
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;
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;
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;
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;
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;
199 sess = g_new0(CryptoDevBackendBuiltinSession, 1);
200 sess->cipher = cipher;
201 sess->direction = sess_info->direction;
202 sess->type = sess_info->op_type;
204 builtin->sessions[index] = sess;
206 return index;
209 static int64_t cryptodev_builtin_sym_create_session(
210 CryptoDevBackend *backend,
211 CryptoDevBackendSymSessionInfo *sess_info,
212 uint32_t queue_index, Error **errp)
214 CryptoDevBackendBuiltin *builtin =
215 CRYPTODEV_BACKEND_BUILTIN(backend);
216 int64_t session_id = -1;
217 int ret;
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;
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;
237 return session_id;
240 static int cryptodev_builtin_sym_close_session(
241 CryptoDevBackend *backend,
242 uint64_t session_id,
243 uint32_t queue_index, Error **errp)
245 CryptoDevBackendBuiltin *builtin =
246 CRYPTODEV_BACKEND_BUILTIN(backend);
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;
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;
261 static int cryptodev_builtin_sym_operation(
262 CryptoDevBackend *backend,
263 CryptoDevBackendSymOpInfo *op_info,
264 uint32_t queue_index, Error **errp)
266 CryptoDevBackendBuiltin *builtin =
267 CRYPTODEV_BACKEND_BUILTIN(backend);
268 CryptoDevBackendBuiltinSession *sess;
269 int ret;
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;
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;
284 sess = builtin->sessions[op_info->session_id];
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;
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;
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;
305 return VIRTIO_CRYPTO_OK;
308 static void cryptodev_builtin_cleanup(
309 CryptoDevBackend *backend,
310 Error **errp)
312 CryptoDevBackendBuiltin *builtin =
313 CRYPTODEV_BACKEND_BUILTIN(backend);
314 size_t i;
315 int queues = backend->conf.peers.queues;
316 CryptoDevBackendClient *cc;
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);
325 assert(queues == 1);
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;
336 static void
337 cryptodev_builtin_class_init(ObjectClass *oc, void *data)
339 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
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;
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),
355 static void
356 cryptodev_builtin_register_types(void)
358 type_register_static(&cryptodev_builtin_info);
361 type_init(cryptodev_builtin_register_types);