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