]> git.proxmox.com Git - mirror_qemu.git/blame - crypto/akcipher-gcrypt.c.inc
Merge tag 'migration-20231020-pull-request' of https://gitlab.com/juan.quintela/qemu...
[mirror_qemu.git] / crypto / akcipher-gcrypt.c.inc
CommitLineData
e09d1c27
LH
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 QCryptoRSAPaddingAlgorithm padding_alg;
36 QCryptoHashAlgorithm 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_AKCIPHER_ALG_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_AKCIPHER_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_AKCIPHER_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 QCryptoRSAPaddingAlgorithm_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_ALG_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 QCryptoRSAPaddingAlgorithm_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_ALG_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_ALG_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 QCryptoHashAlgorithm_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_ALG_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 QCryptoHashAlgorithm_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_AKCIPHER_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_AKCIPHER_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_AKCIPHER_ALG_RSA:
572 switch (opts->u.rsa.padding_alg) {
573 case QCRYPTO_RSA_PADDING_ALG_RAW:
574 return true;
575
576 case QCRYPTO_RSA_PADDING_ALG_PKCS1:
577 switch (opts->u.rsa.hash_alg) {
578 case QCRYPTO_HASH_ALG_MD5:
579 case QCRYPTO_HASH_ALG_SHA1:
580 case QCRYPTO_HASH_ALG_SHA256:
581 case QCRYPTO_HASH_ALG_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}