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