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