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