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 */
dhm_read_bignum(mbedtls_mpi * X,unsigned char ** p,const unsigned char * end)42 static int dhm_read_bignum(mbedtls_mpi *X,
43 unsigned char **p,
44 const unsigned char *end)
45 {
46 int ret, n;
47
48 if (end - *p < 2) {
49 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
50 }
51
52 n = MBEDTLS_GET_UINT16_BE(*p, 0);
53 (*p) += 2;
54
55 if ((size_t) (end - *p) < (size_t) n) {
56 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
57 }
58
59 if ((ret = mbedtls_mpi_read_binary(X, *p, n)) != 0) {
60 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED, ret);
61 }
62
63 (*p) += n;
64
65 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 */
dhm_check_range(const mbedtls_mpi * param,const mbedtls_mpi * P)80 static int dhm_check_range(const mbedtls_mpi *param, const mbedtls_mpi *P)
81 {
82 mbedtls_mpi U;
83 int ret = 0;
84
85 mbedtls_mpi_init(&U);
86
87 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&U, P, 2));
88
89 if (mbedtls_mpi_cmp_int(param, 2) < 0 ||
90 mbedtls_mpi_cmp_mpi(param, &U) > 0) {
91 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
92 }
93
94 cleanup:
95 mbedtls_mpi_free(&U);
96 return ret;
97 }
98
mbedtls_dhm_init(mbedtls_dhm_context * ctx)99 void mbedtls_dhm_init(mbedtls_dhm_context *ctx)
100 {
101 memset(ctx, 0, sizeof(mbedtls_dhm_context));
102 }
103
mbedtls_dhm_get_bitlen(const mbedtls_dhm_context * ctx)104 size_t mbedtls_dhm_get_bitlen(const mbedtls_dhm_context *ctx)
105 {
106 return mbedtls_mpi_bitlen(&ctx->P);
107 }
108
mbedtls_dhm_get_len(const mbedtls_dhm_context * ctx)109 size_t mbedtls_dhm_get_len(const mbedtls_dhm_context *ctx)
110 {
111 return mbedtls_mpi_size(&ctx->P);
112 }
113
mbedtls_dhm_get_value(const mbedtls_dhm_context * ctx,mbedtls_dhm_parameter param,mbedtls_mpi * dest)114 int mbedtls_dhm_get_value(const mbedtls_dhm_context *ctx,
115 mbedtls_dhm_parameter param,
116 mbedtls_mpi *dest)
117 {
118 const mbedtls_mpi *src = NULL;
119 switch (param) {
120 case MBEDTLS_DHM_PARAM_P:
121 src = &ctx->P;
122 break;
123 case MBEDTLS_DHM_PARAM_G:
124 src = &ctx->G;
125 break;
126 case MBEDTLS_DHM_PARAM_X:
127 src = &ctx->X;
128 break;
129 case MBEDTLS_DHM_PARAM_GX:
130 src = &ctx->GX;
131 break;
132 case MBEDTLS_DHM_PARAM_GY:
133 src = &ctx->GY;
134 break;
135 case MBEDTLS_DHM_PARAM_K:
136 src = &ctx->K;
137 break;
138 default:
139 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
140 }
141 return mbedtls_mpi_copy(dest, src);
142 }
143
144 /*
145 * Parse the ServerKeyExchange parameters
146 */
mbedtls_dhm_read_params(mbedtls_dhm_context * ctx,unsigned char ** p,const unsigned char * end)147 int mbedtls_dhm_read_params(mbedtls_dhm_context *ctx,
148 unsigned char **p,
149 const unsigned char *end)
150 {
151 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
152
153 if ((ret = dhm_read_bignum(&ctx->P, p, end)) != 0 ||
154 (ret = dhm_read_bignum(&ctx->G, p, end)) != 0 ||
155 (ret = dhm_read_bignum(&ctx->GY, p, end)) != 0) {
156 return ret;
157 }
158
159 if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
160 return ret;
161 }
162
163 return 0;
164 }
165
166 /*
167 * Pick a random R in the range [2, M-2] for blinding or key generation.
168 */
dhm_random_below(mbedtls_mpi * R,const mbedtls_mpi * M,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)169 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 MBEDTLS_MPI_CHK(mbedtls_mpi_random(R, 3, M, f_rng, p_rng));
175 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(R, R, 1));
176
177 cleanup:
178 return ret;
179 }
180
dhm_make_common(mbedtls_dhm_context * ctx,int x_size,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)181 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 int ret = 0;
186
187 if (mbedtls_mpi_cmp_int(&ctx->P, 0) == 0) {
188 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
189 }
190 if (x_size < 0) {
191 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
192 }
193
194 if ((unsigned) x_size < mbedtls_mpi_size(&ctx->P)) {
195 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 ret = dhm_random_below(&ctx->X, &ctx->P, f_rng, p_rng);
199 if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
200 return MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED;
201 }
202 if (ret != 0) {
203 return ret;
204 }
205 }
206
207 /*
208 * Calculate GX = G^X mod P
209 */
210 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->GX, &ctx->G, &ctx->X,
211 &ctx->P, &ctx->RP));
212
213 if ((ret = dhm_check_range(&ctx->GX, &ctx->P)) != 0) {
214 return ret;
215 }
216
217 cleanup:
218 return ret;
219 }
220
221 /*
222 * Setup and write the ServerKeyExchange parameters
223 */
mbedtls_dhm_make_params(mbedtls_dhm_context * ctx,int x_size,unsigned char * output,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)224 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 ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
234 if (ret != 0) {
235 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 n1 = mbedtls_mpi_size(&ctx->P);
253 n2 = mbedtls_mpi_size(&ctx->G);
254 n3 = mbedtls_mpi_size(&ctx->GX);
255
256 p = output;
257 DHM_MPI_EXPORT(&ctx->P, n1);
258 DHM_MPI_EXPORT(&ctx->G, n2);
259 DHM_MPI_EXPORT(&ctx->GX, n3);
260
261 *olen = (size_t) (p - output);
262
263 cleanup:
264 if (ret != 0 && ret > -128) {
265 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED, ret);
266 }
267 return ret;
268 }
269
270 /*
271 * Set prime modulus and generator
272 */
mbedtls_dhm_set_group(mbedtls_dhm_context * ctx,const mbedtls_mpi * P,const mbedtls_mpi * G)273 int mbedtls_dhm_set_group(mbedtls_dhm_context *ctx,
274 const mbedtls_mpi *P,
275 const mbedtls_mpi *G)
276 {
277 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
278
279 if ((ret = mbedtls_mpi_copy(&ctx->P, P)) != 0 ||
280 (ret = mbedtls_mpi_copy(&ctx->G, G)) != 0) {
281 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_SET_GROUP_FAILED, ret);
282 }
283
284 return 0;
285 }
286
287 /*
288 * Import the peer's public value G^Y
289 */
mbedtls_dhm_read_public(mbedtls_dhm_context * ctx,const unsigned char * input,size_t ilen)290 int mbedtls_dhm_read_public(mbedtls_dhm_context *ctx,
291 const unsigned char *input, size_t ilen)
292 {
293 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
294
295 if (ilen < 1 || ilen > mbedtls_dhm_get_len(ctx)) {
296 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
297 }
298
299 if ((ret = mbedtls_mpi_read_binary(&ctx->GY, input, ilen)) != 0) {
300 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED, ret);
301 }
302
303 return 0;
304 }
305
306 /*
307 * Create own private value X and export G^X
308 */
mbedtls_dhm_make_public(mbedtls_dhm_context * ctx,int x_size,unsigned char * output,size_t olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)309 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 if (olen < 1 || olen > mbedtls_dhm_get_len(ctx)) {
317 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
318 }
319
320 ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
321 if (ret == MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) {
322 return MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED;
323 }
324 if (ret != 0) {
325 goto cleanup;
326 }
327
328 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->GX, output, olen));
329
330 cleanup:
331 if (ret != 0 && ret > -128) {
332 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED, ret);
333 }
334 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 */
dhm_update_blinding(mbedtls_dhm_context * ctx,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)344 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 if (mbedtls_mpi_cmp_mpi(&ctx->X, &ctx->pX) != 0) {
354 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&ctx->pX, &ctx->X));
355 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vi, 1));
356 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vf, 1));
357
358 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 if (mbedtls_mpi_cmp_int(&ctx->Vi, 1) != 0) {
366 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vi, &ctx->Vi, &ctx->Vi));
367 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->P));
368
369 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf));
370 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
371
372 return 0;
373 }
374
375 /*
376 * We need to generate blinding values from scratch
377 */
378
379 /* Vi = random( 2, P-2 ) */
380 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 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(NULL, &ctx->Vf, &ctx->Vi, &ctx->P));
384 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP));
385
386 cleanup:
387 return ret;
388 }
389
390 /*
391 * Derive and export the shared secret (G^Y)^X mod P
392 */
mbedtls_dhm_calc_secret(mbedtls_dhm_context * ctx,unsigned char * output,size_t output_size,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)393 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 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
399 mbedtls_mpi GYb;
400
401 if (f_rng == NULL) {
402 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
403 }
404
405 if (output_size < mbedtls_dhm_get_len(ctx)) {
406 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
407 }
408
409 if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
410 return ret;
411 }
412
413 mbedtls_mpi_init(&GYb);
414
415 /* Blind peer's value */
416 MBEDTLS_MPI_CHK(dhm_update_blinding(ctx, f_rng, p_rng));
417 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&GYb, &ctx->GY, &ctx->Vi));
418 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&GYb, &GYb, &ctx->P));
419
420 /* Do modular exponentiation */
421 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->K, &GYb, &ctx->X,
422 &ctx->P, &ctx->RP));
423
424 /* Unblind secret value */
425 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->K, &ctx->K, &ctx->Vf));
426 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 *olen = mbedtls_mpi_size(&ctx->K);
431 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->K, output, *olen));
432
433 cleanup:
434 mbedtls_mpi_free(&GYb);
435
436 if (ret != 0) {
437 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED, ret);
438 }
439
440 return 0;
441 }
442
443 /*
444 * Free the components of a DHM key
445 */
mbedtls_dhm_free(mbedtls_dhm_context * ctx)446 void mbedtls_dhm_free(mbedtls_dhm_context *ctx)
447 {
448 if (ctx == NULL) {
449 return;
450 }
451
452 mbedtls_mpi_free(&ctx->pX);
453 mbedtls_mpi_free(&ctx->Vf);
454 mbedtls_mpi_free(&ctx->Vi);
455 mbedtls_mpi_free(&ctx->RP);
456 mbedtls_mpi_free(&ctx->K);
457 mbedtls_mpi_free(&ctx->GY);
458 mbedtls_mpi_free(&ctx->GX);
459 mbedtls_mpi_free(&ctx->X);
460 mbedtls_mpi_free(&ctx->G);
461 mbedtls_mpi_free(&ctx->P);
462
463 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_dhm_context));
464 }
465
466 #if defined(MBEDTLS_ASN1_PARSE_C)
467 /*
468 * Parse DHM parameters
469 */
mbedtls_dhm_parse_dhm(mbedtls_dhm_context * dhm,const unsigned char * dhmin,size_t dhminlen)470 int mbedtls_dhm_parse_dhm(mbedtls_dhm_context *dhm, const unsigned char *dhmin,
471 size_t dhminlen)
472 {
473 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 mbedtls_pem_init(&pem);
482
483 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
484 if (dhminlen == 0 || dhmin[dhminlen - 1] != '\0') {
485 ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
486 } else {
487 ret = mbedtls_pem_read_buffer(&pem,
488 "-----BEGIN DH PARAMETERS-----",
489 "-----END DH PARAMETERS-----",
490 dhmin, NULL, 0, &dhminlen);
491 }
492
493 if (ret == 0) {
494 /*
495 * Was PEM encoded
496 */
497 dhminlen = pem.buflen;
498 } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
499 goto exit;
500 }
501
502 p = (ret == 0) ? pem.buf : (unsigned char *) dhmin;
503 #else
504 p = (unsigned char *) dhmin;
505 #endif /* MBEDTLS_PEM_PARSE_C */
506 end = p + dhminlen;
507
508 /*
509 * DHParams ::= SEQUENCE {
510 * prime INTEGER, -- P
511 * generator INTEGER, -- g
512 * privateValueLength INTEGER OPTIONAL
513 * }
514 */
515 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
516 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
517 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
518 goto exit;
519 }
520
521 end = p + len;
522
523 if ((ret = mbedtls_asn1_get_mpi(&p, end, &dhm->P)) != 0 ||
524 (ret = mbedtls_asn1_get_mpi(&p, end, &dhm->G)) != 0) {
525 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
526 goto exit;
527 }
528
529 if (p != end) {
530 /* This might be the optional privateValueLength.
531 * If so, we can cleanly discard it */
532 mbedtls_mpi rec;
533 mbedtls_mpi_init(&rec);
534 ret = mbedtls_asn1_get_mpi(&p, end, &rec);
535 mbedtls_mpi_free(&rec);
536 if (ret != 0) {
537 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
538 goto exit;
539 }
540 if (p != end) {
541 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT,
542 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
543 goto exit;
544 }
545 }
546
547 ret = 0;
548
549 exit:
550 #if defined(MBEDTLS_PEM_PARSE_C)
551 mbedtls_pem_free(&pem);
552 #endif
553 if (ret != 0) {
554 mbedtls_dhm_free(dhm);
555 }
556
557 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 */
load_file(const char * path,unsigned char ** buf,size_t * n)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 */
mbedtls_dhm_parse_dhmfile(mbedtls_dhm_context * dhm,const char * path)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 */
mbedtls_dhm_self_test(int verbose)666 int mbedtls_dhm_self_test(int verbose)
667 {
668 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
669 mbedtls_dhm_context dhm;
670
671 mbedtls_dhm_init(&dhm);
672
673 if (verbose != 0) {
674 mbedtls_printf(" DHM parameter load: ");
675 }
676
677 if ((ret = mbedtls_dhm_parse_dhm(&dhm,
678 (const unsigned char *) mbedtls_test_dhm_params,
679 mbedtls_test_dhm_params_len)) != 0) {
680 if (verbose != 0) {
681 mbedtls_printf("failed\n");
682 }
683
684 ret = 1;
685 goto exit;
686 }
687
688 if (verbose != 0) {
689 mbedtls_printf("passed\n\n");
690 }
691
692 exit:
693 mbedtls_dhm_free(&dhm);
694
695 return ret;
696 }
697
698 #endif /* MBEDTLS_SELF_TEST */
699
700 #endif /* MBEDTLS_DHM_C */
701