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