Sync with TP.
[gnutls.git] / lib / pk-libgcrypt.c
blob89844b8426e2cbb8c010c3e7914263e45bfb2790
1 /*
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010
3 * Free Software Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GNUTLS.
9 * The GNUTLS library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * 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.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 /* This file contains the functions needed for RSA/DSA public key
27 * encryption and signatures.
30 #include <gnutls_int.h>
31 #include <gnutls_mpi.h>
32 #include <gnutls_pk.h>
33 #include <gnutls_errors.h>
34 #include <gnutls_datum.h>
35 #include <gnutls_global.h>
36 #include <gnutls_num.h>
37 #include <x509/x509_int.h>
38 #include <x509/common.h>
39 #include <random.h>
40 #include <gnutls_pk.h>
41 #include <gcrypt.h>
43 /* this is based on code from old versions of libgcrypt (centuries ago)
46 int (*generate) (gnutls_pk_algorithm_t, unsigned int level /*bits */ ,
47 gnutls_pk_params_st *);
49 static int
50 _wrap_gcry_pk_encrypt (gnutls_pk_algorithm_t algo,
51 gnutls_datum_t * ciphertext,
52 const gnutls_datum_t * plaintext,
53 const gnutls_pk_params_st * pk_params)
55 gcry_sexp_t s_ciph = NULL, s_data = NULL, s_pkey = NULL;
56 int rc = -1;
57 int ret;
58 bigint_t data, res;
59 gcry_sexp_t list;
61 if (_gnutls_mpi_scan_nz (&data, plaintext->data, plaintext->size) != 0)
63 gnutls_assert ();
64 return GNUTLS_E_MPI_SCAN_FAILED;
67 /* make a sexp from pkey */
68 switch (algo)
70 case GNUTLS_PK_RSA:
71 if (pk_params->params_nr >= 2)
72 rc = gcry_sexp_build (&s_pkey, NULL,
73 "(public-key(rsa(n%m)(e%m)))",
74 pk_params->params[0], pk_params->params[1]);
75 break;
77 default:
78 gnutls_assert ();
79 ret = GNUTLS_E_INTERNAL_ERROR;
80 goto cleanup;
83 if (rc != 0)
85 gnutls_assert ();
86 ret = GNUTLS_E_INTERNAL_ERROR;
87 goto cleanup;
90 /* put the data into a simple list */
91 if (gcry_sexp_build (&s_data, NULL, "%m", data))
93 gnutls_assert ();
94 ret = GNUTLS_E_MEMORY_ERROR;
95 goto cleanup;
98 /* pass it to libgcrypt */
99 rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
100 if (rc != 0)
102 gnutls_assert ();
103 ret = GNUTLS_E_PK_ENCRYPTION_FAILED;
104 goto cleanup;
107 list = gcry_sexp_find_token (s_ciph, "a", 0);
108 if (list == NULL)
110 gnutls_assert ();
111 ret = GNUTLS_E_INTERNAL_ERROR;
112 goto cleanup;
115 res = gcry_sexp_nth_mpi (list, 1, 0);
116 gcry_sexp_release (list);
117 if (res == NULL)
119 gnutls_assert ();
120 ret = GNUTLS_E_INTERNAL_ERROR;
121 goto cleanup;
124 ret = _gnutls_mpi_dprint_size (res, ciphertext, plaintext->size);
125 _gnutls_mpi_release (&res);
126 if (ret < 0)
128 gnutls_assert ();
129 goto cleanup;
132 ret = 0;
134 cleanup:
135 _gnutls_mpi_release (&data);
136 if (s_ciph)
137 gcry_sexp_release (s_ciph);
138 if (s_data)
139 gcry_sexp_release (s_data);
140 if (s_pkey)
141 gcry_sexp_release (s_pkey);
143 return ret;
146 static int
147 _wrap_gcry_pk_decrypt (gnutls_pk_algorithm_t algo,
148 gnutls_datum_t * plaintext,
149 const gnutls_datum_t * ciphertext,
150 const gnutls_pk_params_st * pk_params)
152 gcry_sexp_t s_plain = NULL, s_data = NULL, s_pkey = NULL;
153 int rc = -1;
154 int ret;
155 bigint_t data, res;
157 if (_gnutls_mpi_scan_nz (&data, ciphertext->data, ciphertext->size) != 0)
159 gnutls_assert ();
160 return GNUTLS_E_MPI_SCAN_FAILED;
163 /* make a sexp from pkey */
164 switch (algo)
166 case GNUTLS_PK_RSA:
167 if (pk_params->params_nr >= 6)
168 rc = gcry_sexp_build (&s_pkey, NULL,
169 "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
170 pk_params->params[0], pk_params->params[1],
171 pk_params->params[2], pk_params->params[3],
172 pk_params->params[4], pk_params->params[5]);
173 break;
175 default:
176 gnutls_assert ();
177 ret = GNUTLS_E_INTERNAL_ERROR;
178 goto cleanup;
181 if (rc != 0)
183 gnutls_assert ();
184 ret = GNUTLS_E_INTERNAL_ERROR;
185 goto cleanup;
188 /* put the data into a simple list */
189 if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data))
191 gnutls_assert ();
192 ret = GNUTLS_E_INTERNAL_ERROR;
193 goto cleanup;
196 /* pass it to libgcrypt */
197 rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey);
198 if (rc != 0)
200 gnutls_assert ();
201 ret = GNUTLS_E_PK_DECRYPTION_FAILED;
202 goto cleanup;
205 res = gcry_sexp_nth_mpi (s_plain, 0, 0);
206 if (res == NULL)
208 gnutls_assert ();
209 ret = GNUTLS_E_INTERNAL_ERROR;
210 goto cleanup;
213 ret = _gnutls_mpi_dprint_size (res, plaintext, ciphertext->size);
214 _gnutls_mpi_release (&res);
215 if (ret < 0)
217 gnutls_assert ();
218 goto cleanup;
221 ret = 0;
223 cleanup:
224 _gnutls_mpi_release (&data);
225 if (s_plain)
226 gcry_sexp_release (s_plain);
227 if (s_data)
228 gcry_sexp_release (s_data);
229 if (s_pkey)
230 gcry_sexp_release (s_pkey);
232 return ret;
237 /* in case of DSA puts into data, r,s
239 static int
240 _wrap_gcry_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature,
241 const gnutls_datum_t * vdata,
242 const gnutls_pk_params_st * pk_params)
244 gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
245 gcry_sexp_t list = NULL;
246 int rc = -1, ret;
247 bigint_t hash;
248 bigint_t res[2] = { NULL, NULL };
250 if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
252 gnutls_assert ();
253 return GNUTLS_E_MPI_SCAN_FAILED;
256 /* make a sexp from pkey */
257 switch (algo)
259 case GNUTLS_PK_DSA:
260 if (pk_params->params_nr >= 5)
261 rc = gcry_sexp_build (&s_key, NULL,
262 "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
263 pk_params->params[0], pk_params->params[1],
264 pk_params->params[2], pk_params->params[3],
265 pk_params->params[4]);
266 else
268 gnutls_assert ();
271 break;
272 case GNUTLS_PK_RSA:
273 if (pk_params->params_nr >= 6)
274 rc = gcry_sexp_build (&s_key, NULL,
275 "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
276 pk_params->params[0], pk_params->params[1],
277 pk_params->params[2], pk_params->params[3],
278 pk_params->params[4], pk_params->params[5]);
279 else
281 gnutls_assert ();
283 break;
285 default:
286 gnutls_assert ();
287 ret = GNUTLS_E_INTERNAL_ERROR;
288 goto cleanup;
291 if (rc != 0)
293 gnutls_assert ();
294 ret = GNUTLS_E_INTERNAL_ERROR;
295 goto cleanup;
298 /* put the data into a simple list */
299 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
301 gnutls_assert ();
302 ret = GNUTLS_E_INTERNAL_ERROR;
303 goto cleanup;
307 /* pass it to libgcrypt */
308 rc = gcry_pk_sign (&s_sig, s_hash, s_key);
309 if (rc != 0)
311 gnutls_assert ();
312 ret = GNUTLS_E_PK_SIGN_FAILED;
313 goto cleanup;
316 ret = GNUTLS_E_INTERNAL_ERROR;
318 switch (algo)
320 case GNUTLS_PK_DSA:
322 list = gcry_sexp_find_token (s_sig, "r", 0);
323 if (list == NULL)
325 gnutls_assert ();
326 ret = GNUTLS_E_INTERNAL_ERROR;
327 goto cleanup;
330 res[0] = gcry_sexp_nth_mpi (list, 1, 0);
331 gcry_sexp_release (list);
333 list = gcry_sexp_find_token (s_sig, "s", 0);
334 if (list == NULL)
336 gnutls_assert ();
337 ret = GNUTLS_E_INTERNAL_ERROR;
338 goto cleanup;
341 res[1] = gcry_sexp_nth_mpi (list, 1, 0);
342 gcry_sexp_release (list);
344 ret = _gnutls_encode_ber_rs (signature, res[0], res[1]);
345 if (ret < 0)
347 gnutls_assert ();
348 goto cleanup;
351 break;
353 case GNUTLS_PK_RSA:
355 list = gcry_sexp_find_token (s_sig, "s", 0);
356 if (list == NULL)
358 gnutls_assert ();
359 ret = GNUTLS_E_INTERNAL_ERROR;
360 goto cleanup;
363 res[0] = gcry_sexp_nth_mpi (list, 1, 0);
364 gcry_sexp_release (list);
366 ret = _gnutls_mpi_dprint (res[0], signature);
367 if (ret < 0)
369 gnutls_assert ();
370 goto cleanup;
373 break;
375 default:
376 gnutls_assert ();
377 ret = GNUTLS_E_INTERNAL_ERROR;
378 goto cleanup;
381 ret = 0;
383 cleanup:
384 _gnutls_mpi_release (&hash);
385 if (res[0])
386 _gnutls_mpi_release (&res[0]);
387 if (res[1])
388 _gnutls_mpi_release (&res[1]);
389 if (s_sig)
390 gcry_sexp_release (s_sig);
391 if (s_hash)
392 gcry_sexp_release (s_hash);
393 if (s_key)
394 gcry_sexp_release (s_key);
396 return ret;
399 static int
400 _wrap_gcry_pk_verify (gnutls_pk_algorithm_t algo,
401 const gnutls_datum_t * vdata,
402 const gnutls_datum_t * signature,
403 const gnutls_pk_params_st * pk_params)
405 gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
406 int rc = -1, ret;
407 bigint_t hash;
408 bigint_t tmp[2] = { NULL, NULL };
410 if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
412 gnutls_assert ();
413 return GNUTLS_E_MPI_SCAN_FAILED;
416 /* make a sexp from pkey */
417 switch (algo)
419 case GNUTLS_PK_DSA:
420 if (pk_params->params_nr >= 4)
421 rc = gcry_sexp_build (&s_pkey, NULL,
422 "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
423 pk_params->params[0], pk_params->params[1],
424 pk_params->params[2], pk_params->params[3]);
425 break;
426 case GNUTLS_PK_RSA:
427 if (pk_params->params_nr >= 2)
428 rc = gcry_sexp_build (&s_pkey, NULL,
429 "(public-key(rsa(n%m)(e%m)))",
430 pk_params->params[0], pk_params->params[1]);
431 break;
433 default:
434 gnutls_assert ();
435 ret = GNUTLS_E_INTERNAL_ERROR;
436 goto cleanup;
439 if (rc != 0)
441 gnutls_assert ();
442 ret = GNUTLS_E_INTERNAL_ERROR;
443 goto cleanup;
446 /* put the data into a simple list */
447 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
449 gnutls_assert ();
450 ret = GNUTLS_E_INTERNAL_ERROR;
451 goto cleanup;
454 switch (algo)
456 case GNUTLS_PK_DSA:
457 ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]);
458 if (ret < 0)
460 gnutls_assert ();
461 goto cleanup;
463 rc = gcry_sexp_build (&s_sig, NULL,
464 "(sig-val(dsa(r%m)(s%m)))", tmp[0], tmp[1]);
465 _gnutls_mpi_release (&tmp[0]);
466 _gnutls_mpi_release (&tmp[1]);
467 break;
469 case GNUTLS_PK_RSA:
470 ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size);
471 if (ret < 0)
473 gnutls_assert ();
474 goto cleanup;
476 rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", tmp[0]);
477 _gnutls_mpi_release (&tmp[0]);
478 break;
480 default:
481 gnutls_assert ();
482 ret = GNUTLS_E_INTERNAL_ERROR;
483 goto cleanup;
486 if (rc != 0)
488 gnutls_assert ();
489 ret = GNUTLS_E_INTERNAL_ERROR;
490 goto cleanup;
493 rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
495 if (rc != 0)
497 gnutls_assert ();
498 ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
499 goto cleanup;
502 ret = 0;
504 cleanup:
505 _gnutls_mpi_release (&hash);
506 if (s_sig)
507 gcry_sexp_release (s_sig);
508 if (s_hash)
509 gcry_sexp_release (s_hash);
510 if (s_pkey)
511 gcry_sexp_release (s_pkey);
513 return ret;
516 static int
517 _dsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
520 int ret;
521 gcry_sexp_t parms, key, list;
523 /* FIXME: Remove me once we depend on 1.3.1 */
524 if (bits > 1024 && gcry_check_version ("1.3.1") == NULL)
526 gnutls_assert ();
527 return GNUTLS_E_INVALID_REQUEST;
530 if (bits < 512)
532 gnutls_assert ();
533 return GNUTLS_E_INVALID_REQUEST;
536 ret = gcry_sexp_build (&parms, NULL, "(genkey(dsa(nbits %d)))", bits);
537 if (ret != 0)
539 gnutls_assert ();
540 return GNUTLS_E_INTERNAL_ERROR;
543 /* generate the DSA key
545 ret = gcry_pk_genkey (&key, parms);
546 gcry_sexp_release (parms);
548 if (ret != 0)
550 gnutls_assert ();
551 return GNUTLS_E_INTERNAL_ERROR;
554 list = gcry_sexp_find_token (key, "p", 0);
555 if (list == NULL)
557 gnutls_assert ();
558 gcry_sexp_release (key);
559 return GNUTLS_E_INTERNAL_ERROR;
562 resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
563 gcry_sexp_release (list);
565 list = gcry_sexp_find_token (key, "q", 0);
566 if (list == NULL)
568 gnutls_assert ();
569 gcry_sexp_release (key);
570 return GNUTLS_E_INTERNAL_ERROR;
573 resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
574 gcry_sexp_release (list);
576 list = gcry_sexp_find_token (key, "g", 0);
577 if (list == NULL)
579 gnutls_assert ();
580 gcry_sexp_release (key);
581 return GNUTLS_E_INTERNAL_ERROR;
584 resarr[2] = gcry_sexp_nth_mpi (list, 1, 0);
585 gcry_sexp_release (list);
587 list = gcry_sexp_find_token (key, "y", 0);
588 if (list == NULL)
590 gnutls_assert ();
591 gcry_sexp_release (key);
592 return GNUTLS_E_INTERNAL_ERROR;
595 resarr[3] = gcry_sexp_nth_mpi (list, 1, 0);
596 gcry_sexp_release (list);
599 list = gcry_sexp_find_token (key, "x", 0);
600 if (list == NULL)
602 gnutls_assert ();
603 gcry_sexp_release (key);
604 return GNUTLS_E_INTERNAL_ERROR;
607 resarr[4] = gcry_sexp_nth_mpi (list, 1, 0);
609 gcry_sexp_release (list);
610 gcry_sexp_release (key);
612 _gnutls_mpi_log ("p: ", resarr[0]);
613 _gnutls_mpi_log ("q: ", resarr[1]);
614 _gnutls_mpi_log ("g: ", resarr[2]);
615 _gnutls_mpi_log ("y: ", resarr[3]);
616 _gnutls_mpi_log ("x: ", resarr[4]);
618 *resarr_len = 5;
620 return 0;
624 static int
625 _rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
628 int ret;
629 gcry_sexp_t parms, key, list;
631 ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits);
632 if (ret != 0)
634 gnutls_assert ();
635 return GNUTLS_E_INTERNAL_ERROR;
638 /* generate the RSA key */
639 ret = gcry_pk_genkey (&key, parms);
640 gcry_sexp_release (parms);
642 if (ret != 0)
644 gnutls_assert ();
645 return GNUTLS_E_INTERNAL_ERROR;
648 list = gcry_sexp_find_token (key, "n", 0);
649 if (list == NULL)
651 gnutls_assert ();
652 gcry_sexp_release (key);
653 return GNUTLS_E_INTERNAL_ERROR;
656 resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
657 gcry_sexp_release (list);
659 list = gcry_sexp_find_token (key, "e", 0);
660 if (list == NULL)
662 gnutls_assert ();
663 gcry_sexp_release (key);
664 return GNUTLS_E_INTERNAL_ERROR;
667 resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
668 gcry_sexp_release (list);
670 list = gcry_sexp_find_token (key, "d", 0);
671 if (list == NULL)
673 gnutls_assert ();
674 gcry_sexp_release (key);
675 return GNUTLS_E_INTERNAL_ERROR;
678 resarr[2] = gcry_sexp_nth_mpi (list, 1, 0);
679 gcry_sexp_release (list);
681 list = gcry_sexp_find_token (key, "p", 0);
682 if (list == NULL)
684 gnutls_assert ();
685 gcry_sexp_release (key);
686 return GNUTLS_E_INTERNAL_ERROR;
689 resarr[3] = gcry_sexp_nth_mpi (list, 1, 0);
690 gcry_sexp_release (list);
693 list = gcry_sexp_find_token (key, "q", 0);
694 if (list == NULL)
696 gnutls_assert ();
697 gcry_sexp_release (key);
698 return GNUTLS_E_INTERNAL_ERROR;
701 resarr[4] = gcry_sexp_nth_mpi (list, 1, 0);
702 gcry_sexp_release (list);
705 list = gcry_sexp_find_token (key, "u", 0);
706 if (list == NULL)
708 gnutls_assert ();
709 gcry_sexp_release (key);
710 return GNUTLS_E_INTERNAL_ERROR;
713 resarr[5] = gcry_sexp_nth_mpi (list, 1, 0);
715 gcry_sexp_release (list);
716 gcry_sexp_release (key);
718 _gnutls_mpi_log ("n: ", resarr[0]);
719 _gnutls_mpi_log ("e: ", resarr[1]);
720 _gnutls_mpi_log ("d: ", resarr[2]);
721 _gnutls_mpi_log ("p: ", resarr[3]);
722 _gnutls_mpi_log ("q: ", resarr[4]);
723 _gnutls_mpi_log ("u: ", resarr[5]);
725 *resarr_len = 6;
727 return 0;
731 static int
732 wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo,
733 unsigned int level /*bits */ ,
734 gnutls_pk_params_st * params)
737 switch (algo)
740 case GNUTLS_PK_DSA:
741 params->params_nr = DSA_PRIVATE_PARAMS;
742 if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
744 gnutls_assert ();
745 return GNUTLS_E_INTERNAL_ERROR;
747 return _dsa_generate_params (params->params, &params->params_nr, level);
749 case GNUTLS_PK_RSA:
750 params->params_nr = RSA_PRIVATE_PARAMS;
751 if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
753 gnutls_assert ();
754 return GNUTLS_E_INTERNAL_ERROR;
756 return _rsa_generate_params (params->params, &params->params_nr, level);
758 default:
759 gnutls_assert ();
760 return GNUTLS_E_INVALID_REQUEST;
765 static int
766 wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo,
767 gnutls_direction_t direction,
768 gnutls_pk_params_st * params)
770 int ret;
772 /* only for RSA we invert the coefficient --pgp type */
774 if (algo != GNUTLS_PK_RSA)
775 return 0;
777 if (params->params[5])
778 _gnutls_mpi_release (&params->params[5]);
779 params->params[5] =
780 _gnutls_mpi_new (_gnutls_mpi_get_nbits (params->params[0]));
782 if (params->params[5] == NULL)
784 gnutls_assert ();
785 return GNUTLS_E_MEMORY_ERROR;
788 if (direction == GNUTLS_IMPORT)
789 ret =
790 gcry_mpi_invm (params->params[5], params->params[3], params->params[4]);
791 else
792 ret =
793 gcry_mpi_invm (params->params[5], params->params[4], params->params[3]);
794 if (ret == 0)
796 gnutls_assert ();
797 return GNUTLS_E_INVALID_REQUEST;
800 return 0;
803 int crypto_pk_prio = INT_MAX;
805 gnutls_crypto_pk_st _gnutls_pk_ops = {
806 .encrypt = _wrap_gcry_pk_encrypt,
807 .decrypt = _wrap_gcry_pk_decrypt,
808 .sign = _wrap_gcry_pk_sign,
809 .verify = _wrap_gcry_pk_verify,
810 .generate = wrap_gcry_pk_generate_params,
811 .pk_fixup_private_params = wrap_gcry_pk_fixup,