blob: 102c24ab2a9e3b1f50a590a80a2e22715e3196dd [file] [log] [blame]
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001/*
2 * Elliptic curve J-PAKE
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman7ff79652023-11-03 12:04:52 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02006 */
7
8/*
Manuel Pégourié-Gonnard6b798b92015-08-14 11:18:30 +02009 * References in the code are to the Thread v1.0 Specification,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +020010 * available to members of the Thread Group http://threadgroup.org/
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020011 */
12
Gilles Peskinedb09ef62020-06-03 01:43:33 +020013#include "common.h"
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020014
15#if defined(MBEDTLS_ECJPAKE_C)
16
17#include "mbedtls/ecjpake.h"
Hanno Becker71c8e1b2018-12-14 17:09:39 +000018#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000019#include "mbedtls/error.h"
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020020
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020021#include <string.h>
22
Hanno Becker616d1ca2018-01-24 10:25:05 +000023#if !defined(MBEDTLS_ECJPAKE_ALT)
24
Hanno Becker71c8e1b2018-12-14 17:09:39 +000025/* Parameter validation macros based on platform_util.h */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010026#define ECJPAKE_VALIDATE_RET(cond) \
27 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA)
28#define ECJPAKE_VALIDATE(cond) \
29 MBEDTLS_INTERNAL_VALIDATE(cond)
Hanno Becker71c8e1b2018-12-14 17:09:39 +000030
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020031/*
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +020032 * Convert a mbedtls_ecjpake_role to identifier string
33 */
34static const char * const ecjpake_id[] = {
35 "client",
36 "server"
37};
38
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010039#define ID_MINE (ecjpake_id[ctx->role])
40#define ID_PEER (ecjpake_id[1 - ctx->role])
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +020041
42/*
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020043 * Initialize context
44 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010045void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx)
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020046{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010047 ECJPAKE_VALIDATE(ctx != NULL);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020048
49 ctx->md_info = NULL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010050 mbedtls_ecp_group_init(&ctx->grp);
Manuel Pégourié-Gonnardb7da1942015-10-19 13:35:22 +020051 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020052
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010053 mbedtls_ecp_point_init(&ctx->Xm1);
54 mbedtls_ecp_point_init(&ctx->Xm2);
55 mbedtls_ecp_point_init(&ctx->Xp1);
56 mbedtls_ecp_point_init(&ctx->Xp2);
57 mbedtls_ecp_point_init(&ctx->Xp);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020058
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010059 mbedtls_mpi_init(&ctx->xm1);
60 mbedtls_mpi_init(&ctx->xm2);
61 mbedtls_mpi_init(&ctx->s);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020062}
63
64/*
65 * Free context
66 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010067void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx)
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020068{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010069 if (ctx == NULL) {
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020070 return;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010071 }
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020072
73 ctx->md_info = NULL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010074 mbedtls_ecp_group_free(&ctx->grp);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020075
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010076 mbedtls_ecp_point_free(&ctx->Xm1);
77 mbedtls_ecp_point_free(&ctx->Xm2);
78 mbedtls_ecp_point_free(&ctx->Xp1);
79 mbedtls_ecp_point_free(&ctx->Xp2);
80 mbedtls_ecp_point_free(&ctx->Xp);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020081
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010082 mbedtls_mpi_free(&ctx->xm1);
83 mbedtls_mpi_free(&ctx->xm2);
84 mbedtls_mpi_free(&ctx->s);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020085}
86
87/*
88 * Setup context
89 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010090int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx,
91 mbedtls_ecjpake_role role,
92 mbedtls_md_type_t hash,
93 mbedtls_ecp_group_id curve,
94 const unsigned char *secret,
95 size_t len)
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020096{
Janos Follath24eed8d2019-11-22 13:21:35 +000097 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker185e5162018-12-19 09:48:50 +000098
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010099 ECJPAKE_VALIDATE_RET(ctx != NULL);
100 ECJPAKE_VALIDATE_RET(role == MBEDTLS_ECJPAKE_CLIENT ||
101 role == MBEDTLS_ECJPAKE_SERVER);
102 ECJPAKE_VALIDATE_RET(secret != NULL || len == 0);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200103
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200104 ctx->role = role;
105
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100106 if ((ctx->md_info = mbedtls_md_info_from_type(hash)) == NULL) {
107 return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
108 }
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200109
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100110 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200111
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100112 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200113
114cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100115 if (ret != 0) {
116 mbedtls_ecjpake_free(ctx);
117 }
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200118
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100119 return ret;
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200120}
121
122/*
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200123 * Check if context is ready for use
124 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100125int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx)
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200126{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 ECJPAKE_VALIDATE_RET(ctx != NULL);
Hanno Becker71c8e1b2018-12-14 17:09:39 +0000128
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100129 if (ctx->md_info == NULL ||
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200130 ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100131 ctx->s.p == NULL) {
132 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200133 }
134
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100135 return 0;
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200136}
137
138/*
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200139 * Write a point plus its length to a buffer
140 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100141static int ecjpake_write_len_point(unsigned char **p,
142 const unsigned char *end,
143 const mbedtls_ecp_group *grp,
144 const int pf,
145 const mbedtls_ecp_point *P)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200146{
Janos Follath24eed8d2019-11-22 13:21:35 +0000147 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200148 size_t len;
149
150 /* Need at least 4 for length plus 1 for point */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100151 if (end < *p || end - *p < 5) {
152 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
153 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200154
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100155 ret = mbedtls_ecp_point_write_binary(grp, P, pf,
156 &len, *p + 4, end - (*p + 4));
157 if (ret != 0) {
158 return ret;
159 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200160
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100161 MBEDTLS_PUT_UINT32_BE(len, *p, 0);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200162
163 *p += 4 + len;
164
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100165 return 0;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200166}
167
168/*
169 * Size of the temporary buffer for ecjpake_hash:
Manuel Pégourié-Gonnard4b20c0e2015-10-20 16:16:38 +0200170 * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200171 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100172#define ECJPAKE_HASH_BUF_LEN (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200173
174/*
175 * Compute hash for ZKP (7.4.2.2.2.1)
176 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100177static int ecjpake_hash(const mbedtls_md_info_t *md_info,
178 const mbedtls_ecp_group *grp,
179 const int pf,
180 const mbedtls_ecp_point *G,
181 const mbedtls_ecp_point *V,
182 const mbedtls_ecp_point *X,
183 const char *id,
184 mbedtls_mpi *h)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200185{
Janos Follath24eed8d2019-11-22 13:21:35 +0000186 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200187 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
188 unsigned char *p = buf;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100189 const unsigned char *end = buf + sizeof(buf);
190 const size_t id_len = strlen(id);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200191 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
192
193 /* Write things to temporary buffer */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100194 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, G));
195 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, V));
196 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, X));
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200197
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100198 if (end - p < 4) {
199 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
200 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200201
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100202 MBEDTLS_PUT_UINT32_BE(id_len, p, 0);
Joe Subbiania651e6f2021-08-23 11:35:25 +0100203 p += 4;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200204
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100205 if (end < p || (size_t) (end - p) < id_len) {
206 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
207 }
Manuel Pégourié-Gonnard4b20c0e2015-10-20 16:16:38 +0200208
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100209 memcpy(p, id, id_len);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200210 p += id_len;
211
212 /* Compute hash */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100213 MBEDTLS_MPI_CHK(mbedtls_md(md_info, buf, p - buf, hash));
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200214
215 /* Turn it into an integer mod n */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100216 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(h, hash,
217 mbedtls_md_get_size(md_info)));
218 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(h, h, &grp->N));
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200219
220cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100221 return ret;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200222}
223
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200224/*
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200225 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
226 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100227static int ecjpake_zkp_read(const mbedtls_md_info_t *md_info,
228 const mbedtls_ecp_group *grp,
229 const int pf,
230 const mbedtls_ecp_point *G,
231 const mbedtls_ecp_point *X,
232 const char *id,
233 const unsigned char **p,
234 const unsigned char *end)
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200235{
Janos Follath24eed8d2019-11-22 13:21:35 +0000236 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200237 mbedtls_ecp_point V, VV;
238 mbedtls_mpi r, h;
239 size_t r_len;
240
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100241 mbedtls_ecp_point_init(&V);
242 mbedtls_ecp_point_init(&VV);
243 mbedtls_mpi_init(&r);
244 mbedtls_mpi_init(&h);
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200245
246 /*
247 * struct {
248 * ECPoint V;
249 * opaque r<1..2^8-1>;
250 * } ECSchnorrZKP;
251 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100252 if (end < *p) {
253 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
254 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200255
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, end - *p));
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200257
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100258 if (end < *p || (size_t) (end - *p) < 1) {
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200259 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
260 goto cleanup;
261 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200262
263 r_len = *(*p)++;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200264
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100265 if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) {
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200266 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
267 goto cleanup;
268 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200269
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100270 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200271 *p += r_len;
272
273 /*
274 * Verification
275 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100276 MBEDTLS_MPI_CHK(ecjpake_hash(md_info, grp, pf, G, &V, X, id, &h));
277 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd((mbedtls_ecp_group *) grp,
278 &VV, &h, X, &r, G));
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200279
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100280 if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200281 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
282 goto cleanup;
283 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200284
285cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100286 mbedtls_ecp_point_free(&V);
287 mbedtls_ecp_point_free(&VV);
288 mbedtls_mpi_free(&r);
289 mbedtls_mpi_free(&h);
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200290
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100291 return ret;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200292}
293
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200294/*
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200295 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
296 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100297static int ecjpake_zkp_write(const mbedtls_md_info_t *md_info,
298 const mbedtls_ecp_group *grp,
299 const int pf,
300 const mbedtls_ecp_point *G,
301 const mbedtls_mpi *x,
302 const mbedtls_ecp_point *X,
303 const char *id,
304 unsigned char **p,
305 const unsigned char *end,
306 int (*f_rng)(void *, unsigned char *, size_t),
307 void *p_rng)
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200308{
Janos Follath24eed8d2019-11-22 13:21:35 +0000309 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200310 mbedtls_ecp_point V;
311 mbedtls_mpi v;
312 mbedtls_mpi h; /* later recycled to hold r */
313 size_t len;
314
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100315 if (end < *p) {
316 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
317 }
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200318
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100319 mbedtls_ecp_point_init(&V);
320 mbedtls_mpi_init(&v);
321 mbedtls_mpi_init(&h);
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200322
323 /* Compute signature */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100324 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp,
325 G, &v, &V, f_rng, p_rng));
326 MBEDTLS_MPI_CHK(ecjpake_hash(md_info, grp, pf, G, &V, X, id, &h));
327 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&h, &h, x)); /* x*h */
328 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&h, &v, &h)); /* v - x*h */
329 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&h, &h, &grp->N)); /* r */
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200330
331 /* Write it out */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100332 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
333 pf, &len, *p, end - *p));
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200334 *p += len;
335
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100336 len = mbedtls_mpi_size(&h); /* actually r */
337 if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) {
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200338 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
339 goto cleanup;
340 }
341
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100342 *(*p)++ = MBEDTLS_BYTE_0(len);
343 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len)); /* r */
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200344 *p += len;
345
346cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100347 mbedtls_ecp_point_free(&V);
348 mbedtls_mpi_free(&v);
349 mbedtls_mpi_free(&h);
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200350
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100351 return ret;
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200352}
353
354/*
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200355 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
356 * Output: verified public key X
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200357 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100358static int ecjpake_kkp_read(const mbedtls_md_info_t *md_info,
359 const mbedtls_ecp_group *grp,
360 const int pf,
361 const mbedtls_ecp_point *G,
362 mbedtls_ecp_point *X,
363 const char *id,
364 const unsigned char **p,
365 const unsigned char *end)
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200366{
Janos Follath24eed8d2019-11-22 13:21:35 +0000367 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200368
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100369 if (end < *p) {
370 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
371 }
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200372
373 /*
374 * struct {
375 * ECPoint X;
376 * ECSchnorrZKP zkp;
377 * } ECJPAKEKeyKP;
378 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100379 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, end - *p));
380 if (mbedtls_ecp_is_zero(X)) {
Manuel Pégourié-Gonnard30590952015-08-17 10:37:40 +0200381 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
382 goto cleanup;
383 }
384
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100385 MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_info, grp, pf, G, X, id, p, end));
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200386
387cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 return ret;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200389}
390
391/*
392 * Generate an ECJPAKEKeyKP
393 * Output: the serialized structure, plus private/public key pair
394 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100395static int ecjpake_kkp_write(const mbedtls_md_info_t *md_info,
396 const mbedtls_ecp_group *grp,
397 const int pf,
398 const mbedtls_ecp_point *G,
399 mbedtls_mpi *x,
400 mbedtls_ecp_point *X,
401 const char *id,
402 unsigned char **p,
403 const unsigned char *end,
404 int (*f_rng)(void *, unsigned char *, size_t),
405 void *p_rng)
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200406{
Janos Follath24eed8d2019-11-22 13:21:35 +0000407 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200408 size_t len;
409
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100410 if (end < *p) {
411 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
412 }
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200413
414 /* Generate key (7.4.2.3.1) and write it out */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100415 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, G, x, X,
416 f_rng, p_rng));
417 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, X,
418 pf, &len, *p, end - *p));
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200419 *p += len;
420
421 /* Generate and write proof */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100422 MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_info, grp, pf, G, x, X, id,
423 p, end, f_rng, p_rng));
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200424
425cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100426 return ret;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200427}
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200428
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200429/*
430 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
Shaun Case0e7791f2021-12-20 21:14:10 -0800431 * Outputs: verified peer public keys Xa, Xb
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200432 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100433static int ecjpake_kkpp_read(const mbedtls_md_info_t *md_info,
434 const mbedtls_ecp_group *grp,
435 const int pf,
436 const mbedtls_ecp_point *G,
437 mbedtls_ecp_point *Xa,
438 mbedtls_ecp_point *Xb,
439 const char *id,
440 const unsigned char *buf,
441 size_t len)
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200442{
Janos Follath24eed8d2019-11-22 13:21:35 +0000443 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200444 const unsigned char *p = buf;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200445 const unsigned char *end = buf + len;
446
447 /*
448 * struct {
449 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
450 * } ECJPAKEKeyKPPairList;
451 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100452 MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_info, grp, pf, G, Xa, id, &p, end));
453 MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_info, grp, pf, G, Xb, id, &p, end));
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200454
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100455 if (p != end) {
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200456 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100457 }
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200458
459cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100460 return ret;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200461}
462
463/*
464 * Generate a ECJPAKEKeyKPPairList
465 * Outputs: the serialized structure, plus two private/public key pairs
466 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100467static int ecjpake_kkpp_write(const mbedtls_md_info_t *md_info,
468 const mbedtls_ecp_group *grp,
469 const int pf,
470 const mbedtls_ecp_point *G,
471 mbedtls_mpi *xm1,
472 mbedtls_ecp_point *Xa,
473 mbedtls_mpi *xm2,
474 mbedtls_ecp_point *Xb,
475 const char *id,
476 unsigned char *buf,
477 size_t len,
478 size_t *olen,
479 int (*f_rng)(void *, unsigned char *, size_t),
480 void *p_rng)
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200481{
Janos Follath24eed8d2019-11-22 13:21:35 +0000482 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200483 unsigned char *p = buf;
484 const unsigned char *end = buf + len;
485
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100486 MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_info, grp, pf, G, xm1, Xa, id,
487 &p, end, f_rng, p_rng));
488 MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_info, grp, pf, G, xm2, Xb, id,
489 &p, end, f_rng, p_rng));
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200490
491 *olen = p - buf;
492
493cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100494 return ret;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200495}
496
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200497/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200498 * Read and process the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200499 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100500int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
501 const unsigned char *buf,
502 size_t len)
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200503{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100504 ECJPAKE_VALIDATE_RET(ctx != NULL);
505 ECJPAKE_VALIDATE_RET(buf != NULL);
Hanno Becker71c8e1b2018-12-14 17:09:39 +0000506
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100507 return ecjpake_kkpp_read(ctx->md_info, &ctx->grp, ctx->point_format,
508 &ctx->grp.G,
509 &ctx->Xp1, &ctx->Xp2, ID_PEER,
510 buf, len);
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200511}
512
513/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200514 * Generate and write the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200515 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100516int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx,
517 unsigned char *buf, size_t len, size_t *olen,
518 int (*f_rng)(void *, unsigned char *, size_t),
519 void *p_rng)
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200520{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100521 ECJPAKE_VALIDATE_RET(ctx != NULL);
522 ECJPAKE_VALIDATE_RET(buf != NULL);
523 ECJPAKE_VALIDATE_RET(olen != NULL);
524 ECJPAKE_VALIDATE_RET(f_rng != NULL);
Hanno Becker71c8e1b2018-12-14 17:09:39 +0000525
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100526 return ecjpake_kkpp_write(ctx->md_info, &ctx->grp, ctx->point_format,
527 &ctx->grp.G,
528 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
529 ID_MINE, buf, len, olen, f_rng, p_rng);
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200530}
531
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200532/*
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200533 * Compute the sum of three points R = A + B + C
534 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100535static int ecjpake_ecp_add3(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
536 const mbedtls_ecp_point *A,
537 const mbedtls_ecp_point *B,
538 const mbedtls_ecp_point *C)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200539{
Janos Follath24eed8d2019-11-22 13:21:35 +0000540 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200541 mbedtls_mpi one;
542
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100543 mbedtls_mpi_init(&one);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200544
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100545 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
546 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, A, &one, B));
547 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, R, &one, C));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200548
549cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100550 mbedtls_mpi_free(&one);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200551
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100552 return ret;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200553}
554
555/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200556 * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200557 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100558int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
559 const unsigned char *buf,
560 size_t len)
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200561{
Janos Follath24eed8d2019-11-22 13:21:35 +0000562 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200563 const unsigned char *p = buf;
564 const unsigned char *end = buf + len;
565 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200566 mbedtls_ecp_point G; /* C: GB, S: GA */
Hanno Becker185e5162018-12-19 09:48:50 +0000567
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100568 ECJPAKE_VALIDATE_RET(ctx != NULL);
569 ECJPAKE_VALIDATE_RET(buf != NULL);
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200570
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100571 mbedtls_ecp_group_init(&grp);
572 mbedtls_ecp_point_init(&G);
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200573
574 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200575 * Server: GA = X3 + X4 + X1 (7.4.2.6.1)
576 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
577 * Unified: G = Xm1 + Xm2 + Xp1
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200578 * We need that before parsing in order to check Xp as we read it
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200579 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100580 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
581 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200582
583 /*
584 * struct {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200585 * ECParameters curve_params; // only client reading server msg
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200586 * ECJPAKEKeyKP ecjpake_key_kp;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200587 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200588 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100589 if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) {
590 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_group(&grp, &p, len));
591 if (grp.id != ctx->grp.id) {
Manuel Pégourié-Gonnardd9802af2015-08-17 12:47:38 +0200592 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
593 goto cleanup;
594 }
595 }
596
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100597 MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_info, &ctx->grp,
598 ctx->point_format,
599 &G, &ctx->Xp, ID_PEER, &p, end));
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200600
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100601 if (p != end) {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200602 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
603 goto cleanup;
604 }
605
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200606cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100607 mbedtls_ecp_group_free(&grp);
608 mbedtls_ecp_point_free(&G);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200609
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100610 return ret;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200611}
612
613/*
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200614 * Compute R = +/- X * S mod N, taking care not to leak S
615 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100616static int ecjpake_mul_secret(mbedtls_mpi *R, int sign,
617 const mbedtls_mpi *X,
618 const mbedtls_mpi *S,
619 const mbedtls_mpi *N,
620 int (*f_rng)(void *, unsigned char *, size_t),
621 void *p_rng)
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200622{
Janos Follath24eed8d2019-11-22 13:21:35 +0000623 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200624 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
625
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100626 mbedtls_mpi_init(&b);
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200627
628 /* b = s + rnd-128-bit * N */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100629 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&b, 16, f_rng, p_rng));
630 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&b, &b, N));
631 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&b, &b, S));
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200632
633 /* R = sign * X * b mod N */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100634 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200635 R->s *= sign;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100636 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200637
638cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100639 mbedtls_mpi_free(&b);
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200640
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100641 return ret;
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200642}
643
644/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200645 * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200646 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100647int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx,
648 unsigned char *buf, size_t len, size_t *olen,
649 int (*f_rng)(void *, unsigned char *, size_t),
650 void *p_rng)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200651{
Janos Follath24eed8d2019-11-22 13:21:35 +0000652 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200653 mbedtls_ecp_point G; /* C: GA, S: GB */
654 mbedtls_ecp_point Xm; /* C: Xc, S: Xs */
655 mbedtls_mpi xm; /* C: xc, S: xs */
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200656 unsigned char *p = buf;
657 const unsigned char *end = buf + len;
658 size_t ec_len;
Hanno Becker185e5162018-12-19 09:48:50 +0000659
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100660 ECJPAKE_VALIDATE_RET(ctx != NULL);
661 ECJPAKE_VALIDATE_RET(buf != NULL);
662 ECJPAKE_VALIDATE_RET(olen != NULL);
663 ECJPAKE_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200664
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100665 mbedtls_ecp_point_init(&G);
666 mbedtls_ecp_point_init(&Xm);
667 mbedtls_mpi_init(&xm);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200668
669 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200670 * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200671 *
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200672 * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA
673 * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB
674 * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200675 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100676 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
677 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1));
678 MBEDTLS_MPI_CHK(ecjpake_mul_secret(&xm, 1, &ctx->xm2, &ctx->s,
679 &ctx->grp.N, f_rng, p_rng));
680 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &Xm, &xm, &G, f_rng, p_rng));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200681
682 /*
683 * Now write things out
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200684 *
685 * struct {
686 * ECParameters curve_params; // only server writing its message
687 * ECJPAKEKeyKP ecjpake_key_kp;
688 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200689 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100690 if (ctx->role == MBEDTLS_ECJPAKE_SERVER) {
691 if (end < p) {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200692 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
693 goto cleanup;
694 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100695 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len,
696 p, end - p));
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200697 p += ec_len;
698 }
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200699
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100700 if (end < p) {
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200701 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
702 goto cleanup;
703 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100704 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm,
705 ctx->point_format, &ec_len, p, end - p));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200706 p += ec_len;
707
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100708 MBEDTLS_MPI_CHK(ecjpake_zkp_write(ctx->md_info, &ctx->grp,
709 ctx->point_format,
710 &G, &xm, &Xm, ID_MINE,
711 &p, end, f_rng, p_rng));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200712
713 *olen = p - buf;
714
715cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100716 mbedtls_ecp_point_free(&G);
717 mbedtls_ecp_point_free(&Xm);
718 mbedtls_mpi_free(&xm);
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200719
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100720 return ret;
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200721}
722
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200723/*
724 * Derive PMS (7.4.2.7 / 7.4.2.8)
725 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100726int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx,
727 unsigned char *buf, size_t len, size_t *olen,
728 int (*f_rng)(void *, unsigned char *, size_t),
729 void *p_rng)
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200730{
Janos Follath24eed8d2019-11-22 13:21:35 +0000731 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200732 mbedtls_ecp_point K;
733 mbedtls_mpi m_xm2_s, one;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200734 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
735 size_t x_bytes;
Hanno Becker185e5162018-12-19 09:48:50 +0000736
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100737 ECJPAKE_VALIDATE_RET(ctx != NULL);
738 ECJPAKE_VALIDATE_RET(buf != NULL);
739 ECJPAKE_VALIDATE_RET(olen != NULL);
740 ECJPAKE_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200741
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100742 *olen = mbedtls_md_get_size(ctx->md_info);
743 if (len < *olen) {
744 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
745 }
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200746
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100747 mbedtls_ecp_point_init(&K);
748 mbedtls_mpi_init(&m_xm2_s);
749 mbedtls_mpi_init(&one);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200750
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100751 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200752
753 /*
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200754 * Client: K = ( Xs - X4 * x2 * s ) * x2
755 * Server: K = ( Xc - X2 * x4 * s ) * x4
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200756 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200757 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100758 MBEDTLS_MPI_CHK(ecjpake_mul_secret(&m_xm2_s, -1, &ctx->xm2, &ctx->s,
759 &ctx->grp.N, f_rng, p_rng));
760 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&ctx->grp, &K,
761 &one, &ctx->Xp,
762 &m_xm2_s, &ctx->Xp2));
763 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &K, &ctx->xm2, &K,
764 f_rng, p_rng));
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200765
766 /* PMS = SHA-256( K.X ) */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100767 x_bytes = (ctx->grp.pbits + 7) / 8;
768 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K.X, kx, x_bytes));
769 MBEDTLS_MPI_CHK(mbedtls_md(ctx->md_info, kx, x_bytes, buf));
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200770
771cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100772 mbedtls_ecp_point_free(&K);
773 mbedtls_mpi_free(&m_xm2_s);
774 mbedtls_mpi_free(&one);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200775
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100776 return ret;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200777}
778
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200779#undef ID_MINE
780#undef ID_PEER
781
Hanno Becker616d1ca2018-01-24 10:25:05 +0000782#endif /* ! MBEDTLS_ECJPAKE_ALT */
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200783
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200784#if defined(MBEDTLS_SELF_TEST)
785
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200786#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200787
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200788#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
789 !defined(MBEDTLS_SHA256_C)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100790int mbedtls_ecjpake_self_test(int verbose)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200791{
792 (void) verbose;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100793 return 0;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200794}
795#else
796
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200797static const unsigned char ecjpake_test_password[] = {
798 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
799 0x65, 0x73, 0x74
800};
801
Steven Cooreman64f27732021-01-11 17:20:10 +0100802#if !defined(MBEDTLS_ECJPAKE_ALT)
803
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200804static const unsigned char ecjpake_test_x1[] = {
805 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
806 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
807 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
808};
809
810static const unsigned char ecjpake_test_x2[] = {
811 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
812 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
813 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
814};
815
816static const unsigned char ecjpake_test_x3[] = {
817 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
818 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
819 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
820};
821
822static const unsigned char ecjpake_test_x4[] = {
823 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
824 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
825 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
826};
827
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200828static const unsigned char ecjpake_test_cli_one[] = {
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200829 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
830 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
831 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
832 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
833 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
834 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
835 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
836 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
837 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
838 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
839 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
840 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
841 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200842 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
843 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
844 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
845 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
846 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
847 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
848 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
849 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
850 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
851 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
852 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
853 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
854 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
855 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
856 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200857};
858
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200859static const unsigned char ecjpake_test_srv_one[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200860 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
861 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
862 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
863 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
864 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
865 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
866 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
867 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
868 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
869 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
870 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
871 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
872 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
873 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
874 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
875 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
876 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
877 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
878 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
879 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
880 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
881 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
882 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
883 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
884 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
885 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
886 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
887 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
888};
889
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200890static const unsigned char ecjpake_test_srv_two[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200891 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
892 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
893 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
894 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
895 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
896 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
897 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
898 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
899 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
900 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
901 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
902 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
903 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
904 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
905};
906
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200907static const unsigned char ecjpake_test_cli_two[] = {
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200908 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
909 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
910 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
911 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
912 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
913 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
914 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
915 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
916 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
917 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
918 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
919 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
920 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
921 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
922};
923
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200924static const unsigned char ecjpake_test_pms[] = {
925 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
926 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
927 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
928};
929
Antonin Décimo36e89b52019-01-23 15:24:37 +0100930/* Load my private keys and generate the corresponding public keys */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100931static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
932 const unsigned char *xm1, size_t len1,
933 const unsigned char *xm2, size_t len2)
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200934{
Janos Follath24eed8d2019-11-22 13:21:35 +0000935 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200936
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100937 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm1, xm1, len1));
938 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm2, xm2, len2));
939 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm1, &ctx->xm1,
940 &ctx->grp.G, NULL, NULL));
941 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm2, &ctx->xm2,
942 &ctx->grp.G, NULL, NULL));
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200943
944cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100945 return ret;
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200946}
947
Steven Cooreman64f27732021-01-11 17:20:10 +0100948#endif /* ! MBEDTLS_ECJPAKE_ALT */
949
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200950/* For tests we don't need a secure RNG;
951 * use the LGC from Numerical Recipes for simplicity */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100952static int ecjpake_lgc(void *p, unsigned char *out, size_t len)
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200953{
954 static uint32_t x = 42;
955 (void) p;
956
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100957 while (len > 0) {
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200958 size_t use_len = len > 4 ? 4 : len;
959 x = 1664525 * x + 1013904223;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100960 memcpy(out, &x, use_len);
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200961 out += use_len;
962 len -= use_len;
963 }
964
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100965 return 0;
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200966}
967
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100968#define TEST_ASSERT(x) \
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200969 do { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100970 if (x) \
971 ret = 0; \
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200972 else \
973 { \
974 ret = 1; \
975 goto cleanup; \
976 } \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100977 } while (0)
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200978
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200979/*
980 * Checkup routine
981 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100982int mbedtls_ecjpake_self_test(int verbose)
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200983{
Janos Follath24eed8d2019-11-22 13:21:35 +0000984 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200985 mbedtls_ecjpake_context cli;
986 mbedtls_ecjpake_context srv;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200987 unsigned char buf[512], pms[32];
988 size_t len, pmslen;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200989
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100990 mbedtls_ecjpake_init(&cli);
991 mbedtls_ecjpake_init(&srv);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200992
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100993 if (verbose != 0) {
994 mbedtls_printf(" ECJPAKE test #0 (setup): ");
995 }
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200996
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100997 TEST_ASSERT(mbedtls_ecjpake_setup(&cli, MBEDTLS_ECJPAKE_CLIENT,
998 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
999 ecjpake_test_password,
1000 sizeof(ecjpake_test_password)) == 0);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001001
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001002 TEST_ASSERT(mbedtls_ecjpake_setup(&srv, MBEDTLS_ECJPAKE_SERVER,
1003 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1004 ecjpake_test_password,
1005 sizeof(ecjpake_test_password)) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001006
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001007 if (verbose != 0) {
1008 mbedtls_printf("passed\n");
1009 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001010
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001011 if (verbose != 0) {
1012 mbedtls_printf(" ECJPAKE test #1 (random handshake): ");
1013 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001014
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001015 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
1016 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001017
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001018 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001019
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001020 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1021 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001022
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001023 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001024
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001025 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1026 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +02001027
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001028 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +02001029
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001030 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1031 pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001032
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001033 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1034 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +02001035
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001036 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +02001037
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001038 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1039 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001040
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001041 TEST_ASSERT(len == pmslen);
1042 TEST_ASSERT(memcmp(buf, pms, len) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001043
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001044 if (verbose != 0) {
1045 mbedtls_printf("passed\n");
1046 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001047
Steven Cooreman64f27732021-01-11 17:20:10 +01001048#if !defined(MBEDTLS_ECJPAKE_ALT)
1049 /* 'reference handshake' tests can only be run against implementations
1050 * for which we have 100% control over how the random ephemeral keys
Gilles Peskinef08ca832023-09-12 19:21:54 +02001051 * are generated. This is only the case for the internal Mbed TLS
Steven Cooreman64f27732021-01-11 17:20:10 +01001052 * implementation, so these tests are skipped in case the internal
1053 * implementation is swapped out for an alternative one. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001054 if (verbose != 0) {
1055 mbedtls_printf(" ECJPAKE test #2 (reference handshake): ");
1056 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001057
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001058 /* Simulate generation of round one */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001059 MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1060 ecjpake_test_x1, sizeof(ecjpake_test_x1),
1061 ecjpake_test_x2, sizeof(ecjpake_test_x2)));
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001062
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001063 MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1064 ecjpake_test_x3, sizeof(ecjpake_test_x3),
1065 ecjpake_test_x4, sizeof(ecjpake_test_x4)));
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001066
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001067 /* Read round one */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001068 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1069 ecjpake_test_cli_one,
1070 sizeof(ecjpake_test_cli_one)) == 0);
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001071
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001072 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1073 ecjpake_test_srv_one,
1074 sizeof(ecjpake_test_srv_one)) == 0);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001075
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001076 /* Skip generation of round two, read round two */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001077 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1078 ecjpake_test_srv_two,
1079 sizeof(ecjpake_test_srv_two)) == 0);
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +02001080
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001081 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1082 ecjpake_test_cli_two,
1083 sizeof(ecjpake_test_cli_two)) == 0);
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +02001084
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001085 /* Server derives PMS */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001086 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1087 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001088
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001089 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1090 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001091
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001092 memset(buf, 0, len); /* Avoid interferences with next step */
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001093
1094 /* Client derives PMS */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001095 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1096 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001097
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001098 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1099 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001100
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001101 if (verbose != 0) {
1102 mbedtls_printf("passed\n");
1103 }
Steven Cooreman64f27732021-01-11 17:20:10 +01001104#endif /* ! MBEDTLS_ECJPAKE_ALT */
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +02001105
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001106cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001107 mbedtls_ecjpake_free(&cli);
1108 mbedtls_ecjpake_free(&srv);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001109
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001110 if (ret != 0) {
1111 if (verbose != 0) {
1112 mbedtls_printf("failed\n");
1113 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001114
1115 ret = 1;
1116 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001117
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001118 if (verbose != 0) {
1119 mbedtls_printf("\n");
1120 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001121
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001122 return ret;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001123}
1124
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +02001125#undef TEST_ASSERT
1126
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001127#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1128
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001129#endif /* MBEDTLS_SELF_TEST */
1130
1131#endif /* MBEDTLS_ECJPAKE_C */