1/* 2 * QEMU Crypto akcipher algorithms 3 * 4 * Copyright (c) 2022 Bytedance 5 * Author: lei he <helei.sig11@bytedance.com> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22#include <gcrypt.h> 23 24#include "qemu/osdep.h" 25#include "qemu/host-utils.h" 26#include "crypto/akcipher.h" 27#include "crypto/random.h" 28#include "qapi/error.h" 29#include "sysemu/cryptodev.h" 30#include "rsakey.h" 31 32typedef struct QCryptoGcryptRSA { 33 QCryptoAkCipher akcipher; 34 gcry_sexp_t key; 35 QCryptoRSAPaddingAlgo padding_alg; 36 QCryptoHashAlgo hash_alg; 37} QCryptoGcryptRSA; 38 39static void qcrypto_gcrypt_rsa_free(QCryptoAkCipher *akcipher) 40{ 41 QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; 42 if (!rsa) { 43 return; 44 } 45 46 gcry_sexp_release(rsa->key); 47 g_free(rsa); 48} 49 50static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new( 51 const QCryptoAkCipherOptionsRSA *opt, 52 QCryptoAkCipherKeyType type, 53 const uint8_t *key, size_t keylen, 54 Error **errp); 55 56QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, 57 QCryptoAkCipherKeyType type, 58 const uint8_t *key, size_t keylen, 59 Error **errp) 60{ 61 switch (opts->alg) { 62 case QCRYPTO_AK_CIPHER_ALGO_RSA: 63 return (QCryptoAkCipher *)qcrypto_gcrypt_rsa_new( 64 &opts->u.rsa, type, key, keylen, errp); 65 66 default: 67 error_setg(errp, "Unsupported algorithm: %u", opts->alg); 68 return NULL; 69 } 70 71 return NULL; 72} 73 74static void qcrypto_gcrypt_set_rsa_size(QCryptoAkCipher *akcipher, gcry_mpi_t n) 75{ 76 size_t key_size = (gcry_mpi_get_nbits(n) + 7) / 8; 77 akcipher->max_plaintext_len = key_size; 78 akcipher->max_ciphertext_len = key_size; 79 akcipher->max_dgst_len = key_size; 80 akcipher->max_signature_len = key_size; 81} 82 83static int qcrypto_gcrypt_parse_rsa_private_key( 84 QCryptoGcryptRSA *rsa, 85 const uint8_t *key, size_t keylen, Error **errp) 86{ 87 g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( 88 QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE, key, keylen, errp); 89 gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL, u = NULL; 90 bool compute_mul_inv = false; 91 int ret = -1; 92 gcry_error_t err; 93 94 if (!rsa_key) { 95 return ret; 96 } 97 98 err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD, 99 rsa_key->n.data, rsa_key->n.len, NULL); 100 if (gcry_err_code(err) != 0) { 101 error_setg(errp, "Failed to parse RSA parameter n: %s/%s", 102 gcry_strsource(err), gcry_strerror(err)); 103 goto cleanup; 104 } 105 106 err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD, 107 rsa_key->e.data, rsa_key->e.len, NULL); 108 if (gcry_err_code(err) != 0) { 109 error_setg(errp, "Failed to parse RSA parameter e: %s/%s", 110 gcry_strsource(err), gcry_strerror(err)); 111 goto cleanup; 112 } 113 114 err = gcry_mpi_scan(&d, GCRYMPI_FMT_STD, 115 rsa_key->d.data, rsa_key->d.len, NULL); 116 if (gcry_err_code(err) != 0) { 117 error_setg(errp, "Failed to parse RSA parameter d: %s/%s", 118 gcry_strsource(err), gcry_strerror(err)); 119 goto cleanup; 120 } 121 122 err = gcry_mpi_scan(&p, GCRYMPI_FMT_STD, 123 rsa_key->p.data, rsa_key->p.len, NULL); 124 if (gcry_err_code(err) != 0) { 125 error_setg(errp, "Failed to parse RSA parameter p: %s/%s", 126 gcry_strsource(err), gcry_strerror(err)); 127 goto cleanup; 128 } 129 130 err = gcry_mpi_scan(&q, GCRYMPI_FMT_STD, 131 rsa_key->q.data, rsa_key->q.len, NULL); 132 if (gcry_err_code(err) != 0) { 133 error_setg(errp, "Failed to parse RSA parameter q: %s/%s", 134 gcry_strsource(err), gcry_strerror(err)); 135 goto cleanup; 136 } 137 138 if (gcry_mpi_cmp_ui(p, 0) > 0 && gcry_mpi_cmp_ui(q, 0) > 0) { 139 compute_mul_inv = true; 140 141 u = gcry_mpi_new(0); 142 if (gcry_mpi_cmp(p, q) > 0) { 143 gcry_mpi_swap(p, q); 144 } 145 gcry_mpi_invm(u, p, q); 146 } 147 148 if (compute_mul_inv) { 149 err = gcry_sexp_build(&rsa->key, NULL, 150 "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))", 151 n, e, d, p, q, u); 152 } else { 153 err = gcry_sexp_build(&rsa->key, NULL, 154 "(private-key (rsa (n %m) (e %m) (d %m)))", n, e, d); 155 } 156 if (gcry_err_code(err) != 0) { 157 error_setg(errp, "Failed to build RSA private key: %s/%s", 158 gcry_strsource(err), gcry_strerror(err)); 159 goto cleanup; 160 } 161 qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n); 162 ret = 0; 163 164cleanup: 165 gcry_mpi_release(n); 166 gcry_mpi_release(e); 167 gcry_mpi_release(d); 168 gcry_mpi_release(p); 169 gcry_mpi_release(q); 170 gcry_mpi_release(u); 171 return ret; 172} 173 174static int qcrypto_gcrypt_parse_rsa_public_key(QCryptoGcryptRSA *rsa, 175 const uint8_t *key, 176 size_t keylen, 177 Error **errp) 178{ 179 180 g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse( 181 QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC, key, keylen, errp); 182 gcry_mpi_t n = NULL, e = NULL; 183 int ret = -1; 184 gcry_error_t err; 185 186 if (!rsa_key) { 187 return ret; 188 } 189 190 err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD, 191 rsa_key->n.data, rsa_key->n.len, NULL); 192 if (gcry_err_code(err) != 0) { 193 error_setg(errp, "Failed to parse RSA parameter n: %s/%s", 194 gcry_strsource(err), gcry_strerror(err)); 195 goto cleanup; 196 } 197 198 err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD, 199 rsa_key->e.data, rsa_key->e.len, NULL); 200 if (gcry_err_code(err) != 0) { 201 error_setg(errp, "Failed to parse RSA parameter e: %s/%s", 202 gcry_strsource(err), gcry_strerror(err)); 203 goto cleanup; 204 } 205 206 err = gcry_sexp_build(&rsa->key, NULL, 207 "(public-key (rsa (n %m) (e %m)))", n, e); 208 if (gcry_err_code(err) != 0) { 209 error_setg(errp, "Failed to build RSA public key: %s/%s", 210 gcry_strsource(err), gcry_strerror(err)); 211 goto cleanup; 212 } 213 qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n); 214 ret = 0; 215 216cleanup: 217 gcry_mpi_release(n); 218 gcry_mpi_release(e); 219 return ret; 220} 221 222static int qcrypto_gcrypt_rsa_encrypt(QCryptoAkCipher *akcipher, 223 const void *in, size_t in_len, 224 void *out, size_t out_len, 225 Error **errp) 226{ 227 QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; 228 int ret = -1; 229 gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL; 230 gcry_sexp_t cipher_sexp_item = NULL; 231 gcry_mpi_t cipher_mpi = NULL; 232 const char *result; 233 gcry_error_t err; 234 size_t actual_len; 235 236 if (in_len > akcipher->max_plaintext_len) { 237 error_setg(errp, "Plaintext length is greater than key size: %d", 238 akcipher->max_plaintext_len); 239 return ret; 240 } 241 242 err = gcry_sexp_build(&data_sexp, NULL, 243 "(data (flags %s) (value %b))", 244 QCryptoRSAPaddingAlgo_str(rsa->padding_alg), 245 in_len, in); 246 if (gcry_err_code(err) != 0) { 247 error_setg(errp, "Failed to build plaintext: %s/%s", 248 gcry_strsource(err), gcry_strerror(err)); 249 goto cleanup; 250 } 251 252 err = gcry_pk_encrypt(&cipher_sexp, data_sexp, rsa->key); 253 if (gcry_err_code(err) != 0) { 254 error_setg(errp, "Failed to encrypt: %s/%s", 255 gcry_strsource(err), gcry_strerror(err)); 256 goto cleanup; 257 } 258 259 /* S-expression of cipher: (enc-val (rsa (a a-mpi))) */ 260 cipher_sexp_item = gcry_sexp_find_token(cipher_sexp, "a", 0); 261 if (!cipher_sexp_item || gcry_sexp_length(cipher_sexp_item) != 2) { 262 error_setg(errp, "Invalid ciphertext result"); 263 goto cleanup; 264 } 265 266 if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALGO_RAW) { 267 cipher_mpi = gcry_sexp_nth_mpi(cipher_sexp_item, 1, GCRYMPI_FMT_USG); 268 if (!cipher_mpi) { 269 error_setg(errp, "Invalid ciphertext result"); 270 goto cleanup; 271 } 272 err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len, 273 &actual_len, cipher_mpi); 274 if (gcry_err_code(err) != 0) { 275 error_setg(errp, "Failed to print MPI: %s/%s", 276 gcry_strsource(err), gcry_strerror(err)); 277 goto cleanup; 278 } 279 280 if (actual_len > out_len) { 281 error_setg(errp, "Ciphertext buffer length is too small"); 282 goto cleanup; 283 } 284 285 /* We always padding leading-zeros for RSA-RAW */ 286 if (actual_len < out_len) { 287 memmove((uint8_t *)out + (out_len - actual_len), out, actual_len); 288 memset(out, 0, out_len - actual_len); 289 } 290 ret = out_len; 291 292 } else { 293 result = gcry_sexp_nth_data(cipher_sexp_item, 1, &actual_len); 294 if (!result) { 295 error_setg(errp, "Invalid ciphertext result"); 296 goto cleanup; 297 } 298 if (actual_len > out_len) { 299 error_setg(errp, "Ciphertext buffer length is too small"); 300 goto cleanup; 301 } 302 memcpy(out, result, actual_len); 303 ret = actual_len; 304 } 305 306cleanup: 307 gcry_sexp_release(data_sexp); 308 gcry_sexp_release(cipher_sexp); 309 gcry_sexp_release(cipher_sexp_item); 310 gcry_mpi_release(cipher_mpi); 311 return ret; 312} 313 314static int qcrypto_gcrypt_rsa_decrypt(QCryptoAkCipher *akcipher, 315 const void *in, size_t in_len, 316 void *out, size_t out_len, 317 Error **errp) 318{ 319 QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; 320 int ret = -1; 321 gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL; 322 gcry_mpi_t data_mpi = NULL; 323 gcry_error_t err; 324 size_t actual_len; 325 const char *result; 326 327 if (in_len > akcipher->max_ciphertext_len) { 328 error_setg(errp, "Ciphertext length is greater than key size: %d", 329 akcipher->max_ciphertext_len); 330 return ret; 331 } 332 333 err = gcry_sexp_build(&cipher_sexp, NULL, 334 "(enc-val (flags %s) (rsa (a %b) ))", 335 QCryptoRSAPaddingAlgo_str(rsa->padding_alg), 336 in_len, in); 337 if (gcry_err_code(err) != 0) { 338 error_setg(errp, "Failed to build ciphertext: %s/%s", 339 gcry_strsource(err), gcry_strerror(err)); 340 goto cleanup; 341 } 342 343 err = gcry_pk_decrypt(&data_sexp, cipher_sexp, rsa->key); 344 if (gcry_err_code(err) != 0) { 345 error_setg(errp, "Failed to decrypt: %s/%s", 346 gcry_strsource(err), gcry_strerror(err)); 347 goto cleanup; 348 } 349 350 /* S-expression of plaintext: (value plaintext) */ 351 if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALGO_RAW) { 352 data_mpi = gcry_sexp_nth_mpi(data_sexp, 1, GCRYMPI_FMT_USG); 353 if (!data_mpi) { 354 error_setg(errp, "Invalid plaintext result"); 355 goto cleanup; 356 } 357 err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len, 358 &actual_len, data_mpi); 359 if (gcry_err_code(err) != 0) { 360 error_setg(errp, "Failed to print MPI: %s/%s", 361 gcry_strsource(err), gcry_strerror(err)); 362 goto cleanup; 363 } 364 if (actual_len > out_len) { 365 error_setg(errp, "Plaintext buffer length is too small"); 366 goto cleanup; 367 } 368 /* We always padding leading-zeros for RSA-RAW */ 369 if (actual_len < out_len) { 370 memmove((uint8_t *)out + (out_len - actual_len), out, actual_len); 371 memset(out, 0, out_len - actual_len); 372 } 373 ret = out_len; 374 } else { 375 result = gcry_sexp_nth_data(data_sexp, 1, &actual_len); 376 if (!result) { 377 error_setg(errp, "Invalid plaintext result"); 378 goto cleanup; 379 } 380 if (actual_len > out_len) { 381 error_setg(errp, "Plaintext buffer length is too small"); 382 goto cleanup; 383 } 384 memcpy(out, result, actual_len); 385 ret = actual_len; 386 } 387 388cleanup: 389 gcry_sexp_release(cipher_sexp); 390 gcry_sexp_release(data_sexp); 391 gcry_mpi_release(data_mpi); 392 return ret; 393} 394 395static int qcrypto_gcrypt_rsa_sign(QCryptoAkCipher *akcipher, 396 const void *in, size_t in_len, 397 void *out, size_t out_len, Error **errp) 398{ 399 QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; 400 int ret = -1; 401 gcry_sexp_t dgst_sexp = NULL, sig_sexp = NULL; 402 gcry_sexp_t sig_sexp_item = NULL; 403 const char *result; 404 gcry_error_t err; 405 size_t actual_len; 406 407 if (in_len > akcipher->max_dgst_len) { 408 error_setg(errp, "Data length is greater than key size: %d", 409 akcipher->max_dgst_len); 410 return ret; 411 } 412 413 if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALGO_PKCS1) { 414 error_setg(errp, "Invalid padding %u", rsa->padding_alg); 415 return ret; 416 } 417 418 err = gcry_sexp_build(&dgst_sexp, NULL, 419 "(data (flags pkcs1) (hash %s %b))", 420 QCryptoHashAlgo_str(rsa->hash_alg), 421 in_len, in); 422 if (gcry_err_code(err) != 0) { 423 error_setg(errp, "Failed to build dgst: %s/%s", 424 gcry_strsource(err), gcry_strerror(err)); 425 goto cleanup; 426 } 427 428 err = gcry_pk_sign(&sig_sexp, dgst_sexp, rsa->key); 429 if (gcry_err_code(err) != 0) { 430 error_setg(errp, "Failed to make signature: %s/%s", 431 gcry_strsource(err), gcry_strerror(err)); 432 goto cleanup; 433 } 434 435 /* S-expression of signature: (sig-val (rsa (s s-mpi))) */ 436 sig_sexp_item = gcry_sexp_find_token(sig_sexp, "s", 0); 437 if (!sig_sexp_item || gcry_sexp_length(sig_sexp_item) != 2) { 438 error_setg(errp, "Invalid signature result"); 439 goto cleanup; 440 } 441 442 result = gcry_sexp_nth_data(sig_sexp_item, 1, &actual_len); 443 if (!result) { 444 error_setg(errp, "Invalid signature result"); 445 goto cleanup; 446 } 447 448 if (actual_len > out_len) { 449 error_setg(errp, "Signature buffer length is too small"); 450 goto cleanup; 451 } 452 memcpy(out, result, actual_len); 453 ret = actual_len; 454 455cleanup: 456 gcry_sexp_release(dgst_sexp); 457 gcry_sexp_release(sig_sexp); 458 gcry_sexp_release(sig_sexp_item); 459 460 return ret; 461} 462 463static int qcrypto_gcrypt_rsa_verify(QCryptoAkCipher *akcipher, 464 const void *in, size_t in_len, 465 const void *in2, size_t in2_len, 466 Error **errp) 467{ 468 QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher; 469 int ret = -1; 470 gcry_sexp_t sig_sexp = NULL, dgst_sexp = NULL; 471 gcry_error_t err; 472 473 if (in_len > akcipher->max_signature_len) { 474 error_setg(errp, "Signature length is greater than key size: %d", 475 akcipher->max_signature_len); 476 return ret; 477 } 478 479 if (in2_len > akcipher->max_dgst_len) { 480 error_setg(errp, "Data length is greater than key size: %d", 481 akcipher->max_dgst_len); 482 return ret; 483 } 484 485 if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALGO_PKCS1) { 486 error_setg(errp, "Invalid padding %u", rsa->padding_alg); 487 return ret; 488 } 489 490 err = gcry_sexp_build(&sig_sexp, NULL, 491 "(sig-val (rsa (s %b)))", in_len, in); 492 if (gcry_err_code(err) != 0) { 493 error_setg(errp, "Failed to build signature: %s/%s", 494 gcry_strsource(err), gcry_strerror(err)); 495 goto cleanup; 496 } 497 498 err = gcry_sexp_build(&dgst_sexp, NULL, 499 "(data (flags pkcs1) (hash %s %b))", 500 QCryptoHashAlgo_str(rsa->hash_alg), 501 in2_len, in2); 502 if (gcry_err_code(err) != 0) { 503 error_setg(errp, "Failed to build dgst: %s/%s", 504 gcry_strsource(err), gcry_strerror(err)); 505 goto cleanup; 506 } 507 508 err = gcry_pk_verify(sig_sexp, dgst_sexp, rsa->key); 509 if (gcry_err_code(err) != 0) { 510 error_setg(errp, "Failed to verify signature: %s/%s", 511 gcry_strsource(err), gcry_strerror(err)); 512 goto cleanup; 513 } 514 ret = 0; 515 516cleanup: 517 gcry_sexp_release(dgst_sexp); 518 gcry_sexp_release(sig_sexp); 519 520 return ret; 521} 522 523QCryptoAkCipherDriver gcrypt_rsa = { 524 .encrypt = qcrypto_gcrypt_rsa_encrypt, 525 .decrypt = qcrypto_gcrypt_rsa_decrypt, 526 .sign = qcrypto_gcrypt_rsa_sign, 527 .verify = qcrypto_gcrypt_rsa_verify, 528 .free = qcrypto_gcrypt_rsa_free, 529}; 530 531static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new( 532 const QCryptoAkCipherOptionsRSA *opt, 533 QCryptoAkCipherKeyType type, 534 const uint8_t *key, size_t keylen, 535 Error **errp) 536{ 537 QCryptoGcryptRSA *rsa = g_new0(QCryptoGcryptRSA, 1); 538 rsa->padding_alg = opt->padding_alg; 539 rsa->hash_alg = opt->hash_alg; 540 rsa->akcipher.driver = &gcrypt_rsa; 541 542 switch (type) { 543 case QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE: 544 if (qcrypto_gcrypt_parse_rsa_private_key(rsa, key, keylen, errp) != 0) { 545 goto error; 546 } 547 break; 548 549 case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC: 550 if (qcrypto_gcrypt_parse_rsa_public_key(rsa, key, keylen, errp) != 0) { 551 goto error; 552 } 553 break; 554 555 default: 556 error_setg(errp, "Unknown akcipher key type %d", type); 557 goto error; 558 } 559 560 return rsa; 561 562error: 563 qcrypto_gcrypt_rsa_free((QCryptoAkCipher *)rsa); 564 return NULL; 565} 566 567 568bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) 569{ 570 switch (opts->alg) { 571 case QCRYPTO_AK_CIPHER_ALGO_RSA: 572 switch (opts->u.rsa.padding_alg) { 573 case QCRYPTO_RSA_PADDING_ALGO_RAW: 574 return true; 575 576 case QCRYPTO_RSA_PADDING_ALGO_PKCS1: 577 switch (opts->u.rsa.hash_alg) { 578 case QCRYPTO_HASH_ALGO_MD5: 579 case QCRYPTO_HASH_ALGO_SHA1: 580 case QCRYPTO_HASH_ALGO_SHA256: 581 case QCRYPTO_HASH_ALGO_SHA512: 582 return true; 583 584 default: 585 return false; 586 } 587 588 default: 589 return false; 590 } 591 592 default: 593 return true; 594 } 595} 596