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