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