2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 /* This file contains the functions needed for RSA/DSA public key
26 * encryption and signatures.
29 #include <gnutls_int.h>
30 #include <gnutls_mpi.h>
31 #include <gnutls_pk.h>
32 #include <gnutls_errors.h>
33 #include <gnutls_datum.h>
34 #include <gnutls_global.h>
35 #include <gnutls_num.h>
36 #include <x509/x509_int.h>
37 #include <x509/common.h>
39 #include <gnutls_pk.h>
42 /* this is based on code from old versions of libgcrypt (centuries ago)
45 int (*generate
) (gnutls_pk_algorithm_t
, unsigned int level
/*bits */ ,
46 gnutls_pk_params_st
*);
49 _wrap_gcry_pk_encrypt (gnutls_pk_algorithm_t algo
,
50 gnutls_datum_t
* ciphertext
,
51 const gnutls_datum_t
* plaintext
,
52 const gnutls_pk_params_st
* pk_params
)
54 gcry_sexp_t s_ciph
= NULL
, s_data
= NULL
, s_pkey
= NULL
;
60 if (_gnutls_mpi_scan_nz (&data
, plaintext
->data
, plaintext
->size
) != 0)
63 return GNUTLS_E_MPI_SCAN_FAILED
;
66 /* make a sexp from pkey */
70 if (pk_params
->params_nr
>= 2)
71 rc
= gcry_sexp_build (&s_pkey
, NULL
,
72 "(public-key(rsa(n%m)(e%m)))",
73 pk_params
->params
[0], pk_params
->params
[1]);
78 ret
= GNUTLS_E_INTERNAL_ERROR
;
85 ret
= GNUTLS_E_INTERNAL_ERROR
;
89 /* put the data into a simple list */
90 if (gcry_sexp_build (&s_data
, NULL
, "%m", data
))
93 ret
= GNUTLS_E_MEMORY_ERROR
;
97 /* pass it to libgcrypt */
98 rc
= gcry_pk_encrypt (&s_ciph
, s_data
, s_pkey
);
102 ret
= GNUTLS_E_PK_ENCRYPTION_FAILED
;
106 list
= gcry_sexp_find_token (s_ciph
, "a", 0);
110 ret
= GNUTLS_E_INTERNAL_ERROR
;
114 res
= gcry_sexp_nth_mpi (list
, 1, 0);
115 gcry_sexp_release (list
);
119 ret
= GNUTLS_E_INTERNAL_ERROR
;
123 ret
= _gnutls_mpi_dprint_size (res
, ciphertext
, plaintext
->size
);
124 _gnutls_mpi_release (&res
);
134 _gnutls_mpi_release (&data
);
136 gcry_sexp_release (s_ciph
);
138 gcry_sexp_release (s_data
);
140 gcry_sexp_release (s_pkey
);
146 _wrap_gcry_pk_decrypt (gnutls_pk_algorithm_t algo
,
147 gnutls_datum_t
* plaintext
,
148 const gnutls_datum_t
* ciphertext
,
149 const gnutls_pk_params_st
* pk_params
)
151 gcry_sexp_t s_plain
= NULL
, s_data
= NULL
, s_pkey
= NULL
;
156 if (_gnutls_mpi_scan_nz (&data
, ciphertext
->data
, ciphertext
->size
) != 0)
159 return GNUTLS_E_MPI_SCAN_FAILED
;
162 /* make a sexp from pkey */
166 if (pk_params
->params_nr
>= 6)
167 rc
= gcry_sexp_build (&s_pkey
, NULL
,
168 "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
169 pk_params
->params
[0], pk_params
->params
[1],
170 pk_params
->params
[2], pk_params
->params
[3],
171 pk_params
->params
[4], pk_params
->params
[5]);
176 ret
= GNUTLS_E_INTERNAL_ERROR
;
183 ret
= GNUTLS_E_INTERNAL_ERROR
;
187 /* put the data into a simple list */
188 if (gcry_sexp_build (&s_data
, NULL
, "(enc-val(rsa(a%m)))", data
))
191 ret
= GNUTLS_E_INTERNAL_ERROR
;
195 /* pass it to libgcrypt */
196 rc
= gcry_pk_decrypt (&s_plain
, s_data
, s_pkey
);
200 ret
= GNUTLS_E_PK_DECRYPTION_FAILED
;
204 res
= gcry_sexp_nth_mpi (s_plain
, 0, 0);
208 ret
= GNUTLS_E_INTERNAL_ERROR
;
212 ret
= _gnutls_mpi_dprint_size (res
, plaintext
, ciphertext
->size
);
213 _gnutls_mpi_release (&res
);
223 _gnutls_mpi_release (&data
);
225 gcry_sexp_release (s_plain
);
227 gcry_sexp_release (s_data
);
229 gcry_sexp_release (s_pkey
);
236 /* in case of DSA puts into data, r,s
239 _wrap_gcry_pk_sign (gnutls_pk_algorithm_t algo
, gnutls_datum_t
* signature
,
240 const gnutls_datum_t
* vdata
,
241 const gnutls_pk_params_st
* pk_params
)
243 gcry_sexp_t s_hash
= NULL
, s_key
= NULL
, s_sig
= NULL
;
244 gcry_sexp_t list
= NULL
;
247 bigint_t res
[2] = { NULL
, NULL
};
249 if (_gnutls_mpi_scan_nz (&hash
, vdata
->data
, vdata
->size
) != 0)
252 return GNUTLS_E_MPI_SCAN_FAILED
;
255 /* make a sexp from pkey */
259 if (pk_params
->params_nr
>= 5)
260 rc
= gcry_sexp_build (&s_key
, NULL
,
261 "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
262 pk_params
->params
[0], pk_params
->params
[1],
263 pk_params
->params
[2], pk_params
->params
[3],
264 pk_params
->params
[4]);
272 if (pk_params
->params_nr
>= 6)
273 rc
= gcry_sexp_build (&s_key
, NULL
,
274 "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
275 pk_params
->params
[0], pk_params
->params
[1],
276 pk_params
->params
[2], pk_params
->params
[3],
277 pk_params
->params
[4], pk_params
->params
[5]);
286 ret
= GNUTLS_E_INTERNAL_ERROR
;
293 ret
= GNUTLS_E_INTERNAL_ERROR
;
297 /* put the data into a simple list */
298 if (gcry_sexp_build (&s_hash
, NULL
, "%m", hash
))
301 ret
= GNUTLS_E_INTERNAL_ERROR
;
306 /* pass it to libgcrypt */
307 rc
= gcry_pk_sign (&s_sig
, s_hash
, s_key
);
311 ret
= GNUTLS_E_PK_SIGN_FAILED
;
315 ret
= GNUTLS_E_INTERNAL_ERROR
;
321 list
= gcry_sexp_find_token (s_sig
, "r", 0);
325 ret
= GNUTLS_E_INTERNAL_ERROR
;
329 res
[0] = gcry_sexp_nth_mpi (list
, 1, 0);
330 gcry_sexp_release (list
);
332 list
= gcry_sexp_find_token (s_sig
, "s", 0);
336 ret
= GNUTLS_E_INTERNAL_ERROR
;
340 res
[1] = gcry_sexp_nth_mpi (list
, 1, 0);
341 gcry_sexp_release (list
);
343 ret
= _gnutls_encode_ber_rs (signature
, res
[0], res
[1]);
354 list
= gcry_sexp_find_token (s_sig
, "s", 0);
358 ret
= GNUTLS_E_INTERNAL_ERROR
;
362 res
[0] = gcry_sexp_nth_mpi (list
, 1, 0);
363 gcry_sexp_release (list
);
365 ret
= _gnutls_mpi_dprint (res
[0], signature
);
376 ret
= GNUTLS_E_INTERNAL_ERROR
;
383 _gnutls_mpi_release (&hash
);
385 _gnutls_mpi_release (&res
[0]);
387 _gnutls_mpi_release (&res
[1]);
389 gcry_sexp_release (s_sig
);
391 gcry_sexp_release (s_hash
);
393 gcry_sexp_release (s_key
);
399 _wrap_gcry_pk_verify (gnutls_pk_algorithm_t algo
,
400 const gnutls_datum_t
* vdata
,
401 const gnutls_datum_t
* signature
,
402 const gnutls_pk_params_st
* pk_params
)
404 gcry_sexp_t s_sig
= NULL
, s_hash
= NULL
, s_pkey
= NULL
;
407 bigint_t tmp
[2] = { NULL
, NULL
};
409 if (_gnutls_mpi_scan_nz (&hash
, vdata
->data
, vdata
->size
) != 0)
412 return GNUTLS_E_MPI_SCAN_FAILED
;
415 /* make a sexp from pkey */
419 if (pk_params
->params_nr
>= 4)
420 rc
= gcry_sexp_build (&s_pkey
, NULL
,
421 "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
422 pk_params
->params
[0], pk_params
->params
[1],
423 pk_params
->params
[2], pk_params
->params
[3]);
426 if (pk_params
->params_nr
>= 2)
427 rc
= gcry_sexp_build (&s_pkey
, NULL
,
428 "(public-key(rsa(n%m)(e%m)))",
429 pk_params
->params
[0], pk_params
->params
[1]);
434 ret
= GNUTLS_E_INTERNAL_ERROR
;
441 ret
= GNUTLS_E_INTERNAL_ERROR
;
445 /* put the data into a simple list */
446 if (gcry_sexp_build (&s_hash
, NULL
, "%m", hash
))
449 ret
= GNUTLS_E_INTERNAL_ERROR
;
456 ret
= _gnutls_decode_ber_rs (signature
, &tmp
[0], &tmp
[1]);
462 rc
= gcry_sexp_build (&s_sig
, NULL
,
463 "(sig-val(dsa(r%m)(s%m)))", tmp
[0], tmp
[1]);
464 _gnutls_mpi_release (&tmp
[0]);
465 _gnutls_mpi_release (&tmp
[1]);
469 ret
= _gnutls_mpi_scan_nz (&tmp
[0], signature
->data
, signature
->size
);
475 rc
= gcry_sexp_build (&s_sig
, NULL
, "(sig-val(rsa(s%m)))", tmp
[0]);
476 _gnutls_mpi_release (&tmp
[0]);
481 ret
= GNUTLS_E_INTERNAL_ERROR
;
488 ret
= GNUTLS_E_INTERNAL_ERROR
;
492 rc
= gcry_pk_verify (s_sig
, s_hash
, s_pkey
);
497 ret
= GNUTLS_E_PK_SIG_VERIFY_FAILED
;
504 _gnutls_mpi_release (&hash
);
506 gcry_sexp_release (s_sig
);
508 gcry_sexp_release (s_hash
);
510 gcry_sexp_release (s_pkey
);
516 _dsa_generate_params (bigint_t
* resarr
, int *resarr_len
, int bits
)
520 gcry_sexp_t parms
, key
, list
;
522 /* FIXME: Remove me once we depend on 1.3.1 */
523 if (bits
> 1024 && gcry_check_version ("1.3.1") == NULL
)
526 return GNUTLS_E_INVALID_REQUEST
;
532 return GNUTLS_E_INVALID_REQUEST
;
535 ret
= gcry_sexp_build (&parms
, NULL
, "(genkey(dsa(nbits %d)))", bits
);
539 return GNUTLS_E_INTERNAL_ERROR
;
542 /* generate the DSA key
544 ret
= gcry_pk_genkey (&key
, parms
);
545 gcry_sexp_release (parms
);
550 return GNUTLS_E_INTERNAL_ERROR
;
553 list
= gcry_sexp_find_token (key
, "p", 0);
557 gcry_sexp_release (key
);
558 return GNUTLS_E_INTERNAL_ERROR
;
561 resarr
[0] = gcry_sexp_nth_mpi (list
, 1, 0);
562 gcry_sexp_release (list
);
564 list
= gcry_sexp_find_token (key
, "q", 0);
568 gcry_sexp_release (key
);
569 return GNUTLS_E_INTERNAL_ERROR
;
572 resarr
[1] = gcry_sexp_nth_mpi (list
, 1, 0);
573 gcry_sexp_release (list
);
575 list
= gcry_sexp_find_token (key
, "g", 0);
579 gcry_sexp_release (key
);
580 return GNUTLS_E_INTERNAL_ERROR
;
583 resarr
[2] = gcry_sexp_nth_mpi (list
, 1, 0);
584 gcry_sexp_release (list
);
586 list
= gcry_sexp_find_token (key
, "y", 0);
590 gcry_sexp_release (key
);
591 return GNUTLS_E_INTERNAL_ERROR
;
594 resarr
[3] = gcry_sexp_nth_mpi (list
, 1, 0);
595 gcry_sexp_release (list
);
598 list
= gcry_sexp_find_token (key
, "x", 0);
602 gcry_sexp_release (key
);
603 return GNUTLS_E_INTERNAL_ERROR
;
606 resarr
[4] = gcry_sexp_nth_mpi (list
, 1, 0);
608 gcry_sexp_release (list
);
609 gcry_sexp_release (key
);
611 _gnutls_mpi_log ("p: ", resarr
[0]);
612 _gnutls_mpi_log ("q: ", resarr
[1]);
613 _gnutls_mpi_log ("g: ", resarr
[2]);
614 _gnutls_mpi_log ("y: ", resarr
[3]);
615 _gnutls_mpi_log ("x: ", resarr
[4]);
624 _rsa_generate_params (bigint_t
* resarr
, int *resarr_len
, int bits
)
628 gcry_sexp_t parms
, key
, list
;
630 ret
= gcry_sexp_build (&parms
, NULL
, "(genkey(rsa(nbits %d)))", bits
);
634 return GNUTLS_E_INTERNAL_ERROR
;
637 /* generate the RSA key */
638 ret
= gcry_pk_genkey (&key
, parms
);
639 gcry_sexp_release (parms
);
644 return GNUTLS_E_INTERNAL_ERROR
;
647 list
= gcry_sexp_find_token (key
, "n", 0);
651 gcry_sexp_release (key
);
652 return GNUTLS_E_INTERNAL_ERROR
;
655 resarr
[0] = gcry_sexp_nth_mpi (list
, 1, 0);
656 gcry_sexp_release (list
);
658 list
= gcry_sexp_find_token (key
, "e", 0);
662 gcry_sexp_release (key
);
663 return GNUTLS_E_INTERNAL_ERROR
;
666 resarr
[1] = gcry_sexp_nth_mpi (list
, 1, 0);
667 gcry_sexp_release (list
);
669 list
= gcry_sexp_find_token (key
, "d", 0);
673 gcry_sexp_release (key
);
674 return GNUTLS_E_INTERNAL_ERROR
;
677 resarr
[2] = gcry_sexp_nth_mpi (list
, 1, 0);
678 gcry_sexp_release (list
);
680 list
= gcry_sexp_find_token (key
, "p", 0);
684 gcry_sexp_release (key
);
685 return GNUTLS_E_INTERNAL_ERROR
;
688 resarr
[3] = gcry_sexp_nth_mpi (list
, 1, 0);
689 gcry_sexp_release (list
);
692 list
= gcry_sexp_find_token (key
, "q", 0);
696 gcry_sexp_release (key
);
697 return GNUTLS_E_INTERNAL_ERROR
;
700 resarr
[4] = gcry_sexp_nth_mpi (list
, 1, 0);
701 gcry_sexp_release (list
);
704 list
= gcry_sexp_find_token (key
, "u", 0);
708 gcry_sexp_release (key
);
709 return GNUTLS_E_INTERNAL_ERROR
;
712 resarr
[5] = gcry_sexp_nth_mpi (list
, 1, 0);
714 gcry_sexp_release (list
);
715 gcry_sexp_release (key
);
717 _gnutls_mpi_log ("n: ", resarr
[0]);
718 _gnutls_mpi_log ("e: ", resarr
[1]);
719 _gnutls_mpi_log ("d: ", resarr
[2]);
720 _gnutls_mpi_log ("p: ", resarr
[3]);
721 _gnutls_mpi_log ("q: ", resarr
[4]);
722 _gnutls_mpi_log ("u: ", resarr
[5]);
731 wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo
,
732 unsigned int level
/*bits */ ,
733 gnutls_pk_params_st
* params
)
740 params
->params_nr
= DSA_PRIVATE_PARAMS
;
741 if (params
->params_nr
> GNUTLS_MAX_PK_PARAMS
)
744 return GNUTLS_E_INTERNAL_ERROR
;
746 return _dsa_generate_params (params
->params
, ¶ms
->params_nr
, level
);
749 params
->params_nr
= RSA_PRIVATE_PARAMS
;
750 if (params
->params_nr
> GNUTLS_MAX_PK_PARAMS
)
753 return GNUTLS_E_INTERNAL_ERROR
;
755 return _rsa_generate_params (params
->params
, ¶ms
->params_nr
, level
);
759 return GNUTLS_E_INVALID_REQUEST
;
765 wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo
,
766 gnutls_direction_t direction
,
767 gnutls_pk_params_st
* params
)
771 /* only for RSA we invert the coefficient --pgp type */
773 if (algo
!= GNUTLS_PK_RSA
)
776 if (params
->params
[5])
777 _gnutls_mpi_release (¶ms
->params
[5]);
779 _gnutls_mpi_new (_gnutls_mpi_get_nbits (params
->params
[0]));
781 if (params
->params
[5] == NULL
)
784 return GNUTLS_E_MEMORY_ERROR
;
787 if (direction
== GNUTLS_IMPORT
)
789 gcry_mpi_invm (params
->params
[5], params
->params
[3], params
->params
[4]);
792 gcry_mpi_invm (params
->params
[5], params
->params
[4], params
->params
[3]);
796 return GNUTLS_E_INVALID_REQUEST
;
802 int crypto_pk_prio
= INT_MAX
;
804 gnutls_crypto_pk_st _gnutls_pk_ops
= {
805 .encrypt
= _wrap_gcry_pk_encrypt
,
806 .decrypt
= _wrap_gcry_pk_decrypt
,
807 .sign
= _wrap_gcry_pk_sign
,
808 .verify
= _wrap_gcry_pk_verify
,
809 .generate
= wrap_gcry_pk_generate_params
,
810 .pk_fixup_private_params
= wrap_gcry_pk_fixup
,