blob: 08870a8793bd74178510458c5b4726e10c43b973 [file] [log] [blame]
Edison Aic6672fd2018-02-28 15:01:47 +08001// SPDX-License-Identifier: Apache-2.0
Jens Wiklander817466c2018-05-22 13:49:31 +02002/*
3 * Diffie-Hellman-Merkle key exchange
4 *
5 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Jens Wiklander817466c2018-05-22 13:49:31 +02006 *
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 * This file is part of mbed TLS (https://tls.mbed.org)
20 */
21/*
22 * The following sources were referenced in the design of this implementation
23 * of the Diffie-Hellman-Merkle algorithm:
24 *
25 * [1] Handbook of Applied Cryptography - 1997, Chapter 12
26 * Menezes, van Oorschot and Vanstone
27 *
28 */
29
30#if !defined(MBEDTLS_CONFIG_FILE)
31#include "mbedtls/config.h"
32#else
33#include MBEDTLS_CONFIG_FILE
34#endif
35
36#if defined(MBEDTLS_DHM_C)
37
38#include "mbedtls/dhm.h"
Jens Wiklander3d3b0592019-03-20 15:30:29 +010039#include "mbedtls/platform_util.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020040
41#include <string.h>
42
43#if defined(MBEDTLS_PEM_PARSE_C)
44#include "mbedtls/pem.h"
45#endif
46
47#if defined(MBEDTLS_ASN1_PARSE_C)
48#include "mbedtls/asn1.h"
49#endif
50
51#if defined(MBEDTLS_PLATFORM_C)
52#include "mbedtls/platform.h"
53#else
54#include <stdlib.h>
55#include <stdio.h>
56#define mbedtls_printf printf
57#define mbedtls_calloc calloc
58#define mbedtls_free free
59#endif
60
Jens Wiklander3d3b0592019-03-20 15:30:29 +010061#if !defined(MBEDTLS_DHM_ALT)
62
63#define DHM_VALIDATE_RET( cond ) \
64 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
65#define DHM_VALIDATE( cond ) \
66 MBEDTLS_INTERNAL_VALIDATE( cond )
Jens Wiklander817466c2018-05-22 13:49:31 +020067
68/*
69 * helper to validate the mbedtls_mpi size and import it
70 */
71static int dhm_read_bignum( mbedtls_mpi *X,
72 unsigned char **p,
73 const unsigned char *end )
74{
75 int ret, n;
76
77 if( end - *p < 2 )
78 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
79
80 n = ( (*p)[0] << 8 ) | (*p)[1];
81 (*p) += 2;
82
83 if( (int)( end - *p ) < n )
84 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
85
86 if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
87 return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
88
89 (*p) += n;
90
91 return( 0 );
92}
93
94/*
95 * Verify sanity of parameter with regards to P
96 *
97 * Parameter should be: 2 <= public_param <= P - 2
98 *
Jens Wiklander3d3b0592019-03-20 15:30:29 +010099 * This means that we need to return an error if
100 * public_param < 2 or public_param > P-2
101 *
Jens Wiklander817466c2018-05-22 13:49:31 +0200102 * For more information on the attack, see:
103 * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
104 * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
105 */
106static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
107{
108 mbedtls_mpi L, U;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100109 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200110
111 mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
112
113 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
114 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
115
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100116 if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 ||
117 mbedtls_mpi_cmp_mpi( param, &U ) > 0 )
Jens Wiklander817466c2018-05-22 13:49:31 +0200118 {
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100119 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +0200120 }
121
122cleanup:
123 mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
124 return( ret );
125}
126
127void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
128{
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100129 DHM_VALIDATE( ctx != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200130 memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
131}
132
133/*
134 * Parse the ServerKeyExchange parameters
135 */
136int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
137 unsigned char **p,
138 const unsigned char *end )
139{
140 int ret;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100141 DHM_VALIDATE_RET( ctx != NULL );
142 DHM_VALIDATE_RET( p != NULL && *p != NULL );
143 DHM_VALIDATE_RET( end != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200144
145 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
146 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
147 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
148 return( ret );
149
150 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
151 return( ret );
152
153 ctx->len = mbedtls_mpi_size( &ctx->P );
154
155 return( 0 );
156}
157
158/*
159 * Setup and write the ServerKeyExchange parameters
160 */
161int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
162 unsigned char *output, size_t *olen,
163 int (*f_rng)(void *, unsigned char *, size_t),
164 void *p_rng )
165{
166 int ret, count = 0;
167 size_t n1, n2, n3;
168 unsigned char *p;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100169 DHM_VALIDATE_RET( ctx != NULL );
170 DHM_VALIDATE_RET( output != NULL );
171 DHM_VALIDATE_RET( olen != NULL );
172 DHM_VALIDATE_RET( f_rng != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200173
174 if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
175 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
176
177 /*
178 * Generate X as large as possible ( < P )
179 */
180 do
181 {
182 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
183
184 while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
185 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
186
187 if( count++ > 10 )
188 return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
189 }
190 while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
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 /*
202 * export P, G, GX
203 */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100204#define DHM_MPI_EXPORT( X, n ) \
205 do { \
206 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ), \
207 p + 2, \
208 ( n ) ) ); \
209 *p++ = (unsigned char)( ( n ) >> 8 ); \
210 *p++ = (unsigned char)( ( n ) ); \
211 p += ( n ); \
212 } while( 0 )
Jens Wiklander817466c2018-05-22 13:49:31 +0200213
214 n1 = mbedtls_mpi_size( &ctx->P );
215 n2 = mbedtls_mpi_size( &ctx->G );
216 n3 = mbedtls_mpi_size( &ctx->GX );
217
218 p = output;
219 DHM_MPI_EXPORT( &ctx->P , n1 );
220 DHM_MPI_EXPORT( &ctx->G , n2 );
221 DHM_MPI_EXPORT( &ctx->GX, n3 );
222
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100223 *olen = p - output;
Jens Wiklander817466c2018-05-22 13:49:31 +0200224
225 ctx->len = n1;
226
227cleanup:
228
229 if( ret != 0 )
230 return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
231
232 return( 0 );
233}
234
235/*
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100236 * Set prime modulus and generator
237 */
238int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
239 const mbedtls_mpi *P,
240 const mbedtls_mpi *G )
241{
242 int ret;
243 DHM_VALIDATE_RET( ctx != NULL );
244 DHM_VALIDATE_RET( P != NULL );
245 DHM_VALIDATE_RET( G != NULL );
246
247 if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
248 ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
249 {
250 return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret );
251 }
252
253 ctx->len = mbedtls_mpi_size( &ctx->P );
254 return( 0 );
255}
256
257/*
Jens Wiklander817466c2018-05-22 13:49:31 +0200258 * Import the peer's public value G^Y
259 */
260int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
261 const unsigned char *input, size_t ilen )
262{
263 int ret;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100264 DHM_VALIDATE_RET( ctx != NULL );
265 DHM_VALIDATE_RET( input != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200266
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100267 if( ilen < 1 || ilen > ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200268 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
269
270 if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
271 return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
272
273 return( 0 );
274}
275
276/*
277 * Create own private value X and export G^X
278 */
279int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
280 unsigned char *output, size_t olen,
281 int (*f_rng)(void *, unsigned char *, size_t),
282 void *p_rng )
283{
284 int ret, count = 0;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100285 DHM_VALIDATE_RET( ctx != NULL );
286 DHM_VALIDATE_RET( output != NULL );
287 DHM_VALIDATE_RET( f_rng != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200288
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100289 if( olen < 1 || olen > ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200290 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
291
292 if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
293 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
294
295 /*
296 * generate X and calculate GX = G^X mod P
297 */
298 do
299 {
300 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
301
302 while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
303 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
304
305 if( count++ > 10 )
306 return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
307 }
308 while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
309
310 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
311 &ctx->P , &ctx->RP ) );
312
313 if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
314 return( ret );
315
316 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
317
318cleanup:
319
320 if( ret != 0 )
321 return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
322
323 return( 0 );
324}
325
326/*
327 * Use the blinding method and optimisation suggested in section 10 of:
328 * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
329 * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
330 * Berlin Heidelberg, 1996. p. 104-113.
331 */
332static int dhm_update_blinding( mbedtls_dhm_context *ctx,
333 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
334{
335 int ret, count;
336
337 /*
338 * Don't use any blinding the first time a particular X is used,
339 * but remember it to use blinding next time.
340 */
341 if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
342 {
343 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
344 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
345 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
346
347 return( 0 );
348 }
349
350 /*
351 * Ok, we need blinding. Can we re-use existing values?
352 * If yes, just update them by squaring them.
353 */
354 if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
355 {
356 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
357 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
358
359 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
360 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
361
362 return( 0 );
363 }
364
365 /*
366 * We need to generate blinding values from scratch
367 */
368
369 /* Vi = random( 2, P-1 ) */
370 count = 0;
371 do
372 {
373 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) );
374
375 while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
376 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
377
378 if( count++ > 10 )
379 return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
380 }
381 while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
382
383 /* Vf = Vi^-X mod P */
384 MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
385 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
386
387cleanup:
388 return( ret );
389}
390
391/*
392 * Derive and export the shared secret (G^Y)^X mod P
393 */
394int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
395 unsigned char *output, size_t output_size, size_t *olen,
396 int (*f_rng)(void *, unsigned char *, size_t),
397 void *p_rng )
398{
399 int ret;
400 mbedtls_mpi GYb;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100401 DHM_VALIDATE_RET( ctx != NULL );
402 DHM_VALIDATE_RET( output != NULL );
403 DHM_VALIDATE_RET( olen != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200404
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100405 if( output_size < ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200406 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
407
408 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
409 return( ret );
410
411 mbedtls_mpi_init( &GYb );
412
413 /* Blind peer's value */
414 if( f_rng != NULL )
415 {
416 MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
417 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
418 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
419 }
420 else
421 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
422
423 /* Do modular exponentiation */
424 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
425 &ctx->P, &ctx->RP ) );
426
427 /* Unblind secret value */
428 if( f_rng != NULL )
429 {
430 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
431 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
432 }
433
434 *olen = mbedtls_mpi_size( &ctx->K );
435
436 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
437
438cleanup:
439 mbedtls_mpi_free( &GYb );
440
441 if( ret != 0 )
442 return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
443
444 return( 0 );
445}
446
447/*
448 * Free the components of a DHM key
449 */
450void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
451{
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100452 if( ctx == NULL )
453 return;
Jens Wiklander817466c2018-05-22 13:49:31 +0200454
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100455 mbedtls_mpi_free( &ctx->pX );
456 mbedtls_mpi_free( &ctx->Vf );
457 mbedtls_mpi_free( &ctx->Vi );
458 mbedtls_mpi_free( &ctx->RP );
459 mbedtls_mpi_free( &ctx->K );
460 mbedtls_mpi_free( &ctx->GY );
461 mbedtls_mpi_free( &ctx->GX );
462 mbedtls_mpi_free( &ctx->X );
463 mbedtls_mpi_free( &ctx->G );
464 mbedtls_mpi_free( &ctx->P );
465
466 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200467}
468
469#if defined(MBEDTLS_ASN1_PARSE_C)
470/*
471 * Parse DHM parameters
472 */
473int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
474 size_t dhminlen )
475{
476 int ret;
477 size_t len;
478 unsigned char *p, *end;
479#if defined(MBEDTLS_PEM_PARSE_C)
480 mbedtls_pem_context pem;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100481#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200482
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100483 DHM_VALIDATE_RET( dhm != NULL );
484 DHM_VALIDATE_RET( dhmin != NULL );
485
486#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200487 mbedtls_pem_init( &pem );
488
489 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
490 if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
491 ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
492 else
493 ret = mbedtls_pem_read_buffer( &pem,
494 "-----BEGIN DH PARAMETERS-----",
495 "-----END DH PARAMETERS-----",
496 dhmin, NULL, 0, &dhminlen );
497
498 if( ret == 0 )
499 {
500 /*
501 * Was PEM encoded
502 */
503 dhminlen = pem.buflen;
504 }
505 else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
506 goto exit;
507
508 p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
509#else
510 p = (unsigned char *) dhmin;
511#endif /* MBEDTLS_PEM_PARSE_C */
512 end = p + dhminlen;
513
514 /*
515 * DHParams ::= SEQUENCE {
516 * prime INTEGER, -- P
517 * generator INTEGER, -- g
518 * privateValueLength INTEGER OPTIONAL
519 * }
520 */
521 if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
522 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
523 {
524 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
525 goto exit;
526 }
527
528 end = p + len;
529
530 if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 ||
531 ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
532 {
533 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
534 goto exit;
535 }
536
537 if( p != end )
538 {
539 /* This might be the optional privateValueLength.
540 * If so, we can cleanly discard it */
541 mbedtls_mpi rec;
542 mbedtls_mpi_init( &rec );
543 ret = mbedtls_asn1_get_mpi( &p, end, &rec );
544 mbedtls_mpi_free( &rec );
545 if ( ret != 0 )
546 {
547 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
548 goto exit;
549 }
550 if ( p != end )
551 {
552 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
553 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
554 goto exit;
555 }
556 }
557
558 ret = 0;
559
560 dhm->len = mbedtls_mpi_size( &dhm->P );
561
562exit:
563#if defined(MBEDTLS_PEM_PARSE_C)
564 mbedtls_pem_free( &pem );
565#endif
566 if( ret != 0 )
567 mbedtls_dhm_free( dhm );
568
569 return( ret );
570}
571
572#if defined(MBEDTLS_FS_IO)
573/*
574 * Load all data from a file into a given buffer.
575 *
576 * The file is expected to contain either PEM or DER encoded data.
577 * A terminating null byte is always appended. It is included in the announced
578 * length only if the data looks like it is PEM encoded.
579 */
580static int load_file( const char *path, unsigned char **buf, size_t *n )
581{
582 FILE *f;
583 long size;
584
585 if( ( f = fopen( path, "rb" ) ) == NULL )
586 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
587
588 fseek( f, 0, SEEK_END );
589 if( ( size = ftell( f ) ) == -1 )
590 {
591 fclose( f );
592 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
593 }
594 fseek( f, 0, SEEK_SET );
595
596 *n = (size_t) size;
597
598 if( *n + 1 == 0 ||
599 ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
600 {
601 fclose( f );
602 return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
603 }
604
605 if( fread( *buf, 1, *n, f ) != *n )
606 {
607 fclose( f );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100608
609 mbedtls_platform_zeroize( *buf, *n + 1 );
Jens Wiklander817466c2018-05-22 13:49:31 +0200610 mbedtls_free( *buf );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100611
Jens Wiklander817466c2018-05-22 13:49:31 +0200612 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
613 }
614
615 fclose( f );
616
617 (*buf)[*n] = '\0';
618
619 if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
620 ++*n;
621
622 return( 0 );
623}
624
625/*
626 * Load and parse DHM parameters
627 */
628int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
629{
630 int ret;
631 size_t n;
632 unsigned char *buf;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100633 DHM_VALIDATE_RET( dhm != NULL );
634 DHM_VALIDATE_RET( path != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200635
636 if( ( ret = load_file( path, &buf, &n ) ) != 0 )
637 return( ret );
638
639 ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
640
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100641 mbedtls_platform_zeroize( buf, n );
Jens Wiklander817466c2018-05-22 13:49:31 +0200642 mbedtls_free( buf );
643
644 return( ret );
645}
646#endif /* MBEDTLS_FS_IO */
647#endif /* MBEDTLS_ASN1_PARSE_C */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100648#endif /* MBEDTLS_DHM_ALT */
Jens Wiklander817466c2018-05-22 13:49:31 +0200649
650#if defined(MBEDTLS_SELF_TEST)
651
Jerome Forissier5b25c762020-04-07 11:18:49 +0200652#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200653static 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";
Jerome Forissier5b25c762020-04-07 11:18:49 +0200659#else /* MBEDTLS_PEM_PARSE_C */
660static 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 */
Jens Wiklander817466c2018-05-22 13:49:31 +0200674
675static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
676
677/*
678 * Checkup routine
679 */
680int mbedtls_dhm_self_test( int verbose )
681{
682 int ret;
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
704exit:
705 mbedtls_dhm_free( &dhm );
706
707 return( ret );
708}
709
710#endif /* MBEDTLS_SELF_TEST */
711
712#endif /* MBEDTLS_DHM_C */