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