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