blob: accd5a85cf1a7a81e6c91cc28491b03e92134a31 [file] [log] [blame]
Jens Wiklander817466c2018-05-22 13:49:31 +02001/*
2 * Diffie-Hellman-Merkle key exchange
3 *
Jerome Forissier79013242021-07-28 10:24:04 +02004 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
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.
Jens Wiklander817466c2018-05-22 13:49:31 +020018 */
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
Jerome Forissier79013242021-07-28 10:24:04 +020028#include "common.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020029
30#if defined(MBEDTLS_DHM_C)
31
32#include "mbedtls/dhm.h"
Jens Wiklander3d3b0592019-03-20 15:30:29 +010033#include "mbedtls/platform_util.h"
Jerome Forissier11fa71b2020-04-20 17:17:56 +020034#include "mbedtls/error.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020035
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
Jens Wiklander3d3b0592019-03-20 15:30:29 +010056#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 )
Jens Wiklander817466c2018-05-22 13:49:31 +020062
63/*
64 * helper to validate the mbedtls_mpi size and import it
65 */
66static 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 )
Jerome Forissier79013242021-07-28 10:24:04 +020082 return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED, ret ) );
Jens Wiklander817466c2018-05-22 13:49:31 +020083
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 *
Jens Wiklander3d3b0592019-03-20 15:30:29 +010094 * This means that we need to return an error if
95 * public_param < 2 or public_param > P-2
96 *
Jens Wiklander817466c2018-05-22 13:49:31 +020097 * 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 */
101static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
102{
Jerome Forissier79013242021-07-28 10:24:04 +0200103 mbedtls_mpi U;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100104 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200105
Jerome Forissier79013242021-07-28 10:24:04 +0200106 mbedtls_mpi_init( &U );
Jens Wiklander817466c2018-05-22 13:49:31 +0200107
Jens Wiklander817466c2018-05-22 13:49:31 +0200108 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
109
Jerome Forissier79013242021-07-28 10:24:04 +0200110 if( mbedtls_mpi_cmp_int( param, 2 ) < 0 ||
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100111 mbedtls_mpi_cmp_mpi( param, &U ) > 0 )
Jens Wiklander817466c2018-05-22 13:49:31 +0200112 {
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100113 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +0200114 }
115
116cleanup:
Jerome Forissier79013242021-07-28 10:24:04 +0200117 mbedtls_mpi_free( &U );
Jens Wiklander817466c2018-05-22 13:49:31 +0200118 return( ret );
119}
120
121void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
122{
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100123 DHM_VALIDATE( ctx != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200124 memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
125}
126
127/*
128 * Parse the ServerKeyExchange parameters
129 */
130int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
131 unsigned char **p,
132 const unsigned char *end )
133{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200134 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100135 DHM_VALIDATE_RET( ctx != NULL );
136 DHM_VALIDATE_RET( p != NULL && *p != NULL );
137 DHM_VALIDATE_RET( end != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200138
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/*
Jerome Forissier79013242021-07-28 10:24:04 +0200153 * Pick a random R in the range [2, M-2] for blinding or key generation.
Jens Wiklander817466c2018-05-22 13:49:31 +0200154 */
Jerome Forissier79013242021-07-28 10:24:04 +0200155static int dhm_random_below( mbedtls_mpi *R, const mbedtls_mpi *M,
156 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
Jens Wiklander817466c2018-05-22 13:49:31 +0200157{
Jerome Forissier79013242021-07-28 10:24:04 +0200158 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
163cleanup:
164 return( ret );
165}
166
167static 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;
Jens Wiklander817466c2018-05-22 13:49:31 +0200172
173 if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
174 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
Jerome Forissier79013242021-07-28 10:24:04 +0200175 if( x_size < 0 )
176 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
Jens Wiklander817466c2018-05-22 13:49:31 +0200177
Jerome Forissier79013242021-07-28 10:24:04 +0200178 if( (unsigned) x_size < mbedtls_mpi_size( &ctx->P ) )
Jens Wiklander817466c2018-05-22 13:49:31 +0200179 {
180 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200181 }
Jerome Forissier79013242021-07-28 10:24:04 +0200182 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 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200191
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
Jerome Forissier79013242021-07-28 10:24:04 +0200201cleanup:
202 return( ret );
203}
204
205/*
206 * Setup and write the ServerKeyExchange parameters
207 */
208int 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
Jens Wiklander817466c2018-05-22 13:49:31 +0200225 /*
Jerome Forissier79013242021-07-28 10:24:04 +0200226 * Export P, G, GX. RFC 5246 §4.4 states that "leading zero octets are
227 * not required". We omit leading zeros for compactness.
Jens Wiklander817466c2018-05-22 13:49:31 +0200228 */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100229#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 )
Jens Wiklander817466c2018-05-22 13:49:31 +0200238
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
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100248 *olen = p - output;
Jens Wiklander817466c2018-05-22 13:49:31 +0200249
250 ctx->len = n1;
251
252cleanup:
Jerome Forissier79013242021-07-28 10:24:04 +0200253 if( ret != 0 && ret > -128 )
254 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED, ret );
255 return( ret );
Jens Wiklander817466c2018-05-22 13:49:31 +0200256}
257
258/*
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100259 * Set prime modulus and generator
260 */
261int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
262 const mbedtls_mpi *P,
263 const mbedtls_mpi *G )
264{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200265 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100266 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 {
Jerome Forissier79013242021-07-28 10:24:04 +0200273 return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_SET_GROUP_FAILED, ret ) );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100274 }
275
276 ctx->len = mbedtls_mpi_size( &ctx->P );
277 return( 0 );
278}
279
280/*
Jens Wiklander817466c2018-05-22 13:49:31 +0200281 * Import the peer's public value G^Y
282 */
283int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
284 const unsigned char *input, size_t ilen )
285{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200286 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100287 DHM_VALIDATE_RET( ctx != NULL );
288 DHM_VALIDATE_RET( input != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200289
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100290 if( ilen < 1 || ilen > ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200291 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
292
293 if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
Jerome Forissier79013242021-07-28 10:24:04 +0200294 return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED, ret ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200295
296 return( 0 );
297}
298
299/*
300 * Create own private value X and export G^X
301 */
302int 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{
Jerome Forissier79013242021-07-28 10:24:04 +0200307 int ret;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100308 DHM_VALIDATE_RET( ctx != NULL );
309 DHM_VALIDATE_RET( output != NULL );
310 DHM_VALIDATE_RET( f_rng != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200311
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100312 if( olen < 1 || olen > ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200313 return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
314
Jerome Forissier79013242021-07-28 10:24:04 +0200315 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;
Jens Wiklander817466c2018-05-22 13:49:31 +0200320
321 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
322
323cleanup:
Jerome Forissier79013242021-07-28 10:24:04 +0200324 if( ret != 0 && ret > -128 )
325 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED, ret );
326 return( ret );
Jens Wiklander817466c2018-05-22 13:49:31 +0200327}
328
Jerome Forissier79013242021-07-28 10:24:04 +0200329
Jens Wiklander817466c2018-05-22 13:49:31 +0200330/*
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 */
336static int dhm_update_blinding( mbedtls_dhm_context *ctx,
337 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
338{
Jerome Forissier79013242021-07-28 10:24:04 +0200339 int ret;
340 mbedtls_mpi R;
341
342 mbedtls_mpi_init( &R );
Jens Wiklander817466c2018-05-22 13:49:31 +0200343
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
Jerome Forissier79013242021-07-28 10:24:04 +0200376 /* Vi = random( 2, P-2 ) */
377 MBEDTLS_MPI_CHK( dhm_random_below( &ctx->Vi, &ctx->P, f_rng, p_rng ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200378
Jerome Forissier79013242021-07-28 10:24:04 +0200379 /* 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 ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200388
Jens Wiklander817466c2018-05-22 13:49:31 +0200389 MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
390
391cleanup:
Jerome Forissier79013242021-07-28 10:24:04 +0200392 mbedtls_mpi_free( &R );
393
Jens Wiklander817466c2018-05-22 13:49:31 +0200394 return( ret );
395}
396
397/*
398 * Derive and export the shared secret (G^Y)^X mod P
399 */
400int 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{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200405 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200406 mbedtls_mpi GYb;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100407 DHM_VALIDATE_RET( ctx != NULL );
408 DHM_VALIDATE_RET( output != NULL );
409 DHM_VALIDATE_RET( olen != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200410
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100411 if( output_size < ctx->len )
Jens Wiklander817466c2018-05-22 13:49:31 +0200412 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
Jerome Forissier79013242021-07-28 10:24:04 +0200440 /* Output the secret without any leading zero byte. This is mandatory
441 * for TLS per RFC 5246 §8.1.2. */
Jens Wiklander817466c2018-05-22 13:49:31 +0200442 *olen = mbedtls_mpi_size( &ctx->K );
Jens Wiklander817466c2018-05-22 13:49:31 +0200443 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
444
445cleanup:
446 mbedtls_mpi_free( &GYb );
447
448 if( ret != 0 )
Jerome Forissier79013242021-07-28 10:24:04 +0200449 return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED, ret ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200450
451 return( 0 );
452}
453
454/*
455 * Free the components of a DHM key
456 */
457void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
458{
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100459 if( ctx == NULL )
460 return;
Jens Wiklander817466c2018-05-22 13:49:31 +0200461
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100462 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 ) );
Jens Wiklander817466c2018-05-22 13:49:31 +0200474}
475
476#if defined(MBEDTLS_ASN1_PARSE_C)
477/*
478 * Parse DHM parameters
479 */
480int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
481 size_t dhminlen )
482{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200483 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200484 size_t len;
485 unsigned char *p, *end;
486#if defined(MBEDTLS_PEM_PARSE_C)
487 mbedtls_pem_context pem;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100488#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200489
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100490 DHM_VALIDATE_RET( dhm != NULL );
491 DHM_VALIDATE_RET( dhmin != NULL );
492
493#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200494 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 {
Jerome Forissier79013242021-07-28 10:24:04 +0200531 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_INVALID_FORMAT, ret );
Jens Wiklander817466c2018-05-22 13:49:31 +0200532 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 {
Jerome Forissier79013242021-07-28 10:24:04 +0200540 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_INVALID_FORMAT, ret );
Jens Wiklander817466c2018-05-22 13:49:31 +0200541 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 {
Jerome Forissier79013242021-07-28 10:24:04 +0200554 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_INVALID_FORMAT, ret );
Jens Wiklander817466c2018-05-22 13:49:31 +0200555 goto exit;
556 }
557 if ( p != end )
558 {
Jerome Forissier79013242021-07-28 10:24:04 +0200559 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_DHM_INVALID_FORMAT,
560 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
Jens Wiklander817466c2018-05-22 13:49:31 +0200561 goto exit;
562 }
563 }
564
565 ret = 0;
566
567 dhm->len = mbedtls_mpi_size( &dhm->P );
568
569exit:
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 */
587static 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 );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100615
616 mbedtls_platform_zeroize( *buf, *n + 1 );
Jens Wiklander817466c2018-05-22 13:49:31 +0200617 mbedtls_free( *buf );
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100618
Jens Wiklander817466c2018-05-22 13:49:31 +0200619 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 */
635int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
636{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200637 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200638 size_t n;
639 unsigned char *buf;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100640 DHM_VALIDATE_RET( dhm != NULL );
641 DHM_VALIDATE_RET( path != NULL );
Jens Wiklander817466c2018-05-22 13:49:31 +0200642
643 if( ( ret = load_file( path, &buf, &n ) ) != 0 )
644 return( ret );
645
646 ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
647
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100648 mbedtls_platform_zeroize( buf, n );
Jens Wiklander817466c2018-05-22 13:49:31 +0200649 mbedtls_free( buf );
650
651 return( ret );
652}
653#endif /* MBEDTLS_FS_IO */
654#endif /* MBEDTLS_ASN1_PARSE_C */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100655#endif /* MBEDTLS_DHM_ALT */
Jens Wiklander817466c2018-05-22 13:49:31 +0200656
657#if defined(MBEDTLS_SELF_TEST)
658
Jerome Forissier5b25c762020-04-07 11:18:49 +0200659#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200660static 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";
Jerome Forissier5b25c762020-04-07 11:18:49 +0200666#else /* MBEDTLS_PEM_PARSE_C */
667static 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 */
Jens Wiklander817466c2018-05-22 13:49:31 +0200681
682static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
683
684/*
685 * Checkup routine
686 */
687int mbedtls_dhm_self_test( int verbose )
688{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200689 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200690 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
711exit:
712 mbedtls_dhm_free( &dhm );
713
714 return( ret );
715}
716
717#endif /* MBEDTLS_SELF_TEST */
718
719#endif /* MBEDTLS_DHM_C */