1 /*
2  * Copyright (c) 2001-2022, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "mbedtls/build_info.h"
8 
9 #if defined(MBEDTLS_DHM_C)
10 #if defined(MBEDTLS_DHM_ALT)
11 #include <string.h>
12 
13 #if defined(MBEDTLS_PEM_PARSE_C)
14 #include "mbedtls/pem.h"
15 #endif
16 
17 #if defined(MBEDTLS_ASN1_PARSE_C)
18 #include "mbedtls/asn1.h"
19 #endif
20 
21 #define mbedtls_calloc    calloc
22 #define mbedtls_free       free
23 
24 /* include pki.h for using HW Exponentiation function */
25 #include "cc_bitops.h"
26 #include "cc_common_math.h"
27 #include "cc_pal_types.h"
28 #include "cc_pal_mem.h"
29 #include "dhm_alt.h"
30 #include "pka.h"
31 #include "pki.h"
32 
33 /* Implementation that should never be optimized out by the compiler */
mbedtls_zeroize(void * v,size_t n)34 static void mbedtls_zeroize( void *v, size_t n ) {
35     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
36 }
37 
38 /*
39  * helper to validate the mbedtls_mpi size and import it
40  */
dhm_read_bignum(mbedtls_mpi * X,unsigned char ** p,const unsigned char * end)41 static int dhm_read_bignum( mbedtls_mpi *X,
42                             unsigned char **p,
43                             const unsigned char *end )
44 {
45     int ret, n;
46 
47     if( end - *p < 2 )
48         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
49 
50     n = ( (*p)[0] << 8 ) | (*p)[1];
51     (*p) += 2;
52 
53     if( (int)( end - *p ) < n )
54         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
55 
56     if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
57         return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
58 
59     (*p) += n;
60 
61     return( 0 );
62 }
63 
64 /*
65  * Verify sanity of parameter with regards to P
66  *
67  * Parameter should be: 2 <= public_param <= P - 2
68  *
69  * For more information on the attack, see:
70  *  http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
71  *  http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
72  */
dhm_check_range(const mbedtls_mpi * param,const mbedtls_mpi * P)73 static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
74 {
75     mbedtls_mpi L, U;
76     int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
77 
78     mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
79 
80     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
81     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
82 
83     if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 &&
84         mbedtls_mpi_cmp_mpi( param, &U ) <= 0 ) {
85         ret = 0;
86     }
87 
88 cleanup:
89     mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
90     return( ret );
91 }
92 
93 
94 #define EXP_MOD_HW 1
95 #ifdef EXP_MOD_HW
96 
97 /**
98  *  Execute modular exponentiation using ARM HW PKA.
99  *
100  *  Notes: Assumed all parameters are checked before calling this function.
101  *         All sizes aligned to 32-bit words, leading zeros are present if exist.
102  *         Values of A and E should be less than modulus size.
103  *         PKA registers used: r0,r1,r2,r3,r4, r30,r31.
104  *
105  *
106  * @return  no return value
107  */
108 
mbedtls_mpi_exp_mod_hw(mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * E,const mbedtls_mpi * N,mbedtls_mpi * _RR)109 static int mbedtls_mpi_exp_mod_hw(
110         mbedtls_mpi *X/*out*/, const mbedtls_mpi *A/*in*/, const mbedtls_mpi *E/*in*/,
111         const mbedtls_mpi *N/*in*/, mbedtls_mpi *_RR/*in*/ )
112 {
113     int err = 0;
114     uint32_t n_size_bits, a_size_bits;
115     uint32_t n_len_words, a_len_words;
116     mbedtls_mpi T;
117 
118     mbedtls_mpi_init( &T );
119 
120     /* compare range of input parameters */
121     if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) {
122         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
123     }
124     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) {
125         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
126     }
127 
128     /* get actual length of A and N in bits and words */
129     a_size_bits = mbedtls_mpi_bitlen( A );
130     n_size_bits = mbedtls_mpi_bitlen( N );
131     n_len_words = CALC_FULL_32BIT_WORDS( n_size_bits );
132     a_len_words = CALC_FULL_32BIT_WORDS( a_size_bits );
133 
134     /* if prime N size is very small or very big (not meets to HW PKA and standards requirements),
135      * then use SW mbedtls function. These exceptions are not important for real practic.  */
136     if( n_size_bits < PKA_MIN_OPERATION_SIZE_BITS || n_size_bits > PKA_MAX_OPERATION_SIZE_BITS ) {
137           err = mbedtls_mpi_exp_mod( X, A, E, N, _RR );
138           goto End;
139     }
140 
141     /* allocate positive X  */
142     err = mbedtls_mpi_grow( X, N->n/* + 1*/ );
143     X->s = 1;
144 
145     if ( err != 0 ) {
146         goto End;
147     }
148 
149     /* if needed reduce A according to its sign and modulus N and then
150        perform exponentiation using PKA HW. */
151     if( a_size_bits > n_size_bits ) {
152         err = mbedtls_mpi_grow( &T, N->n/* + 1*/ );
153         if ( err != 0 ) {
154             goto End;
155         }
156         /* reduction by modulus P using PKA. */
157         err = PkiLongNumDiv( A->p, a_len_words, N->p, n_len_words, T.p/*ModRes*/, NULL/*DivRes*/ );
158         if (err != 0) {
159             goto End;
160         }
161 
162         /* execute exponentiation on PKA HW */
163         err = PkiExecModExpLeW( X->p/*out*/, T.p/*in*/, n_len_words, N->p/*modulus*/, n_size_bits, E->p, E->n );
164         if ( err != 0 ) {
165             goto End;
166         }
167     }
168     /* exponentiation without reduction */
169     else {
170         /* execute exponentiation on PKA HW */
171         err = PkiExecModExpLeW( X->p/*out*/, A->p/*in*/, a_len_words, N->p/*modulus*/, n_size_bits, E->p, E->n );
172         if ( err != 0 ) {
173             goto End;
174         }
175     }
176 
177     /* modular correction for negative base A */
178     if( ( A->s == -1 )  && ( E->n != 0 ) && (( E->p[0] & 1 ) != 0) )
179     {
180         X->s = -1;
181         err = mbedtls_mpi_add_mpi( X, N, X );
182         if ( err != 0 ) {
183             goto End;
184         }
185     }
186 
187 
188 End:
189 
190     if(err) {
191         mbedtls_zeroize( X->p, X->n );
192     }
193     mbedtls_mpi_free(&T);
194 
195     return err;
196 
197 }
198 #else
199 #define mbedtls_mpi_exp_mod_hw mbedtls_mpi_exp_mod
200 #endif
201 
mbedtls_dhm_init(mbedtls_dhm_context * ctx)202 void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
203 {
204     if (NULL == ctx)
205     {
206         CC_PalAbort("ctx cannot be NULL");
207     }
208 
209     CC_PalMemSetZero(ctx, sizeof(mbedtls_dhm_context));
210 
211 }
212 
213 /*
214  * Parse the ServerKeyExchange parameters
215  */
mbedtls_dhm_read_params(mbedtls_dhm_context * ctx,unsigned char ** p,const unsigned char * end)216 int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
217                      unsigned char **p,
218                      const unsigned char *end )
219 {
220     int ret;
221     if ( (ctx == NULL) ||
222          (p == NULL) ||
223          (end == NULL) ) {
224         return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
225     }
226     if (*p == NULL) {
227         return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
228     }
229 
230     if( ( ret = dhm_read_bignum( &ctx->P,  p, end ) ) != 0 ||
231         ( ret = dhm_read_bignum( &ctx->G,  p, end ) ) != 0 ||
232         ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ){
233         return( ret );
234     }
235 
236     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ){
237         return( ret );
238     }
239 
240     ctx->len = mbedtls_mpi_size( &ctx->P );
241 
242     return( 0 );
243 }
244 
245 /*
246  * Setup and write the ServerKeyExchange parameters
247  */
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)248 int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
249                      unsigned char *output, size_t *olen,
250                      int (*f_rng)(void *, unsigned char *, size_t),
251                      void *p_rng )
252 {
253     int ret, count = 0;
254     size_t n1, n2, n3;
255     unsigned char *p;
256 
257     if ( (ctx == NULL) || (output == NULL) || (olen == NULL) ||
258          (f_rng == NULL) || (p_rng == NULL)) {
259         return MBEDTLS_ERR_DHM_BAD_INPUT_DATA ;
260     }
261     /*
262      * x size must be less or equal to size of P
263      */
264     if ((x_size > (int)mbedtls_mpi_size(&ctx->P)) || (x_size <= 0)){
265         return MBEDTLS_ERR_DHM_BAD_INPUT_DATA ;
266     }
267 
268     if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ){
269         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
270     }
271     /*
272      * Generate X as large as possible ( < P )
273      */
274     do
275     {
276         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
277 
278         while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
279             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
280 
281         if( count++ > 10 )
282             return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
283     }
284     while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
285 
286     /*
287      * Calculate GX = G^X mod P
288      */
289     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod_hw( &ctx->GX, &ctx->G, &ctx->X,
290                           &ctx->P , &ctx->RP ) );
291     if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ){
292         return( ret );
293     }
294     /*
295      * export P, G, GX
296      */
297 #define DHM_MPI_EXPORT(X,n)                     \
298     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \
299     *p++ = (unsigned char)( n >> 8 );           \
300     *p++ = (unsigned char)( n      ); p += n;
301 
302     n1 = mbedtls_mpi_size( &ctx->P  );
303     n2 = mbedtls_mpi_size( &ctx->G  );
304     n3 = mbedtls_mpi_size( &ctx->GX );
305 
306     p = output;
307     DHM_MPI_EXPORT( &ctx->P , n1 );
308     DHM_MPI_EXPORT( &ctx->G , n2 );
309     DHM_MPI_EXPORT( &ctx->GX, n3 );
310 
311     *olen  = p - output;
312 
313     ctx->len = n1;
314 
315 cleanup:
316 
317     if( ret != 0 ){
318         return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
319     }
320     return( 0 );
321 }
322 
323 /*
324  * Set prime modulus and generator
325  */
mbedtls_dhm_set_group(mbedtls_dhm_context * ctx,const mbedtls_mpi * P,const mbedtls_mpi * G)326 int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
327                            const mbedtls_mpi *P,
328                            const mbedtls_mpi *G )
329 {
330     int ret;
331 
332     if( ctx == NULL || P == NULL || G == NULL )
333         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
334 
335     if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
336         ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
337     {
338         return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret );
339     }
340 
341     ctx->len = mbedtls_mpi_size( &ctx->P );
342     return( 0 );
343 }
344 
345 /*
346  * Import the peer's public value G^Y
347  */
mbedtls_dhm_read_public(mbedtls_dhm_context * ctx,const unsigned char * input,size_t ilen)348 int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
349                      const unsigned char *input, size_t ilen )
350 {
351     int ret;
352 
353     if( ctx == NULL || input == NULL || ilen < 1 || ilen > ctx->len )
354         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
355 
356     if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
357         return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
358 
359     return( 0 );
360 }
361 
362 /*
363  * Create own private value X and export G^X
364  */
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)365 int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
366                      unsigned char *output, size_t olen,
367                      int (*f_rng)(void *, unsigned char *, size_t),
368                      void *p_rng )
369 {
370     int ret, count = 0;
371 
372     if( ctx == NULL || output == NULL || f_rng == NULL || p_rng ==NULL || olen < ctx->len )
373         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
374     if( (x_size > (int)ctx->len ) || (x_size <= 0))
375         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
376 
377     if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
378         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
379 
380     /*
381      * generate X and calculate GX = G^X mod P
382      */
383     do
384     {
385         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
386 
387         while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
388             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
389 
390         if( count++ > 10 )
391             return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
392     }
393     while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
394 
395     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod_hw( &ctx->GX, &ctx->G, &ctx->X,
396                           &ctx->P , &ctx->RP ) );
397 
398     if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
399         return( ret );
400 
401     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
402 
403 cleanup:
404 
405     if( ret != 0 )
406         return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
407 
408     return( 0 );
409 }
410 
411 /*
412  * Use the blinding method and optimisation suggested in section 10 of:
413  *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
414  *  DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
415  *  Berlin Heidelberg, 1996. p. 104-113.
416  */
dhm_update_blinding(mbedtls_dhm_context * ctx,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)417 static int dhm_update_blinding( mbedtls_dhm_context *ctx,
418                     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
419 {
420     int ret, count;
421 
422     /*
423      * Don't use any blinding the first time a particular X is used,
424      * but remember it to use blinding next time.
425      */
426     if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
427     {
428         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
429         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
430         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
431 
432         return( 0 );
433     }
434 
435     /*
436      * Ok, we need blinding. Can we re-use existing values?
437      * If yes, just update them by squaring them.
438      */
439     if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
440     {
441         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
442         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
443 
444         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
445         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
446 
447         return( 0 );
448     }
449 
450     /*
451      * We need to generate blinding values from scratch
452      */
453 
454     /* Vi = random( 2, P-1 ) */
455     count = 0;
456     do
457     {
458         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) );
459 
460         while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
461             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
462 
463         if( count++ > 10 )
464             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
465     }
466     while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
467 
468     /* Vf = Vi^-X mod P */
469     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
470     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod_hw( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
471 
472 cleanup:
473     return( ret );
474 }
475 
476 /*
477  * Derive and export the shared secret (G^Y)^X mod P
478  */
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)479 int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
480                      unsigned char *output, size_t output_size, size_t *olen,
481                      int (*f_rng)(void *, unsigned char *, size_t),
482                      void *p_rng )
483 {
484     int ret;
485     mbedtls_mpi GYb;
486 
487     if( ctx == NULL || output == NULL || olen == NULL || output_size < ctx->len )
488         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
489 
490     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) {
491         return( ret );
492     }
493 
494     mbedtls_mpi_init( &GYb );
495 
496     /* Blind peer's value */
497     if( f_rng != NULL )
498     {
499         MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
500         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
501         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
502     }
503     else
504         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
505 
506     /* Do modular exponentiation */
507     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod_hw( &ctx->K, &GYb, &ctx->X,
508                           &ctx->P, &ctx->RP ) );
509 
510     /* Unblind secret value */
511     if( f_rng != NULL )
512     {
513        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
514        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
515     }
516 
517     *olen = mbedtls_mpi_size( &ctx->K );
518     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
519 
520 cleanup:
521     mbedtls_mpi_free( &GYb );
522     if( ret != 0 )
523         return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
524 
525     return( 0 );
526 }
527 
528 /*
529  * Free the components of a DHM key
530  */
mbedtls_dhm_free(mbedtls_dhm_context * ctx)531 void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
532 {
533     if ( ctx != NULL) {
534         mbedtls_mpi_free( &ctx->pX); mbedtls_mpi_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->Vi );
535         mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY );
536         mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->G );
537         mbedtls_mpi_free( &ctx->P );
538 
539         mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
540     }
541 }
542 
543 #if defined(MBEDTLS_ASN1_PARSE_C)
544 /*
545  * Parse DHM parameters
546  */
mbedtls_dhm_parse_dhm(mbedtls_dhm_context * dhm,const unsigned char * dhmin,size_t dhminlen)547 int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
548                    size_t dhminlen )
549 {
550     int ret;
551     size_t len;
552     unsigned char *p, *end;
553 #if defined(MBEDTLS_PEM_PARSE_C)
554     mbedtls_pem_context pem;
555 
556     mbedtls_pem_init( &pem );
557 
558     if ((dhm == NULL) || (dhmin == NULL)){
559         return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
560     }
561     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
562     if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
563         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
564     else
565         ret = mbedtls_pem_read_buffer( &pem,
566                                "-----BEGIN DH PARAMETERS-----",
567                                "-----END DH PARAMETERS-----",
568                                dhmin, NULL, 0, &dhminlen );
569 
570     if( ret == 0 )
571     {
572         /*
573          * Was PEM encoded
574          */
575         dhminlen = pem.buflen;
576     }
577     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
578         goto exit;
579 
580     p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
581 #else
582     p = (unsigned char *) dhmin;
583 #endif /* MBEDTLS_PEM_PARSE_C */
584     end = p + dhminlen;
585 
586     /*
587      *  DHParams ::= SEQUENCE {
588      *      prime              INTEGER,  -- P
589      *      generator          INTEGER,  -- g
590      *      privateValueLength INTEGER OPTIONAL
591      *  }
592      */
593     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
594             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
595     {
596         ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
597         goto exit;
598     }
599 
600     end = p + len;
601 
602     if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P  ) ) != 0 ||
603         ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
604     {
605         ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
606         goto exit;
607     }
608 
609     if( p != end )
610     {
611         /* This might be the optional privateValueLength.
612          * If so, we can cleanly discard it */
613         mbedtls_mpi rec;
614         mbedtls_mpi_init( &rec );
615         ret = mbedtls_asn1_get_mpi( &p, end, &rec );
616         mbedtls_mpi_free( &rec );
617         if ( ret != 0 )
618         {
619             ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
620             goto exit;
621         }
622         if ( p != end )
623         {
624             ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
625                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
626             goto exit;
627         }
628     }
629 
630     ret = 0;
631 
632     dhm->len = mbedtls_mpi_size( &dhm->P );
633 
634 exit:
635 #if defined(MBEDTLS_PEM_PARSE_C)
636     mbedtls_pem_free( &pem );
637 #endif
638     if( ret != 0 )
639         mbedtls_dhm_free( dhm );
640 
641     return( ret );
642 }
643 
644 #if defined(MBEDTLS_FS_IO)
645 /*
646  * Load all data from a file into a given buffer.
647  *
648  * The file is expected to contain either PEM or DER encoded data.
649  * A terminating null byte is always appended. It is included in the announced
650  * length only if the data looks like it is PEM encoded.
651  */
load_file(const char * path,unsigned char ** buf,size_t * n)652 static int load_file( const char *path, unsigned char **buf, size_t *n )
653 {
654     FILE *f;
655     long size;
656 
657     if( ( f = fopen( path, "rb" ) ) == NULL )
658         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
659 
660     fseek( f, 0, SEEK_END );
661     if( ( size = ftell( f ) ) == -1 )
662     {
663         fclose( f );
664         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
665     }
666     fseek( f, 0, SEEK_SET );
667 
668     *n = (size_t) size;
669 
670     if( *n + 1 == 0 ||
671         ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
672     {
673         fclose( f );
674         return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
675     }
676 
677     if( fread( *buf, 1, *n, f ) != *n )
678     {
679         fclose( f );
680         mbedtls_free( *buf );
681         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
682     }
683 
684     fclose( f );
685 
686     (*buf)[*n] = '\0';
687 
688     if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
689         ++*n;
690 
691     return( 0 );
692 }
693 
694 /*
695  * Load and parse DHM parameters
696  */
mbedtls_dhm_parse_dhmfile(mbedtls_dhm_context * dhm,const char * path)697 int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
698 {
699     int ret;
700     size_t n;
701     unsigned char *buf;
702 
703     if ( (dhm == NULL) || (path == NULL) ){
704         return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
705     }
706 
707     if( ( ret = load_file( path, &buf, &n ) ) != 0 ){
708         return( ret );
709     }
710 
711     ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
712 
713     mbedtls_zeroize( buf, n );
714     mbedtls_free( buf );
715 
716     return( ret );
717 }
718 #endif /* MBEDTLS_FS_IO */
719 #endif /* MBEDTLS_ASN1_PARSE_C */
720 
721 #endif /* MBEDTLS_DHM_ALT */
722 #endif /* MBEDTLS_DHM_C */
723