Fix memory leak.
[gnutls.git] / lib / gnutls_dh_primes.c
blob8abab8f8730f5e9456c86f721f0c5dc1e276ca32
1 /*
2 * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008 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 #include <gnutls_int.h>
26 #include <gnutls_errors.h>
27 #include <gnutls_datum.h>
28 #include <x509_b64.h> /* for PKCS3 PEM decoding */
29 #include <gnutls_global.h>
30 #include <gnutls_dh.h>
31 #include "x509/x509_int.h"
32 #include "debug.h"
35 /* returns the prime and the generator of DH params.
37 const mpi_t *
38 _gnutls_dh_params_to_mpi (gnutls_dh_params_t dh_primes)
40 if (dh_primes == NULL || dh_primes->params[1] == NULL ||
41 dh_primes->params[0] == NULL)
43 return NULL;
46 return dh_primes->params;
49 int
50 _gnutls_dh_generate_prime (mpi_t * ret_g, mpi_t * ret_n, unsigned int bits)
52 mpi_t g = NULL, prime = NULL;
53 gcry_error_t err;
54 int result, times = 0, qbits;
55 mpi_t *factors = NULL;
57 /* Calculate the size of a prime factor of (prime-1)/2.
58 * This is an emulation of the values in "Selecting Cryptographic Key Sizes" paper.
60 if (bits < 256)
61 qbits = bits / 2;
62 else
64 qbits = (bits/40) + 105;
67 if (qbits & 1) /* better have an even number */
68 qbits++;
70 /* find a prime number of size bits.
75 if (times)
77 _gnutls_mpi_release (&prime);
78 gcry_prime_release_factors (factors);
81 err = gcry_prime_generate (&prime, bits, qbits,
82 &factors, NULL, NULL, GCRY_STRONG_RANDOM,
83 GCRY_PRIME_FLAG_SPECIAL_FACTOR);
85 if (err != 0)
87 gnutls_assert ();
88 result = GNUTLS_E_INTERNAL_ERROR;
89 goto cleanup;
92 err = gcry_prime_check (prime, 0);
94 times++;
96 while (err != 0 && times < 10);
98 if (err != 0)
100 gnutls_assert ();
101 result = GNUTLS_E_INTERNAL_ERROR;
102 goto cleanup;
105 /* generate the group generator.
107 err = gcry_prime_group_generator (&g, prime, factors, NULL);
108 if (err != 0)
110 gnutls_assert ();
111 result = GNUTLS_E_INTERNAL_ERROR;
112 goto cleanup;
115 gcry_prime_release_factors (factors);
116 factors = NULL;
118 if (ret_g)
119 *ret_g = g;
120 else
121 _gnutls_mpi_release (&g);
122 if (ret_n)
123 *ret_n = prime;
124 else
125 _gnutls_mpi_release (&prime);
127 return 0;
129 cleanup:
130 gcry_prime_release_factors (factors);
131 _gnutls_mpi_release (&g);
132 _gnutls_mpi_release (&prime);
134 return result;
138 /* Replaces the prime in the static DH parameters, with a randomly
139 * generated one.
142 * gnutls_dh_params_import_raw - import DH parameters
143 * @dh_params: Is a structure that will hold the prime numbers
144 * @prime: holds the new prime
145 * @generator: holds the new generator
147 * This function will replace the pair of prime and generator for use in
148 * the Diffie-Hellman key exchange. The new parameters should be stored in the
149 * appropriate gnutls_datum.
153 gnutls_dh_params_import_raw (gnutls_dh_params_t dh_params,
154 const gnutls_datum_t * prime,
155 const gnutls_datum_t * generator)
157 mpi_t tmp_prime, tmp_g;
158 size_t siz;
160 siz = prime->size;
161 if (_gnutls_mpi_scan_nz (&tmp_prime, prime->data, &siz))
163 gnutls_assert ();
164 return GNUTLS_E_MPI_SCAN_FAILED;
167 siz = generator->size;
168 if (_gnutls_mpi_scan_nz (&tmp_g, generator->data, &siz))
170 _gnutls_mpi_release (&tmp_prime);
171 gnutls_assert ();
172 return GNUTLS_E_MPI_SCAN_FAILED;
175 /* store the generated values
177 dh_params->params[0] = tmp_prime;
178 dh_params->params[1] = tmp_g;
180 return 0;
185 * gnutls_dh_params_init - initialize the DH parameters
186 * @dh_params: Is a structure that will hold the prime numbers
188 * This function will initialize the DH parameters structure.
192 gnutls_dh_params_init (gnutls_dh_params_t * dh_params)
195 (*dh_params) = gnutls_calloc (1, sizeof (dh_params_st));
196 if (*dh_params == NULL)
198 gnutls_assert ();
199 return GNUTLS_E_MEMORY_ERROR;
202 return 0;
207 * gnutls_dh_params_deinit - deinitialize the DH parameters
208 * @dh_params: Is a structure that holds the prime numbers
210 * This function will deinitialize the DH parameters structure.
213 void
214 gnutls_dh_params_deinit (gnutls_dh_params_t dh_params)
216 if (dh_params == NULL)
217 return;
219 _gnutls_mpi_release (&dh_params->params[0]);
220 _gnutls_mpi_release (&dh_params->params[1]);
222 gnutls_free (dh_params);
227 * gnutls_dh_params_cpy - copy a DH parameters structure
228 * @dst: Is the destination structure, which should be initialized.
229 * @src: Is the source structure
231 * This function will copy the DH parameters structure from source
232 * to destination.
236 gnutls_dh_params_cpy (gnutls_dh_params_t dst, gnutls_dh_params_t src)
238 if (src == NULL)
239 return GNUTLS_E_INVALID_REQUEST;
241 dst->params[0] = _gnutls_mpi_copy (src->params[0]);
242 dst->params[1] = _gnutls_mpi_copy (src->params[1]);
244 if (dst->params[0] == NULL || dst->params[1] == NULL)
245 return GNUTLS_E_MEMORY_ERROR;
247 return 0;
252 * gnutls_dh_params_generate2 - generate new DH parameters
253 * @params: Is the structure that the DH parameters will be stored
254 * @bits: is the prime's number of bits
256 * This function will generate a new pair of prime and generator for use in
257 * the Diffie-Hellman key exchange. The new parameters will be allocated using
258 * gnutls_malloc() and will be stored in the appropriate datum.
259 * This function is normally slow.
261 * Note that the bits value should be one of 768, 1024, 2048, 3072 or 4096.
262 * Also note that the DH parameters are only useful to servers.
263 * Since clients use the parameters sent by the server, it's of
264 * no use to call this in client side.
268 gnutls_dh_params_generate2 (gnutls_dh_params_t params, unsigned int bits)
270 int ret;
272 ret = _gnutls_dh_generate_prime (&params->params[1],
273 &params->params[0], bits);
274 if (ret < 0)
276 gnutls_assert ();
277 return ret;
280 return 0;
284 * gnutls_dh_params_import_pkcs3 - import DH params from a pkcs3 structure
285 * @params: A structure where the parameters will be copied to
286 * @pkcs3_params: should contain a PKCS3 DHParams structure PEM or DER encoded
287 * @format: the format of params. PEM or DER.
289 * This function will extract the DHParams found in a PKCS3 formatted
290 * structure. This is the format generated by "openssl dhparam" tool.
292 * If the structure is PEM encoded, it should have a header
293 * of "BEGIN DH PARAMETERS".
295 * In case of failure a negative value will be returned, and
296 * 0 on success.
300 gnutls_dh_params_import_pkcs3 (gnutls_dh_params_t params,
301 const gnutls_datum_t * pkcs3_params,
302 gnutls_x509_crt_fmt_t format)
304 ASN1_TYPE c2;
305 int result, need_free = 0;
306 gnutls_datum_t _params;
308 if (format == GNUTLS_X509_FMT_PEM)
310 opaque *out;
312 result = _gnutls_fbase64_decode ("DH PARAMETERS",
313 pkcs3_params->data,
314 pkcs3_params->size, &out);
316 if (result <= 0)
318 if (result == 0)
319 result = GNUTLS_E_INTERNAL_ERROR;
320 gnutls_assert ();
321 return result;
324 _params.data = out;
325 _params.size = result;
327 need_free = 1;
330 else
332 _params.data = pkcs3_params->data;
333 _params.size = pkcs3_params->size;
336 if ((result = asn1_create_element
337 (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2))
338 != ASN1_SUCCESS)
340 gnutls_assert ();
341 if (need_free != 0)
343 gnutls_free (_params.data);
344 _params.data = NULL;
346 return _gnutls_asn2err (result);
349 result = asn1_der_decoding (&c2, _params.data, _params.size, NULL);
351 if (need_free != 0)
353 gnutls_free (_params.data);
354 _params.data = NULL;
357 if (result != ASN1_SUCCESS)
359 /* couldn't decode DER */
361 _gnutls_x509_log ("DHParams: Decoding error %d\n", result);
362 gnutls_assert ();
363 asn1_delete_structure (&c2);
364 return _gnutls_asn2err (result);
367 /* Read PRIME
369 result = _gnutls_x509_read_int (c2, "prime", &params->params[0]);
370 if (result < 0)
372 asn1_delete_structure (&c2);
373 gnutls_assert ();
374 return result;
377 /* read the generator
379 result = _gnutls_x509_read_int (c2, "base", &params->params[1]);
380 if (result < 0)
382 asn1_delete_structure (&c2);
383 _gnutls_mpi_release (&params->params[0]);
384 gnutls_assert ();
385 return result;
388 asn1_delete_structure (&c2);
390 return 0;
394 * gnutls_dh_params_export_pkcs3 - export DH params to a pkcs3 structure
395 * @params: Holds the DH parameters
396 * @format: the format of output params. One of PEM or DER.
397 * @params_data: will contain a PKCS3 DHParams structure PEM or DER encoded
398 * @params_data_size: holds the size of params_data (and will be replaced by the actual size of parameters)
400 * This function will export the given dh parameters to a PKCS3
401 * DHParams structure. This is the format generated by "openssl dhparam" tool.
402 * If the buffer provided is not long enough to hold the output, then
403 * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
405 * If the structure is PEM encoded, it will have a header
406 * of "BEGIN DH PARAMETERS".
408 * In case of failure a negative value will be returned, and
409 * 0 on success.
413 gnutls_dh_params_export_pkcs3 (gnutls_dh_params_t params,
414 gnutls_x509_crt_fmt_t format,
415 unsigned char *params_data,
416 size_t * params_data_size)
418 ASN1_TYPE c2;
419 int result, _params_data_size;
420 size_t g_size, p_size;
421 opaque *p_data, *g_data;
422 opaque *all_data;
424 _gnutls_mpi_print_lz (NULL, &g_size, params->params[1]);
425 _gnutls_mpi_print_lz (NULL, &p_size, params->params[0]);
427 all_data = gnutls_malloc (g_size + p_size);
428 if (all_data == NULL)
430 gnutls_assert ();
431 return GNUTLS_E_MEMORY_ERROR;
434 p_data = &all_data[0];
435 g_data = &all_data[p_size];
437 _gnutls_mpi_print_lz (p_data, &p_size, params->params[0]);
438 _gnutls_mpi_print_lz (g_data, &g_size, params->params[1]);
440 /* Ok. Now we have the data. Create the asn1 structures
443 if ((result = asn1_create_element
444 (_gnutls_get_gnutls_asn (), "GNUTLS.DHParameter", &c2))
445 != ASN1_SUCCESS)
447 gnutls_assert ();
448 gnutls_free (all_data);
449 return _gnutls_asn2err (result);
452 /* Write PRIME
454 if ((result = asn1_write_value (c2, "prime",
455 p_data, p_size)) != ASN1_SUCCESS)
457 gnutls_assert ();
458 gnutls_free (all_data);
459 asn1_delete_structure (&c2);
460 return _gnutls_asn2err (result);
463 /* Write the GENERATOR
465 if ((result = asn1_write_value (c2, "base",
466 g_data, g_size)) != ASN1_SUCCESS)
468 gnutls_assert ();
469 gnutls_free (all_data);
470 asn1_delete_structure (&c2);
471 return _gnutls_asn2err (result);
474 gnutls_free (all_data);
476 if ((result = asn1_write_value (c2, "privateValueLength",
477 NULL, 0)) != ASN1_SUCCESS)
479 gnutls_assert ();
480 asn1_delete_structure (&c2);
481 return _gnutls_asn2err (result);
484 if (format == GNUTLS_X509_FMT_DER)
486 if (params_data == NULL)
487 *params_data_size = 0;
489 _params_data_size = *params_data_size;
490 result =
491 asn1_der_coding (c2, "", params_data, &_params_data_size, NULL);
492 *params_data_size = _params_data_size;
493 asn1_delete_structure (&c2);
495 if (result != ASN1_SUCCESS)
497 gnutls_assert ();
498 if (result == ASN1_MEM_ERROR)
499 return GNUTLS_E_SHORT_MEMORY_BUFFER;
501 return _gnutls_asn2err (result);
505 else
506 { /* PEM */
507 opaque *tmp;
508 opaque *out;
509 int len;
511 len = 0;
512 asn1_der_coding (c2, "", NULL, &len, NULL);
514 tmp = gnutls_malloc (len);
515 if (tmp == NULL)
517 gnutls_assert ();
518 asn1_delete_structure (&c2);
519 return GNUTLS_E_MEMORY_ERROR;
522 if ((result =
523 asn1_der_coding (c2, "", tmp, &len, NULL)) != ASN1_SUCCESS)
525 gnutls_assert ();
526 gnutls_free (tmp);
527 asn1_delete_structure (&c2);
528 return _gnutls_asn2err (result);
531 asn1_delete_structure (&c2);
533 result = _gnutls_fbase64_encode ("DH PARAMETERS", tmp, len, &out);
535 gnutls_free (tmp);
537 if (result < 0)
539 gnutls_assert ();
540 return result;
543 if (result == 0)
544 { /* oooops */
545 gnutls_assert ();
546 gnutls_free (out);
547 return GNUTLS_E_INTERNAL_ERROR;
550 if ((unsigned) result + 1 > *params_data_size)
552 gnutls_assert ();
553 gnutls_free (out);
554 *params_data_size = result + 1;
555 return GNUTLS_E_SHORT_MEMORY_BUFFER;
558 *params_data_size = result;
560 if (params_data)
562 memcpy (params_data, out, result);
563 params_data[result] = 0;
565 gnutls_free (out);
569 return 0;
573 * gnutls_dh_params_export_raw - export the raw DH parameters
574 * @params: Holds the DH parameters
575 * @prime: will hold the new prime
576 * @generator: will hold the new generator
577 * @bits: if non null will hold is the prime's number of bits
579 * This function will export the pair of prime and generator for use in
580 * the Diffie-Hellman key exchange. The new parameters will be allocated using
581 * gnutls_malloc() and will be stored in the appropriate datum.
585 gnutls_dh_params_export_raw (gnutls_dh_params_t params,
586 gnutls_datum_t * prime,
587 gnutls_datum_t * generator, unsigned int *bits)
590 size_t size;
592 if (params->params[1] == NULL || params->params[0] == NULL)
594 gnutls_assert ();
595 return GNUTLS_E_INVALID_REQUEST;
598 size = 0;
599 _gnutls_mpi_print (NULL, &size, params->params[1]);
601 generator->data = gnutls_malloc (size);
602 if (generator->data == NULL)
604 return GNUTLS_E_MEMORY_ERROR;
607 generator->size = size;
608 _gnutls_mpi_print (generator->data, &size, params->params[1]);
611 size = 0;
612 _gnutls_mpi_print (NULL, &size, params->params[0]);
614 prime->data = gnutls_malloc (size);
615 if (prime->data == NULL)
617 gnutls_free (generator->data);
618 generator->data = NULL;
619 return GNUTLS_E_MEMORY_ERROR;
621 prime->size = size;
622 _gnutls_mpi_print (prime->data, &size, params->params[0]);
624 if (bits)
625 *bits = _gnutls_mpi_get_nbits (params->params[0]);
627 return 0;