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