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