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