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