Add.
[gnutls.git] / lib / pk-libgcrypt.c
blob330fbfb3a8b0adf53cdf55165f07d105efff7fbe
1 /*
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,
21 * USA
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>
38 #include <random.h>
39 #include <gnutls_pk.h>
40 #include <gcrypt.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 *);
48 static int
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;
55 int rc = -1;
56 int ret;
57 bigint_t data, res;
58 gcry_sexp_t list;
60 if (_gnutls_mpi_scan_nz (&data, plaintext->data, plaintext->size) != 0)
62 gnutls_assert ();
63 return GNUTLS_E_MPI_SCAN_FAILED;
66 /* make a sexp from pkey */
67 switch (algo)
69 case GNUTLS_PK_RSA:
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]);
74 break;
76 default:
77 gnutls_assert ();
78 ret = GNUTLS_E_INTERNAL_ERROR;
79 goto cleanup;
82 if (rc != 0)
84 gnutls_assert ();
85 ret = GNUTLS_E_INTERNAL_ERROR;
86 goto cleanup;
89 /* put the data into a simple list */
90 if (gcry_sexp_build (&s_data, NULL, "%m", data))
92 gnutls_assert ();
93 ret = GNUTLS_E_MEMORY_ERROR;
94 goto cleanup;
97 /* pass it to libgcrypt */
98 rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
99 if (rc != 0)
101 gnutls_assert ();
102 ret = GNUTLS_E_PK_ENCRYPTION_FAILED;
103 goto cleanup;
106 list = gcry_sexp_find_token (s_ciph, "a", 0);
107 if (list == NULL)
109 gnutls_assert ();
110 ret = GNUTLS_E_INTERNAL_ERROR;
111 goto cleanup;
114 res = gcry_sexp_nth_mpi (list, 1, 0);
115 gcry_sexp_release (list);
116 if (res == NULL)
118 gnutls_assert ();
119 ret = GNUTLS_E_INTERNAL_ERROR;
120 goto cleanup;
123 ret = _gnutls_mpi_dprint_size (res, ciphertext, plaintext->size);
124 _gnutls_mpi_release (&res);
125 if (ret < 0)
127 gnutls_assert ();
128 goto cleanup;
131 ret = 0;
133 cleanup:
134 _gnutls_mpi_release (&data);
135 if (s_ciph)
136 gcry_sexp_release (s_ciph);
137 if (s_data)
138 gcry_sexp_release (s_data);
139 if (s_pkey)
140 gcry_sexp_release (s_pkey);
142 return ret;
145 static int
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;
152 int rc = -1;
153 int ret;
154 bigint_t data, res;
156 if (_gnutls_mpi_scan_nz (&data, ciphertext->data, ciphertext->size) != 0)
158 gnutls_assert ();
159 return GNUTLS_E_MPI_SCAN_FAILED;
162 /* make a sexp from pkey */
163 switch (algo)
165 case GNUTLS_PK_RSA:
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]);
172 break;
174 default:
175 gnutls_assert ();
176 ret = GNUTLS_E_INTERNAL_ERROR;
177 goto cleanup;
180 if (rc != 0)
182 gnutls_assert ();
183 ret = GNUTLS_E_INTERNAL_ERROR;
184 goto cleanup;
187 /* put the data into a simple list */
188 if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data))
190 gnutls_assert ();
191 ret = GNUTLS_E_INTERNAL_ERROR;
192 goto cleanup;
195 /* pass it to libgcrypt */
196 rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey);
197 if (rc != 0)
199 gnutls_assert ();
200 ret = GNUTLS_E_PK_DECRYPTION_FAILED;
201 goto cleanup;
204 res = gcry_sexp_nth_mpi (s_plain, 0, 0);
205 if (res == NULL)
207 gnutls_assert ();
208 ret = GNUTLS_E_INTERNAL_ERROR;
209 goto cleanup;
212 ret = _gnutls_mpi_dprint_size (res, plaintext, ciphertext->size);
213 _gnutls_mpi_release (&res);
214 if (ret < 0)
216 gnutls_assert ();
217 goto cleanup;
220 ret = 0;
222 cleanup:
223 _gnutls_mpi_release (&data);
224 if (s_plain)
225 gcry_sexp_release (s_plain);
226 if (s_data)
227 gcry_sexp_release (s_data);
228 if (s_pkey)
229 gcry_sexp_release (s_pkey);
231 return ret;
236 /* in case of DSA puts into data, r,s
238 static int
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;
245 int rc = -1, ret;
246 bigint_t hash;
247 bigint_t res[2] = { NULL, NULL };
249 if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
251 gnutls_assert ();
252 return GNUTLS_E_MPI_SCAN_FAILED;
255 /* make a sexp from pkey */
256 switch (algo)
258 case GNUTLS_PK_DSA:
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]);
265 else
267 gnutls_assert ();
270 break;
271 case GNUTLS_PK_RSA:
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]);
278 else
280 gnutls_assert ();
282 break;
284 default:
285 gnutls_assert ();
286 ret = GNUTLS_E_INTERNAL_ERROR;
287 goto cleanup;
290 if (rc != 0)
292 gnutls_assert ();
293 ret = GNUTLS_E_INTERNAL_ERROR;
294 goto cleanup;
297 /* put the data into a simple list */
298 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
300 gnutls_assert ();
301 ret = GNUTLS_E_INTERNAL_ERROR;
302 goto cleanup;
306 /* pass it to libgcrypt */
307 rc = gcry_pk_sign (&s_sig, s_hash, s_key);
308 if (rc != 0)
310 gnutls_assert ();
311 ret = GNUTLS_E_PK_SIGN_FAILED;
312 goto cleanup;
315 ret = GNUTLS_E_INTERNAL_ERROR;
317 switch (algo)
319 case GNUTLS_PK_DSA:
321 list = gcry_sexp_find_token (s_sig, "r", 0);
322 if (list == NULL)
324 gnutls_assert ();
325 ret = GNUTLS_E_INTERNAL_ERROR;
326 goto cleanup;
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);
333 if (list == NULL)
335 gnutls_assert ();
336 ret = GNUTLS_E_INTERNAL_ERROR;
337 goto cleanup;
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]);
344 if (ret < 0)
346 gnutls_assert ();
347 goto cleanup;
350 break;
352 case GNUTLS_PK_RSA:
354 list = gcry_sexp_find_token (s_sig, "s", 0);
355 if (list == NULL)
357 gnutls_assert ();
358 ret = GNUTLS_E_INTERNAL_ERROR;
359 goto cleanup;
362 res[0] = gcry_sexp_nth_mpi (list, 1, 0);
363 gcry_sexp_release (list);
365 ret = _gnutls_mpi_dprint (res[0], signature);
366 if (ret < 0)
368 gnutls_assert ();
369 goto cleanup;
372 break;
374 default:
375 gnutls_assert ();
376 ret = GNUTLS_E_INTERNAL_ERROR;
377 goto cleanup;
380 ret = 0;
382 cleanup:
383 _gnutls_mpi_release (&hash);
384 if (res[0])
385 _gnutls_mpi_release (&res[0]);
386 if (res[1])
387 _gnutls_mpi_release (&res[1]);
388 if (s_sig)
389 gcry_sexp_release (s_sig);
390 if (s_hash)
391 gcry_sexp_release (s_hash);
392 if (s_key)
393 gcry_sexp_release (s_key);
395 return ret;
398 static int
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;
405 int rc = -1, ret;
406 bigint_t hash;
407 bigint_t tmp[2] = { NULL, NULL };
409 if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
411 gnutls_assert ();
412 return GNUTLS_E_MPI_SCAN_FAILED;
415 /* make a sexp from pkey */
416 switch (algo)
418 case GNUTLS_PK_DSA:
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]);
424 break;
425 case GNUTLS_PK_RSA:
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]);
430 break;
432 default:
433 gnutls_assert ();
434 ret = GNUTLS_E_INTERNAL_ERROR;
435 goto cleanup;
438 if (rc != 0)
440 gnutls_assert ();
441 ret = GNUTLS_E_INTERNAL_ERROR;
442 goto cleanup;
445 /* put the data into a simple list */
446 if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
448 gnutls_assert ();
449 ret = GNUTLS_E_INTERNAL_ERROR;
450 goto cleanup;
453 switch (algo)
455 case GNUTLS_PK_DSA:
456 ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]);
457 if (ret < 0)
459 gnutls_assert ();
460 goto cleanup;
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]);
466 break;
468 case GNUTLS_PK_RSA:
469 ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size);
470 if (ret < 0)
472 gnutls_assert ();
473 goto cleanup;
475 rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", tmp[0]);
476 _gnutls_mpi_release (&tmp[0]);
477 break;
479 default:
480 gnutls_assert ();
481 ret = GNUTLS_E_INTERNAL_ERROR;
482 goto cleanup;
485 if (rc != 0)
487 gnutls_assert ();
488 ret = GNUTLS_E_INTERNAL_ERROR;
489 goto cleanup;
492 rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
494 if (rc != 0)
496 gnutls_assert ();
497 ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
498 goto cleanup;
501 ret = 0;
503 cleanup:
504 _gnutls_mpi_release (&hash);
505 if (s_sig)
506 gcry_sexp_release (s_sig);
507 if (s_hash)
508 gcry_sexp_release (s_hash);
509 if (s_pkey)
510 gcry_sexp_release (s_pkey);
512 return ret;
515 static int
516 _dsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
519 int ret;
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)
525 gnutls_assert ();
526 return GNUTLS_E_INVALID_REQUEST;
529 if (bits < 512)
531 gnutls_assert ();
532 return GNUTLS_E_INVALID_REQUEST;
535 ret = gcry_sexp_build (&parms, NULL, "(genkey(dsa(nbits %d)))", bits);
536 if (ret != 0)
538 gnutls_assert ();
539 return GNUTLS_E_INTERNAL_ERROR;
542 /* generate the DSA key
544 ret = gcry_pk_genkey (&key, parms);
545 gcry_sexp_release (parms);
547 if (ret != 0)
549 gnutls_assert ();
550 return GNUTLS_E_INTERNAL_ERROR;
553 list = gcry_sexp_find_token (key, "p", 0);
554 if (list == NULL)
556 gnutls_assert ();
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);
565 if (list == NULL)
567 gnutls_assert ();
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);
576 if (list == NULL)
578 gnutls_assert ();
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);
587 if (list == NULL)
589 gnutls_assert ();
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);
599 if (list == NULL)
601 gnutls_assert ();
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]);
617 *resarr_len = 5;
619 return 0;
623 static int
624 _rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
627 int ret;
628 gcry_sexp_t parms, key, list;
630 ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits);
631 if (ret != 0)
633 gnutls_assert ();
634 return GNUTLS_E_INTERNAL_ERROR;
637 /* generate the RSA key */
638 ret = gcry_pk_genkey (&key, parms);
639 gcry_sexp_release (parms);
641 if (ret != 0)
643 gnutls_assert ();
644 return GNUTLS_E_INTERNAL_ERROR;
647 list = gcry_sexp_find_token (key, "n", 0);
648 if (list == NULL)
650 gnutls_assert ();
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);
659 if (list == NULL)
661 gnutls_assert ();
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);
670 if (list == NULL)
672 gnutls_assert ();
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);
681 if (list == NULL)
683 gnutls_assert ();
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);
693 if (list == NULL)
695 gnutls_assert ();
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);
705 if (list == NULL)
707 gnutls_assert ();
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]);
724 *resarr_len = 6;
726 return 0;
730 static int
731 wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo,
732 unsigned int level /*bits */ ,
733 gnutls_pk_params_st * params)
736 switch (algo)
739 case GNUTLS_PK_DSA:
740 params->params_nr = DSA_PRIVATE_PARAMS;
741 if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
743 gnutls_assert ();
744 return GNUTLS_E_INTERNAL_ERROR;
746 return _dsa_generate_params (params->params, &params->params_nr, level);
748 case GNUTLS_PK_RSA:
749 params->params_nr = RSA_PRIVATE_PARAMS;
750 if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
752 gnutls_assert ();
753 return GNUTLS_E_INTERNAL_ERROR;
755 return _rsa_generate_params (params->params, &params->params_nr, level);
757 default:
758 gnutls_assert ();
759 return GNUTLS_E_INVALID_REQUEST;
764 static int
765 wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo,
766 gnutls_direction_t direction,
767 gnutls_pk_params_st * params)
769 int ret;
771 /* only for RSA we invert the coefficient --pgp type */
773 if (algo != GNUTLS_PK_RSA)
774 return 0;
776 if (params->params[5])
777 _gnutls_mpi_release (&params->params[5]);
778 params->params[5] =
779 _gnutls_mpi_new (_gnutls_mpi_get_nbits (params->params[0]));
781 if (params->params[5] == NULL)
783 gnutls_assert ();
784 return GNUTLS_E_MEMORY_ERROR;
787 if (direction == GNUTLS_IMPORT)
788 ret =
789 gcry_mpi_invm (params->params[5], params->params[3], params->params[4]);
790 else
791 ret =
792 gcry_mpi_invm (params->params[5], params->params[4], params->params[3]);
793 if (ret == 0)
795 gnutls_assert ();
796 return GNUTLS_E_INVALID_REQUEST;
799 return 0;
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,