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 cc->info_str = g_strdup_printf("cryptodev-builtin0"); 77 cc->queue_index = 0; 78 cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN; 79 backend->conf.peers.ccs[0] = cc; 80 81 backend->conf.crypto_services = 82 1u << VIRTIO_CRYPTO_SERVICE_CIPHER | 83 1u << VIRTIO_CRYPTO_SERVICE_HASH | 84 1u << VIRTIO_CRYPTO_SERVICE_MAC | 85 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER; 86 backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC; 87 backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1; 88 backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA; 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(CryptoDevBackendOpInfo); 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_get_rsa_hash_algo( 155 int virtio_rsa_hash, Error **errp) 156 { 157 switch (virtio_rsa_hash) { 158 case VIRTIO_CRYPTO_RSA_MD5: 159 return QCRYPTO_HASH_ALG_MD5; 160 161 case VIRTIO_CRYPTO_RSA_SHA1: 162 return QCRYPTO_HASH_ALG_SHA1; 163 164 case VIRTIO_CRYPTO_RSA_SHA256: 165 return QCRYPTO_HASH_ALG_SHA256; 166 167 case VIRTIO_CRYPTO_RSA_SHA512: 168 return QCRYPTO_HASH_ALG_SHA512; 169 170 default: 171 error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash); 172 return -1; 173 } 174 } 175 176 static int cryptodev_builtin_set_rsa_options( 177 int virtio_padding_algo, 178 int virtio_hash_algo, 179 QCryptoAkCipherOptionsRSA *opt, 180 Error **errp) 181 { 182 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) { 183 int hash_alg; 184 185 hash_alg = cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp); 186 if (hash_alg < 0) { 187 return -1; 188 } 189 opt->hash_alg = hash_alg; 190 opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1; 191 return 0; 192 } 193 194 if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) { 195 opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW; 196 return 0; 197 } 198 199 error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo); 200 return -1; 201 } 202 203 static int cryptodev_builtin_create_cipher_session( 204 CryptoDevBackendBuiltin *builtin, 205 CryptoDevBackendSymSessionInfo *sess_info, 206 Error **errp) 207 { 208 int algo; 209 int mode; 210 QCryptoCipher *cipher; 211 int index; 212 CryptoDevBackendBuiltinSession *sess; 213 214 if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) { 215 error_setg(errp, "Unsupported optype :%u", sess_info->op_type); 216 return -1; 217 } 218 219 index = cryptodev_builtin_get_unused_session_index(builtin); 220 if (index < 0) { 221 error_setg(errp, "Total number of sessions created exceeds %u", 222 MAX_NUM_SESSIONS); 223 return -1; 224 } 225 226 switch (sess_info->cipher_alg) { 227 case VIRTIO_CRYPTO_CIPHER_AES_ECB: 228 mode = QCRYPTO_CIPHER_MODE_ECB; 229 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 230 mode, errp); 231 if (algo < 0) { 232 return -1; 233 } 234 break; 235 case VIRTIO_CRYPTO_CIPHER_AES_CBC: 236 mode = QCRYPTO_CIPHER_MODE_CBC; 237 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 238 mode, errp); 239 if (algo < 0) { 240 return -1; 241 } 242 break; 243 case VIRTIO_CRYPTO_CIPHER_AES_CTR: 244 mode = QCRYPTO_CIPHER_MODE_CTR; 245 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 246 mode, errp); 247 if (algo < 0) { 248 return -1; 249 } 250 break; 251 case VIRTIO_CRYPTO_CIPHER_AES_XTS: 252 mode = QCRYPTO_CIPHER_MODE_XTS; 253 algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, 254 mode, errp); 255 if (algo < 0) { 256 return -1; 257 } 258 break; 259 case VIRTIO_CRYPTO_CIPHER_3DES_ECB: 260 mode = QCRYPTO_CIPHER_MODE_ECB; 261 algo = QCRYPTO_CIPHER_ALG_3DES; 262 break; 263 case VIRTIO_CRYPTO_CIPHER_3DES_CBC: 264 mode = QCRYPTO_CIPHER_MODE_CBC; 265 algo = QCRYPTO_CIPHER_ALG_3DES; 266 break; 267 case VIRTIO_CRYPTO_CIPHER_3DES_CTR: 268 mode = QCRYPTO_CIPHER_MODE_CTR; 269 algo = QCRYPTO_CIPHER_ALG_3DES; 270 break; 271 default: 272 error_setg(errp, "Unsupported cipher alg :%u", 273 sess_info->cipher_alg); 274 return -1; 275 } 276 277 cipher = qcrypto_cipher_new(algo, mode, 278 sess_info->cipher_key, 279 sess_info->key_len, 280 errp); 281 if (!cipher) { 282 return -1; 283 } 284 285 sess = g_new0(CryptoDevBackendBuiltinSession, 1); 286 sess->cipher = cipher; 287 sess->direction = sess_info->direction; 288 sess->type = sess_info->op_type; 289 290 builtin->sessions[index] = sess; 291 292 return index; 293 } 294 295 static int cryptodev_builtin_create_akcipher_session( 296 CryptoDevBackendBuiltin *builtin, 297 CryptoDevBackendAsymSessionInfo *sess_info, 298 Error **errp) 299 { 300 CryptoDevBackendBuiltinSession *sess; 301 QCryptoAkCipher *akcipher; 302 int index; 303 QCryptoAkCipherKeyType type; 304 QCryptoAkCipherOptions opts; 305 306 switch (sess_info->algo) { 307 case VIRTIO_CRYPTO_AKCIPHER_RSA: 308 opts.alg = QCRYPTO_AKCIPHER_ALG_RSA; 309 if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo, 310 sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) { 311 return -1; 312 } 313 break; 314 315 /* TODO support DSA&ECDSA until qemu crypto framework support these */ 316 317 default: 318 error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo); 319 return -1; 320 } 321 322 switch (sess_info->keytype) { 323 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: 324 type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC; 325 break; 326 327 case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: 328 type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; 329 break; 330 331 default: 332 error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype); 333 return -1; 334 } 335 336 index = cryptodev_builtin_get_unused_session_index(builtin); 337 if (index < 0) { 338 error_setg(errp, "Total number of sessions created exceeds %u", 339 MAX_NUM_SESSIONS); 340 return -1; 341 } 342 343 akcipher = qcrypto_akcipher_new(&opts, type, sess_info->key, 344 sess_info->keylen, errp); 345 if (!akcipher) { 346 return -1; 347 } 348 349 sess = g_new0(CryptoDevBackendBuiltinSession, 1); 350 sess->akcipher = akcipher; 351 352 builtin->sessions[index] = sess; 353 354 return index; 355 } 356 357 static int cryptodev_builtin_create_session( 358 CryptoDevBackend *backend, 359 CryptoDevBackendSessionInfo *sess_info, 360 uint32_t queue_index, 361 CryptoDevCompletionFunc cb, 362 void *opaque) 363 { 364 CryptoDevBackendBuiltin *builtin = 365 CRYPTODEV_BACKEND_BUILTIN(backend); 366 CryptoDevBackendSymSessionInfo *sym_sess_info; 367 CryptoDevBackendAsymSessionInfo *asym_sess_info; 368 int ret, status; 369 Error *local_error = NULL; 370 371 switch (sess_info->op_code) { 372 case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: 373 sym_sess_info = &sess_info->u.sym_sess_info; 374 ret = cryptodev_builtin_create_cipher_session( 375 builtin, sym_sess_info, &local_error); 376 break; 377 378 case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: 379 asym_sess_info = &sess_info->u.asym_sess_info; 380 ret = cryptodev_builtin_create_akcipher_session( 381 builtin, asym_sess_info, &local_error); 382 break; 383 384 case VIRTIO_CRYPTO_HASH_CREATE_SESSION: 385 case VIRTIO_CRYPTO_MAC_CREATE_SESSION: 386 default: 387 error_setg(&local_error, "Unsupported opcode :%" PRIu32 "", 388 sess_info->op_code); 389 return -VIRTIO_CRYPTO_NOTSUPP; 390 } 391 392 if (local_error) { 393 error_report_err(local_error); 394 } 395 if (ret < 0) { 396 status = -VIRTIO_CRYPTO_ERR; 397 } else { 398 sess_info->session_id = ret; 399 status = VIRTIO_CRYPTO_OK; 400 } 401 if (cb) { 402 cb(opaque, status); 403 } 404 return 0; 405 } 406 407 static int cryptodev_builtin_close_session( 408 CryptoDevBackend *backend, 409 uint64_t session_id, 410 uint32_t queue_index, 411 CryptoDevCompletionFunc cb, 412 void *opaque) 413 { 414 CryptoDevBackendBuiltin *builtin = 415 CRYPTODEV_BACKEND_BUILTIN(backend); 416 CryptoDevBackendBuiltinSession *session; 417 418 assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]); 419 420 session = builtin->sessions[session_id]; 421 if (session->cipher) { 422 qcrypto_cipher_free(session->cipher); 423 } else if (session->akcipher) { 424 qcrypto_akcipher_free(session->akcipher); 425 } 426 427 g_free(session); 428 builtin->sessions[session_id] = NULL; 429 if (cb) { 430 cb(opaque, VIRTIO_CRYPTO_OK); 431 } 432 return 0; 433 } 434 435 static int cryptodev_builtin_sym_operation( 436 CryptoDevBackendBuiltinSession *sess, 437 CryptoDevBackendSymOpInfo *op_info, Error **errp) 438 { 439 int ret; 440 441 if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { 442 error_setg(errp, 443 "Algorithm chain is unsupported for cryptdoev-builtin"); 444 return -VIRTIO_CRYPTO_NOTSUPP; 445 } 446 447 if (op_info->iv_len > 0) { 448 ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, 449 op_info->iv_len, errp); 450 if (ret < 0) { 451 return -VIRTIO_CRYPTO_ERR; 452 } 453 } 454 455 if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) { 456 ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src, 457 op_info->dst, op_info->src_len, errp); 458 if (ret < 0) { 459 return -VIRTIO_CRYPTO_ERR; 460 } 461 } else { 462 ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src, 463 op_info->dst, op_info->src_len, errp); 464 if (ret < 0) { 465 return -VIRTIO_CRYPTO_ERR; 466 } 467 } 468 469 return VIRTIO_CRYPTO_OK; 470 } 471 472 static int cryptodev_builtin_asym_operation( 473 CryptoDevBackendBuiltinSession *sess, uint32_t op_code, 474 CryptoDevBackendAsymOpInfo *op_info, Error **errp) 475 { 476 int ret; 477 478 switch (op_code) { 479 case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: 480 ret = qcrypto_akcipher_encrypt(sess->akcipher, 481 op_info->src, op_info->src_len, 482 op_info->dst, op_info->dst_len, errp); 483 break; 484 485 case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: 486 ret = qcrypto_akcipher_decrypt(sess->akcipher, 487 op_info->src, op_info->src_len, 488 op_info->dst, op_info->dst_len, errp); 489 break; 490 491 case VIRTIO_CRYPTO_AKCIPHER_SIGN: 492 ret = qcrypto_akcipher_sign(sess->akcipher, 493 op_info->src, op_info->src_len, 494 op_info->dst, op_info->dst_len, errp); 495 break; 496 497 case VIRTIO_CRYPTO_AKCIPHER_VERIFY: 498 ret = qcrypto_akcipher_verify(sess->akcipher, 499 op_info->src, op_info->src_len, 500 op_info->dst, op_info->dst_len, errp); 501 break; 502 503 default: 504 return -VIRTIO_CRYPTO_ERR; 505 } 506 507 if (ret < 0) { 508 if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { 509 return -VIRTIO_CRYPTO_KEY_REJECTED; 510 } 511 return -VIRTIO_CRYPTO_ERR; 512 } 513 514 /* Buffer is too short, typically the driver should handle this case */ 515 if (unlikely(ret > op_info->dst_len)) { 516 if (errp && !*errp) { 517 error_setg(errp, "dst buffer too short"); 518 } 519 520 return -VIRTIO_CRYPTO_ERR; 521 } 522 523 op_info->dst_len = ret; 524 525 return VIRTIO_CRYPTO_OK; 526 } 527 528 static int cryptodev_builtin_operation( 529 CryptoDevBackend *backend, 530 CryptoDevBackendOpInfo *op_info, 531 uint32_t queue_index, 532 CryptoDevCompletionFunc cb, 533 void *opaque) 534 { 535 CryptoDevBackendBuiltin *builtin = 536 CRYPTODEV_BACKEND_BUILTIN(backend); 537 CryptoDevBackendBuiltinSession *sess; 538 CryptoDevBackendSymOpInfo *sym_op_info; 539 CryptoDevBackendAsymOpInfo *asym_op_info; 540 QCryptodevBackendAlgType algtype = op_info->algtype; 541 int status = -VIRTIO_CRYPTO_ERR; 542 Error *local_error = NULL; 543 544 if (op_info->session_id >= MAX_NUM_SESSIONS || 545 builtin->sessions[op_info->session_id] == NULL) { 546 error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "", 547 op_info->session_id); 548 return -VIRTIO_CRYPTO_INVSESS; 549 } 550 551 sess = builtin->sessions[op_info->session_id]; 552 if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) { 553 sym_op_info = op_info->u.sym_op_info; 554 status = cryptodev_builtin_sym_operation(sess, sym_op_info, 555 &local_error); 556 } else if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) { 557 asym_op_info = op_info->u.asym_op_info; 558 status = cryptodev_builtin_asym_operation(sess, op_info->op_code, 559 asym_op_info, &local_error); 560 } 561 562 if (local_error) { 563 error_report_err(local_error); 564 } 565 if (cb) { 566 cb(opaque, status); 567 } 568 return 0; 569 } 570 571 static void cryptodev_builtin_cleanup( 572 CryptoDevBackend *backend, 573 Error **errp) 574 { 575 CryptoDevBackendBuiltin *builtin = 576 CRYPTODEV_BACKEND_BUILTIN(backend); 577 size_t i; 578 int queues = backend->conf.peers.queues; 579 CryptoDevBackendClient *cc; 580 581 for (i = 0; i < MAX_NUM_SESSIONS; i++) { 582 if (builtin->sessions[i] != NULL) { 583 cryptodev_builtin_close_session(backend, i, 0, NULL, NULL); 584 } 585 } 586 587 for (i = 0; i < queues; i++) { 588 cc = backend->conf.peers.ccs[i]; 589 if (cc) { 590 cryptodev_backend_free_client(cc); 591 backend->conf.peers.ccs[i] = NULL; 592 } 593 } 594 595 cryptodev_backend_set_ready(backend, false); 596 } 597 598 static void 599 cryptodev_builtin_class_init(ObjectClass *oc, void *data) 600 { 601 CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); 602 603 bc->init = cryptodev_builtin_init; 604 bc->cleanup = cryptodev_builtin_cleanup; 605 bc->create_session = cryptodev_builtin_create_session; 606 bc->close_session = cryptodev_builtin_close_session; 607 bc->do_op = cryptodev_builtin_operation; 608 } 609 610 static const TypeInfo cryptodev_builtin_info = { 611 .name = TYPE_CRYPTODEV_BACKEND_BUILTIN, 612 .parent = TYPE_CRYPTODEV_BACKEND, 613 .class_init = cryptodev_builtin_class_init, 614 .instance_size = sizeof(CryptoDevBackendBuiltin), 615 }; 616 617 static void 618 cryptodev_builtin_register_types(void) 619 { 620 type_register_static(&cryptodev_builtin_info); 621 } 622 623 type_init(cryptodev_builtin_register_types); 624