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