xref: /optee_os/lib/libmbedtls/mbedtls/library/dhm.c (revision 19116a65b6728f04be40b827236dce7a34da49e1)
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