1 /*
2  * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3  * Copyright (C) 2017 Red Hat, 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 License
20  * along with this program.  If not, see <https://www.gnu.org/licenses/>
21  *
22  */
23 
24 #include "gnutls_int.h"
25 #include "errors.h"
26 #include <datum.h>
27 #include <x509_b64.h>		/* for PKCS3 PEM decoding */
28 #include <global.h>
29 #include <dh.h>
30 #include <pk.h>
31 #include <x509/common.h>
32 #include <gnutls/crypto.h>
33 #include "x509/x509_int.h"
34 #include <mpi.h>
35 #include "debug.h"
36 #include "state.h"
37 
38 static
set_dh_pk_params(gnutls_session_t session,bigint_t g,bigint_t p,bigint_t q,unsigned q_bits)39 int set_dh_pk_params(gnutls_session_t session, bigint_t g, bigint_t p,
40 		     bigint_t q, unsigned q_bits)
41 {
42 	/* just in case we are resuming a session */
43 	gnutls_pk_params_release(&session->key.proto.tls12.dh.params);
44 
45 	gnutls_pk_params_init(&session->key.proto.tls12.dh.params);
46 
47 	session->key.proto.tls12.dh.params.params[DH_G] = _gnutls_mpi_copy(g);
48 	if (session->key.proto.tls12.dh.params.params[DH_G] == NULL)
49 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
50 
51 	session->key.proto.tls12.dh.params.params[DH_P] = _gnutls_mpi_copy(p);
52 	if (session->key.proto.tls12.dh.params.params[DH_P] == NULL) {
53 		_gnutls_mpi_release(&session->key.proto.tls12.dh.params.params[DH_G]);
54 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
55 	}
56 
57 	if (q) {
58 		session->key.proto.tls12.dh.params.params[DH_Q] = _gnutls_mpi_copy(q);
59 		if (session->key.proto.tls12.dh.params.params[DH_Q] == NULL) {
60 			_gnutls_mpi_release(&session->key.proto.tls12.dh.params.params[DH_P]);
61 			_gnutls_mpi_release(&session->key.proto.tls12.dh.params.params[DH_G]);
62 			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
63 		}
64 	}
65 	/* include, possibly empty, q */
66 	session->key.proto.tls12.dh.params.params_nr = 3;
67 	session->key.proto.tls12.dh.params.algo = GNUTLS_PK_DH;
68 	session->key.proto.tls12.dh.params.qbits = q_bits;
69 
70 	return 0;
71 }
72 
73 /* Use all available information to decide the DH parameters to use,
74  * that being the negotiated RFC7919 group, the callback, and the
75  * provided parameters structure.
76  */
77 int
_gnutls_figure_dh_params(gnutls_session_t session,gnutls_dh_params_t dh_params,gnutls_params_function * func,gnutls_sec_param_t sec_param)78 _gnutls_figure_dh_params(gnutls_session_t session, gnutls_dh_params_t dh_params,
79 		      gnutls_params_function * func, gnutls_sec_param_t sec_param)
80 {
81 	gnutls_params_st params;
82 	bigint_t p, g, q = NULL;
83 	unsigned free_pg = 0;
84 	int ret;
85 	unsigned q_bits = 0, i;
86 	const gnutls_group_entry_st *group;
87 
88 	group = get_group(session);
89 
90 	params.deinit = 0;
91 
92 	/* if we negotiated RFC7919 FFDHE */
93 	if (group && group->pk == GNUTLS_PK_DH) {
94 		for (i=0;i<session->internals.priorities->groups.size;i++) {
95 			if (session->internals.priorities->groups.entry[i] == group) {
96 				ret = _gnutls_mpi_init_scan_nz(&p,
97 						session->internals.priorities->groups.entry[i]->prime->data,
98 						session->internals.priorities->groups.entry[i]->prime->size);
99 				if (ret < 0)
100 					return gnutls_assert_val(ret);
101 
102 				free_pg = 1;
103 
104 				ret = _gnutls_mpi_init_scan_nz(&g,
105 						session->internals.priorities->groups.entry[i]->generator->data,
106 						session->internals.priorities->groups.entry[i]->generator->size);
107 				if (ret < 0) {
108 					gnutls_assert();
109 					goto cleanup;
110 				}
111 
112 				ret = _gnutls_mpi_init_scan_nz(&q,
113 						session->internals.priorities->groups.entry[i]->q->data,
114 						session->internals.priorities->groups.entry[i]->q->size);
115 				if (ret < 0) {
116 					gnutls_assert();
117 					goto cleanup;
118 				}
119 
120 				session->internals.hsk_flags |= HSK_USED_FFDHE;
121 				q_bits = *session->internals.priorities->groups.entry[i]->q_bits;
122 				goto finished;
123 			}
124 		}
125 
126 		/* didn't find anything, that shouldn't have occurred
127 		 * as we received that extension */
128 		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
129 	} else if (sec_param) {
130 		unsigned bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param)/8;
131 
132 		for (i=0;i<session->internals.priorities->groups.size;i++) {
133 			if (!session->internals.priorities->groups.entry[i]->prime)
134 				continue;
135 
136 			if (bits <= session->internals.priorities->groups.entry[i]->prime->size) {
137 				ret = _gnutls_mpi_init_scan_nz(&p,
138 						session->internals.priorities->groups.entry[i]->prime->data,
139 						session->internals.priorities->groups.entry[i]->prime->size);
140 				if (ret < 0)
141 					return gnutls_assert_val(ret);
142 
143 				free_pg = 1;
144 
145 				ret = _gnutls_mpi_init_scan_nz(&g,
146 						session->internals.priorities->groups.entry[i]->generator->data,
147 						session->internals.priorities->groups.entry[i]->generator->size);
148 				if (ret < 0) {
149 					gnutls_assert();
150 					goto cleanup;
151 				}
152 
153 				q_bits = *session->internals.priorities->groups.entry[i]->q_bits;
154 				goto finished;
155 			}
156 		}
157 
158 	}
159 
160 	if (dh_params) {
161 		p = dh_params->params[0];
162 		g = dh_params->params[1];
163 		q_bits = dh_params->q_bits;
164 	} else if (func) {
165 		ret = func(session, GNUTLS_PARAMS_DH, &params);
166 		if (ret == 0 && params.type == GNUTLS_PARAMS_DH) {
167 			p = params.params.dh->params[0];
168 			g = params.params.dh->params[1];
169 			q_bits = params.params.dh->q_bits;
170 		} else
171 			return gnutls_assert_val(GNUTLS_E_NO_TEMPORARY_DH_PARAMS);
172 	} else
173 		return gnutls_assert_val(GNUTLS_E_NO_TEMPORARY_DH_PARAMS);
174 
175  finished:
176 	_gnutls_dh_save_group(session, g, p);
177 
178 	ret = set_dh_pk_params(session, g, p, q, q_bits);
179 	if (ret < 0) {
180 		gnutls_assert();
181 	}
182 
183  cleanup:
184 	if (free_pg) {
185 		_gnutls_mpi_release(&p);
186 		_gnutls_mpi_release(&q);
187 		_gnutls_mpi_release(&g);
188 	}
189 	if (params.deinit && params.type == GNUTLS_PARAMS_DH)
190 		gnutls_dh_params_deinit(params.params.dh);
191 
192 	return ret;
193 
194 }
195 
196 /* returns the prime and the generator of DH params.
197  */
_gnutls_dh_params_to_mpi(gnutls_dh_params_t dh_primes)198 const bigint_t *_gnutls_dh_params_to_mpi(gnutls_dh_params_t dh_primes)
199 {
200 	if (dh_primes == NULL || dh_primes->params[1] == NULL ||
201 	    dh_primes->params[0] == NULL) {
202 		return NULL;
203 	}
204 
205 	return dh_primes->params;
206 }
207 
208 
209 /**
210  * gnutls_dh_params_import_raw:
211  * @dh_params: The parameters
212  * @prime: holds the new prime
213  * @generator: holds the new generator
214  *
215  * This function will replace the pair of prime and generator for use
216  * in the Diffie-Hellman key exchange.  The new parameters should be
217  * stored in the appropriate gnutls_datum.
218  *
219  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
220  *   otherwise a negative error code is returned.
221  **/
222 int
gnutls_dh_params_import_raw(gnutls_dh_params_t dh_params,const gnutls_datum_t * prime,const gnutls_datum_t * generator)223 gnutls_dh_params_import_raw(gnutls_dh_params_t dh_params,
224 			    const gnutls_datum_t * prime,
225 			    const gnutls_datum_t * generator)
226 {
227 	return gnutls_dh_params_import_raw2(dh_params, prime, generator, 0);
228 }
229 
230 /**
231  * gnutls_dh_params_import_dsa:
232  * @dh_params: The parameters
233  * @key: holds a DSA private key
234  *
235  * This function will import the prime and generator of the DSA key for use
236  * in the Diffie-Hellman key exchange.
237  *
238  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
239  *   otherwise a negative error code is returned.
240  **/
241 int
gnutls_dh_params_import_dsa(gnutls_dh_params_t dh_params,gnutls_x509_privkey_t key)242 gnutls_dh_params_import_dsa(gnutls_dh_params_t dh_params, gnutls_x509_privkey_t key)
243 {
244 	gnutls_datum_t p, g, q;
245 	int ret;
246 
247 	ret = gnutls_x509_privkey_export_dsa_raw(key, &p, &q, &g, NULL, NULL);
248 	if (ret < 0)
249 		return gnutls_assert_val(ret);
250 
251 	ret = gnutls_dh_params_import_raw3(dh_params, &p, &q, &g);
252 
253 	gnutls_free(p.data);
254 	gnutls_free(g.data);
255 	gnutls_free(q.data);
256 
257 	return ret;
258 }
259 
260 /**
261  * gnutls_dh_params_import_raw2:
262  * @dh_params: The parameters
263  * @prime: holds the new prime
264  * @generator: holds the new generator
265  * @key_bits: the private key bits (set to zero when unknown)
266  *
267  * This function will replace the pair of prime and generator for use
268  * in the Diffie-Hellman key exchange.  The new parameters should be
269  * stored in the appropriate gnutls_datum.
270  *
271  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
272  *   otherwise a negative error code is returned.
273  **/
274 int
gnutls_dh_params_import_raw2(gnutls_dh_params_t dh_params,const gnutls_datum_t * prime,const gnutls_datum_t * generator,unsigned key_bits)275 gnutls_dh_params_import_raw2(gnutls_dh_params_t dh_params,
276 			     const gnutls_datum_t * prime,
277 			     const gnutls_datum_t * generator,
278 			     unsigned key_bits)
279 {
280 	bigint_t tmp_prime, tmp_g;
281 	size_t siz;
282 
283 	siz = prime->size;
284 	if (_gnutls_mpi_init_scan_nz(&tmp_prime, prime->data, siz)) {
285 		gnutls_assert();
286 		return GNUTLS_E_MPI_SCAN_FAILED;
287 	}
288 
289 	siz = generator->size;
290 	if (_gnutls_mpi_init_scan_nz(&tmp_g, generator->data, siz)) {
291 		_gnutls_mpi_release(&tmp_prime);
292 		gnutls_assert();
293 		return GNUTLS_E_MPI_SCAN_FAILED;
294 	}
295 
296 	/* store the generated values
297 	 */
298 	dh_params->params[0] = tmp_prime;
299 	dh_params->params[1] = tmp_g;
300 	dh_params->q_bits = key_bits;
301 
302 	return 0;
303 }
304 
305 /**
306  * gnutls_dh_params_import_raw3:
307  * @dh_params: The parameters
308  * @prime: holds the new prime
309  * @q: holds the subgroup if available, otherwise NULL
310  * @generator: holds the new generator
311  *
312  * This function will replace the pair of prime and generator for use
313  * in the Diffie-Hellman key exchange.  The new parameters should be
314  * stored in the appropriate gnutls_datum.
315  *
316  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
317  *   otherwise a negative error code is returned.
318  **/
319 int
gnutls_dh_params_import_raw3(gnutls_dh_params_t dh_params,const gnutls_datum_t * prime,const gnutls_datum_t * q,const gnutls_datum_t * generator)320 gnutls_dh_params_import_raw3(gnutls_dh_params_t dh_params,
321 			     const gnutls_datum_t * prime,
322 			     const gnutls_datum_t * q,
323 			     const gnutls_datum_t * generator)
324 {
325 	bigint_t tmp_p, tmp_g, tmp_q = NULL;
326 
327 	if (_gnutls_mpi_init_scan_nz(&tmp_p, prime->data, prime->size)) {
328 		gnutls_assert();
329 		return GNUTLS_E_MPI_SCAN_FAILED;
330 	}
331 
332 	if (_gnutls_mpi_init_scan_nz(&tmp_g, generator->data,
333 				     generator->size)) {
334 		_gnutls_mpi_release(&tmp_p);
335 		gnutls_assert();
336 		return GNUTLS_E_MPI_SCAN_FAILED;
337 	}
338 
339 	if (q) {
340 		if (_gnutls_mpi_init_scan_nz(&tmp_q, q->data, q->size)) {
341 			_gnutls_mpi_release(&tmp_p);
342 			_gnutls_mpi_release(&tmp_g);
343 			gnutls_assert();
344 			return GNUTLS_E_MPI_SCAN_FAILED;
345 		}
346 	} else if (_gnutls_fips_mode_enabled()) {
347 		/* Mandatory in FIPS mode */
348 		gnutls_assert();
349 		return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
350 	}
351 
352 	/* store the generated values
353 	 */
354 	dh_params->params[0] = tmp_p;
355 	dh_params->params[1] = tmp_g;
356 	dh_params->params[2] = tmp_q;
357 	if (tmp_q)
358 		dh_params->q_bits = _gnutls_mpi_get_nbits(tmp_q);
359 
360 	return 0;
361 }
362 
363 /**
364  * gnutls_dh_params_init:
365  * @dh_params: The parameters
366  *
367  * This function will initialize the DH parameters type.
368  *
369  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
370  *   otherwise a negative error code is returned.
371  **/
gnutls_dh_params_init(gnutls_dh_params_t * dh_params)372 int gnutls_dh_params_init(gnutls_dh_params_t * dh_params)
373 {
374 
375 	(*dh_params) = gnutls_calloc(1, sizeof(dh_params_st));
376 	if (*dh_params == NULL) {
377 		gnutls_assert();
378 		return GNUTLS_E_MEMORY_ERROR;
379 	}
380 
381 	return 0;
382 
383 }
384 
385 /**
386  * gnutls_dh_params_deinit:
387  * @dh_params: The parameters
388  *
389  * This function will deinitialize the DH parameters type.
390  **/
gnutls_dh_params_deinit(gnutls_dh_params_t dh_params)391 void gnutls_dh_params_deinit(gnutls_dh_params_t dh_params)
392 {
393 	if (dh_params == NULL)
394 		return;
395 
396 	_gnutls_mpi_release(&dh_params->params[0]);
397 	_gnutls_mpi_release(&dh_params->params[1]);
398 	_gnutls_mpi_release(&dh_params->params[2]);
399 
400 	gnutls_free(dh_params);
401 
402 }
403 
404 /**
405  * gnutls_dh_params_cpy:
406  * @dst: Is the destination parameters, which should be initialized.
407  * @src: Is the source parameters
408  *
409  * This function will copy the DH parameters structure from source
410  * to destination. The destination should be already initialized.
411  *
412  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
413  *   otherwise a negative error code is returned.
414  **/
gnutls_dh_params_cpy(gnutls_dh_params_t dst,gnutls_dh_params_t src)415 int gnutls_dh_params_cpy(gnutls_dh_params_t dst, gnutls_dh_params_t src)
416 {
417 	if (src == NULL)
418 		return GNUTLS_E_INVALID_REQUEST;
419 
420 	dst->params[0] = _gnutls_mpi_copy(src->params[0]);
421 	dst->params[1] = _gnutls_mpi_copy(src->params[1]);
422 	if (src->params[2])
423 		dst->params[2] = _gnutls_mpi_copy(src->params[2]);
424 	dst->q_bits = src->q_bits;
425 
426 	if (dst->params[0] == NULL || dst->params[1] == NULL)
427 		return GNUTLS_E_MEMORY_ERROR;
428 
429 	return 0;
430 }
431 
432 
433 /**
434  * gnutls_dh_params_generate2:
435  * @dparams: The parameters
436  * @bits: is the prime's number of bits
437  *
438  * This function will generate a new pair of prime and generator for use in
439  * the Diffie-Hellman key exchange. This may take long time.
440  *
441  * It is recommended not to set the number of bits directly, but
442  * use gnutls_sec_param_to_pk_bits() instead.
443 
444  * Also note that the DH parameters are only useful to servers.
445  * Since clients use the parameters sent by the server, it's of
446  * no use to call this in client side.
447  *
448  * The parameters generated are of the DSA form. It also is possible
449  * to generate provable parameters (following the Shawe-Taylor
450  * algorithm), using gnutls_x509_privkey_generate2() with DSA option
451  * and the %GNUTLS_PRIVKEY_FLAG_PROVABLE flag set. These can the
452  * be imported with gnutls_dh_params_import_dsa().
453  *
454  * It is no longer recommended for applications to generate parameters.
455  * See the "Parameter generation" section in the manual.
456  *
457  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
458  *   otherwise a negative error code is returned.
459  **/
460 int
gnutls_dh_params_generate2(gnutls_dh_params_t dparams,unsigned int bits)461 gnutls_dh_params_generate2(gnutls_dh_params_t dparams, unsigned int bits)
462 {
463 	int ret;
464 	gnutls_pk_params_st params;
465 
466 	gnutls_pk_params_init(&params);
467 
468 	ret = _gnutls_pk_generate_params(GNUTLS_PK_DH, bits, &params);
469 	if (ret < 0)
470 		return gnutls_assert_val(ret);
471 
472 	dparams->params[0] = params.params[DSA_P];
473 	dparams->params[1] = params.params[DSA_G];
474 	dparams->q_bits = _gnutls_mpi_get_nbits(params.params[DSA_Q]);
475 
476 	_gnutls_mpi_release(&params.params[DSA_Q]);
477 
478 	return 0;
479 }
480 
481 /**
482  * gnutls_dh_params_import_pkcs3:
483  * @params: The parameters
484  * @pkcs3_params: should contain a PKCS3 DHParams structure PEM or DER encoded
485  * @format: the format of params. PEM or DER.
486  *
487  * This function will extract the DHParams found in a PKCS3 formatted
488  * structure. This is the format generated by "openssl dhparam" tool.
489  *
490  * If the structure is PEM encoded, it should have a header
491  * of "BEGIN DH PARAMETERS".
492  *
493  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
494  *   otherwise a negative error code is returned.
495  **/
496 int
gnutls_dh_params_import_pkcs3(gnutls_dh_params_t params,const gnutls_datum_t * pkcs3_params,gnutls_x509_crt_fmt_t format)497 gnutls_dh_params_import_pkcs3(gnutls_dh_params_t params,
498 			      const gnutls_datum_t * pkcs3_params,
499 			      gnutls_x509_crt_fmt_t format)
500 {
501 	ASN1_TYPE c2;
502 	int result, need_free = 0;
503 	unsigned int q_bits;
504 	gnutls_datum_t _params;
505 
506 	if (format == GNUTLS_X509_FMT_PEM) {
507 
508 		result = _gnutls_fbase64_decode("DH PARAMETERS",
509 						pkcs3_params->data,
510 						pkcs3_params->size,
511 						&_params);
512 
513 		if (result < 0) {
514 			gnutls_assert();
515 			return result;
516 		}
517 
518 		need_free = 1;
519 	} else {
520 		_params.data = pkcs3_params->data;
521 		_params.size = pkcs3_params->size;
522 	}
523 
524 	if ((result = asn1_create_element
525 	     (_gnutls_get_gnutls_asn(), "GNUTLS.DHParameter", &c2))
526 	    != ASN1_SUCCESS) {
527 		gnutls_assert();
528 		if (need_free != 0) {
529 			gnutls_free(_params.data);
530 			_params.data = NULL;
531 		}
532 		return _gnutls_asn2err(result);
533 	}
534 
535 	/* PKCS#3 doesn't specify whether DHParameter is encoded as
536 	 * BER or DER, thus we don't restrict libtasn1 to DER subset */
537 	result = asn1_der_decoding(&c2, _params.data, _params.size, NULL);
538 
539 	if (need_free != 0) {
540 		gnutls_free(_params.data);
541 		_params.data = NULL;
542 	}
543 
544 	if (result != ASN1_SUCCESS) {
545 		/* couldn't decode DER */
546 
547 		_gnutls_debug_log("DHParams: Decoding error %d\n", result);
548 		gnutls_assert();
549 		asn1_delete_structure(&c2);
550 		return _gnutls_asn2err(result);
551 	}
552 
553 	/* Read q length */
554 	result = _gnutls_x509_read_uint(c2, "privateValueLength", &q_bits);
555 	if (result < 0) {
556 		gnutls_assert();
557 		params->q_bits = 0;
558 	} else
559 		params->q_bits = q_bits;
560 
561 	/* Read PRIME
562 	 */
563 	result = _gnutls_x509_read_int(c2, "prime", &params->params[0]);
564 	if (result < 0) {
565 		asn1_delete_structure(&c2);
566 		gnutls_assert();
567 		return result;
568 	}
569 
570 	if (_gnutls_mpi_cmp_ui(params->params[0], 0) == 0) {
571 		asn1_delete_structure(&c2);
572 		return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
573 	}
574 
575 	/* read the generator
576 	 */
577 	result = _gnutls_x509_read_int(c2, "base", &params->params[1]);
578 	if (result < 0) {
579 		asn1_delete_structure(&c2);
580 		_gnutls_mpi_release(&params->params[0]);
581 		gnutls_assert();
582 		return result;
583 	}
584 
585 	if (_gnutls_mpi_cmp_ui(params->params[1], 0) == 0) {
586 		asn1_delete_structure(&c2);
587 		_gnutls_mpi_release(&params->params[0]);
588 		return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
589 	}
590 
591 	asn1_delete_structure(&c2);
592 
593 	return 0;
594 }
595 
596 /**
597  * gnutls_dh_params_export_pkcs3:
598  * @params: Holds the DH parameters
599  * @format: the format of output params. One of PEM or DER.
600  * @params_data: will contain a PKCS3 DHParams structure PEM or DER encoded
601  * @params_data_size: holds the size of params_data (and will be replaced by the actual size of parameters)
602  *
603  * This function will export the given dh parameters to a PKCS3
604  * DHParams structure. This is the format generated by "openssl dhparam" tool.
605  * If the buffer provided is not long enough to hold the output, then
606  * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
607  *
608  * If the structure is PEM encoded, it will have a header
609  * of "BEGIN DH PARAMETERS".
610  *
611  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
612  *   otherwise a negative error code is returned.
613  **/
614 int
gnutls_dh_params_export_pkcs3(gnutls_dh_params_t params,gnutls_x509_crt_fmt_t format,unsigned char * params_data,size_t * params_data_size)615 gnutls_dh_params_export_pkcs3(gnutls_dh_params_t params,
616 			      gnutls_x509_crt_fmt_t format,
617 			      unsigned char *params_data,
618 			      size_t * params_data_size)
619 {
620 	gnutls_datum_t out = {NULL, 0};
621 	int ret;
622 
623 	ret = gnutls_dh_params_export2_pkcs3(params, format, &out);
624 	if (ret < 0)
625 		return gnutls_assert_val(ret);
626 
627 	if (*params_data_size < (unsigned) out.size + 1) {
628 		gnutls_assert();
629 		gnutls_free(out.data);
630 		*params_data_size = out.size + 1;
631 		return GNUTLS_E_SHORT_MEMORY_BUFFER;
632 	}
633 
634 	assert(out.data != NULL);
635 	*params_data_size = out.size;
636 	if (params_data) {
637 		memcpy(params_data, out.data, out.size);
638 		params_data[out.size] = 0;
639 	}
640 
641 	gnutls_free(out.data);
642 
643 	return 0;
644 }
645 
646 /**
647  * gnutls_dh_params_export2_pkcs3:
648  * @params: Holds the DH parameters
649  * @format: the format of output params. One of PEM or DER.
650  * @out: will contain a PKCS3 DHParams structure PEM or DER encoded
651  *
652  * This function will export the given dh parameters to a PKCS3
653  * DHParams structure. This is the format generated by "openssl dhparam" tool.
654  * The data in @out will be allocated using gnutls_malloc().
655  *
656  * If the structure is PEM encoded, it will have a header
657  * of "BEGIN DH PARAMETERS".
658  *
659  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
660  *   otherwise a negative error code is returned.
661  *
662  * Since: 3.1.3
663  **/
664 int
gnutls_dh_params_export2_pkcs3(gnutls_dh_params_t params,gnutls_x509_crt_fmt_t format,gnutls_datum_t * out)665 gnutls_dh_params_export2_pkcs3(gnutls_dh_params_t params,
666 			       gnutls_x509_crt_fmt_t format,
667 			       gnutls_datum_t * out)
668 {
669 	ASN1_TYPE c2;
670 	int result;
671 	size_t g_size, p_size;
672 	uint8_t *p_data, *g_data;
673 	uint8_t *all_data;
674 
675 	_gnutls_mpi_print_lz(params->params[1], NULL, &g_size);
676 	_gnutls_mpi_print_lz(params->params[0], NULL, &p_size);
677 
678 	all_data = gnutls_malloc(g_size + p_size);
679 	if (all_data == NULL) {
680 		gnutls_assert();
681 		return GNUTLS_E_MEMORY_ERROR;
682 	}
683 
684 	p_data = &all_data[0];
685 	_gnutls_mpi_print_lz(params->params[0], p_data, &p_size);
686 
687 	g_data = &all_data[p_size];
688 	_gnutls_mpi_print_lz(params->params[1], g_data, &g_size);
689 
690 
691 	/* Ok. Now we have the data. Create the asn1 structures
692 	 */
693 
694 	if ((result = asn1_create_element
695 	     (_gnutls_get_gnutls_asn(), "GNUTLS.DHParameter", &c2))
696 	    != ASN1_SUCCESS) {
697 		gnutls_assert();
698 		gnutls_free(all_data);
699 		return _gnutls_asn2err(result);
700 	}
701 
702 	/* Write PRIME
703 	 */
704 	if ((result = asn1_write_value(c2, "prime",
705 				       p_data, p_size)) != ASN1_SUCCESS) {
706 		gnutls_assert();
707 		gnutls_free(all_data);
708 		asn1_delete_structure(&c2);
709 		return _gnutls_asn2err(result);
710 	}
711 
712 	if (params->q_bits > 0)
713 		result =
714 		    _gnutls_x509_write_uint32(c2, "privateValueLength",
715 					      params->q_bits);
716 	else
717 		result =
718 		    asn1_write_value(c2, "privateValueLength", NULL, 0);
719 
720 	if (result < 0) {
721 		gnutls_assert();
722 		gnutls_free(all_data);
723 		asn1_delete_structure(&c2);
724 		return _gnutls_asn2err(result);
725 	}
726 
727 	/* Write the GENERATOR
728 	 */
729 	if ((result = asn1_write_value(c2, "base",
730 				       g_data, g_size)) != ASN1_SUCCESS) {
731 		gnutls_assert();
732 		gnutls_free(all_data);
733 		asn1_delete_structure(&c2);
734 		return _gnutls_asn2err(result);
735 	}
736 
737 	gnutls_free(all_data);
738 
739 
740 	if (format == GNUTLS_X509_FMT_DER) {
741 		result = _gnutls_x509_der_encode(c2, "", out, 0);
742 
743 		asn1_delete_structure(&c2);
744 
745 		if (result < 0)
746 			return gnutls_assert_val(result);
747 
748 	} else {		/* PEM */
749 		gnutls_datum_t t;
750 
751 		result = _gnutls_x509_der_encode(c2, "", &t, 0);
752 
753 		asn1_delete_structure(&c2);
754 
755 		if (result < 0)
756 			return gnutls_assert_val(result);
757 
758 		result =
759 		    _gnutls_fbase64_encode("DH PARAMETERS", t.data, t.size,
760 					   out);
761 
762 		gnutls_free(t.data);
763 
764 		if (result < 0) {
765 			gnutls_assert();
766 			return result;
767 		}
768 	}
769 
770 	return 0;
771 }
772 
773 /**
774  * gnutls_dh_params_export_raw:
775  * @params: Holds the DH parameters
776  * @prime: will hold the new prime
777  * @generator: will hold the new generator
778  * @bits: if non null will hold the secret key's number of bits
779  *
780  * This function will export the pair of prime and generator for use
781  * in the Diffie-Hellman key exchange.  The new parameters will be
782  * allocated using gnutls_malloc() and will be stored in the
783  * appropriate datum.
784  *
785  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
786  *   otherwise a negative error code is returned.
787  **/
788 int
gnutls_dh_params_export_raw(gnutls_dh_params_t params,gnutls_datum_t * prime,gnutls_datum_t * generator,unsigned int * bits)789 gnutls_dh_params_export_raw(gnutls_dh_params_t params,
790 			    gnutls_datum_t * prime,
791 			    gnutls_datum_t * generator, unsigned int *bits)
792 {
793 	int ret;
794 
795 	if (params->params[1] == NULL || params->params[0] == NULL) {
796 		gnutls_assert();
797 		return GNUTLS_E_INVALID_REQUEST;
798 	}
799 
800 	ret = _gnutls_mpi_dprint(params->params[1], generator);
801 	if (ret < 0) {
802 		gnutls_assert();
803 		return ret;
804 	}
805 
806 	ret = _gnutls_mpi_dprint(params->params[0], prime);
807 	if (ret < 0) {
808 		gnutls_assert();
809 		_gnutls_free_datum(generator);
810 		return ret;
811 	}
812 
813 	if (bits)
814 		*bits = params->q_bits;
815 
816 	return 0;
817 
818 }
819