Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_dh_primes.c
1 /*
2  * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008, 2009, 2010 Free
3  * Software Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
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.
13  *
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.
18  *
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
23  *
24  */
25
26 #include <gnutls_int.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_datum.h>
29 #include <x509_b64.h>           /* for PKCS3 PEM decoding */
30 #include <gnutls_global.h>
31 #include <gnutls_dh.h>
32 #include <gnutls_pk.h>
33 #include <gnutls/crypto.h>
34 #include "x509/x509_int.h"
35 #include "debug.h"
36
37
38 /* returns the prime and the generator of DH params.
39  */
40 const bigint_t *
41 _gnutls_dh_params_to_mpi (gnutls_dh_params_t dh_primes)
42 {
43   if (dh_primes == NULL || dh_primes->params[1] == NULL ||
44       dh_primes->params[0] == NULL)
45     {
46       return NULL;
47     }
48
49   return dh_primes->params;
50 }
51
52
53 /**
54  * gnutls_dh_params_import_raw:
55  * @dh_params: Is a structure that will hold the prime numbers
56  * @prime: holds the new prime
57  * @generator: holds the new generator
58  *
59  * This function will replace the pair of prime and generator for use
60  * in the Diffie-Hellman key exchange.  The new parameters should be
61  * stored in the appropriate gnutls_datum.
62  *
63  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
64  *   otherwise an error code is returned.
65  **/
66 int
67 gnutls_dh_params_import_raw (gnutls_dh_params_t dh_params,
68                              const gnutls_datum_t * prime,
69                              const gnutls_datum_t * generator)
70 {
71   bigint_t tmp_prime, tmp_g;
72   size_t siz;
73
74   siz = prime->size;
75   if (_gnutls_mpi_scan_nz (&tmp_prime, prime->data, siz))
76     {
77       gnutls_assert ();
78       return GNUTLS_E_MPI_SCAN_FAILED;
79     }
80
81   siz = generator->size;
82   if (_gnutls_mpi_scan_nz (&tmp_g, generator->data, siz))
83     {
84       _gnutls_mpi_release (&tmp_prime);
85       gnutls_assert ();
86       return GNUTLS_E_MPI_SCAN_FAILED;
87     }
88
89   /* store the generated values
90    */
91   dh_params->params[0] = tmp_prime;
92   dh_params->params[1] = tmp_g;
93
94   return 0;
95
96 }
97
98 /**
99  * gnutls_dh_params_init:
100  * @dh_params: Is a structure that will hold the prime numbers
101  *
102  * This function will initialize the DH parameters structure.
103  *
104  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
105  *   otherwise an error code is returned.
106  **/
107 int
108 gnutls_dh_params_init (gnutls_dh_params_t * dh_params)
109 {
110
111   (*dh_params) = gnutls_calloc (1, sizeof (dh_params_st));
112   if (*dh_params == NULL)
113     {
114       gnutls_assert ();
115       return GNUTLS_E_MEMORY_ERROR;
116     }
117
118   return 0;
119
120 }
121
122 /**
123  * gnutls_dh_params_deinit:
124  * @dh_params: Is a structure that holds the prime numbers
125  *
126  * This function will deinitialize the DH parameters structure.
127  **/
128 void
129 gnutls_dh_params_deinit (gnutls_dh_params_t dh_params)
130 {
131   if (dh_params == NULL)
132     return;
133
134   _gnutls_mpi_release (&dh_params->params[0]);
135   _gnutls_mpi_release (&dh_params->params[1]);
136
137   gnutls_free (dh_params);
138
139 }
140
141 /**
142  * gnutls_dh_params_cpy:
143  * @dst: Is the destination structure, which should be initialized.
144  * @src: Is the source structure
145  *
146  * This function will copy the DH parameters structure from source
147  * to destination.
148  *
149  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
150  *   otherwise an error code is returned.
151  **/
152 int
153 gnutls_dh_params_cpy (gnutls_dh_params_t dst, gnutls_dh_params_t src)
154 {
155   if (src == NULL)
156     return GNUTLS_E_INVALID_REQUEST;
157
158   dst->params[0] = _gnutls_mpi_copy (src->params[0]);
159   dst->params[1] = _gnutls_mpi_copy (src->params[1]);
160
161   if (dst->params[0] == NULL || dst->params[1] == NULL)
162     return GNUTLS_E_MEMORY_ERROR;
163
164   return 0;
165 }
166
167
168 /**
169  * gnutls_dh_params_generate2:
170  * @params: Is the structure that the DH parameters will be stored
171  * @bits: is the prime's number of bits
172  *
173  * This function will generate a new pair of prime and generator for use in
174  * the Diffie-Hellman key exchange. The new parameters will be allocated using
175  * gnutls_malloc() and will be stored in the appropriate datum.
176  * This function is normally slow.
177  *
178  * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits() to
179  * get bits for %GNUTLS_PK_DSA.
180  * Also note that the DH parameters are only useful to servers.
181  * Since clients use the parameters sent by the server, it's of
182  * no use to call this in client side.
183  *
184  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
185  *   otherwise an error code is returned.
186  **/
187 int
188 gnutls_dh_params_generate2 (gnutls_dh_params_t params, unsigned int bits)
189 {
190   int ret;
191   gnutls_group_st group;
192
193   ret = _gnutls_mpi_generate_group (&group, bits);
194   if (ret < 0)
195     {
196       gnutls_assert ();
197       return ret;
198     }
199
200   params->params[0] = group.p;
201   params->params[1] = group.g;
202
203   return 0;
204 }
205
206 /**
207  * gnutls_dh_params_import_pkcs3:
208  * @params: A structure where the parameters will be copied to
209  * @pkcs3_params: should contain a PKCS3 DHParams structure PEM or DER encoded
210  * @format: the format of params. PEM or DER.
211  *
212  * This function will extract the DHParams found in a PKCS3 formatted
213  * structure. This is the format generated by "openssl dhparam" tool.
214  *
215  * If the structure is PEM encoded, it should have a header
216  * of "BEGIN DH PARAMETERS".
217  *
218  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
219  *   otherwise an error code is returned.
220  **/
221 int
222 gnutls_dh_params_import_pkcs3 (gnutls_dh_params_t params,
223                                const gnutls_datum_t * pkcs3_params,
224                                gnutls_x509_crt_fmt_t format)
225 {
226   ASN1_TYPE c2;
227   int result, need_free = 0;
228   gnutls_datum_t _params;
229
230   if (format == GNUTLS_X509_FMT_PEM)
231     {
232       opaque *out;
233
234       result = _gnutls_fbase64_decode ("DH PARAMETERS",
235                                        pkcs3_params->data,
236                                        pkcs3_params->size, &out);
237
238       if (result <= 0)
239         {
240           if (result == 0)
241             result = GNUTLS_E_INTERNAL_ERROR;
242           gnutls_assert ();
243           return result;
244         }
245
246       _params.data = out;
247       _params.size = result;
248
249       need_free = 1;
250
251     }
252   else
253     {
254       _params.data = pkcs3_params->data;
255       _params.size = pkcs3_params->size;
256     }
257
258   if ((result = asn1_create_element
259        (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2))
260       != ASN1_SUCCESS)
261     {
262       gnutls_assert ();
263       if (need_free != 0)
264         {
265           gnutls_free (_params.data);
266           _params.data = NULL;
267         }
268       return _gnutls_asn2err (result);
269     }
270
271   result = asn1_der_decoding (&c2, _params.data, _params.size, NULL);
272
273   if (need_free != 0)
274     {
275       gnutls_free (_params.data);
276       _params.data = NULL;
277     }
278
279   if (result != ASN1_SUCCESS)
280     {
281       /* couldn't decode DER */
282
283       _gnutls_x509_log ("DHParams: Decoding error %d\n", result);
284       gnutls_assert ();
285       asn1_delete_structure (&c2);
286       return _gnutls_asn2err (result);
287     }
288
289   /* Read PRIME 
290    */
291   result = _gnutls_x509_read_int (c2, "prime", &params->params[0]);
292   if (result < 0)
293     {
294       asn1_delete_structure (&c2);
295       gnutls_assert ();
296       return result;
297     }
298
299   /* read the generator
300    */
301   result = _gnutls_x509_read_int (c2, "base", &params->params[1]);
302   if (result < 0)
303     {
304       asn1_delete_structure (&c2);
305       _gnutls_mpi_release (&params->params[0]);
306       gnutls_assert ();
307       return result;
308     }
309
310   asn1_delete_structure (&c2);
311
312   return 0;
313 }
314
315 /**
316  * gnutls_dh_params_export_pkcs3:
317  * @params: Holds the DH parameters
318  * @format: the format of output params. One of PEM or DER.
319  * @params_data: will contain a PKCS3 DHParams structure PEM or DER encoded
320  * @params_data_size: holds the size of params_data (and will be replaced by the actual size of parameters)
321  *
322  * This function will export the given dh parameters to a PKCS3
323  * DHParams structure. This is the format generated by "openssl dhparam" tool.
324  * If the buffer provided is not long enough to hold the output, then
325  * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
326  *
327  * If the structure is PEM encoded, it will have a header
328  * of "BEGIN DH PARAMETERS".
329  *
330  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
331  *   otherwise an error code is returned.
332  **/
333 int
334 gnutls_dh_params_export_pkcs3 (gnutls_dh_params_t params,
335                                gnutls_x509_crt_fmt_t format,
336                                unsigned char *params_data,
337                                size_t * params_data_size)
338 {
339   ASN1_TYPE c2;
340   int result, _params_data_size;
341   size_t g_size, p_size;
342   opaque *p_data, *g_data;
343   opaque *all_data;
344
345   _gnutls_mpi_print_lz (params->params[1], NULL, &g_size);
346   _gnutls_mpi_print_lz (params->params[0], NULL, &p_size);
347
348   all_data = gnutls_malloc (g_size + p_size);
349   if (all_data == NULL)
350     {
351       gnutls_assert ();
352       return GNUTLS_E_MEMORY_ERROR;
353     }
354
355   p_data = &all_data[0];
356   _gnutls_mpi_print_lz (params->params[0], p_data, &p_size);
357
358   g_data = &all_data[p_size];
359   _gnutls_mpi_print_lz (params->params[1], g_data, &g_size);
360
361
362   /* Ok. Now we have the data. Create the asn1 structures
363    */
364
365   if ((result = asn1_create_element
366        (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2))
367       != ASN1_SUCCESS)
368     {
369       gnutls_assert ();
370       gnutls_free (all_data);
371       return _gnutls_asn2err (result);
372     }
373
374   /* Write PRIME 
375    */
376   if ((result = asn1_write_value (c2, "prime",
377                                   p_data, p_size)) != ASN1_SUCCESS)
378     {
379       gnutls_assert ();
380       gnutls_free (all_data);
381       asn1_delete_structure (&c2);
382       return _gnutls_asn2err (result);
383     }
384
385   /* Write the GENERATOR
386    */
387   if ((result = asn1_write_value (c2, "base",
388                                   g_data, g_size)) != ASN1_SUCCESS)
389     {
390       gnutls_assert ();
391       gnutls_free (all_data);
392       asn1_delete_structure (&c2);
393       return _gnutls_asn2err (result);
394     }
395
396   gnutls_free (all_data);
397
398   if ((result = asn1_write_value (c2, "privateValueLength",
399                                   NULL, 0)) != ASN1_SUCCESS)
400     {
401       gnutls_assert ();
402       asn1_delete_structure (&c2);
403       return _gnutls_asn2err (result);
404     }
405
406   if (format == GNUTLS_X509_FMT_DER)
407     {
408       if (params_data == NULL)
409         *params_data_size = 0;
410
411       _params_data_size = *params_data_size;
412       result =
413         asn1_der_coding (c2, "", params_data, &_params_data_size, NULL);
414       *params_data_size = _params_data_size;
415       asn1_delete_structure (&c2);
416
417       if (result != ASN1_SUCCESS)
418         {
419           gnutls_assert ();
420           if (result == ASN1_MEM_ERROR)
421             return GNUTLS_E_SHORT_MEMORY_BUFFER;
422
423           return _gnutls_asn2err (result);
424         }
425
426     }
427   else
428     {                           /* PEM */
429       opaque *tmp;
430       opaque *out;
431       int len;
432
433       len = 0;
434       asn1_der_coding (c2, "", NULL, &len, NULL);
435
436       tmp = gnutls_malloc (len);
437       if (tmp == NULL)
438         {
439           gnutls_assert ();
440           asn1_delete_structure (&c2);
441           return GNUTLS_E_MEMORY_ERROR;
442         }
443
444       if ((result =
445            asn1_der_coding (c2, "", tmp, &len, NULL)) != ASN1_SUCCESS)
446         {
447           gnutls_assert ();
448           gnutls_free (tmp);
449           asn1_delete_structure (&c2);
450           return _gnutls_asn2err (result);
451         }
452
453       asn1_delete_structure (&c2);
454
455       result = _gnutls_fbase64_encode ("DH PARAMETERS", tmp, len, &out);
456
457       gnutls_free (tmp);
458
459       if (result < 0)
460         {
461           gnutls_assert ();
462           return result;
463         }
464
465       if (result == 0)
466         {                       /* oooops */
467           gnutls_assert ();
468           gnutls_free (out);
469           return GNUTLS_E_INTERNAL_ERROR;
470         }
471
472       if ((unsigned) result > *params_data_size)
473         {
474           gnutls_assert ();
475           gnutls_free (out);
476           *params_data_size = result;
477           return GNUTLS_E_SHORT_MEMORY_BUFFER;
478         }
479
480       *params_data_size = result - 1;
481
482       if (params_data)
483         memcpy (params_data, out, result);
484
485       gnutls_free (out);
486
487     }
488
489   return 0;
490 }
491
492 /**
493  * gnutls_dh_params_export_raw:
494  * @params: Holds the DH parameters
495  * @prime: will hold the new prime
496  * @generator: will hold the new generator
497  * @bits: if non null will hold is the prime's number of bits
498  *
499  * This function will export the pair of prime and generator for use
500  * in the Diffie-Hellman key exchange.  The new parameters will be
501  * allocated using gnutls_malloc() and will be stored in the
502  * appropriate datum.
503  *
504  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
505  *   otherwise an error code is returned.
506  **/
507 int
508 gnutls_dh_params_export_raw (gnutls_dh_params_t params,
509                              gnutls_datum_t * prime,
510                              gnutls_datum_t * generator, unsigned int *bits)
511 {
512   int ret;
513
514   if (params->params[1] == NULL || params->params[0] == NULL)
515     {
516       gnutls_assert ();
517       return GNUTLS_E_INVALID_REQUEST;
518     }
519
520   ret = _gnutls_mpi_dprint (params->params[1], generator);
521   if (ret < 0)
522     {
523       gnutls_assert ();
524       return ret;
525     }
526
527   ret = _gnutls_mpi_dprint (params->params[0], prime);
528   if (ret < 0)
529     {
530       gnutls_assert ();
531       _gnutls_free_datum (generator);
532       return ret;
533     }
534
535   if (bits)
536     *bits = _gnutls_mpi_get_nbits (params->params[0]);
537
538   return 0;
539
540 }