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