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 "crypto/akcipher.h" 30 #include "qom/object.h" 31 32 33 /** 34 * @TYPE_CRYPTODEV_BACKEND_BUILTIN: 35 * name of backend that uses QEMU cipher API 36 */ 37 #define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin" 38 39 OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN) 40 41 42 typedef struct CryptoDevBackendBuiltinSession { 43 QCryptoCipher *cipher; 44 uint8_t direction; /* encryption or decryption */ 45 uint8_t type; /* cipher? hash? aead? */ 46 QCryptoAkCipher *akcipher; 47 QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next; 48 } CryptoDevBackendBuiltinSession; 49 50 /* Max number of symmetric/asymmetric sessions */ 51 #define MAX_NUM_SESSIONS 256 52 53 #define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512 54 #define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN 64 55 56 struct CryptoDevBackendBuiltin { 57 CryptoDevBackend parent_obj; 58 59 CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS]; 60 }; 61 62 static void cryptodev_builtin_init( 63 CryptoDevBackend *backend, Error **errp) 64 { 65 /* Only support one queue */ 66 int queues = backend->conf.peers.queues; 67 CryptoDevBackendClient *cc; 68 69 if (queues != 1) { 70 error_setg(errp, 71 "Only support one queue in cryptdov-builtin backend"); 72 return; 73 } 74 75 cc = cryptodev_backend_new_client( 76 "cryptodev-builtin", NULL); 77 cc->info_str = g_strdup_printf("cryptodev-builtin0"); 78 cc->queue_index = 0; 79 cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN; 80 backend->conf.peers.ccs[0] = cc; 81 82 backend->conf.crypto_services = 83 1u << VIRTIO_CRYPTO_SERVICE_CIPHER | 84 1u << VIRTIO_CRYPTO_SERVICE_HASH | 85 1u << VIRTIO_CRYPTO_SERVICE_MAC | 86 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER; 87 backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC; 88 backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1; 89 backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA; 90 /* 91 * Set the Maximum length of crypto request. 92 * Why this value? Just avoid to overflow when 93 * memory allocation for each crypto request. 94 */ 95 backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo); 96 backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN; 97 backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN; 98 99 cryptodev_backend_set_ready(backend, true); 100 } 101 102 static int 103 cryptodev_builtin_get_unused_session_index( 104 CryptoDevBackendBuiltin *builtin) 105 { 106 size_t i; 107 108 for (i = 0; i < MAX_NUM_SESSIONS; i++) { 109 if (builtin->sessions[i] == NULL) { 110 return i; 111 } 112 } 113 114 return -1; 115 } 116 117 #define AES_KEYSIZE_128 16 118 #define AES_KEYSIZE_192 24 119 #define AES_KEYSIZE_256 32 120 #define AES_KEYSIZE_128_XTS AES_KEYSIZE_256 121 #define AES_KEYSIZE_256_XTS 64 122 123 static int 124 cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp) 125 { 126 int algo; 127 128 if (key_len == AES_KEYSIZE_128) { 129 algo = QCRYPTO_CIPHER_ALG_AES_128; 130 } else if (key_len == AES_KEYSIZE_192) { 131 algo = QCRYPTO_CIPHER_ALG_AES_192; 132 } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */ 133 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 134 algo = QCRYPTO_CIPHER_ALG_AES_128; 135 } else { 136 algo = QCRYPTO_CIPHER_ALG_AES_256; 137 } 138 } else if (key_len == AES_KEYSIZE_256_XTS) { 139 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 140 algo = QCRYPTO_CIPHER_ALG_AES_256; 141 } else { 142 goto err; 143 } 144 } else { 145 goto err; 146 } 147 148 return algo; 149 150 err: 151 error_setg(errp, "Unsupported key length :%u", key_len); 152 return -1; 153 } 154 155 static int cryptodev_builtin_get_rsa_hash_algo( 156 int virtio_rsa_hash, Error **errp) 157 { 158 switch (virtio_rsa_hash) { 159 case VIRTIO_CRYPTO_RSA_MD5: 160 return QCRYPTO_HASH_ALG_MD5; 161 162 case VIRTIO_CRYPTO_RSA_SHA1: 163 return QCRYPTO_HASH_ALG_SHA1; 164 165 case VIRTIO_CRYPTO_RSA_SHA256: 166 return QCRYPTO_HASH_ALG_SHA256; 167 168 case VIRTIO_CRYPTO_RSA_SHA512: 169 return QCRYPTO_HASH_ALG_SHA512; 170 171 default: 172 error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash); 173 return -1; 174 } 175 } 176 177 static int cryptodev_builtin_set_rsa_options( 178 int virtio_padding_algo, 179 int virtio_hash_algo, 180 QCryptoAkCipherOptionsRSA *opt, 181 Error **errp) 182 { 183 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) { 184 int hash_alg; 185 186 hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp); 187 if (hash_alg < 0) { 188 return -1; 189 } 190 opt->hash_alg = hash_alg; 191 opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1; 192 return 0; 193 } 194 195 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) { 196 opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW; 197 return 0; 198 } 199 200 error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo); 201 return -1; 202 } 203 204 static int cryptodev_builtin_create_cipher_session( 205 CryptoDevBackendBuiltin *builtin, 206 CryptoDevBackendSymSessionInfo *sess_info, 207 Error **errp) 208 { 209 int algo; 210 int mode; 211 QCryptoCipher *cipher; 212 int index; 213 CryptoDevBackendBuiltinSession *sess; 214 215 if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) { 216 error_setg(errp, "Unsupported optype :%u", sess_info->op_type); 217 return -1; 218 } 219 220 index = cryptodev_builtin_get_unused_session_index(builtin); 221 if (index < 0) { 222 error_setg(errp, "Total number of sessions created exceeds %u", 223 MAX_NUM_SESSIONS); 224 return -1; 225 } 226 227 switch (sess_info->cipher_alg) { 228 case VIRTIO_CRYPTO_CIPHER_AES_ECB: 229 mode = QCRYPTO_CIPHER_MODE_ECB; 230 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 231 mode, errp); 232 if (algo < 0) { 233 return -1; 234 } 235 break; 236 case VIRTIO_CRYPTO_CIPHER_AES_CBC: 237 mode = QCRYPTO_CIPHER_MODE_CBC; 238 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 239 mode, errp); 240 if (algo < 0) { 241 return -1; 242 } 243 break; 244 case VIRTIO_CRYPTO_CIPHER_AES_CTR: 245 mode = QCRYPTO_CIPHER_MODE_CTR; 246 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 247 mode, errp); 248 if (algo < 0) { 249 return -1; 250 } 251 break; 252 case VIRTIO_CRYPTO_CIPHER_AES_XTS: 253 mode = QCRYPTO_CIPHER_MODE_XTS; 254 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 255 mode, errp); 256 if (algo < 0) { 257 return -1; 258 } 259 break; 260 case VIRTIO_CRYPTO_CIPHER_3DES_ECB: 261 mode = QCRYPTO_CIPHER_MODE_ECB; 262 algo = QCRYPTO_CIPHER_ALG_3DES; 263 break; 264 case VIRTIO_CRYPTO_CIPHER_3DES_CBC: 265 mode = QCRYPTO_CIPHER_MODE_CBC; 266 algo = QCRYPTO_CIPHER_ALG_3DES; 267 break; 268 case VIRTIO_CRYPTO_CIPHER_3DES_CTR: 269 mode = QCRYPTO_CIPHER_MODE_CTR; 270 algo = QCRYPTO_CIPHER_ALG_3DES; 271 break; 272 default: 273 error_setg(errp, "Unsupported cipher alg :%u", 274 sess_info->cipher_alg); 275 return -1; 276 } 277 278 cipher = qcrypto_cipher_new(algo, mode, 279 sess_info->cipher_key, 280 sess_info->key_len, 281 errp); 282 if (!cipher) { 283 return -1; 284 } 285 286 sess = g_new0(CryptoDevBackendBuiltinSession, 1); 287 sess->cipher = cipher; 288 sess->direction = sess_info->direction; 289 sess->type = sess_info->op_type; 290 291 builtin->sessions[index] = sess; 292 293 return index; 294 } 295 296 static int cryptodev_builtin_create_akcipher_session( 297 CryptoDevBackendBuiltin *builtin, 298 CryptoDevBackendAsymSessionInfo *sess_info, 299 Error **errp) 300 { 301 CryptoDevBackendBuiltinSession *sess; 302 QCryptoAkCipher *akcipher; 303 int index; 304 QCryptoAkCipherKeyType type; 305 QCryptoAkCipherOptions opts; 306 307 switch (sess_info->algo) { 308 case VIRTIO_CRYPTO_AKCIPHER_RSA: 309 opts.alg = QCRYPTO_AKCIPHER_ALG_RSA; 310 if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo, 311 sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) { 312 return -1; 313 } 314 break; 315 316 /* TODO support DSA&ECDSA until qemu crypto framework support these */ 317 318 default: 319 error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo); 320 return -1; 321 } 322 323 switch (sess_info->keytype) { 324 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: 325 type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC; 326 break; 327 328 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: 329 type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; 330 break; 331 332 default: 333 error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype); 334 return -1; 335 } 336 337 index = cryptodev_builtin_get_unused_session_index(builtin); 338 if (index < 0) { 339 error_setg(errp, "Total number of sessions created exceeds %u", 340 MAX_NUM_SESSIONS); 341 return -1; 342 } 343 344 akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key, 345 sess_info->keylen, errp); 346 if (!akcipher) { 347 return -1; 348 } 349 350 sess = g_new0(CryptoDevBackendBuiltinSession, 1); 351 sess->akcipher = akcipher; 352 353 builtin->sessions[index] = sess; 354 355 return index; 356 } 357 358 static int64_t cryptodev_builtin_create_session( 359 CryptoDevBackend *backend, 360 CryptoDevBackendSessionInfo *sess_info, 361 uint32_t queue_index, Error **errp) 362 { 363 CryptoDevBackendBuiltin *builtin = 364 CRYPTODEV_BACKEND_BUILTIN(backend); 365 CryptoDevBackendSymSessionInfo *sym_sess_info; 366 CryptoDevBackendAsymSessionInfo *asym_sess_info; 367 368 switch (sess_info->op_code) { 369 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: 370 sym_sess_info = &sess_info->u.sym_sess_info; 371 return cryptodev_builtin_create_cipher_session( 372 builtin, sym_sess_info, errp); 373 374 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: 375 asym_sess_info = &sess_info->u.asym_sess_info; 376 return cryptodev_builtin_create_akcipher_session( 377 builtin, asym_sess_info, errp); 378 379 case VIRTIO_CRYPTO_HASH_CREATE_SESSION: 380 case VIRTIO_CRYPTO_MAC_CREATE_SESSION: 381 default: 382 error_setg(errp, "Unsupported opcode :%" PRIu32 "", 383 sess_info->op_code); 384 return -1; 385 } 386 387 return -1; 388 } 389 390 static int cryptodev_builtin_close_session( 391 CryptoDevBackend *backend, 392 uint64_t session_id, 393 uint32_t queue_index, Error **errp) 394 { 395 CryptoDevBackendBuiltin *builtin = 396 CRYPTODEV_BACKEND_BUILTIN(backend); 397 CryptoDevBackendBuiltinSession *session; 398 399 assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]); 400 401 session = builtin->sessions[session_id]; 402 if (session->cipher) { 403 qcrypto_cipher_free(session->cipher); 404 } else if (session->akcipher) { 405 qcrypto_akcipher_free(session->akcipher); 406 } 407 408 g_free(session); 409 builtin->sessions[session_id] = NULL; 410 return 0; 411 } 412 413 static int cryptodev_builtin_sym_operation( 414 CryptoDevBackendBuiltinSession *sess, 415 CryptoDevBackendSymOpInfo *op_info, Error **errp) 416 { 417 int ret; 418 419 if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { 420 error_setg(errp, 421 "Algorithm chain is unsupported for cryptdoev-builtin"); 422 return -VIRTIO_CRYPTO_NOTSUPP; 423 } 424 425 if (op_info->iv_len > 0) { 426 ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, 427 op_info->iv_len, errp); 428 if (ret < 0) { 429 return -VIRTIO_CRYPTO_ERR; 430 } 431 } 432 433 if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) { 434 ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src, 435 op_info->dst, op_info->src_len, errp); 436 if (ret < 0) { 437 return -VIRTIO_CRYPTO_ERR; 438 } 439 } else { 440 ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src, 441 op_info->dst, op_info->src_len, errp); 442 if (ret < 0) { 443 return -VIRTIO_CRYPTO_ERR; 444 } 445 } 446 447 return VIRTIO_CRYPTO_OK; 448 } 449 450 static int cryptodev_builtin_asym_operation( 451 CryptoDevBackendBuiltinSession *sess, uint32_t op_code, 452 CryptoDevBackendAsymOpInfo *op_info, Error **errp) 453 { 454 int ret; 455 456 switch (op_code) { 457 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: 458 ret = qcrypto_akcipher_encrypt(sess->akcipher, 459 op_info->src, op_info->src_len, 460 op_info->dst, op_info->dst_len, errp); 461 break; 462 463 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: 464 ret = qcrypto_akcipher_decrypt(sess->akcipher, 465 op_info->src, op_info->src_len, 466 op_info->dst, op_info->dst_len, errp); 467 break; 468 469 case VIRTIO_CRYPTO_AKCIPHER_SIGN: 470 ret = qcrypto_akcipher_sign(sess->akcipher, 471 op_info->src, op_info->src_len, 472 op_info->dst, op_info->dst_len, errp); 473 break; 474 475 case VIRTIO_CRYPTO_AKCIPHER_VERIFY: 476 ret = qcrypto_akcipher_verify(sess->akcipher, 477 op_info->src, op_info->src_len, 478 op_info->dst, op_info->dst_len, errp); 479 break; 480 481 default: 482 return -VIRTIO_CRYPTO_ERR; 483 } 484 485 if (ret < 0) { 486 if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { 487 return -VIRTIO_CRYPTO_KEY_REJECTED; 488 } 489 return -VIRTIO_CRYPTO_ERR; 490 } 491 492 /* Buffer is too short, typically the driver should handle this case */ 493 if (unlikely(ret > op_info->dst_len)) { 494 if (errp && !*errp) { 495 error_setg(errp, "dst buffer too short"); 496 } 497 498 return -VIRTIO_CRYPTO_ERR; 499 } 500 501 op_info->dst_len = ret; 502 503 return VIRTIO_CRYPTO_OK; 504 } 505 506 static int cryptodev_builtin_operation( 507 CryptoDevBackend *backend, 508 CryptoDevBackendOpInfo *op_info, 509 uint32_t queue_index, Error **errp) 510 { 511 CryptoDevBackendBuiltin *builtin = 512 CRYPTODEV_BACKEND_BUILTIN(backend); 513 CryptoDevBackendBuiltinSession *sess; 514 CryptoDevBackendSymOpInfo *sym_op_info; 515 CryptoDevBackendAsymOpInfo *asym_op_info; 516 enum CryptoDevBackendAlgType algtype = op_info->algtype; 517 int ret = -VIRTIO_CRYPTO_ERR; 518 519 if (op_info->session_id >= MAX_NUM_SESSIONS || 520 builtin->sessions[op_info->session_id] == NULL) { 521 error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", 522 op_info->session_id); 523 return -VIRTIO_CRYPTO_INVSESS; 524 } 525 526 sess = builtin->sessions[op_info->session_id]; 527 if (algtype == CRYPTODEV_BACKEND_ALG_SYM) { 528 sym_op_info = op_info->u.sym_op_info; 529 ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp); 530 } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) { 531 asym_op_info = op_info->u.asym_op_info; 532 ret = cryptodev_builtin_asym_operation(sess, op_info->op_code, 533 asym_op_info, errp); 534 } 535 536 return ret; 537 } 538 539 static void cryptodev_builtin_cleanup( 540 CryptoDevBackend *backend, 541 Error **errp) 542 { 543 CryptoDevBackendBuiltin *builtin = 544 CRYPTODEV_BACKEND_BUILTIN(backend); 545 size_t i; 546 int queues = backend->conf.peers.queues; 547 CryptoDevBackendClient *cc; 548 549 for (i = 0; i < MAX_NUM_SESSIONS; i++) { 550 if (builtin->sessions[i] != NULL) { 551 cryptodev_builtin_close_session(backend, i, 0, &error_abort); 552 } 553 } 554 555 for (i = 0; i < queues; i++) { 556 cc = backend->conf.peers.ccs[i]; 557 if (cc) { 558 cryptodev_backend_free_client(cc); 559 backend->conf.peers.ccs[i] = NULL; 560 } 561 } 562 563 cryptodev_backend_set_ready(backend, false); 564 } 565 566 static void 567 cryptodev_builtin_class_init(ObjectClass *oc, void *data) 568 { 569 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); 570 571 bc->init = cryptodev_builtin_init; 572 bc->cleanup = cryptodev_builtin_cleanup; 573 bc->create_session = cryptodev_builtin_create_session; 574 bc->close_session = cryptodev_builtin_close_session; 575 bc->do_op = cryptodev_builtin_operation; 576 } 577 578 static const TypeInfo cryptodev_builtin_info = { 579 .name = TYPE_CRYPTODEV_BACKEND_BUILTIN, 580 .parent = TYPE_CRYPTODEV_BACKEND, 581 .class_init = cryptodev_builtin_class_init, 582 .instance_size = sizeof(CryptoDevBackendBuiltin), 583 }; 584 585 static void 586 cryptodev_builtin_register_types(void) 587 { 588 type_register_static(&cryptodev_builtin_info); 589 } 590 591 type_init(cryptodev_builtin_register_types); 592