blob: bcc07f544194e56185ceb3d4e90d02776d44b0c3 [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
Tom Van Eyckc1633172024-04-09 18:44:13 +02005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Jens Wiklander817466c2018-05-22 13:49:31 +02006 */
7/*
8 * The following sources were referenced in the design of this implementation
9 * of the Diffie-Hellman-Merkle algorithm:
10 *
11 * [1] Handbook of Applied Cryptography - 1997, Chapter 12
12 * Menezes, van Oorschot and Vanstone
13 *
14 */
15
Jerome Forissier79013242021-07-28 10:24:04 +020016#include "common.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020017
18#if defined(MBEDTLS_DHM_C)
19
20#include "mbedtls/dhm.h"
Jens Wiklander3d3b0592019-03-20 15:30:29 +010021#include "mbedtls/platform_util.h"
Jerome Forissier11fa71b2020-04-20 17:17:56 +020022#include "mbedtls/error.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020023
24#include <string.h>
25
26#if defined(MBEDTLS_PEM_PARSE_C)
27#include "mbedtls/pem.h"
28#endif
29
30#if defined(MBEDTLS_ASN1_PARSE_C)
31#include "mbedtls/asn1.h"
32#endif
33
Jens Wiklander817466c2018-05-22 13:49:31 +020034#include "mbedtls/platform.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020035
Jens Wiklander3d3b0592019-03-20 15:30:29 +010036#if !defined(MBEDTLS_DHM_ALT)
37
Jens Wiklander817466c2018-05-22 13:49:31 +020038/*
39 * helper to validate the mbedtls_mpi size and import it
40 */
Jens Wiklander32b31802023-10-06 16:59:46 +020041static int dhm_read_bignum(mbedtls_mpi *X,
42 unsigned char **p,
43 const unsigned char *end)
Jens Wiklander817466c2018-05-22 13:49:31 +020044{
45 int ret, n;
46
Jens Wiklander32b31802023-10-06 16:59:46 +020047 if (end - *p < 2) {
48 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
49 }
Jens Wiklander817466c2018-05-22 13:49:31 +020050
Tom Van Eyckc1633172024-04-09 18:44:13 +020051 n = MBEDTLS_GET_UINT16_BE(*p, 0);
Jens Wiklander817466c2018-05-22 13:49:31 +020052 (*p) += 2;
53
Tom Van Eyckc1633172024-04-09 18:44:13 +020054 if ((size_t) (end - *p) < (size_t) n) {
Jens Wiklander32b31802023-10-06 16:59:46 +020055 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
56 }
Jens Wiklander817466c2018-05-22 13:49:31 +020057
Jens Wiklander32b31802023-10-06 16:59:46 +020058 if ((ret = mbedtls_mpi_read_binary(X, *p, n)) != 0) {
59 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED, ret);
60 }
Jens Wiklander817466c2018-05-22 13:49:31 +020061
62 (*p) += n;
63
Jens Wiklander32b31802023-10-06 16:59:46 +020064 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +020065}
66
67/*
68 * Verify sanity of parameter with regards to P
69 *
70 * Parameter should be: 2 <= public_param <= P - 2
71 *
Jens Wiklander3d3b0592019-03-20 15:30:29 +010072 * This means that we need to return an error if
73 * public_param < 2 or public_param > P-2
74 *
Jens Wiklander817466c2018-05-22 13:49:31 +020075 * For more information on the attack, see:
76 * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
77 * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
78 */
Jens Wiklander32b31802023-10-06 16:59:46 +020079static int dhm_check_range(const mbedtls_mpi *param, const mbedtls_mpi *P)
Jens Wiklander817466c2018-05-22 13:49:31 +020080{
Jerome Forissier79013242021-07-28 10:24:04 +020081 mbedtls_mpi U;
Jens Wiklander3d3b0592019-03-20 15:30:29 +010082 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +020083
Jens Wiklander32b31802023-10-06 16:59:46 +020084 mbedtls_mpi_init(&U);
Jens Wiklander817466c2018-05-22 13:49:31 +020085
Jens Wiklander32b31802023-10-06 16:59:46 +020086 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&U, P, 2));
Jens Wiklander817466c2018-05-22 13:49:31 +020087
Jens Wiklander32b31802023-10-06 16:59:46 +020088 if (mbedtls_mpi_cmp_int(param, 2) < 0 ||
89 mbedtls_mpi_cmp_mpi(param, &U) > 0) {
Jens Wiklander3d3b0592019-03-20 15:30:29 +010090 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +020091 }
92
93cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +020094 mbedtls_mpi_free(&U);
95 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +020096}
97
Jens Wiklander32b31802023-10-06 16:59:46 +020098void mbedtls_dhm_init(mbedtls_dhm_context *ctx)
Jens Wiklander817466c2018-05-22 13:49:31 +020099{
Jens Wiklander32b31802023-10-06 16:59:46 +0200100 memset(ctx, 0, sizeof(mbedtls_dhm_context));
101}
102
103size_t mbedtls_dhm_get_bitlen(const mbedtls_dhm_context *ctx)
104{
105 return mbedtls_mpi_bitlen(&ctx->P);
106}
107
108size_t mbedtls_dhm_get_len(const mbedtls_dhm_context *ctx)
109{
110 return mbedtls_mpi_size(&ctx->P);
111}
112
113int mbedtls_dhm_get_value(const mbedtls_dhm_context *ctx,
114 mbedtls_dhm_parameter param,
115 mbedtls_mpi *dest)
116{
117 const mbedtls_mpi *src = NULL;
118 switch (param) {
119 case MBEDTLS_DHM_PARAM_P:
120 src = &ctx->P;
121 break;
122 case MBEDTLS_DHM_PARAM_G:
123 src = &ctx->G;
124 break;
125 case MBEDTLS_DHM_PARAM_X:
126 src = &ctx->X;
127 break;
128 case MBEDTLS_DHM_PARAM_GX:
129 src = &ctx->GX;
130 break;
131 case MBEDTLS_DHM_PARAM_GY:
132 src = &ctx->GY;
133 break;
134 case MBEDTLS_DHM_PARAM_K:
135 src = &ctx->K;
136 break;
137 default:
138 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
139 }
140 return mbedtls_mpi_copy(dest, src);
Jens Wiklander817466c2018-05-22 13:49:31 +0200141}
142
143/*
144 * Parse the ServerKeyExchange parameters
145 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200146int mbedtls_dhm_read_params(mbedtls_dhm_context *ctx,
147 unsigned char **p,
148 const unsigned char *end)
Jens Wiklander817466c2018-05-22 13:49:31 +0200149{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200150 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200151
Jens Wiklander32b31802023-10-06 16:59:46 +0200152 if ((ret = dhm_read_bignum(&ctx->P, p, end)) != 0 ||
153 (ret = dhm_read_bignum(&ctx->G, p, end)) != 0 ||
154 (ret = dhm_read_bignum(&ctx->GY, p, end)) != 0) {
155 return ret;
156 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200157
Jens Wiklander32b31802023-10-06 16:59:46 +0200158 if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
159 return ret;
160 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200161
Jens Wiklander32b31802023-10-06 16:59:46 +0200162 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200163}
164
165/*
Jerome Forissier79013242021-07-28 10:24:04 +0200166 * Pick a random R in the range [2, M-2] for blinding or key generation.
Jens Wiklander817466c2018-05-22 13:49:31 +0200167 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200168static int dhm_random_below(mbedtls_mpi *R, const mbedtls_mpi *M,
169 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200170{
Jerome Forissier79013242021-07-28 10:24:04 +0200171 int ret;
172
Jens Wiklander32b31802023-10-06 16:59:46 +0200173 MBEDTLS_MPI_CHK(mbedtls_mpi_random(R, 3, M, f_rng, p_rng));
174 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(R, R, 1));
Jerome Forissier79013242021-07-28 10:24:04 +0200175
176cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200177 return ret;
Jerome Forissier79013242021-07-28 10:24:04 +0200178}
179
Jens Wiklander32b31802023-10-06 16:59:46 +0200180static int dhm_make_common(mbedtls_dhm_context *ctx, int x_size,
181 int (*f_rng)(void *, unsigned char *, size_t),
182 void *p_rng)
Jerome Forissier79013242021-07-28 10:24:04 +0200183{
184 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200185
Jens Wiklander32b31802023-10-06 16:59:46 +0200186 if (mbedtls_mpi_cmp_int(&ctx->P, 0) == 0) {
187 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +0200188 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200189 if (x_size < 0) {
190 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
191 }
192
193 if ((unsigned) x_size < mbedtls_mpi_size(&ctx->P)) {
194 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&ctx->X, x_size, f_rng, p_rng));
195 } else {
Jerome Forissier79013242021-07-28 10:24:04 +0200196 /* Generate X as large as possible ( <= P - 2 ) */
Jens Wiklander32b31802023-10-06 16:59:46 +0200197 ret = dhm_random_below(&ctx->X, &ctx->P, f_rng, p_rng);
198 if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
199 return MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED;
200 }
201 if (ret != 0) {
202 return ret;
203 }
Jerome Forissier79013242021-07-28 10:24:04 +0200204 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200205
206 /*
207 * Calculate GX = G^X mod P
208 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200209 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->GX, &ctx->G, &ctx->X,
210 &ctx->P, &ctx->RP));
Jens Wiklander817466c2018-05-22 13:49:31 +0200211
Jens Wiklander32b31802023-10-06 16:59:46 +0200212 if ((ret = dhm_check_range(&ctx->GX, &ctx->P)) != 0) {
213 return ret;
214 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200215
Jerome Forissier79013242021-07-28 10:24:04 +0200216cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200217 return ret;
Jerome Forissier79013242021-07-28 10:24:04 +0200218}
219
220/*
221 * Setup and write the ServerKeyExchange parameters
222 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200223int mbedtls_dhm_make_params(mbedtls_dhm_context *ctx, int x_size,
224 unsigned char *output, size_t *olen,
225 int (*f_rng)(void *, unsigned char *, size_t),
226 void *p_rng)
Jerome Forissier79013242021-07-28 10:24:04 +0200227{
228 int ret;
229 size_t n1, n2, n3;
230 unsigned char *p;
Jerome Forissier79013242021-07-28 10:24:04 +0200231
Jens Wiklander32b31802023-10-06 16:59:46 +0200232 ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
233 if (ret != 0) {
Jerome Forissier79013242021-07-28 10:24:04 +0200234 goto cleanup;
Jens Wiklander32b31802023-10-06 16:59:46 +0200235 }
Jerome Forissier79013242021-07-28 10:24:04 +0200236
Jens Wiklander817466c2018-05-22 13:49:31 +0200237 /*
Jerome Forissier79013242021-07-28 10:24:04 +0200238 * Export P, G, GX. RFC 5246 §4.4 states that "leading zero octets are
239 * not required". We omit leading zeros for compactness.
Jens Wiklander817466c2018-05-22 13:49:31 +0200240 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200241#define DHM_MPI_EXPORT(X, n) \
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100242 do { \
Jens Wiklander32b31802023-10-06 16:59:46 +0200243 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary((X), \
244 p + 2, \
245 (n))); \
246 *p++ = MBEDTLS_BYTE_1(n); \
247 *p++ = MBEDTLS_BYTE_0(n); \
248 p += (n); \
249 } while (0)
Jens Wiklander817466c2018-05-22 13:49:31 +0200250
Jens Wiklander32b31802023-10-06 16:59:46 +0200251 n1 = mbedtls_mpi_size(&ctx->P);
252 n2 = mbedtls_mpi_size(&ctx->G);
253 n3 = mbedtls_mpi_size(&ctx->GX);
Jens Wiklander817466c2018-05-22 13:49:31 +0200254
255 p = output;
Jens Wiklander32b31802023-10-06 16:59:46 +0200256 DHM_MPI_EXPORT(&ctx->P, n1);
257 DHM_MPI_EXPORT(&ctx->G, n2);
258 DHM_MPI_EXPORT(&ctx->GX, n3);
Jens Wiklander817466c2018-05-22 13:49:31 +0200259
Tom Van Eyckc1633172024-04-09 18:44:13 +0200260 *olen = (size_t) (p - output);
Jens Wiklander817466c2018-05-22 13:49:31 +0200261
Jens Wiklander817466c2018-05-22 13:49:31 +0200262cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200263 if (ret != 0 && ret > -128) {
264 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED, ret);
265 }
266 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200267}
268
269/*
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100270 * Set prime modulus and generator
271 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200272int mbedtls_dhm_set_group(mbedtls_dhm_context *ctx,
273 const mbedtls_mpi *P,
274 const mbedtls_mpi *G)
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100275{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200276 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100277
Jens Wiklander32b31802023-10-06 16:59:46 +0200278 if ((ret = mbedtls_mpi_copy(&ctx->P, P)) != 0 ||
279 (ret = mbedtls_mpi_copy(&ctx->G, G)) != 0) {
280 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_SET_GROUP_FAILED, ret);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100281 }
282
Jens Wiklander32b31802023-10-06 16:59:46 +0200283 return 0;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100284}
285
286/*
Jens Wiklander817466c2018-05-22 13:49:31 +0200287 * Import the peer's public value G^Y
288 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200289int mbedtls_dhm_read_public(mbedtls_dhm_context *ctx,
290 const unsigned char *input, size_t ilen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200291{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200292 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200293
Jens Wiklander32b31802023-10-06 16:59:46 +0200294 if (ilen < 1 || ilen > mbedtls_dhm_get_len(ctx)) {
295 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
296 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200297
Jens Wiklander32b31802023-10-06 16:59:46 +0200298 if ((ret = mbedtls_mpi_read_binary(&ctx->GY, input, ilen)) != 0) {
299 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED, ret);
300 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200301
Jens Wiklander32b31802023-10-06 16:59:46 +0200302 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200303}
304
305/*
306 * Create own private value X and export G^X
307 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200308int mbedtls_dhm_make_public(mbedtls_dhm_context *ctx, int x_size,
309 unsigned char *output, size_t olen,
310 int (*f_rng)(void *, unsigned char *, size_t),
311 void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200312{
Jerome Forissier79013242021-07-28 10:24:04 +0200313 int ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200314
Jens Wiklander32b31802023-10-06 16:59:46 +0200315 if (olen < 1 || olen > mbedtls_dhm_get_len(ctx)) {
316 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
317 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200318
Jens Wiklander32b31802023-10-06 16:59:46 +0200319 ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
320 if (ret == MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) {
321 return MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED;
322 }
323 if (ret != 0) {
Jerome Forissier79013242021-07-28 10:24:04 +0200324 goto cleanup;
Jens Wiklander32b31802023-10-06 16:59:46 +0200325 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200326
Jens Wiklander32b31802023-10-06 16:59:46 +0200327 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->GX, output, olen));
Jens Wiklander817466c2018-05-22 13:49:31 +0200328
329cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200330 if (ret != 0 && ret > -128) {
331 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED, ret);
332 }
333 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200334}
335
Jerome Forissier79013242021-07-28 10:24:04 +0200336
Jens Wiklander817466c2018-05-22 13:49:31 +0200337/*
338 * Use the blinding method and optimisation suggested in section 10 of:
339 * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
340 * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
341 * Berlin Heidelberg, 1996. p. 104-113.
342 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200343static int dhm_update_blinding(mbedtls_dhm_context *ctx,
344 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200345{
Jerome Forissier79013242021-07-28 10:24:04 +0200346 int ret;
347 mbedtls_mpi R;
348
Jens Wiklander32b31802023-10-06 16:59:46 +0200349 mbedtls_mpi_init(&R);
Jens Wiklander817466c2018-05-22 13:49:31 +0200350
351 /*
352 * Don't use any blinding the first time a particular X is used,
353 * but remember it to use blinding next time.
354 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200355 if (mbedtls_mpi_cmp_mpi(&ctx->X, &ctx->pX) != 0) {
356 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&ctx->pX, &ctx->X));
357 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vi, 1));
358 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vf, 1));
Jens Wiklander817466c2018-05-22 13:49:31 +0200359
Jens Wiklander32b31802023-10-06 16:59:46 +0200360 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200361 }
362
363 /*
364 * Ok, we need blinding. Can we re-use existing values?
365 * If yes, just update them by squaring them.
366 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200367 if (mbedtls_mpi_cmp_int(&ctx->Vi, 1) != 0) {
368 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vi, &ctx->Vi, &ctx->Vi));
369 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200370
Jens Wiklander32b31802023-10-06 16:59:46 +0200371 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf));
372 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200373
Jens Wiklander32b31802023-10-06 16:59:46 +0200374 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200375 }
376
377 /*
378 * We need to generate blinding values from scratch
379 */
380
Jerome Forissier79013242021-07-28 10:24:04 +0200381 /* Vi = random( 2, P-2 ) */
Jens Wiklander32b31802023-10-06 16:59:46 +0200382 MBEDTLS_MPI_CHK(dhm_random_below(&ctx->Vi, &ctx->P, f_rng, p_rng));
Jens Wiklander817466c2018-05-22 13:49:31 +0200383
Jerome Forissier79013242021-07-28 10:24:04 +0200384 /* Vf = Vi^-X mod P
385 * First compute Vi^-1 = R * (R Vi)^-1, (avoiding leaks from inv_mod),
386 * then elevate to the Xth power. */
Jens Wiklander32b31802023-10-06 16:59:46 +0200387 MBEDTLS_MPI_CHK(dhm_random_below(&R, &ctx->P, f_rng, p_rng));
388 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vi, &R));
389 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
390 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&ctx->Vf, &ctx->Vf, &ctx->P));
391 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &R));
392 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200393
Jens Wiklander32b31802023-10-06 16:59:46 +0200394 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP));
Jens Wiklander817466c2018-05-22 13:49:31 +0200395
396cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200397 mbedtls_mpi_free(&R);
Jerome Forissier79013242021-07-28 10:24:04 +0200398
Jens Wiklander32b31802023-10-06 16:59:46 +0200399 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200400}
401
402/*
403 * Derive and export the shared secret (G^Y)^X mod P
404 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200405int mbedtls_dhm_calc_secret(mbedtls_dhm_context *ctx,
406 unsigned char *output, size_t output_size, size_t *olen,
407 int (*f_rng)(void *, unsigned char *, size_t),
408 void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200409{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200410 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200411 mbedtls_mpi GYb;
412
Jens Wiklander32b31802023-10-06 16:59:46 +0200413 if (f_rng == NULL) {
414 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
415 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200416
Jens Wiklander32b31802023-10-06 16:59:46 +0200417 if (output_size < mbedtls_dhm_get_len(ctx)) {
418 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
419 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200420
Jens Wiklander32b31802023-10-06 16:59:46 +0200421 if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
422 return ret;
423 }
424
425 mbedtls_mpi_init(&GYb);
Jens Wiklander817466c2018-05-22 13:49:31 +0200426
427 /* Blind peer's value */
Jens Wiklander32b31802023-10-06 16:59:46 +0200428 MBEDTLS_MPI_CHK(dhm_update_blinding(ctx, f_rng, p_rng));
429 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&GYb, &ctx->GY, &ctx->Vi));
430 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&GYb, &GYb, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200431
432 /* Do modular exponentiation */
Jens Wiklander32b31802023-10-06 16:59:46 +0200433 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->K, &GYb, &ctx->X,
434 &ctx->P, &ctx->RP));
Jens Wiklander817466c2018-05-22 13:49:31 +0200435
436 /* Unblind secret value */
Jens Wiklander32b31802023-10-06 16:59:46 +0200437 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->K, &ctx->K, &ctx->Vf));
438 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->K, &ctx->K, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200439
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 Wiklander32b31802023-10-06 16:59:46 +0200442 *olen = mbedtls_mpi_size(&ctx->K);
443 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->K, output, *olen));
Jens Wiklander817466c2018-05-22 13:49:31 +0200444
445cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200446 mbedtls_mpi_free(&GYb);
Jens Wiklander817466c2018-05-22 13:49:31 +0200447
Jens Wiklander32b31802023-10-06 16:59:46 +0200448 if (ret != 0) {
449 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED, ret);
450 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200451
Jens Wiklander32b31802023-10-06 16:59:46 +0200452 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200453}
454
455/*
456 * Free the components of a DHM key
457 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200458void mbedtls_dhm_free(mbedtls_dhm_context *ctx)
Jens Wiklander817466c2018-05-22 13:49:31 +0200459{
Jens Wiklander32b31802023-10-06 16:59:46 +0200460 if (ctx == NULL) {
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100461 return;
Jens Wiklander32b31802023-10-06 16:59:46 +0200462 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200463
Jens Wiklander32b31802023-10-06 16:59:46 +0200464 mbedtls_mpi_free(&ctx->pX);
465 mbedtls_mpi_free(&ctx->Vf);
466 mbedtls_mpi_free(&ctx->Vi);
467 mbedtls_mpi_free(&ctx->RP);
468 mbedtls_mpi_free(&ctx->K);
469 mbedtls_mpi_free(&ctx->GY);
470 mbedtls_mpi_free(&ctx->GX);
471 mbedtls_mpi_free(&ctx->X);
472 mbedtls_mpi_free(&ctx->G);
473 mbedtls_mpi_free(&ctx->P);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100474
Jens Wiklander32b31802023-10-06 16:59:46 +0200475 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_dhm_context));
Jens Wiklander817466c2018-05-22 13:49:31 +0200476}
477
478#if defined(MBEDTLS_ASN1_PARSE_C)
479/*
480 * Parse DHM parameters
481 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200482int mbedtls_dhm_parse_dhm(mbedtls_dhm_context *dhm, const unsigned char *dhmin,
483 size_t dhminlen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200484{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200485 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200486 size_t len;
487 unsigned char *p, *end;
488#if defined(MBEDTLS_PEM_PARSE_C)
489 mbedtls_pem_context pem;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100490#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200491
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100492#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander32b31802023-10-06 16:59:46 +0200493 mbedtls_pem_init(&pem);
Jens Wiklander817466c2018-05-22 13:49:31 +0200494
495 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
Jens Wiklander32b31802023-10-06 16:59:46 +0200496 if (dhminlen == 0 || dhmin[dhminlen - 1] != '\0') {
Jens Wiklander817466c2018-05-22 13:49:31 +0200497 ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
Jens Wiklander32b31802023-10-06 16:59:46 +0200498 } else {
499 ret = mbedtls_pem_read_buffer(&pem,
500 "-----BEGIN DH PARAMETERS-----",
501 "-----END DH PARAMETERS-----",
502 dhmin, NULL, 0, &dhminlen);
503 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200504
Jens Wiklander32b31802023-10-06 16:59:46 +0200505 if (ret == 0) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200506 /*
507 * Was PEM encoded
508 */
509 dhminlen = pem.buflen;
Jens Wiklander32b31802023-10-06 16:59:46 +0200510 } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200511 goto exit;
Jens Wiklander32b31802023-10-06 16:59:46 +0200512 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200513
Jens Wiklander32b31802023-10-06 16:59:46 +0200514 p = (ret == 0) ? pem.buf : (unsigned char *) dhmin;
Jens Wiklander817466c2018-05-22 13:49:31 +0200515#else
516 p = (unsigned char *) dhmin;
517#endif /* MBEDTLS_PEM_PARSE_C */
518 end = p + dhminlen;
519
520 /*
521 * DHParams ::= SEQUENCE {
522 * prime INTEGER, -- P
523 * generator INTEGER, -- g
524 * privateValueLength INTEGER OPTIONAL
525 * }
526 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200527 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
528 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
529 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200530 goto exit;
531 }
532
533 end = p + len;
534
Jens Wiklander32b31802023-10-06 16:59:46 +0200535 if ((ret = mbedtls_asn1_get_mpi(&p, end, &dhm->P)) != 0 ||
536 (ret = mbedtls_asn1_get_mpi(&p, end, &dhm->G)) != 0) {
537 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200538 goto exit;
539 }
540
Jens Wiklander32b31802023-10-06 16:59:46 +0200541 if (p != end) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200542 /* This might be the optional privateValueLength.
543 * If so, we can cleanly discard it */
544 mbedtls_mpi rec;
Jens Wiklander32b31802023-10-06 16:59:46 +0200545 mbedtls_mpi_init(&rec);
546 ret = mbedtls_asn1_get_mpi(&p, end, &rec);
547 mbedtls_mpi_free(&rec);
548 if (ret != 0) {
549 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200550 goto exit;
551 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200552 if (p != end) {
553 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT,
554 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Jens Wiklander817466c2018-05-22 13:49:31 +0200555 goto exit;
556 }
557 }
558
559 ret = 0;
560
Jens Wiklander817466c2018-05-22 13:49:31 +0200561exit:
562#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander32b31802023-10-06 16:59:46 +0200563 mbedtls_pem_free(&pem);
Jens Wiklander817466c2018-05-22 13:49:31 +0200564#endif
Jens Wiklander32b31802023-10-06 16:59:46 +0200565 if (ret != 0) {
566 mbedtls_dhm_free(dhm);
567 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200568
Jens Wiklander32b31802023-10-06 16:59:46 +0200569 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200570}
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 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200580static int load_file(const char *path, unsigned char **buf, size_t *n)
Jens Wiklander817466c2018-05-22 13:49:31 +0200581{
582 FILE *f;
583 long size;
584
Jens Wiklander32b31802023-10-06 16:59:46 +0200585 if ((f = fopen(path, "rb")) == NULL) {
586 return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
Jens Wiklander817466c2018-05-22 13:49:31 +0200587 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200588 /* The data loaded here is public, so don't bother disabling buffering. */
589
590 fseek(f, 0, SEEK_END);
591 if ((size = ftell(f)) == -1) {
592 fclose(f);
593 return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
594 }
595 fseek(f, 0, SEEK_SET);
Jens Wiklander817466c2018-05-22 13:49:31 +0200596
597 *n = (size_t) size;
598
Jens Wiklander32b31802023-10-06 16:59:46 +0200599 if (*n + 1 == 0 ||
600 (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
601 fclose(f);
602 return MBEDTLS_ERR_DHM_ALLOC_FAILED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200603 }
604
Jens Wiklander32b31802023-10-06 16:59:46 +0200605 if (fread(*buf, 1, *n, f) != *n) {
606 fclose(f);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100607
Tom Van Eyckc1633172024-04-09 18:44:13 +0200608 mbedtls_zeroize_and_free(*buf, *n + 1);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100609
Jens Wiklander32b31802023-10-06 16:59:46 +0200610 return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
Jens Wiklander817466c2018-05-22 13:49:31 +0200611 }
612
Jens Wiklander32b31802023-10-06 16:59:46 +0200613 fclose(f);
Jens Wiklander817466c2018-05-22 13:49:31 +0200614
615 (*buf)[*n] = '\0';
616
Jens Wiklander32b31802023-10-06 16:59:46 +0200617 if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200618 ++*n;
Jens Wiklander32b31802023-10-06 16:59:46 +0200619 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200620
Jens Wiklander32b31802023-10-06 16:59:46 +0200621 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200622}
623
624/*
625 * Load and parse DHM parameters
626 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200627int mbedtls_dhm_parse_dhmfile(mbedtls_dhm_context *dhm, const char *path)
Jens Wiklander817466c2018-05-22 13:49:31 +0200628{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200629 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200630 size_t n;
631 unsigned char *buf;
632
Jens Wiklander32b31802023-10-06 16:59:46 +0200633 if ((ret = load_file(path, &buf, &n)) != 0) {
634 return ret;
635 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200636
Jens Wiklander32b31802023-10-06 16:59:46 +0200637 ret = mbedtls_dhm_parse_dhm(dhm, buf, n);
Jens Wiklander817466c2018-05-22 13:49:31 +0200638
Tom Van Eyckc1633172024-04-09 18:44:13 +0200639 mbedtls_zeroize_and_free(buf, n);
Jens Wiklander817466c2018-05-22 13:49:31 +0200640
Jens Wiklander32b31802023-10-06 16:59:46 +0200641 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200642}
643#endif /* MBEDTLS_FS_IO */
644#endif /* MBEDTLS_ASN1_PARSE_C */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100645#endif /* MBEDTLS_DHM_ALT */
Jens Wiklander817466c2018-05-22 13:49:31 +0200646
647#if defined(MBEDTLS_SELF_TEST)
648
Jerome Forissier5b25c762020-04-07 11:18:49 +0200649#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200650static const char mbedtls_test_dhm_params[] =
Jens Wiklander32b31802023-10-06 16:59:46 +0200651 "-----BEGIN DH PARAMETERS-----\r\n"
652 "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
653 "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
654 "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
655 "-----END DH PARAMETERS-----\r\n";
Jerome Forissier5b25c762020-04-07 11:18:49 +0200656#else /* MBEDTLS_PEM_PARSE_C */
657static const char mbedtls_test_dhm_params[] = {
Jens Wiklander32b31802023-10-06 16:59:46 +0200658 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
659 0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
660 0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
661 0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
662 0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
663 0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
664 0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
665 0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
666 0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
667 0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
668 0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
669 0x49, 0x75, 0xb3, 0x02, 0x01, 0x02
670};
Jerome Forissier5b25c762020-04-07 11:18:49 +0200671#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200672
Jens Wiklander32b31802023-10-06 16:59:46 +0200673static const size_t mbedtls_test_dhm_params_len = sizeof(mbedtls_test_dhm_params);
Jens Wiklander817466c2018-05-22 13:49:31 +0200674
675/*
676 * Checkup routine
677 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200678int mbedtls_dhm_self_test(int verbose)
Jens Wiklander817466c2018-05-22 13:49:31 +0200679{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200680 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200681 mbedtls_dhm_context dhm;
682
Jens Wiklander32b31802023-10-06 16:59:46 +0200683 mbedtls_dhm_init(&dhm);
Jens Wiklander817466c2018-05-22 13:49:31 +0200684
Jens Wiklander32b31802023-10-06 16:59:46 +0200685 if (verbose != 0) {
686 mbedtls_printf(" DHM parameter load: ");
687 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200688
Jens Wiklander32b31802023-10-06 16:59:46 +0200689 if ((ret = mbedtls_dhm_parse_dhm(&dhm,
690 (const unsigned char *) mbedtls_test_dhm_params,
691 mbedtls_test_dhm_params_len)) != 0) {
692 if (verbose != 0) {
693 mbedtls_printf("failed\n");
694 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200695
696 ret = 1;
697 goto exit;
698 }
699
Jens Wiklander32b31802023-10-06 16:59:46 +0200700 if (verbose != 0) {
701 mbedtls_printf("passed\n\n");
702 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200703
704exit:
Jens Wiklander32b31802023-10-06 16:59:46 +0200705 mbedtls_dhm_free(&dhm);
Jens Wiklander817466c2018-05-22 13:49:31 +0200706
Jens Wiklander32b31802023-10-06 16:59:46 +0200707 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200708}
709
710#endif /* MBEDTLS_SELF_TEST */
711
712#endif /* MBEDTLS_DHM_C */