Line data Source code
1 : /*
2 : * Diffie-Hellman-Merkle key exchange
3 : *
4 : * Copyright The Mbed TLS Contributors
5 : * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 : */
7 : /*
8 : * The following sources were referenced in the design of this implementation
9 : * of the Diffie-Hellman-Merkle algorithm:
10 : *
11 : * [1] Handbook of Applied Cryptography - 1997, Chapter 12
12 : * Menezes, van Oorschot and Vanstone
13 : *
14 : */
15 :
16 : #include "common.h"
17 :
18 : #if defined(MBEDTLS_DHM_C)
19 :
20 : #include "mbedtls/dhm.h"
21 : #include "mbedtls/platform_util.h"
22 : #include "mbedtls/error.h"
23 :
24 : #include <string.h>
25 :
26 : #if defined(MBEDTLS_PEM_PARSE_C)
27 : #include "mbedtls/pem.h"
28 : #endif
29 :
30 : #if defined(MBEDTLS_ASN1_PARSE_C)
31 : #include "mbedtls/asn1.h"
32 : #endif
33 :
34 : #include "mbedtls/platform.h"
35 :
36 : #if !defined(MBEDTLS_DHM_ALT)
37 :
38 : /*
39 : * helper to validate the mbedtls_mpi size and import it
40 : */
41 0 : static int dhm_read_bignum(mbedtls_mpi *X,
42 : unsigned char **p,
43 : const unsigned char *end)
44 : {
45 : int ret, n;
46 :
47 0 : if (end - *p < 2) {
48 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
49 : }
50 :
51 0 : n = MBEDTLS_GET_UINT16_BE(*p, 0);
52 0 : (*p) += 2;
53 :
54 0 : if ((size_t) (end - *p) < (size_t) n) {
55 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
56 : }
57 :
58 0 : if ((ret = mbedtls_mpi_read_binary(X, *p, n)) != 0) {
59 0 : return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED, ret);
60 : }
61 :
62 0 : (*p) += n;
63 :
64 0 : return 0;
65 : }
66 :
67 : /*
68 : * Verify sanity of parameter with regards to P
69 : *
70 : * Parameter should be: 2 <= public_param <= P - 2
71 : *
72 : * This means that we need to return an error if
73 : * public_param < 2 or public_param > P-2
74 : *
75 : * For more information on the attack, see:
76 : * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
77 : * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
78 : */
79 4 : static int dhm_check_range(const mbedtls_mpi *param, const mbedtls_mpi *P)
80 : {
81 : mbedtls_mpi U;
82 4 : int ret = 0;
83 :
84 4 : mbedtls_mpi_init(&U);
85 :
86 4 : MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&U, P, 2));
87 :
88 8 : if (mbedtls_mpi_cmp_int(param, 2) < 0 ||
89 4 : mbedtls_mpi_cmp_mpi(param, &U) > 0) {
90 0 : ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
91 : }
92 :
93 4 : cleanup:
94 4 : mbedtls_mpi_free(&U);
95 4 : return ret;
96 : }
97 :
98 2 : void mbedtls_dhm_init(mbedtls_dhm_context *ctx)
99 : {
100 2 : memset(ctx, 0, sizeof(mbedtls_dhm_context));
101 2 : }
102 :
103 0 : size_t mbedtls_dhm_get_bitlen(const mbedtls_dhm_context *ctx)
104 : {
105 0 : return mbedtls_mpi_bitlen(&ctx->P);
106 : }
107 :
108 6 : size_t mbedtls_dhm_get_len(const mbedtls_dhm_context *ctx)
109 : {
110 6 : return mbedtls_mpi_size(&ctx->P);
111 : }
112 :
113 0 : int mbedtls_dhm_get_value(const mbedtls_dhm_context *ctx,
114 : mbedtls_dhm_parameter param,
115 : mbedtls_mpi *dest)
116 : {
117 0 : const mbedtls_mpi *src = NULL;
118 0 : switch (param) {
119 0 : case MBEDTLS_DHM_PARAM_P:
120 0 : src = &ctx->P;
121 0 : break;
122 0 : case MBEDTLS_DHM_PARAM_G:
123 0 : src = &ctx->G;
124 0 : break;
125 0 : case MBEDTLS_DHM_PARAM_X:
126 0 : src = &ctx->X;
127 0 : break;
128 0 : case MBEDTLS_DHM_PARAM_GX:
129 0 : src = &ctx->GX;
130 0 : break;
131 0 : case MBEDTLS_DHM_PARAM_GY:
132 0 : src = &ctx->GY;
133 0 : break;
134 0 : case MBEDTLS_DHM_PARAM_K:
135 0 : src = &ctx->K;
136 0 : break;
137 0 : default:
138 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
139 : }
140 0 : return mbedtls_mpi_copy(dest, src);
141 : }
142 :
143 : /*
144 : * Parse the ServerKeyExchange parameters
145 : */
146 0 : int mbedtls_dhm_read_params(mbedtls_dhm_context *ctx,
147 : unsigned char **p,
148 : const unsigned char *end)
149 : {
150 0 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
151 :
152 0 : if ((ret = dhm_read_bignum(&ctx->P, p, end)) != 0 ||
153 0 : (ret = dhm_read_bignum(&ctx->G, p, end)) != 0 ||
154 0 : (ret = dhm_read_bignum(&ctx->GY, p, end)) != 0) {
155 0 : return ret;
156 : }
157 :
158 0 : if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
159 0 : return ret;
160 : }
161 :
162 0 : return 0;
163 : }
164 :
165 : /*
166 : * Pick a random R in the range [2, M-2] for blinding or key generation.
167 : */
168 2 : static int dhm_random_below(mbedtls_mpi *R, const mbedtls_mpi *M,
169 : int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
170 : {
171 : int ret;
172 :
173 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_random(R, 3, M, f_rng, p_rng));
174 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(R, R, 1));
175 :
176 2 : cleanup:
177 2 : return ret;
178 : }
179 :
180 2 : static int dhm_make_common(mbedtls_dhm_context *ctx, int x_size,
181 : int (*f_rng)(void *, unsigned char *, size_t),
182 : void *p_rng)
183 : {
184 2 : int ret = 0;
185 :
186 2 : if (mbedtls_mpi_cmp_int(&ctx->P, 0) == 0) {
187 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
188 : }
189 2 : if (x_size < 0) {
190 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
191 : }
192 :
193 2 : if ((unsigned) x_size < mbedtls_mpi_size(&ctx->P)) {
194 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&ctx->X, x_size, f_rng, p_rng));
195 : } else {
196 : /* Generate X as large as possible ( <= P - 2 ) */
197 2 : ret = dhm_random_below(&ctx->X, &ctx->P, f_rng, p_rng);
198 2 : if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
199 0 : return MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED;
200 : }
201 2 : if (ret != 0) {
202 0 : return ret;
203 : }
204 : }
205 :
206 : /*
207 : * Calculate GX = G^X mod P
208 : */
209 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->GX, &ctx->G, &ctx->X,
210 : &ctx->P, &ctx->RP));
211 :
212 2 : if ((ret = dhm_check_range(&ctx->GX, &ctx->P)) != 0) {
213 0 : return ret;
214 : }
215 :
216 2 : cleanup:
217 2 : return ret;
218 : }
219 :
220 : /*
221 : * Setup and write the ServerKeyExchange parameters
222 : */
223 0 : int mbedtls_dhm_make_params(mbedtls_dhm_context *ctx, int x_size,
224 : unsigned char *output, size_t *olen,
225 : int (*f_rng)(void *, unsigned char *, size_t),
226 : void *p_rng)
227 : {
228 : int ret;
229 : size_t n1, n2, n3;
230 : unsigned char *p;
231 :
232 0 : ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
233 0 : if (ret != 0) {
234 0 : goto cleanup;
235 : }
236 :
237 : /*
238 : * Export P, G, GX. RFC 5246 §4.4 states that "leading zero octets are
239 : * not required". We omit leading zeros for compactness.
240 : */
241 : #define DHM_MPI_EXPORT(X, n) \
242 : do { \
243 : MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary((X), \
244 : p + 2, \
245 : (n))); \
246 : *p++ = MBEDTLS_BYTE_1(n); \
247 : *p++ = MBEDTLS_BYTE_0(n); \
248 : p += (n); \
249 : } while (0)
250 :
251 0 : n1 = mbedtls_mpi_size(&ctx->P);
252 0 : n2 = mbedtls_mpi_size(&ctx->G);
253 0 : n3 = mbedtls_mpi_size(&ctx->GX);
254 :
255 0 : p = output;
256 0 : DHM_MPI_EXPORT(&ctx->P, n1);
257 0 : DHM_MPI_EXPORT(&ctx->G, n2);
258 0 : DHM_MPI_EXPORT(&ctx->GX, n3);
259 :
260 0 : *olen = (size_t) (p - output);
261 :
262 0 : cleanup:
263 0 : if (ret != 0 && ret > -128) {
264 0 : ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED, ret);
265 : }
266 0 : return ret;
267 : }
268 :
269 : /*
270 : * Set prime modulus and generator
271 : */
272 0 : int mbedtls_dhm_set_group(mbedtls_dhm_context *ctx,
273 : const mbedtls_mpi *P,
274 : const mbedtls_mpi *G)
275 : {
276 0 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
277 :
278 0 : if ((ret = mbedtls_mpi_copy(&ctx->P, P)) != 0 ||
279 0 : (ret = mbedtls_mpi_copy(&ctx->G, G)) != 0) {
280 0 : return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_SET_GROUP_FAILED, ret);
281 : }
282 :
283 0 : return 0;
284 : }
285 :
286 : /*
287 : * Import the peer's public value G^Y
288 : */
289 2 : int mbedtls_dhm_read_public(mbedtls_dhm_context *ctx,
290 : const unsigned char *input, size_t ilen)
291 : {
292 2 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
293 :
294 2 : if (ilen < 1 || ilen > mbedtls_dhm_get_len(ctx)) {
295 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
296 : }
297 :
298 2 : if ((ret = mbedtls_mpi_read_binary(&ctx->GY, input, ilen)) != 0) {
299 0 : return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED, ret);
300 : }
301 :
302 2 : return 0;
303 : }
304 :
305 : /*
306 : * Create own private value X and export G^X
307 : */
308 2 : int mbedtls_dhm_make_public(mbedtls_dhm_context *ctx, int x_size,
309 : unsigned char *output, size_t olen,
310 : int (*f_rng)(void *, unsigned char *, size_t),
311 : void *p_rng)
312 : {
313 : int ret;
314 :
315 2 : if (olen < 1 || olen > mbedtls_dhm_get_len(ctx)) {
316 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
317 : }
318 :
319 2 : ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
320 2 : if (ret == MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) {
321 0 : return MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED;
322 : }
323 2 : if (ret != 0) {
324 0 : goto cleanup;
325 : }
326 :
327 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->GX, output, olen));
328 :
329 2 : cleanup:
330 2 : if (ret != 0 && ret > -128) {
331 0 : ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED, ret);
332 : }
333 2 : return ret;
334 : }
335 :
336 :
337 : /*
338 : * Use the blinding method and optimisation suggested in section 10 of:
339 : * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
340 : * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
341 : * Berlin Heidelberg, 1996. p. 104-113.
342 : */
343 2 : static int dhm_update_blinding(mbedtls_dhm_context *ctx,
344 : int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
345 : {
346 : int ret;
347 : mbedtls_mpi R;
348 :
349 2 : mbedtls_mpi_init(&R);
350 :
351 : /*
352 : * Don't use any blinding the first time a particular X is used,
353 : * but remember it to use blinding next time.
354 : */
355 2 : if (mbedtls_mpi_cmp_mpi(&ctx->X, &ctx->pX) != 0) {
356 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&ctx->pX, &ctx->X));
357 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vi, 1));
358 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vf, 1));
359 :
360 2 : return 0;
361 : }
362 :
363 : /*
364 : * Ok, we need blinding. Can we re-use existing values?
365 : * If yes, just update them by squaring them.
366 : */
367 0 : if (mbedtls_mpi_cmp_int(&ctx->Vi, 1) != 0) {
368 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vi, &ctx->Vi, &ctx->Vi));
369 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->P));
370 :
371 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf));
372 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
373 :
374 0 : return 0;
375 : }
376 :
377 : /*
378 : * We need to generate blinding values from scratch
379 : */
380 :
381 : /* Vi = random( 2, P-2 ) */
382 0 : MBEDTLS_MPI_CHK(dhm_random_below(&ctx->Vi, &ctx->P, f_rng, p_rng));
383 :
384 : /* Vf = Vi^-X mod P
385 : * First compute Vi^-1 = R * (R Vi)^-1, (avoiding leaks from inv_mod),
386 : * then elevate to the Xth power. */
387 0 : MBEDTLS_MPI_CHK(dhm_random_below(&R, &ctx->P, f_rng, p_rng));
388 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vi, &R));
389 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
390 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&ctx->Vf, &ctx->Vf, &ctx->P));
391 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &R));
392 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
393 :
394 0 : MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP));
395 :
396 0 : cleanup:
397 0 : mbedtls_mpi_free(&R);
398 :
399 0 : return ret;
400 : }
401 :
402 : /*
403 : * Derive and export the shared secret (G^Y)^X mod P
404 : */
405 2 : int mbedtls_dhm_calc_secret(mbedtls_dhm_context *ctx,
406 : unsigned char *output, size_t output_size, size_t *olen,
407 : int (*f_rng)(void *, unsigned char *, size_t),
408 : void *p_rng)
409 : {
410 2 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
411 : mbedtls_mpi GYb;
412 :
413 2 : if (f_rng == NULL) {
414 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
415 : }
416 :
417 2 : if (output_size < mbedtls_dhm_get_len(ctx)) {
418 0 : return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
419 : }
420 :
421 2 : if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
422 0 : return ret;
423 : }
424 :
425 2 : mbedtls_mpi_init(&GYb);
426 :
427 : /* Blind peer's value */
428 2 : MBEDTLS_MPI_CHK(dhm_update_blinding(ctx, f_rng, p_rng));
429 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&GYb, &ctx->GY, &ctx->Vi));
430 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&GYb, &GYb, &ctx->P));
431 :
432 : /* Do modular exponentiation */
433 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->K, &GYb, &ctx->X,
434 : &ctx->P, &ctx->RP));
435 :
436 : /* Unblind secret value */
437 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->K, &ctx->K, &ctx->Vf));
438 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->K, &ctx->K, &ctx->P));
439 :
440 : /* Output the secret without any leading zero byte. This is mandatory
441 : * for TLS per RFC 5246 §8.1.2. */
442 2 : *olen = mbedtls_mpi_size(&ctx->K);
443 2 : MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->K, output, *olen));
444 :
445 2 : cleanup:
446 2 : mbedtls_mpi_free(&GYb);
447 :
448 2 : if (ret != 0) {
449 0 : return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED, ret);
450 : }
451 :
452 2 : return 0;
453 : }
454 :
455 : /*
456 : * Free the components of a DHM key
457 : */
458 2 : void mbedtls_dhm_free(mbedtls_dhm_context *ctx)
459 : {
460 2 : if (ctx == NULL) {
461 0 : return;
462 : }
463 :
464 2 : mbedtls_mpi_free(&ctx->pX);
465 2 : mbedtls_mpi_free(&ctx->Vf);
466 2 : mbedtls_mpi_free(&ctx->Vi);
467 2 : mbedtls_mpi_free(&ctx->RP);
468 2 : mbedtls_mpi_free(&ctx->K);
469 2 : mbedtls_mpi_free(&ctx->GY);
470 2 : mbedtls_mpi_free(&ctx->GX);
471 2 : mbedtls_mpi_free(&ctx->X);
472 2 : mbedtls_mpi_free(&ctx->G);
473 2 : mbedtls_mpi_free(&ctx->P);
474 :
475 2 : mbedtls_platform_zeroize(ctx, sizeof(mbedtls_dhm_context));
476 : }
477 :
478 : #if defined(MBEDTLS_ASN1_PARSE_C)
479 : /*
480 : * Parse DHM parameters
481 : */
482 0 : int mbedtls_dhm_parse_dhm(mbedtls_dhm_context *dhm, const unsigned char *dhmin,
483 : size_t dhminlen)
484 : {
485 0 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
486 : size_t len;
487 : unsigned char *p, *end;
488 : #if defined(MBEDTLS_PEM_PARSE_C)
489 : mbedtls_pem_context pem;
490 : #endif /* MBEDTLS_PEM_PARSE_C */
491 :
492 : #if defined(MBEDTLS_PEM_PARSE_C)
493 0 : mbedtls_pem_init(&pem);
494 :
495 : /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
496 0 : if (dhminlen == 0 || dhmin[dhminlen - 1] != '\0') {
497 0 : ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
498 : } else {
499 0 : ret = mbedtls_pem_read_buffer(&pem,
500 : "-----BEGIN DH PARAMETERS-----",
501 : "-----END DH PARAMETERS-----",
502 : dhmin, NULL, 0, &dhminlen);
503 : }
504 :
505 0 : if (ret == 0) {
506 : /*
507 : * Was PEM encoded
508 : */
509 0 : dhminlen = pem.buflen;
510 0 : } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
511 0 : goto exit;
512 : }
513 :
514 0 : p = (ret == 0) ? pem.buf : (unsigned char *) dhmin;
515 : #else
516 : p = (unsigned char *) dhmin;
517 : #endif /* MBEDTLS_PEM_PARSE_C */
518 0 : end = p + dhminlen;
519 :
520 : /*
521 : * DHParams ::= SEQUENCE {
522 : * prime INTEGER, -- P
523 : * generator INTEGER, -- g
524 : * privateValueLength INTEGER OPTIONAL
525 : * }
526 : */
527 0 : if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
528 : MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
529 0 : ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
530 0 : goto exit;
531 : }
532 :
533 0 : end = p + len;
534 :
535 0 : if ((ret = mbedtls_asn1_get_mpi(&p, end, &dhm->P)) != 0 ||
536 0 : (ret = mbedtls_asn1_get_mpi(&p, end, &dhm->G)) != 0) {
537 0 : ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
538 0 : goto exit;
539 : }
540 :
541 0 : if (p != end) {
542 : /* This might be the optional privateValueLength.
543 : * If so, we can cleanly discard it */
544 : mbedtls_mpi rec;
545 0 : mbedtls_mpi_init(&rec);
546 0 : ret = mbedtls_asn1_get_mpi(&p, end, &rec);
547 0 : mbedtls_mpi_free(&rec);
548 0 : if (ret != 0) {
549 0 : ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
550 0 : goto exit;
551 : }
552 0 : if (p != end) {
553 0 : ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT,
554 : MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
555 0 : goto exit;
556 : }
557 : }
558 :
559 0 : ret = 0;
560 :
561 0 : exit:
562 : #if defined(MBEDTLS_PEM_PARSE_C)
563 0 : mbedtls_pem_free(&pem);
564 : #endif
565 0 : if (ret != 0) {
566 0 : mbedtls_dhm_free(dhm);
567 : }
568 :
569 0 : return ret;
570 : }
571 :
572 : #if defined(MBEDTLS_FS_IO)
573 : /*
574 : * Load all data from a file into a given buffer.
575 : *
576 : * The file is expected to contain either PEM or DER encoded data.
577 : * A terminating null byte is always appended. It is included in the announced
578 : * length only if the data looks like it is PEM encoded.
579 : */
580 : static int load_file(const char *path, unsigned char **buf, size_t *n)
581 : {
582 : FILE *f;
583 : long size;
584 :
585 : if ((f = fopen(path, "rb")) == NULL) {
586 : return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
587 : }
588 : /* The data loaded here is public, so don't bother disabling buffering. */
589 :
590 : fseek(f, 0, SEEK_END);
591 : if ((size = ftell(f)) == -1) {
592 : fclose(f);
593 : return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
594 : }
595 : fseek(f, 0, SEEK_SET);
596 :
597 : *n = (size_t) size;
598 :
599 : if (*n + 1 == 0 ||
600 : (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
601 : fclose(f);
602 : return MBEDTLS_ERR_DHM_ALLOC_FAILED;
603 : }
604 :
605 : if (fread(*buf, 1, *n, f) != *n) {
606 : fclose(f);
607 :
608 : mbedtls_zeroize_and_free(*buf, *n + 1);
609 :
610 : return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
611 : }
612 :
613 : fclose(f);
614 :
615 : (*buf)[*n] = '\0';
616 :
617 : if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
618 : ++*n;
619 : }
620 :
621 : return 0;
622 : }
623 :
624 : /*
625 : * Load and parse DHM parameters
626 : */
627 : int mbedtls_dhm_parse_dhmfile(mbedtls_dhm_context *dhm, const char *path)
628 : {
629 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
630 : size_t n;
631 : unsigned char *buf;
632 :
633 : if ((ret = load_file(path, &buf, &n)) != 0) {
634 : return ret;
635 : }
636 :
637 : ret = mbedtls_dhm_parse_dhm(dhm, buf, n);
638 :
639 : mbedtls_zeroize_and_free(buf, n);
640 :
641 : return ret;
642 : }
643 : #endif /* MBEDTLS_FS_IO */
644 : #endif /* MBEDTLS_ASN1_PARSE_C */
645 : #endif /* MBEDTLS_DHM_ALT */
646 :
647 : #if defined(MBEDTLS_SELF_TEST)
648 :
649 : #if defined(MBEDTLS_PEM_PARSE_C)
650 : static const char mbedtls_test_dhm_params[] =
651 : "-----BEGIN DH PARAMETERS-----\r\n"
652 : "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
653 : "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
654 : "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
655 : "-----END DH PARAMETERS-----\r\n";
656 : #else /* MBEDTLS_PEM_PARSE_C */
657 : static const char mbedtls_test_dhm_params[] = {
658 : 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
659 : 0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
660 : 0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
661 : 0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
662 : 0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
663 : 0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
664 : 0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
665 : 0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
666 : 0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
667 : 0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
668 : 0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
669 : 0x49, 0x75, 0xb3, 0x02, 0x01, 0x02
670 : };
671 : #endif /* MBEDTLS_PEM_PARSE_C */
672 :
673 : static const size_t mbedtls_test_dhm_params_len = sizeof(mbedtls_test_dhm_params);
674 :
675 : /*
676 : * Checkup routine
677 : */
678 0 : int mbedtls_dhm_self_test(int verbose)
679 : {
680 0 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
681 : mbedtls_dhm_context dhm;
682 :
683 0 : mbedtls_dhm_init(&dhm);
684 :
685 0 : if (verbose != 0) {
686 0 : mbedtls_printf(" DHM parameter load: ");
687 : }
688 :
689 0 : if ((ret = mbedtls_dhm_parse_dhm(&dhm,
690 : (const unsigned char *) mbedtls_test_dhm_params,
691 : mbedtls_test_dhm_params_len)) != 0) {
692 0 : if (verbose != 0) {
693 0 : mbedtls_printf("failed\n");
694 : }
695 :
696 0 : ret = 1;
697 0 : goto exit;
698 : }
699 :
700 0 : if (verbose != 0) {
701 0 : mbedtls_printf("passed\n\n");
702 : }
703 :
704 0 : exit:
705 0 : mbedtls_dhm_free(&dhm);
706 :
707 0 : return ret;
708 : }
709 :
710 : #endif /* MBEDTLS_SELF_TEST */
711 :
712 : #endif /* MBEDTLS_DHM_C */
|