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