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