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