blob: 9a76fc500c8c54996926905cccfafb183457c617 [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"
Jerome Forissier11fa71b2020-04-20 17:17:56 +020040#include "mbedtls/error.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020041
42#include <string.h>
43
44#if defined(MBEDTLS_PEM_PARSE_C)
45#include "mbedtls/pem.h"
46#endif
47
48#if defined(MBEDTLS_ASN1_PARSE_C)
49#include "mbedtls/asn1.h"
50#endif
51
52#if defined(MBEDTLS_PLATFORM_C)
53#include "mbedtls/platform.h"
54#else
55#include <stdlib.h>
56#include <stdio.h>
57#define mbedtls_printf printf
58#define mbedtls_calloc calloc
59#define mbedtls_free free
60#endif
61
Jens Wiklander3d3b0592019-03-20 15:30:29 +010062#if !defined(MBEDTLS_DHM_ALT)
63
64#define DHM_VALIDATE_RET( cond ) \
65 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
66#define DHM_VALIDATE( cond ) \
67 MBEDTLS_INTERNAL_VALIDATE( cond )
Jens Wiklander817466c2018-05-22 13:49:31 +020068
69/*
70 * helper to validate the mbedtls_mpi size and import it
71 */
72static int dhm_read_bignum( mbedtls_mpi *X,
73 unsigned char **p,
74 const unsigned char *end )
75{
76 int ret, n;
77
78 if( end - *p < 2 )
79 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
80
81 n = ( (*p)[0] << 8 ) | (*p)[1];
82 (*p) += 2;
83
84 if( (int)( end - *p ) < n )
85 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
86
87 if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
88 return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
89
90 (*p) += n;
91
92 return( 0 );
93}
94
95/*
96 * Verify sanity of parameter with regards to P
97 *
98 * Parameter should be: 2 <= public_param <= P - 2
99 *
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100100 * This means that we need to return an error if
101 * public_param < 2 or public_param > P-2
102 *
Jens Wiklander817466c2018-05-22 13:49:31 +0200103 * For more information on the attack, see:
104 * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
105 * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
106 */
107static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
108{
109 mbedtls_mpi L, U;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100110 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200111
112 mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
113
114 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
115 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
116
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100117 if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 ||
118 mbedtls_mpi_cmp_mpi( param, &U ) > 0 )
Jens Wiklander817466c2018-05-22 13:49:31 +0200119 {
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100120 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +0200121 }
122
123cleanup:
124 mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
125 return( ret );
126}
127
128void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
129{
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100130 DHM_VALIDATE( ctx != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200131 memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
132}
133
134/*
135 * Parse the ServerKeyExchange parameters
136 */
137int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
138 unsigned char **p,
139 const unsigned char *end )
140{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200141 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100142 DHM_VALIDATE_RET( ctx != NULL );
143 DHM_VALIDATE_RET( p != NULL && *p != NULL );
144 DHM_VALIDATE_RET( end != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200145
146 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
147 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
148 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
149 return( ret );
150
151 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
152 return( ret );
153
154 ctx->len = mbedtls_mpi_size( &ctx->P );
155
156 return( 0 );
157}
158
159/*
160 * Setup and write the ServerKeyExchange parameters
161 */
162int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
163 unsigned char *output, size_t *olen,
164 int (*f_rng)(void *, unsigned char *, size_t),
165 void *p_rng )
166{
167 int ret, count = 0;
168 size_t n1, n2, n3;
169 unsigned char *p;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100170 DHM_VALIDATE_RET( ctx != NULL );
171 DHM_VALIDATE_RET( output != NULL );
172 DHM_VALIDATE_RET( olen != NULL );
173 DHM_VALIDATE_RET( f_rng != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200174
175 if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
176 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
177
178 /*
179 * Generate X as large as possible ( < P )
180 */
181 do
182 {
183 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
184
185 while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
186 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
187
188 if( count++ > 10 )
189 return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
190 }
191 while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
192
193 /*
194 * Calculate GX = G^X mod P
195 */
196 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
197 &ctx->P , &ctx->RP ) );
198
199 if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
200 return( ret );
201
202 /*
203 * export P, G, GX
204 */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100205#define DHM_MPI_EXPORT( X, n ) \
206 do { \
207 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ), \
208 p + 2, \
209 ( n ) ) ); \
210 *p++ = (unsigned char)( ( n ) >> 8 ); \
211 *p++ = (unsigned char)( ( n ) ); \
212 p += ( n ); \
213 } while( 0 )
Jens Wiklander817466c2018-05-22 13:49:31 +0200214
215 n1 = mbedtls_mpi_size( &ctx->P );
216 n2 = mbedtls_mpi_size( &ctx->G );
217 n3 = mbedtls_mpi_size( &ctx->GX );
218
219 p = output;
220 DHM_MPI_EXPORT( &ctx->P , n1 );
221 DHM_MPI_EXPORT( &ctx->G , n2 );
222 DHM_MPI_EXPORT( &ctx->GX, n3 );
223
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100224 *olen = p - output;
Jens Wiklander817466c2018-05-22 13:49:31 +0200225
226 ctx->len = n1;
227
228cleanup:
229
230 if( ret != 0 )
231 return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
232
233 return( 0 );
234}
235
236/*
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100237 * Set prime modulus and generator
238 */
239int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
240 const mbedtls_mpi *P,
241 const mbedtls_mpi *G )
242{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200243 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100244 DHM_VALIDATE_RET( ctx != NULL );
245 DHM_VALIDATE_RET( P != NULL );
246 DHM_VALIDATE_RET( G != NULL );
247
248 if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
249 ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
250 {
251 return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret );
252 }
253
254 ctx->len = mbedtls_mpi_size( &ctx->P );
255 return( 0 );
256}
257
258/*
Jens Wiklander817466c2018-05-22 13:49:31 +0200259 * Import the peer's public value G^Y
260 */
261int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
262 const unsigned char *input, size_t ilen )
263{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200264 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100265 DHM_VALIDATE_RET( ctx != NULL );
266 DHM_VALIDATE_RET( input != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200267
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100268 if( ilen < 1 || ilen > ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200269 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
270
271 if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
272 return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
273
274 return( 0 );
275}
276
277/*
278 * Create own private value X and export G^X
279 */
280int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
281 unsigned char *output, size_t olen,
282 int (*f_rng)(void *, unsigned char *, size_t),
283 void *p_rng )
284{
285 int ret, count = 0;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100286 DHM_VALIDATE_RET( ctx != NULL );
287 DHM_VALIDATE_RET( output != NULL );
288 DHM_VALIDATE_RET( f_rng != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200289
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100290 if( olen < 1 || olen > ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200291 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
292
293 if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
294 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
295
296 /*
297 * generate X and calculate GX = G^X mod P
298 */
299 do
300 {
301 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
302
303 while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
304 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
305
306 if( count++ > 10 )
307 return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
308 }
309 while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
310
311 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
312 &ctx->P , &ctx->RP ) );
313
314 if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
315 return( ret );
316
317 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
318
319cleanup:
320
321 if( ret != 0 )
322 return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
323
324 return( 0 );
325}
326
327/*
328 * Use the blinding method and optimisation suggested in section 10 of:
329 * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
330 * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
331 * Berlin Heidelberg, 1996. p. 104-113.
332 */
333static int dhm_update_blinding( mbedtls_dhm_context *ctx,
334 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
335{
336 int ret, count;
337
338 /*
339 * Don't use any blinding the first time a particular X is used,
340 * but remember it to use blinding next time.
341 */
342 if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
343 {
344 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
345 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
346 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
347
348 return( 0 );
349 }
350
351 /*
352 * Ok, we need blinding. Can we re-use existing values?
353 * If yes, just update them by squaring them.
354 */
355 if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
356 {
357 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
358 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
359
360 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
361 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
362
363 return( 0 );
364 }
365
366 /*
367 * We need to generate blinding values from scratch
368 */
369
370 /* Vi = random( 2, P-1 ) */
371 count = 0;
372 do
373 {
374 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) );
375
376 while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
377 MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
378
379 if( count++ > 10 )
380 return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
381 }
382 while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
383
384 /* Vf = Vi^-X mod P */
385 MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
386 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
387
388cleanup:
389 return( ret );
390}
391
392/*
393 * Derive and export the shared secret (G^Y)^X mod P
394 */
395int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
396 unsigned char *output, size_t output_size, size_t *olen,
397 int (*f_rng)(void *, unsigned char *, size_t),
398 void *p_rng )
399{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200400 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200401 mbedtls_mpi GYb;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100402 DHM_VALIDATE_RET( ctx != NULL );
403 DHM_VALIDATE_RET( output != NULL );
404 DHM_VALIDATE_RET( olen != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200405
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100406 if( output_size < ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200407 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
408
409 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
410 return( ret );
411
412 mbedtls_mpi_init( &GYb );
413
414 /* Blind peer's value */
415 if( f_rng != NULL )
416 {
417 MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
418 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
419 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
420 }
421 else
422 MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
423
424 /* Do modular exponentiation */
425 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
426 &ctx->P, &ctx->RP ) );
427
428 /* Unblind secret value */
429 if( f_rng != NULL )
430 {
431 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
432 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
433 }
434
435 *olen = mbedtls_mpi_size( &ctx->K );
436
437 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
438
439cleanup:
440 mbedtls_mpi_free( &GYb );
441
442 if( ret != 0 )
443 return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
444
445 return( 0 );
446}
447
448/*
449 * Free the components of a DHM key
450 */
451void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
452{
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100453 if( ctx == NULL )
454 return;
Jens Wiklander817466c2018-05-22 13:49:31 +0200455
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100456 mbedtls_mpi_free( &ctx->pX );
457 mbedtls_mpi_free( &ctx->Vf );
458 mbedtls_mpi_free( &ctx->Vi );
459 mbedtls_mpi_free( &ctx->RP );
460 mbedtls_mpi_free( &ctx->K );
461 mbedtls_mpi_free( &ctx->GY );
462 mbedtls_mpi_free( &ctx->GX );
463 mbedtls_mpi_free( &ctx->X );
464 mbedtls_mpi_free( &ctx->G );
465 mbedtls_mpi_free( &ctx->P );
466
467 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200468}
469
470#if defined(MBEDTLS_ASN1_PARSE_C)
471/*
472 * Parse DHM parameters
473 */
474int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
475 size_t dhminlen )
476{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200477 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200478 size_t len;
479 unsigned char *p, *end;
480#if defined(MBEDTLS_PEM_PARSE_C)
481 mbedtls_pem_context pem;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100482#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200483
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100484 DHM_VALIDATE_RET( dhm != NULL );
485 DHM_VALIDATE_RET( dhmin != NULL );
486
487#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200488 mbedtls_pem_init( &pem );
489
490 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
491 if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
492 ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
493 else
494 ret = mbedtls_pem_read_buffer( &pem,
495 "-----BEGIN DH PARAMETERS-----",
496 "-----END DH PARAMETERS-----",
497 dhmin, NULL, 0, &dhminlen );
498
499 if( ret == 0 )
500 {
501 /*
502 * Was PEM encoded
503 */
504 dhminlen = pem.buflen;
505 }
506 else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
507 goto exit;
508
509 p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
510#else
511 p = (unsigned char *) dhmin;
512#endif /* MBEDTLS_PEM_PARSE_C */
513 end = p + dhminlen;
514
515 /*
516 * DHParams ::= SEQUENCE {
517 * prime INTEGER, -- P
518 * generator INTEGER, -- g
519 * privateValueLength INTEGER OPTIONAL
520 * }
521 */
522 if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
523 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
524 {
525 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
526 goto exit;
527 }
528
529 end = p + len;
530
531 if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 ||
532 ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
533 {
534 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
535 goto exit;
536 }
537
538 if( p != end )
539 {
540 /* This might be the optional privateValueLength.
541 * If so, we can cleanly discard it */
542 mbedtls_mpi rec;
543 mbedtls_mpi_init( &rec );
544 ret = mbedtls_asn1_get_mpi( &p, end, &rec );
545 mbedtls_mpi_free( &rec );
546 if ( ret != 0 )
547 {
548 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
549 goto exit;
550 }
551 if ( p != end )
552 {
553 ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
554 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
555 goto exit;
556 }
557 }
558
559 ret = 0;
560
561 dhm->len = mbedtls_mpi_size( &dhm->P );
562
563exit:
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 */
581static 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
589 fseek( f, 0, SEEK_END );
590 if( ( size = ftell( f ) ) == -1 )
591 {
592 fclose( f );
593 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
594 }
595 fseek( f, 0, SEEK_SET );
596
597 *n = (size_t) size;
598
599 if( *n + 1 == 0 ||
600 ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
601 {
602 fclose( f );
603 return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
604 }
605
606 if( fread( *buf, 1, *n, f ) != *n )
607 {
608 fclose( f );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100609
610 mbedtls_platform_zeroize( *buf, *n + 1 );
Jens Wiklander817466c2018-05-22 13:49:31 +0200611 mbedtls_free( *buf );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100612
Jens Wiklander817466c2018-05-22 13:49:31 +0200613 return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
614 }
615
616 fclose( f );
617
618 (*buf)[*n] = '\0';
619
620 if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
621 ++*n;
622
623 return( 0 );
624}
625
626/*
627 * Load and parse DHM parameters
628 */
629int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
630{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200631 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200632 size_t n;
633 unsigned char *buf;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100634 DHM_VALIDATE_RET( dhm != NULL );
635 DHM_VALIDATE_RET( path != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200636
637 if( ( ret = load_file( path, &buf, &n ) ) != 0 )
638 return( ret );
639
640 ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
641
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100642 mbedtls_platform_zeroize( buf, n );
Jens Wiklander817466c2018-05-22 13:49:31 +0200643 mbedtls_free( buf );
644
645 return( ret );
646}
647#endif /* MBEDTLS_FS_IO */
648#endif /* MBEDTLS_ASN1_PARSE_C */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100649#endif /* MBEDTLS_DHM_ALT */
Jens Wiklander817466c2018-05-22 13:49:31 +0200650
651#if defined(MBEDTLS_SELF_TEST)
652
Jerome Forissier5b25c762020-04-07 11:18:49 +0200653#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200654static const char mbedtls_test_dhm_params[] =
655"-----BEGIN DH PARAMETERS-----\r\n"
656"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
657"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
658"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
659"-----END DH PARAMETERS-----\r\n";
Jerome Forissier5b25c762020-04-07 11:18:49 +0200660#else /* MBEDTLS_PEM_PARSE_C */
661static const char mbedtls_test_dhm_params[] = {
662 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
663 0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
664 0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
665 0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
666 0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
667 0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
668 0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
669 0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
670 0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
671 0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
672 0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
673 0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 };
674#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200675
676static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
677
678/*
679 * Checkup routine
680 */
681int mbedtls_dhm_self_test( int verbose )
682{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200683 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200684 mbedtls_dhm_context dhm;
685
686 mbedtls_dhm_init( &dhm );
687
688 if( verbose != 0 )
689 mbedtls_printf( " DHM parameter load: " );
690
691 if( ( ret = mbedtls_dhm_parse_dhm( &dhm,
692 (const unsigned char *) mbedtls_test_dhm_params,
693 mbedtls_test_dhm_params_len ) ) != 0 )
694 {
695 if( verbose != 0 )
696 mbedtls_printf( "failed\n" );
697
698 ret = 1;
699 goto exit;
700 }
701
702 if( verbose != 0 )
703 mbedtls_printf( "passed\n\n" );
704
705exit:
706 mbedtls_dhm_free( &dhm );
707
708 return( ret );
709}
710
711#endif /* MBEDTLS_SELF_TEST */
712
713#endif /* MBEDTLS_DHM_C */