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 int cryptodev_builtin_create_session( 359 CryptoDevBackend *backend, 360 CryptoDevBackendSessionInfo *sess_info, 361 uint32_t queue_index, 362 CryptoDevCompletionFunc cb, 363 void *opaque) 364 { 365 CryptoDevBackendBuiltin *builtin = 366 CRYPTODEV_BACKEND_BUILTIN(backend); 367 CryptoDevBackendSymSessionInfo *sym_sess_info; 368 CryptoDevBackendAsymSessionInfo *asym_sess_info; 369 int ret, status; 370 Error *local_error = NULL; 371 372 switch (sess_info->op_code) { 373 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: 374 sym_sess_info = &sess_info->u.sym_sess_info; 375 ret = cryptodev_builtin_create_cipher_session( 376 builtin, sym_sess_info, &local_error); 377 break; 378 379 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: 380 asym_sess_info = &sess_info->u.asym_sess_info; 381 ret = cryptodev_builtin_create_akcipher_session( 382 builtin, asym_sess_info, &local_error); 383 break; 384 385 case VIRTIO_CRYPTO_HASH_CREATE_SESSION: 386 case VIRTIO_CRYPTO_MAC_CREATE_SESSION: 387 default: 388 error_setg(&local_error, "Unsupported opcode :%" PRIu32 "", 389 sess_info->op_code); 390 return -VIRTIO_CRYPTO_NOTSUPP; 391 } 392 393 if (local_error) { 394 error_report_err(local_error); 395 } 396 if (ret < 0) { 397 status = -VIRTIO_CRYPTO_ERR; 398 } else { 399 sess_info->session_id = ret; 400 status = VIRTIO_CRYPTO_OK; 401 } 402 if (cb) { 403 cb(opaque, status); 404 } 405 return 0; 406 } 407 408 static int cryptodev_builtin_close_session( 409 CryptoDevBackend *backend, 410 uint64_t session_id, 411 uint32_t queue_index, 412 CryptoDevCompletionFunc cb, 413 void *opaque) 414 { 415 CryptoDevBackendBuiltin *builtin = 416 CRYPTODEV_BACKEND_BUILTIN(backend); 417 CryptoDevBackendBuiltinSession *session; 418 419 assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]); 420 421 session = builtin->sessions[session_id]; 422 if (session->cipher) { 423 qcrypto_cipher_free(session->cipher); 424 } else if (session->akcipher) { 425 qcrypto_akcipher_free(session->akcipher); 426 } 427 428 g_free(session); 429 builtin->sessions[session_id] = NULL; 430 if (cb) { 431 cb(opaque, VIRTIO_CRYPTO_OK); 432 } 433 return 0; 434 } 435 436 static int cryptodev_builtin_sym_operation( 437 CryptoDevBackendBuiltinSession *sess, 438 CryptoDevBackendSymOpInfo *op_info, Error **errp) 439 { 440 int ret; 441 442 if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { 443 error_setg(errp, 444 "Algorithm chain is unsupported for cryptdoev-builtin"); 445 return -VIRTIO_CRYPTO_NOTSUPP; 446 } 447 448 if (op_info->iv_len > 0) { 449 ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, 450 op_info->iv_len, errp); 451 if (ret < 0) { 452 return -VIRTIO_CRYPTO_ERR; 453 } 454 } 455 456 if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) { 457 ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src, 458 op_info->dst, op_info->src_len, errp); 459 if (ret < 0) { 460 return -VIRTIO_CRYPTO_ERR; 461 } 462 } else { 463 ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src, 464 op_info->dst, op_info->src_len, errp); 465 if (ret < 0) { 466 return -VIRTIO_CRYPTO_ERR; 467 } 468 } 469 470 return VIRTIO_CRYPTO_OK; 471 } 472 473 static int cryptodev_builtin_asym_operation( 474 CryptoDevBackendBuiltinSession *sess, uint32_t op_code, 475 CryptoDevBackendAsymOpInfo *op_info, Error **errp) 476 { 477 int ret; 478 479 switch (op_code) { 480 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: 481 ret = qcrypto_akcipher_encrypt(sess->akcipher, 482 op_info->src, op_info->src_len, 483 op_info->dst, op_info->dst_len, errp); 484 break; 485 486 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: 487 ret = qcrypto_akcipher_decrypt(sess->akcipher, 488 op_info->src, op_info->src_len, 489 op_info->dst, op_info->dst_len, errp); 490 break; 491 492 case VIRTIO_CRYPTO_AKCIPHER_SIGN: 493 ret = qcrypto_akcipher_sign(sess->akcipher, 494 op_info->src, op_info->src_len, 495 op_info->dst, op_info->dst_len, errp); 496 break; 497 498 case VIRTIO_CRYPTO_AKCIPHER_VERIFY: 499 ret = qcrypto_akcipher_verify(sess->akcipher, 500 op_info->src, op_info->src_len, 501 op_info->dst, op_info->dst_len, errp); 502 break; 503 504 default: 505 return -VIRTIO_CRYPTO_ERR; 506 } 507 508 if (ret < 0) { 509 if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { 510 return -VIRTIO_CRYPTO_KEY_REJECTED; 511 } 512 return -VIRTIO_CRYPTO_ERR; 513 } 514 515 /* Buffer is too short, typically the driver should handle this case */ 516 if (unlikely(ret > op_info->dst_len)) { 517 if (errp && !*errp) { 518 error_setg(errp, "dst buffer too short"); 519 } 520 521 return -VIRTIO_CRYPTO_ERR; 522 } 523 524 op_info->dst_len = ret; 525 526 return VIRTIO_CRYPTO_OK; 527 } 528 529 static int cryptodev_builtin_operation( 530 CryptoDevBackend *backend, 531 CryptoDevBackendOpInfo *op_info, 532 uint32_t queue_index, 533 CryptoDevCompletionFunc cb, 534 void *opaque) 535 { 536 CryptoDevBackendBuiltin *builtin = 537 CRYPTODEV_BACKEND_BUILTIN(backend); 538 CryptoDevBackendBuiltinSession *sess; 539 CryptoDevBackendSymOpInfo *sym_op_info; 540 CryptoDevBackendAsymOpInfo *asym_op_info; 541 enum CryptoDevBackendAlgType algtype = op_info->algtype; 542 int status = -VIRTIO_CRYPTO_ERR; 543 Error *local_error = NULL; 544 545 if (op_info->session_id >= MAX_NUM_SESSIONS || 546 builtin->sessions[op_info->session_id] == NULL) { 547 error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "", 548 op_info->session_id); 549 return -VIRTIO_CRYPTO_INVSESS; 550 } 551 552 sess = builtin->sessions[op_info->session_id]; 553 if (algtype == CRYPTODEV_BACKEND_ALG_SYM) { 554 sym_op_info = op_info->u.sym_op_info; 555 status = cryptodev_builtin_sym_operation(sess, sym_op_info, 556 &local_error); 557 } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) { 558 asym_op_info = op_info->u.asym_op_info; 559 status = cryptodev_builtin_asym_operation(sess, op_info->op_code, 560 asym_op_info, &local_error); 561 } 562 563 if (local_error) { 564 error_report_err(local_error); 565 } 566 if (cb) { 567 cb(opaque, status); 568 } 569 return 0; 570 } 571 572 static void cryptodev_builtin_cleanup( 573 CryptoDevBackend *backend, 574 Error **errp) 575 { 576 CryptoDevBackendBuiltin *builtin = 577 CRYPTODEV_BACKEND_BUILTIN(backend); 578 size_t i; 579 int queues = backend->conf.peers.queues; 580 CryptoDevBackendClient *cc; 581 582 for (i = 0; i < MAX_NUM_SESSIONS; i++) { 583 if (builtin->sessions[i] != NULL) { 584 cryptodev_builtin_close_session(backend, i, 0, NULL, NULL); 585 } 586 } 587 588 for (i = 0; i < queues; i++) { 589 cc = backend->conf.peers.ccs[i]; 590 if (cc) { 591 cryptodev_backend_free_client(cc); 592 backend->conf.peers.ccs[i] = NULL; 593 } 594 } 595 596 cryptodev_backend_set_ready(backend, false); 597 } 598 599 static void 600 cryptodev_builtin_class_init(ObjectClass *oc, void *data) 601 { 602 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); 603 604 bc->init = cryptodev_builtin_init; 605 bc->cleanup = cryptodev_builtin_cleanup; 606 bc->create_session = cryptodev_builtin_create_session; 607 bc->close_session = cryptodev_builtin_close_session; 608 bc->do_op = cryptodev_builtin_operation; 609 } 610 611 static const TypeInfo cryptodev_builtin_info = { 612 .name = TYPE_CRYPTODEV_BACKEND_BUILTIN, 613 .parent = TYPE_CRYPTODEV_BACKEND, 614 .class_init = cryptodev_builtin_class_init, 615 .instance_size = sizeof(CryptoDevBackendBuiltin), 616 }; 617 618 static void 619 cryptodev_builtin_register_types(void) 620 { 621 type_register_static(&cryptodev_builtin_info); 622 } 623 624 type_init(cryptodev_builtin_register_types); 625