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 = ((*p)[0] << 8) | (*p)[1];
52     (*p) += 2;
53 
54     if ((int) (end - *p) < 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 = 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