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