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