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 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,
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>
40 #include <gnutls_pk.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 *);
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;
61 if (_gnutls_mpi_scan_nz (&data, plaintext->data, plaintext->size) != 0)
64 return GNUTLS_E_MPI_SCAN_FAILED;
67 /* make a sexp from pkey */
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]);
79 ret = GNUTLS_E_INTERNAL_ERROR;
86 ret = GNUTLS_E_INTERNAL_ERROR;
90 /* put the data into a simple list */
91 if (gcry_sexp_build (&s_data, NULL, "%m", data))
94 ret = GNUTLS_E_MEMORY_ERROR;
98 /* pass it to libgcrypt */
99 rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
103 ret = GNUTLS_E_PK_ENCRYPTION_FAILED;
107 list = gcry_sexp_find_token (s_ciph, "a", 0);
111 ret = GNUTLS_E_INTERNAL_ERROR;
115 res = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
116 gcry_sexp_release (list);
120 ret = GNUTLS_E_INTERNAL_ERROR;
124 ret = _gnutls_mpi_dprint_size (res, ciphertext, plaintext->size);
125 _gnutls_mpi_release (&res);
135 _gnutls_mpi_release (&data);
137 gcry_sexp_release (s_ciph);
139 gcry_sexp_release (s_data);
141 gcry_sexp_release (s_pkey);
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;
157 if (_gnutls_mpi_scan_nz (&data, ciphertext->data, ciphertext->size) != 0)
160 return GNUTLS_E_MPI_SCAN_FAILED;
163 /* make a sexp from pkey */
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]);
177 ret = GNUTLS_E_INTERNAL_ERROR;
184 ret = GNUTLS_E_INTERNAL_ERROR;
188 /* put the data into a simple list */
189 if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data))
192 ret = GNUTLS_E_INTERNAL_ERROR;
196 /* pass it to libgcrypt */
197 rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey);
201 ret = GNUTLS_E_PK_DECRYPTION_FAILED;
205 res = gcry_sexp_nth_mpi (s_plain, 0, GCRYMPI_FMT_USG);
209 ret = GNUTLS_E_INTERNAL_ERROR;
213 ret = _gnutls_mpi_dprint_size (res, plaintext, ciphertext->size);
214 _gnutls_mpi_release (&res);
224 _gnutls_mpi_release (&data);
226 gcry_sexp_release (s_plain);
228 gcry_sexp_release (s_data);
230 gcry_sexp_release (s_pkey);
237 /* in case of DSA puts into data, r,s
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;
248 bigint_t res[2] = { NULL, NULL };
250 if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
253 return GNUTLS_E_MPI_SCAN_FAILED;
256 /* make a sexp from pkey */
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]);
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]);
287 ret = GNUTLS_E_INTERNAL_ERROR;
294 ret = GNUTLS_E_INTERNAL_ERROR;
298 /* put the data into a simple list */
299 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
302 ret = GNUTLS_E_INTERNAL_ERROR;
307 /* pass it to libgcrypt */
308 rc = gcry_pk_sign (&s_sig, s_hash, s_key);
312 ret = GNUTLS_E_PK_SIGN_FAILED;
316 ret = GNUTLS_E_INTERNAL_ERROR;
322 list = gcry_sexp_find_token (s_sig, "r", 0);
326 ret = GNUTLS_E_INTERNAL_ERROR;
330 res[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
331 gcry_sexp_release (list);
333 list = gcry_sexp_find_token (s_sig, "s", 0);
337 ret = GNUTLS_E_INTERNAL_ERROR;
341 res[1] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
342 gcry_sexp_release (list);
344 ret = _gnutls_encode_ber_rs (signature, res[0], res[1]);
355 list = gcry_sexp_find_token (s_sig, "s", 0);
359 ret = GNUTLS_E_INTERNAL_ERROR;
363 res[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
364 gcry_sexp_release (list);
366 ret = _gnutls_mpi_dprint (res[0], signature);
377 ret = GNUTLS_E_INTERNAL_ERROR;
384 _gnutls_mpi_release (&hash);
386 _gnutls_mpi_release (&res[0]);
388 _gnutls_mpi_release (&res[1]);
390 gcry_sexp_release (s_sig);
392 gcry_sexp_release (s_hash);
394 gcry_sexp_release (s_key);
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;
408 bigint_t tmp[2] = { NULL, NULL };
410 if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
413 return GNUTLS_E_MPI_SCAN_FAILED;
416 /* make a sexp from pkey */
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]);
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]);
435 ret = GNUTLS_E_INTERNAL_ERROR;
442 ret = GNUTLS_E_INTERNAL_ERROR;
446 /* put the data into a simple list */
447 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
450 ret = GNUTLS_E_INTERNAL_ERROR;
457 ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]);
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]);
470 ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size);
476 rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", tmp[0]);
477 _gnutls_mpi_release (&tmp[0]);
482 ret = GNUTLS_E_INTERNAL_ERROR;
489 ret = GNUTLS_E_INTERNAL_ERROR;
493 rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
498 ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
505 _gnutls_mpi_release (&hash);
507 gcry_sexp_release (s_sig);
509 gcry_sexp_release (s_hash);
511 gcry_sexp_release (s_pkey);
517 _dsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
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)
527 return GNUTLS_E_INVALID_REQUEST;
533 return GNUTLS_E_INVALID_REQUEST;
536 ret = gcry_sexp_build (&parms, NULL, "(genkey(dsa(nbits %d)))", bits);
540 return GNUTLS_E_INTERNAL_ERROR;
543 /* generate the DSA key
545 ret = gcry_pk_genkey (&key, parms);
546 gcry_sexp_release (parms);
551 return GNUTLS_E_INTERNAL_ERROR;
554 list = gcry_sexp_find_token (key, "p", 0);
558 gcry_sexp_release (key);
559 return GNUTLS_E_INTERNAL_ERROR;
562 resarr[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
563 gcry_sexp_release (list);
565 list = gcry_sexp_find_token (key, "q", 0);
569 gcry_sexp_release (key);
570 return GNUTLS_E_INTERNAL_ERROR;
573 resarr[1] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
574 gcry_sexp_release (list);
576 list = gcry_sexp_find_token (key, "g", 0);
580 gcry_sexp_release (key);
581 return GNUTLS_E_INTERNAL_ERROR;
584 resarr[2] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
585 gcry_sexp_release (list);
587 list = gcry_sexp_find_token (key, "y", 0);
591 gcry_sexp_release (key);
592 return GNUTLS_E_INTERNAL_ERROR;
595 resarr[3] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
596 gcry_sexp_release (list);
599 list = gcry_sexp_find_token (key, "x", 0);
603 gcry_sexp_release (key);
604 return GNUTLS_E_INTERNAL_ERROR;
607 resarr[4] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
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]);
625 _rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
629 gcry_sexp_t parms, key, list;
631 if (*resarr_len < RSA_PRIVATE_PARAMS)
634 return GNUTLS_E_INTERNAL_ERROR;
637 ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits);
641 return GNUTLS_E_INTERNAL_ERROR;
644 /* generate the RSA key */
645 ret = gcry_pk_genkey (&key, parms);
646 gcry_sexp_release (parms);
651 return GNUTLS_E_INTERNAL_ERROR;
654 list = gcry_sexp_find_token (key, "n", 0);
658 gcry_sexp_release (key);
659 return GNUTLS_E_INTERNAL_ERROR;
662 resarr[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
663 gcry_sexp_release (list);
665 list = gcry_sexp_find_token (key, "e", 0);
669 gcry_sexp_release (key);
670 return GNUTLS_E_INTERNAL_ERROR;
673 resarr[1] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
674 gcry_sexp_release (list);
676 list = gcry_sexp_find_token (key, "d", 0);
680 gcry_sexp_release (key);
681 return GNUTLS_E_INTERNAL_ERROR;
684 resarr[2] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
685 gcry_sexp_release (list);
687 list = gcry_sexp_find_token (key, "p", 0);
691 gcry_sexp_release (key);
692 return GNUTLS_E_INTERNAL_ERROR;
695 resarr[3] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
696 gcry_sexp_release (list);
699 list = gcry_sexp_find_token (key, "q", 0);
703 gcry_sexp_release (key);
704 return GNUTLS_E_INTERNAL_ERROR;
707 resarr[4] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
708 gcry_sexp_release (list);
711 list = gcry_sexp_find_token (key, "u", 0);
715 gcry_sexp_release (key);
716 return GNUTLS_E_INTERNAL_ERROR;
719 resarr[5] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
721 gcry_sexp_release (list);
722 gcry_sexp_release (key);
724 _gnutls_mpi_log ("n: ", resarr[0]);
725 _gnutls_mpi_log ("e: ", resarr[1]);
726 _gnutls_mpi_log ("d: ", resarr[2]);
727 _gnutls_mpi_log ("p: ", resarr[3]);
728 _gnutls_mpi_log ("q: ", resarr[4]);
729 _gnutls_mpi_log ("u: ", resarr[5]);
731 /* generate e1 and e2 */
735 ret = _gnutls_calc_rsa_exp (resarr, 2 + *resarr_len);
739 ret = GNUTLS_E_MEMORY_ERROR;
748 for (i = 0; i < *resarr_len; i++)
749 _gnutls_mpi_release (&resarr[i]);
756 wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo,
757 unsigned int level /*bits */ ,
758 gnutls_pk_params_st * params)
765 params->params_nr = DSA_PRIVATE_PARAMS;
766 if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
769 return GNUTLS_E_INTERNAL_ERROR;
771 return _dsa_generate_params (params->params, ¶ms->params_nr, level);
774 params->params_nr = RSA_PRIVATE_PARAMS;
775 if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
778 return GNUTLS_E_INTERNAL_ERROR;
780 return _rsa_generate_params (params->params, ¶ms->params_nr, level);
784 return GNUTLS_E_INVALID_REQUEST;
790 wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo,
791 gnutls_direction_t direction,
792 gnutls_pk_params_st * params)
796 /* only for RSA we invert the coefficient --pgp type */
798 if (algo != GNUTLS_PK_RSA)
801 if (params->params[5] == NULL)
803 _gnutls_mpi_new (_gnutls_mpi_get_nbits (params->params[0]));
805 if (params->params[5] == NULL)
808 return GNUTLS_E_MEMORY_ERROR;
812 if (direction == GNUTLS_IMPORT)
814 /* calculate exp1 [6] and exp2 [7] */
815 _gnutls_mpi_release (¶ms->params[6]);
816 _gnutls_mpi_release (¶ms->params[7]);
817 result = _gnutls_calc_rsa_exp (params->params, RSA_PRIVATE_PARAMS);
825 gcry_mpi_invm (params->params[5], params->params[3],
828 params->params_nr = RSA_PRIVATE_PARAMS;
830 else if (direction == GNUTLS_EXPORT)
832 gcry_mpi_invm (params->params[5], params->params[4], params->params[3]);
836 return GNUTLS_E_INVALID_REQUEST;
842 int crypto_pk_prio = INT_MAX;
844 gnutls_crypto_pk_st _gnutls_pk_ops = {
845 .encrypt = _wrap_gcry_pk_encrypt,
846 .decrypt = _wrap_gcry_pk_decrypt,
847 .sign = _wrap_gcry_pk_sign,
848 .verify = _wrap_gcry_pk_verify,
849 .generate = wrap_gcry_pk_generate_params,
850 .pk_fixup_private_params = wrap_gcry_pk_fixup,