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 #define AES_KEYSIZE_128 16 115 #define AES_KEYSIZE_192 24 116 #define AES_KEYSIZE_256 32 117 #define AES_KEYSIZE_128_XTS AES_KEYSIZE_256 118 #define AES_KEYSIZE_256_XTS 64 119 120 static int 121 cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp) 122 { 123 int algo; 124 125 if (key_len == AES_KEYSIZE_128) { 126 algo = QCRYPTO_CIPHER_ALG_AES_128; 127 } else if (key_len == AES_KEYSIZE_192) { 128 algo = QCRYPTO_CIPHER_ALG_AES_192; 129 } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */ 130 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 131 algo = QCRYPTO_CIPHER_ALG_AES_128; 132 } else { 133 algo = QCRYPTO_CIPHER_ALG_AES_256; 134 } 135 } else if (key_len == AES_KEYSIZE_256_XTS) { 136 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 137 algo = QCRYPTO_CIPHER_ALG_AES_256; 138 } else { 139 goto err; 140 } 141 } else { 142 goto err; 143 } 144 145 return algo; 146 147 err: 148 error_setg(errp, "Unsupported key length :%u", key_len); 149 return -1; 150 } 151 152 static int cryptodev_builtin_create_cipher_session( 153 CryptoDevBackendBuiltin *builtin, 154 CryptoDevBackendSymSessionInfo *sess_info, 155 Error **errp) 156 { 157 int algo; 158 int mode; 159 QCryptoCipher *cipher; 160 int index; 161 CryptoDevBackendBuiltinSession *sess; 162 163 if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) { 164 error_setg(errp, "Unsupported optype :%u", sess_info->op_type); 165 return -1; 166 } 167 168 index = cryptodev_builtin_get_unused_session_index(builtin); 169 if (index < 0) { 170 error_setg(errp, "Total number of sessions created exceeds %u", 171 MAX_NUM_SESSIONS); 172 return -1; 173 } 174 175 switch (sess_info->cipher_alg) { 176 case VIRTIO_CRYPTO_CIPHER_AES_ECB: 177 mode = QCRYPTO_CIPHER_MODE_ECB; 178 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 179 mode, errp); 180 if (algo < 0) { 181 return -1; 182 } 183 break; 184 case VIRTIO_CRYPTO_CIPHER_AES_CBC: 185 mode = QCRYPTO_CIPHER_MODE_CBC; 186 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 187 mode, errp); 188 if (algo < 0) { 189 return -1; 190 } 191 break; 192 case VIRTIO_CRYPTO_CIPHER_AES_CTR: 193 mode = QCRYPTO_CIPHER_MODE_CTR; 194 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 195 mode, errp); 196 if (algo < 0) { 197 return -1; 198 } 199 break; 200 case VIRTIO_CRYPTO_CIPHER_AES_XTS: 201 mode = QCRYPTO_CIPHER_MODE_XTS; 202 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 203 mode, errp); 204 if (algo < 0) { 205 return -1; 206 } 207 break; 208 case VIRTIO_CRYPTO_CIPHER_3DES_ECB: 209 mode = QCRYPTO_CIPHER_MODE_ECB; 210 algo = QCRYPTO_CIPHER_ALG_3DES; 211 break; 212 case VIRTIO_CRYPTO_CIPHER_3DES_CBC: 213 mode = QCRYPTO_CIPHER_MODE_CBC; 214 algo = QCRYPTO_CIPHER_ALG_3DES; 215 break; 216 case VIRTIO_CRYPTO_CIPHER_3DES_CTR: 217 mode = QCRYPTO_CIPHER_MODE_CTR; 218 algo = QCRYPTO_CIPHER_ALG_3DES; 219 break; 220 default: 221 error_setg(errp, "Unsupported cipher alg :%u", 222 sess_info->cipher_alg); 223 return -1; 224 } 225 226 cipher = qcrypto_cipher_new(algo, mode, 227 sess_info->cipher_key, 228 sess_info->key_len, 229 errp); 230 if (!cipher) { 231 return -1; 232 } 233 234 sess = g_new0(CryptoDevBackendBuiltinSession, 1); 235 sess->cipher = cipher; 236 sess->direction = sess_info->direction; 237 sess->type = sess_info->op_type; 238 239 builtin->sessions[index] = sess; 240 241 return index; 242 } 243 244 static int64_t cryptodev_builtin_sym_create_session( 245 CryptoDevBackend *backend, 246 CryptoDevBackendSymSessionInfo *sess_info, 247 uint32_t queue_index, Error **errp) 248 { 249 CryptoDevBackendBuiltin *builtin = 250 CRYPTODEV_BACKEND_BUILTIN(backend); 251 int64_t session_id = -1; 252 int ret; 253 254 switch (sess_info->op_code) { 255 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: 256 ret = cryptodev_builtin_create_cipher_session( 257 builtin, sess_info, errp); 258 if (ret < 0) { 259 return ret; 260 } else { 261 session_id = ret; 262 } 263 break; 264 case VIRTIO_CRYPTO_HASH_CREATE_SESSION: 265 case VIRTIO_CRYPTO_MAC_CREATE_SESSION: 266 default: 267 error_setg(errp, "Unsupported opcode :%" PRIu32 "", 268 sess_info->op_code); 269 return -1; 270 } 271 272 return session_id; 273 } 274 275 static int cryptodev_builtin_sym_close_session( 276 CryptoDevBackend *backend, 277 uint64_t session_id, 278 uint32_t queue_index, Error **errp) 279 { 280 CryptoDevBackendBuiltin *builtin = 281 CRYPTODEV_BACKEND_BUILTIN(backend); 282 283 if (session_id >= MAX_NUM_SESSIONS || 284 builtin->sessions[session_id] == NULL) { 285 error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", 286 session_id); 287 return -1; 288 } 289 290 qcrypto_cipher_free(builtin->sessions[session_id]->cipher); 291 g_free(builtin->sessions[session_id]); 292 builtin->sessions[session_id] = NULL; 293 return 0; 294 } 295 296 static int cryptodev_builtin_sym_operation( 297 CryptoDevBackend *backend, 298 CryptoDevBackendSymOpInfo *op_info, 299 uint32_t queue_index, Error **errp) 300 { 301 CryptoDevBackendBuiltin *builtin = 302 CRYPTODEV_BACKEND_BUILTIN(backend); 303 CryptoDevBackendBuiltinSession *sess; 304 int ret; 305 306 if (op_info->session_id >= MAX_NUM_SESSIONS || 307 builtin->sessions[op_info->session_id] == NULL) { 308 error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", 309 op_info->session_id); 310 return -VIRTIO_CRYPTO_INVSESS; 311 } 312 313 if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { 314 error_setg(errp, 315 "Algorithm chain is unsupported for cryptdoev-builtin"); 316 return -VIRTIO_CRYPTO_NOTSUPP; 317 } 318 319 sess = builtin->sessions[op_info->session_id]; 320 321 ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, 322 op_info->iv_len, errp); 323 if (ret < 0) { 324 return -VIRTIO_CRYPTO_ERR; 325 } 326 327 if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) { 328 ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src, 329 op_info->dst, op_info->src_len, errp); 330 if (ret < 0) { 331 return -VIRTIO_CRYPTO_ERR; 332 } 333 } else { 334 ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src, 335 op_info->dst, op_info->src_len, errp); 336 if (ret < 0) { 337 return -VIRTIO_CRYPTO_ERR; 338 } 339 } 340 return VIRTIO_CRYPTO_OK; 341 } 342 343 static void cryptodev_builtin_cleanup( 344 CryptoDevBackend *backend, 345 Error **errp) 346 { 347 CryptoDevBackendBuiltin *builtin = 348 CRYPTODEV_BACKEND_BUILTIN(backend); 349 size_t i; 350 int queues = backend->conf.peers.queues; 351 CryptoDevBackendClient *cc; 352 353 for (i = 0; i < MAX_NUM_SESSIONS; i++) { 354 if (builtin->sessions[i] != NULL) { 355 cryptodev_builtin_sym_close_session( 356 backend, i, 0, errp); 357 } 358 } 359 360 assert(queues == 1); 361 362 for (i = 0; i < queues; i++) { 363 cc = backend->conf.peers.ccs[i]; 364 if (cc) { 365 cryptodev_backend_free_client(cc); 366 backend->conf.peers.ccs[i] = NULL; 367 } 368 } 369 } 370 371 static void 372 cryptodev_builtin_class_init(ObjectClass *oc, void *data) 373 { 374 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); 375 376 bc->init = cryptodev_builtin_init; 377 bc->cleanup = cryptodev_builtin_cleanup; 378 bc->create_session = cryptodev_builtin_sym_create_session; 379 bc->close_session = cryptodev_builtin_sym_close_session; 380 bc->do_sym_op = cryptodev_builtin_sym_operation; 381 } 382 383 static const TypeInfo cryptodev_builtin_info = { 384 .name = TYPE_CRYPTODEV_BACKEND_BUILTIN, 385 .parent = TYPE_CRYPTODEV_BACKEND, 386 .class_init = cryptodev_builtin_class_init, 387 .instance_size = sizeof(CryptoDevBackendBuiltin), 388 }; 389 390 static void 391 cryptodev_builtin_register_types(void) 392 { 393 type_register_static(&cryptodev_builtin_info); 394 } 395 396 type_init(cryptodev_builtin_register_types); 397