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