• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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