blob: 94137a264d749d416d8ce54827c956d9b1b2bdc1 [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
Jens Wiklander817466c2018-05-22 13:49:31 +020046#include "mbedtls/platform.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020047
Jens Wiklander3d3b0592019-03-20 15:30:29 +010048#if !defined(MBEDTLS_DHM_ALT)
49
Jens Wiklander817466c2018-05-22 13:49:31 +020050/*
51 * helper to validate the mbedtls_mpi size and import it
52 */
Jens Wiklander32b31802023-10-06 16:59:46 +020053static int dhm_read_bignum(mbedtls_mpi *X,
54 unsigned char **p,
55 const unsigned char *end)
Jens Wiklander817466c2018-05-22 13:49:31 +020056{
57 int ret, n;
58
Jens Wiklander32b31802023-10-06 16:59:46 +020059 if (end - *p < 2) {
60 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
61 }
Jens Wiklander817466c2018-05-22 13:49:31 +020062
Jens Wiklander32b31802023-10-06 16:59:46 +020063 n = ((*p)[0] << 8) | (*p)[1];
Jens Wiklander817466c2018-05-22 13:49:31 +020064 (*p) += 2;
65
Jens Wiklander32b31802023-10-06 16:59:46 +020066 if ((int) (end - *p) < n) {
67 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
68 }
Jens Wiklander817466c2018-05-22 13:49:31 +020069
Jens Wiklander32b31802023-10-06 16:59:46 +020070 if ((ret = mbedtls_mpi_read_binary(X, *p, n)) != 0) {
71 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED, ret);
72 }
Jens Wiklander817466c2018-05-22 13:49:31 +020073
74 (*p) += n;
75
Jens Wiklander32b31802023-10-06 16:59:46 +020076 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +020077}
78
79/*
80 * Verify sanity of parameter with regards to P
81 *
82 * Parameter should be: 2 <= public_param <= P - 2
83 *
Jens Wiklander3d3b0592019-03-20 15:30:29 +010084 * This means that we need to return an error if
85 * public_param < 2 or public_param > P-2
86 *
Jens Wiklander817466c2018-05-22 13:49:31 +020087 * For more information on the attack, see:
88 * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
89 * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
90 */
Jens Wiklander32b31802023-10-06 16:59:46 +020091static int dhm_check_range(const mbedtls_mpi *param, const mbedtls_mpi *P)
Jens Wiklander817466c2018-05-22 13:49:31 +020092{
Jerome Forissier79013242021-07-28 10:24:04 +020093 mbedtls_mpi U;
Jens Wiklander3d3b0592019-03-20 15:30:29 +010094 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +020095
Jens Wiklander32b31802023-10-06 16:59:46 +020096 mbedtls_mpi_init(&U);
Jens Wiklander817466c2018-05-22 13:49:31 +020097
Jens Wiklander32b31802023-10-06 16:59:46 +020098 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&U, P, 2));
Jens Wiklander817466c2018-05-22 13:49:31 +020099
Jens Wiklander32b31802023-10-06 16:59:46 +0200100 if (mbedtls_mpi_cmp_int(param, 2) < 0 ||
101 mbedtls_mpi_cmp_mpi(param, &U) > 0) {
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100102 ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +0200103 }
104
105cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200106 mbedtls_mpi_free(&U);
107 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200108}
109
Jens Wiklander32b31802023-10-06 16:59:46 +0200110void mbedtls_dhm_init(mbedtls_dhm_context *ctx)
Jens Wiklander817466c2018-05-22 13:49:31 +0200111{
Jens Wiklander32b31802023-10-06 16:59:46 +0200112 memset(ctx, 0, sizeof(mbedtls_dhm_context));
113}
114
115size_t mbedtls_dhm_get_bitlen(const mbedtls_dhm_context *ctx)
116{
117 return mbedtls_mpi_bitlen(&ctx->P);
118}
119
120size_t mbedtls_dhm_get_len(const mbedtls_dhm_context *ctx)
121{
122 return mbedtls_mpi_size(&ctx->P);
123}
124
125int mbedtls_dhm_get_value(const mbedtls_dhm_context *ctx,
126 mbedtls_dhm_parameter param,
127 mbedtls_mpi *dest)
128{
129 const mbedtls_mpi *src = NULL;
130 switch (param) {
131 case MBEDTLS_DHM_PARAM_P:
132 src = &ctx->P;
133 break;
134 case MBEDTLS_DHM_PARAM_G:
135 src = &ctx->G;
136 break;
137 case MBEDTLS_DHM_PARAM_X:
138 src = &ctx->X;
139 break;
140 case MBEDTLS_DHM_PARAM_GX:
141 src = &ctx->GX;
142 break;
143 case MBEDTLS_DHM_PARAM_GY:
144 src = &ctx->GY;
145 break;
146 case MBEDTLS_DHM_PARAM_K:
147 src = &ctx->K;
148 break;
149 default:
150 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
151 }
152 return mbedtls_mpi_copy(dest, src);
Jens Wiklander817466c2018-05-22 13:49:31 +0200153}
154
155/*
156 * Parse the ServerKeyExchange parameters
157 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200158int mbedtls_dhm_read_params(mbedtls_dhm_context *ctx,
159 unsigned char **p,
160 const unsigned char *end)
Jens Wiklander817466c2018-05-22 13:49:31 +0200161{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200162 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200163
Jens Wiklander32b31802023-10-06 16:59:46 +0200164 if ((ret = dhm_read_bignum(&ctx->P, p, end)) != 0 ||
165 (ret = dhm_read_bignum(&ctx->G, p, end)) != 0 ||
166 (ret = dhm_read_bignum(&ctx->GY, p, end)) != 0) {
167 return ret;
168 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200169
Jens Wiklander32b31802023-10-06 16:59:46 +0200170 if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
171 return ret;
172 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200173
Jens Wiklander32b31802023-10-06 16:59:46 +0200174 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200175}
176
177/*
Jerome Forissier79013242021-07-28 10:24:04 +0200178 * Pick a random R in the range [2, M-2] for blinding or key generation.
Jens Wiklander817466c2018-05-22 13:49:31 +0200179 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200180static int dhm_random_below(mbedtls_mpi *R, const mbedtls_mpi *M,
181 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200182{
Jerome Forissier79013242021-07-28 10:24:04 +0200183 int ret;
184
Jens Wiklander32b31802023-10-06 16:59:46 +0200185 MBEDTLS_MPI_CHK(mbedtls_mpi_random(R, 3, M, f_rng, p_rng));
186 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(R, R, 1));
Jerome Forissier79013242021-07-28 10:24:04 +0200187
188cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200189 return ret;
Jerome Forissier79013242021-07-28 10:24:04 +0200190}
191
Jens Wiklander32b31802023-10-06 16:59:46 +0200192static int dhm_make_common(mbedtls_dhm_context *ctx, int x_size,
193 int (*f_rng)(void *, unsigned char *, size_t),
194 void *p_rng)
Jerome Forissier79013242021-07-28 10:24:04 +0200195{
196 int ret = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200197
Jens Wiklander32b31802023-10-06 16:59:46 +0200198 if (mbedtls_mpi_cmp_int(&ctx->P, 0) == 0) {
199 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Jens Wiklander817466c2018-05-22 13:49:31 +0200200 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200201 if (x_size < 0) {
202 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
203 }
204
205 if ((unsigned) x_size < mbedtls_mpi_size(&ctx->P)) {
206 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&ctx->X, x_size, f_rng, p_rng));
207 } else {
Jerome Forissier79013242021-07-28 10:24:04 +0200208 /* Generate X as large as possible ( <= P - 2 ) */
Jens Wiklander32b31802023-10-06 16:59:46 +0200209 ret = dhm_random_below(&ctx->X, &ctx->P, f_rng, p_rng);
210 if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
211 return MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED;
212 }
213 if (ret != 0) {
214 return ret;
215 }
Jerome Forissier79013242021-07-28 10:24:04 +0200216 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200217
218 /*
219 * Calculate GX = G^X mod P
220 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200221 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->GX, &ctx->G, &ctx->X,
222 &ctx->P, &ctx->RP));
Jens Wiklander817466c2018-05-22 13:49:31 +0200223
Jens Wiklander32b31802023-10-06 16:59:46 +0200224 if ((ret = dhm_check_range(&ctx->GX, &ctx->P)) != 0) {
225 return ret;
226 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200227
Jerome Forissier79013242021-07-28 10:24:04 +0200228cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200229 return ret;
Jerome Forissier79013242021-07-28 10:24:04 +0200230}
231
232/*
233 * Setup and write the ServerKeyExchange parameters
234 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200235int mbedtls_dhm_make_params(mbedtls_dhm_context *ctx, int x_size,
236 unsigned char *output, size_t *olen,
237 int (*f_rng)(void *, unsigned char *, size_t),
238 void *p_rng)
Jerome Forissier79013242021-07-28 10:24:04 +0200239{
240 int ret;
241 size_t n1, n2, n3;
242 unsigned char *p;
Jerome Forissier79013242021-07-28 10:24:04 +0200243
Jens Wiklander32b31802023-10-06 16:59:46 +0200244 ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
245 if (ret != 0) {
Jerome Forissier79013242021-07-28 10:24:04 +0200246 goto cleanup;
Jens Wiklander32b31802023-10-06 16:59:46 +0200247 }
Jerome Forissier79013242021-07-28 10:24:04 +0200248
Jens Wiklander817466c2018-05-22 13:49:31 +0200249 /*
Jerome Forissier79013242021-07-28 10:24:04 +0200250 * Export P, G, GX. RFC 5246 §4.4 states that "leading zero octets are
251 * not required". We omit leading zeros for compactness.
Jens Wiklander817466c2018-05-22 13:49:31 +0200252 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200253#define DHM_MPI_EXPORT(X, n) \
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100254 do { \
Jens Wiklander32b31802023-10-06 16:59:46 +0200255 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary((X), \
256 p + 2, \
257 (n))); \
258 *p++ = MBEDTLS_BYTE_1(n); \
259 *p++ = MBEDTLS_BYTE_0(n); \
260 p += (n); \
261 } while (0)
Jens Wiklander817466c2018-05-22 13:49:31 +0200262
Jens Wiklander32b31802023-10-06 16:59:46 +0200263 n1 = mbedtls_mpi_size(&ctx->P);
264 n2 = mbedtls_mpi_size(&ctx->G);
265 n3 = mbedtls_mpi_size(&ctx->GX);
Jens Wiklander817466c2018-05-22 13:49:31 +0200266
267 p = output;
Jens Wiklander32b31802023-10-06 16:59:46 +0200268 DHM_MPI_EXPORT(&ctx->P, n1);
269 DHM_MPI_EXPORT(&ctx->G, n2);
270 DHM_MPI_EXPORT(&ctx->GX, n3);
Jens Wiklander817466c2018-05-22 13:49:31 +0200271
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100272 *olen = p - output;
Jens Wiklander817466c2018-05-22 13:49:31 +0200273
Jens Wiklander817466c2018-05-22 13:49:31 +0200274cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200275 if (ret != 0 && ret > -128) {
276 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED, ret);
277 }
278 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200279}
280
281/*
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100282 * Set prime modulus and generator
283 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200284int mbedtls_dhm_set_group(mbedtls_dhm_context *ctx,
285 const mbedtls_mpi *P,
286 const mbedtls_mpi *G)
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100287{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200288 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100289
Jens Wiklander32b31802023-10-06 16:59:46 +0200290 if ((ret = mbedtls_mpi_copy(&ctx->P, P)) != 0 ||
291 (ret = mbedtls_mpi_copy(&ctx->G, G)) != 0) {
292 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_SET_GROUP_FAILED, ret);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100293 }
294
Jens Wiklander32b31802023-10-06 16:59:46 +0200295 return 0;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100296}
297
298/*
Jens Wiklander817466c2018-05-22 13:49:31 +0200299 * Import the peer's public value G^Y
300 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200301int mbedtls_dhm_read_public(mbedtls_dhm_context *ctx,
302 const unsigned char *input, size_t ilen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200303{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200304 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200305
Jens Wiklander32b31802023-10-06 16:59:46 +0200306 if (ilen < 1 || ilen > mbedtls_dhm_get_len(ctx)) {
307 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
308 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200309
Jens Wiklander32b31802023-10-06 16:59:46 +0200310 if ((ret = mbedtls_mpi_read_binary(&ctx->GY, input, ilen)) != 0) {
311 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED, ret);
312 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200313
Jens Wiklander32b31802023-10-06 16:59:46 +0200314 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200315}
316
317/*
318 * Create own private value X and export G^X
319 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200320int mbedtls_dhm_make_public(mbedtls_dhm_context *ctx, int x_size,
321 unsigned char *output, size_t olen,
322 int (*f_rng)(void *, unsigned char *, size_t),
323 void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200324{
Jerome Forissier79013242021-07-28 10:24:04 +0200325 int ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200326
Jens Wiklander32b31802023-10-06 16:59:46 +0200327 if (olen < 1 || olen > mbedtls_dhm_get_len(ctx)) {
328 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
329 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200330
Jens Wiklander32b31802023-10-06 16:59:46 +0200331 ret = dhm_make_common(ctx, x_size, f_rng, p_rng);
332 if (ret == MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) {
333 return MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED;
334 }
335 if (ret != 0) {
Jerome Forissier79013242021-07-28 10:24:04 +0200336 goto cleanup;
Jens Wiklander32b31802023-10-06 16:59:46 +0200337 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200338
Jens Wiklander32b31802023-10-06 16:59:46 +0200339 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->GX, output, olen));
Jens Wiklander817466c2018-05-22 13:49:31 +0200340
341cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200342 if (ret != 0 && ret > -128) {
343 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED, ret);
344 }
345 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200346}
347
Jerome Forissier79013242021-07-28 10:24:04 +0200348
Jens Wiklander817466c2018-05-22 13:49:31 +0200349/*
350 * Use the blinding method and optimisation suggested in section 10 of:
351 * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
352 * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
353 * Berlin Heidelberg, 1996. p. 104-113.
354 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200355static int dhm_update_blinding(mbedtls_dhm_context *ctx,
356 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200357{
Jerome Forissier79013242021-07-28 10:24:04 +0200358 int ret;
359 mbedtls_mpi R;
360
Jens Wiklander32b31802023-10-06 16:59:46 +0200361 mbedtls_mpi_init(&R);
Jens Wiklander817466c2018-05-22 13:49:31 +0200362
363 /*
364 * Don't use any blinding the first time a particular X is used,
365 * but remember it to use blinding next time.
366 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200367 if (mbedtls_mpi_cmp_mpi(&ctx->X, &ctx->pX) != 0) {
368 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&ctx->pX, &ctx->X));
369 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vi, 1));
370 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ctx->Vf, 1));
Jens Wiklander817466c2018-05-22 13:49:31 +0200371
Jens Wiklander32b31802023-10-06 16:59:46 +0200372 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200373 }
374
375 /*
376 * Ok, we need blinding. Can we re-use existing values?
377 * If yes, just update them by squaring them.
378 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200379 if (mbedtls_mpi_cmp_int(&ctx->Vi, 1) != 0) {
380 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vi, &ctx->Vi, &ctx->Vi));
381 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200382
Jens Wiklander32b31802023-10-06 16:59:46 +0200383 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf));
384 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200385
Jens Wiklander32b31802023-10-06 16:59:46 +0200386 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200387 }
388
389 /*
390 * We need to generate blinding values from scratch
391 */
392
Jerome Forissier79013242021-07-28 10:24:04 +0200393 /* Vi = random( 2, P-2 ) */
Jens Wiklander32b31802023-10-06 16:59:46 +0200394 MBEDTLS_MPI_CHK(dhm_random_below(&ctx->Vi, &ctx->P, f_rng, p_rng));
Jens Wiklander817466c2018-05-22 13:49:31 +0200395
Jerome Forissier79013242021-07-28 10:24:04 +0200396 /* Vf = Vi^-X mod P
397 * First compute Vi^-1 = R * (R Vi)^-1, (avoiding leaks from inv_mod),
398 * then elevate to the Xth power. */
Jens Wiklander32b31802023-10-06 16:59:46 +0200399 MBEDTLS_MPI_CHK(dhm_random_below(&R, &ctx->P, f_rng, p_rng));
400 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vi, &R));
401 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
402 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&ctx->Vf, &ctx->Vf, &ctx->P));
403 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &R));
404 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200405
Jens Wiklander32b31802023-10-06 16:59:46 +0200406 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP));
Jens Wiklander817466c2018-05-22 13:49:31 +0200407
408cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200409 mbedtls_mpi_free(&R);
Jerome Forissier79013242021-07-28 10:24:04 +0200410
Jens Wiklander32b31802023-10-06 16:59:46 +0200411 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200412}
413
414/*
415 * Derive and export the shared secret (G^Y)^X mod P
416 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200417int mbedtls_dhm_calc_secret(mbedtls_dhm_context *ctx,
418 unsigned char *output, size_t output_size, size_t *olen,
419 int (*f_rng)(void *, unsigned char *, size_t),
420 void *p_rng)
Jens Wiklander817466c2018-05-22 13:49:31 +0200421{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200422 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200423 mbedtls_mpi GYb;
424
Jens Wiklander32b31802023-10-06 16:59:46 +0200425 if (f_rng == NULL) {
426 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
427 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200428
Jens Wiklander32b31802023-10-06 16:59:46 +0200429 if (output_size < mbedtls_dhm_get_len(ctx)) {
430 return MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
431 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200432
Jens Wiklander32b31802023-10-06 16:59:46 +0200433 if ((ret = dhm_check_range(&ctx->GY, &ctx->P)) != 0) {
434 return ret;
435 }
436
437 mbedtls_mpi_init(&GYb);
Jens Wiklander817466c2018-05-22 13:49:31 +0200438
439 /* Blind peer's value */
Jens Wiklander32b31802023-10-06 16:59:46 +0200440 MBEDTLS_MPI_CHK(dhm_update_blinding(ctx, f_rng, p_rng));
441 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&GYb, &ctx->GY, &ctx->Vi));
442 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&GYb, &GYb, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200443
444 /* Do modular exponentiation */
Jens Wiklander32b31802023-10-06 16:59:46 +0200445 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->K, &GYb, &ctx->X,
446 &ctx->P, &ctx->RP));
Jens Wiklander817466c2018-05-22 13:49:31 +0200447
448 /* Unblind secret value */
Jens Wiklander32b31802023-10-06 16:59:46 +0200449 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->K, &ctx->K, &ctx->Vf));
450 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->K, &ctx->K, &ctx->P));
Jens Wiklander817466c2018-05-22 13:49:31 +0200451
Jerome Forissier79013242021-07-28 10:24:04 +0200452 /* Output the secret without any leading zero byte. This is mandatory
453 * for TLS per RFC 5246 §8.1.2. */
Jens Wiklander32b31802023-10-06 16:59:46 +0200454 *olen = mbedtls_mpi_size(&ctx->K);
455 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&ctx->K, output, *olen));
Jens Wiklander817466c2018-05-22 13:49:31 +0200456
457cleanup:
Jens Wiklander32b31802023-10-06 16:59:46 +0200458 mbedtls_mpi_free(&GYb);
Jens Wiklander817466c2018-05-22 13:49:31 +0200459
Jens Wiklander32b31802023-10-06 16:59:46 +0200460 if (ret != 0) {
461 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED, ret);
462 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200463
Jens Wiklander32b31802023-10-06 16:59:46 +0200464 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200465}
466
467/*
468 * Free the components of a DHM key
469 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200470void mbedtls_dhm_free(mbedtls_dhm_context *ctx)
Jens Wiklander817466c2018-05-22 13:49:31 +0200471{
Jens Wiklander32b31802023-10-06 16:59:46 +0200472 if (ctx == NULL) {
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100473 return;
Jens Wiklander32b31802023-10-06 16:59:46 +0200474 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200475
Jens Wiklander32b31802023-10-06 16:59:46 +0200476 mbedtls_mpi_free(&ctx->pX);
477 mbedtls_mpi_free(&ctx->Vf);
478 mbedtls_mpi_free(&ctx->Vi);
479 mbedtls_mpi_free(&ctx->RP);
480 mbedtls_mpi_free(&ctx->K);
481 mbedtls_mpi_free(&ctx->GY);
482 mbedtls_mpi_free(&ctx->GX);
483 mbedtls_mpi_free(&ctx->X);
484 mbedtls_mpi_free(&ctx->G);
485 mbedtls_mpi_free(&ctx->P);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100486
Jens Wiklander32b31802023-10-06 16:59:46 +0200487 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_dhm_context));
Jens Wiklander817466c2018-05-22 13:49:31 +0200488}
489
490#if defined(MBEDTLS_ASN1_PARSE_C)
491/*
492 * Parse DHM parameters
493 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200494int mbedtls_dhm_parse_dhm(mbedtls_dhm_context *dhm, const unsigned char *dhmin,
495 size_t dhminlen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200496{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200497 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200498 size_t len;
499 unsigned char *p, *end;
500#if defined(MBEDTLS_PEM_PARSE_C)
501 mbedtls_pem_context pem;
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100502#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200503
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100504#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander32b31802023-10-06 16:59:46 +0200505 mbedtls_pem_init(&pem);
Jens Wiklander817466c2018-05-22 13:49:31 +0200506
507 /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
Jens Wiklander32b31802023-10-06 16:59:46 +0200508 if (dhminlen == 0 || dhmin[dhminlen - 1] != '\0') {
Jens Wiklander817466c2018-05-22 13:49:31 +0200509 ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
Jens Wiklander32b31802023-10-06 16:59:46 +0200510 } else {
511 ret = mbedtls_pem_read_buffer(&pem,
512 "-----BEGIN DH PARAMETERS-----",
513 "-----END DH PARAMETERS-----",
514 dhmin, NULL, 0, &dhminlen);
515 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200516
Jens Wiklander32b31802023-10-06 16:59:46 +0200517 if (ret == 0) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200518 /*
519 * Was PEM encoded
520 */
521 dhminlen = pem.buflen;
Jens Wiklander32b31802023-10-06 16:59:46 +0200522 } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200523 goto exit;
Jens Wiklander32b31802023-10-06 16:59:46 +0200524 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200525
Jens Wiklander32b31802023-10-06 16:59:46 +0200526 p = (ret == 0) ? pem.buf : (unsigned char *) dhmin;
Jens Wiklander817466c2018-05-22 13:49:31 +0200527#else
528 p = (unsigned char *) dhmin;
529#endif /* MBEDTLS_PEM_PARSE_C */
530 end = p + dhminlen;
531
532 /*
533 * DHParams ::= SEQUENCE {
534 * prime INTEGER, -- P
535 * generator INTEGER, -- g
536 * privateValueLength INTEGER OPTIONAL
537 * }
538 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200539 if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
540 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
541 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200542 goto exit;
543 }
544
545 end = p + len;
546
Jens Wiklander32b31802023-10-06 16:59:46 +0200547 if ((ret = mbedtls_asn1_get_mpi(&p, end, &dhm->P)) != 0 ||
548 (ret = mbedtls_asn1_get_mpi(&p, end, &dhm->G)) != 0) {
549 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200550 goto exit;
551 }
552
Jens Wiklander32b31802023-10-06 16:59:46 +0200553 if (p != end) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200554 /* This might be the optional privateValueLength.
555 * If so, we can cleanly discard it */
556 mbedtls_mpi rec;
Jens Wiklander32b31802023-10-06 16:59:46 +0200557 mbedtls_mpi_init(&rec);
558 ret = mbedtls_asn1_get_mpi(&p, end, &rec);
559 mbedtls_mpi_free(&rec);
560 if (ret != 0) {
561 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT, ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200562 goto exit;
563 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200564 if (p != end) {
565 ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_DHM_INVALID_FORMAT,
566 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
Jens Wiklander817466c2018-05-22 13:49:31 +0200567 goto exit;
568 }
569 }
570
571 ret = 0;
572
Jens Wiklander817466c2018-05-22 13:49:31 +0200573exit:
574#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander32b31802023-10-06 16:59:46 +0200575 mbedtls_pem_free(&pem);
Jens Wiklander817466c2018-05-22 13:49:31 +0200576#endif
Jens Wiklander32b31802023-10-06 16:59:46 +0200577 if (ret != 0) {
578 mbedtls_dhm_free(dhm);
579 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200580
Jens Wiklander32b31802023-10-06 16:59:46 +0200581 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200582}
583
584#if defined(MBEDTLS_FS_IO)
585/*
586 * Load all data from a file into a given buffer.
587 *
588 * The file is expected to contain either PEM or DER encoded data.
589 * A terminating null byte is always appended. It is included in the announced
590 * length only if the data looks like it is PEM encoded.
591 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200592static int load_file(const char *path, unsigned char **buf, size_t *n)
Jens Wiklander817466c2018-05-22 13:49:31 +0200593{
594 FILE *f;
595 long size;
596
Jens Wiklander32b31802023-10-06 16:59:46 +0200597 if ((f = fopen(path, "rb")) == NULL) {
598 return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
Jens Wiklander817466c2018-05-22 13:49:31 +0200599 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200600 /* The data loaded here is public, so don't bother disabling buffering. */
601
602 fseek(f, 0, SEEK_END);
603 if ((size = ftell(f)) == -1) {
604 fclose(f);
605 return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
606 }
607 fseek(f, 0, SEEK_SET);
Jens Wiklander817466c2018-05-22 13:49:31 +0200608
609 *n = (size_t) size;
610
Jens Wiklander32b31802023-10-06 16:59:46 +0200611 if (*n + 1 == 0 ||
612 (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
613 fclose(f);
614 return MBEDTLS_ERR_DHM_ALLOC_FAILED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200615 }
616
Jens Wiklander32b31802023-10-06 16:59:46 +0200617 if (fread(*buf, 1, *n, f) != *n) {
618 fclose(f);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100619
Jens Wiklander32b31802023-10-06 16:59:46 +0200620 mbedtls_platform_zeroize(*buf, *n + 1);
621 mbedtls_free(*buf);
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100622
Jens Wiklander32b31802023-10-06 16:59:46 +0200623 return MBEDTLS_ERR_DHM_FILE_IO_ERROR;
Jens Wiklander817466c2018-05-22 13:49:31 +0200624 }
625
Jens Wiklander32b31802023-10-06 16:59:46 +0200626 fclose(f);
Jens Wiklander817466c2018-05-22 13:49:31 +0200627
628 (*buf)[*n] = '\0';
629
Jens Wiklander32b31802023-10-06 16:59:46 +0200630 if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200631 ++*n;
Jens Wiklander32b31802023-10-06 16:59:46 +0200632 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200633
Jens Wiklander32b31802023-10-06 16:59:46 +0200634 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200635}
636
637/*
638 * Load and parse DHM parameters
639 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200640int mbedtls_dhm_parse_dhmfile(mbedtls_dhm_context *dhm, const char *path)
Jens Wiklander817466c2018-05-22 13:49:31 +0200641{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200642 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200643 size_t n;
644 unsigned char *buf;
645
Jens Wiklander32b31802023-10-06 16:59:46 +0200646 if ((ret = load_file(path, &buf, &n)) != 0) {
647 return ret;
648 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200649
Jens Wiklander32b31802023-10-06 16:59:46 +0200650 ret = mbedtls_dhm_parse_dhm(dhm, buf, n);
Jens Wiklander817466c2018-05-22 13:49:31 +0200651
Jens Wiklander32b31802023-10-06 16:59:46 +0200652 mbedtls_platform_zeroize(buf, n);
653 mbedtls_free(buf);
Jens Wiklander817466c2018-05-22 13:49:31 +0200654
Jens Wiklander32b31802023-10-06 16:59:46 +0200655 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200656}
657#endif /* MBEDTLS_FS_IO */
658#endif /* MBEDTLS_ASN1_PARSE_C */
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100659#endif /* MBEDTLS_DHM_ALT */
Jens Wiklander817466c2018-05-22 13:49:31 +0200660
661#if defined(MBEDTLS_SELF_TEST)
662
Jerome Forissier5b25c762020-04-07 11:18:49 +0200663#if defined(MBEDTLS_PEM_PARSE_C)
Jens Wiklander817466c2018-05-22 13:49:31 +0200664static const char mbedtls_test_dhm_params[] =
Jens Wiklander32b31802023-10-06 16:59:46 +0200665 "-----BEGIN DH PARAMETERS-----\r\n"
666 "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
667 "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
668 "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
669 "-----END DH PARAMETERS-----\r\n";
Jerome Forissier5b25c762020-04-07 11:18:49 +0200670#else /* MBEDTLS_PEM_PARSE_C */
671static const char mbedtls_test_dhm_params[] = {
Jens Wiklander32b31802023-10-06 16:59:46 +0200672 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
673 0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
674 0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
675 0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
676 0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
677 0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
678 0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
679 0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
680 0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
681 0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
682 0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
683 0x49, 0x75, 0xb3, 0x02, 0x01, 0x02
684};
Jerome Forissier5b25c762020-04-07 11:18:49 +0200685#endif /* MBEDTLS_PEM_PARSE_C */
Jens Wiklander817466c2018-05-22 13:49:31 +0200686
Jens Wiklander32b31802023-10-06 16:59:46 +0200687static const size_t mbedtls_test_dhm_params_len = sizeof(mbedtls_test_dhm_params);
Jens Wiklander817466c2018-05-22 13:49:31 +0200688
689/*
690 * Checkup routine
691 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200692int mbedtls_dhm_self_test(int verbose)
Jens Wiklander817466c2018-05-22 13:49:31 +0200693{
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200694 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200695 mbedtls_dhm_context dhm;
696
Jens Wiklander32b31802023-10-06 16:59:46 +0200697 mbedtls_dhm_init(&dhm);
Jens Wiklander817466c2018-05-22 13:49:31 +0200698
Jens Wiklander32b31802023-10-06 16:59:46 +0200699 if (verbose != 0) {
700 mbedtls_printf(" DHM parameter load: ");
701 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200702
Jens Wiklander32b31802023-10-06 16:59:46 +0200703 if ((ret = mbedtls_dhm_parse_dhm(&dhm,
704 (const unsigned char *) mbedtls_test_dhm_params,
705 mbedtls_test_dhm_params_len)) != 0) {
706 if (verbose != 0) {
707 mbedtls_printf("failed\n");
708 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200709
710 ret = 1;
711 goto exit;
712 }
713
Jens Wiklander32b31802023-10-06 16:59:46 +0200714 if (verbose != 0) {
715 mbedtls_printf("passed\n\n");
716 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200717
718exit:
Jens Wiklander32b31802023-10-06 16:59:46 +0200719 mbedtls_dhm_free(&dhm);
Jens Wiklander817466c2018-05-22 13:49:31 +0200720
Jens Wiklander32b31802023-10-06 16:59:46 +0200721 return ret;
Jens Wiklander817466c2018-05-22 13:49:31 +0200722}
723
724#endif /* MBEDTLS_SELF_TEST */
725
726#endif /* MBEDTLS_DHM_C */