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
;
632 if (*resarr_len
< RSA_PRIVATE_PARAMS
)
635 return GNUTLS_E_INTERNAL_ERROR
;
638 ret
= gcry_sexp_build (&parms
, NULL
, "(genkey(rsa(nbits %d)))", bits
);
642 return GNUTLS_E_INTERNAL_ERROR
;
645 /* generate the RSA key */
646 ret
= gcry_pk_genkey (&key
, parms
);
647 gcry_sexp_release (parms
);
652 return GNUTLS_E_INTERNAL_ERROR
;
655 list
= gcry_sexp_find_token (key
, "n", 0);
659 gcry_sexp_release (key
);
660 return GNUTLS_E_INTERNAL_ERROR
;
663 resarr
[0] = gcry_sexp_nth_mpi (list
, 1, GCRYMPI_FMT_USG
);
664 gcry_sexp_release (list
);
666 list
= gcry_sexp_find_token (key
, "e", 0);
670 gcry_sexp_release (key
);
671 return GNUTLS_E_INTERNAL_ERROR
;
674 resarr
[1] = gcry_sexp_nth_mpi (list
, 1, GCRYMPI_FMT_USG
);
675 gcry_sexp_release (list
);
677 list
= gcry_sexp_find_token (key
, "d", 0);
681 gcry_sexp_release (key
);
682 return GNUTLS_E_INTERNAL_ERROR
;
685 resarr
[2] = gcry_sexp_nth_mpi (list
, 1, GCRYMPI_FMT_USG
);
686 gcry_sexp_release (list
);
688 list
= gcry_sexp_find_token (key
, "p", 0);
692 gcry_sexp_release (key
);
693 return GNUTLS_E_INTERNAL_ERROR
;
696 resarr
[3] = gcry_sexp_nth_mpi (list
, 1, GCRYMPI_FMT_USG
);
697 gcry_sexp_release (list
);
700 list
= gcry_sexp_find_token (key
, "q", 0);
704 gcry_sexp_release (key
);
705 return GNUTLS_E_INTERNAL_ERROR
;
708 resarr
[4] = gcry_sexp_nth_mpi (list
, 1, GCRYMPI_FMT_USG
);
709 gcry_sexp_release (list
);
712 list
= gcry_sexp_find_token (key
, "u", 0);
716 gcry_sexp_release (key
);
717 return GNUTLS_E_INTERNAL_ERROR
;
720 resarr
[5] = gcry_sexp_nth_mpi (list
, 1, GCRYMPI_FMT_USG
);
722 gcry_sexp_release (list
);
723 gcry_sexp_release (key
);
725 _gnutls_mpi_log ("n: ", resarr
[0]);
726 _gnutls_mpi_log ("e: ", resarr
[1]);
727 _gnutls_mpi_log ("d: ", resarr
[2]);
728 _gnutls_mpi_log ("p: ", resarr
[3]);
729 _gnutls_mpi_log ("q: ", resarr
[4]);
730 _gnutls_mpi_log ("u: ", resarr
[5]);
732 /* generate e1 and e2 */
736 tmp
= _gnutls_mpi_alloc_like (resarr
[0]);
740 ret
= GNUTLS_E_MEMORY_ERROR
;
744 ret
= _gnutls_calc_rsa_exp (resarr
, 2 + *resarr_len
);
748 ret
= GNUTLS_E_MEMORY_ERROR
;
757 for (i
= 0; i
< *resarr_len
; i
++)
758 _gnutls_mpi_release (&resarr
[i
]);
765 wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo
,
766 unsigned int level
/*bits */ ,
767 gnutls_pk_params_st
* params
)
774 params
->params_nr
= DSA_PRIVATE_PARAMS
;
775 if (params
->params_nr
> GNUTLS_MAX_PK_PARAMS
)
778 return GNUTLS_E_INTERNAL_ERROR
;
780 return _dsa_generate_params (params
->params
, ¶ms
->params_nr
, level
);
783 params
->params_nr
= RSA_PRIVATE_PARAMS
;
784 if (params
->params_nr
> GNUTLS_MAX_PK_PARAMS
)
787 return GNUTLS_E_INTERNAL_ERROR
;
789 return _rsa_generate_params (params
->params
, ¶ms
->params_nr
, level
);
793 return GNUTLS_E_INVALID_REQUEST
;
799 wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo
,
800 gnutls_direction_t direction
,
801 gnutls_pk_params_st
* params
)
805 /* only for RSA we invert the coefficient --pgp type */
807 if (algo
!= GNUTLS_PK_RSA
)
810 if (params
->params
[5] == NULL
)
812 _gnutls_mpi_new (_gnutls_mpi_get_nbits (params
->params
[0]));
814 if (params
->params
[5] == NULL
)
817 return GNUTLS_E_MEMORY_ERROR
;
821 if (direction
== GNUTLS_IMPORT
)
823 /* calculate exp1 [6] and exp2 [7] */
824 _gnutls_mpi_release (¶ms
->params
[6]);
825 _gnutls_mpi_release (¶ms
->params
[7]);
826 result
= _gnutls_calc_rsa_exp (params
->params
, RSA_PRIVATE_PARAMS
);
834 gcry_mpi_invm (params
->params
[5], params
->params
[3],
837 params
->params_nr
= RSA_PRIVATE_PARAMS
;
839 else if (direction
== GNUTLS_EXPORT
)
841 gcry_mpi_invm (params
->params
[5], params
->params
[4], params
->params
[3]);
845 return GNUTLS_E_INVALID_REQUEST
;
851 int crypto_pk_prio
= INT_MAX
;
853 gnutls_crypto_pk_st _gnutls_pk_ops
= {
854 .encrypt
= _wrap_gcry_pk_encrypt
,
855 .decrypt
= _wrap_gcry_pk_decrypt
,
856 .sign
= _wrap_gcry_pk_sign
,
857 .verify
= _wrap_gcry_pk_verify
,
858 .generate
= wrap_gcry_pk_generate_params
,
859 .pk_fixup_private_params
= wrap_gcry_pk_fixup
,