blob: 3728d1a580cb73e67a6240479a57c0b6704c7989 [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
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
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.
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020018 */
19
20/*
Manuel Pégourié-Gonnard6b798b92015-08-14 11:18:30 +020021 * References in the code are to the Thread v1.0 Specification,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +020022 * available to members of the Thread Group http://threadgroup.org/
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020023 */
24
Gilles Peskinedb09ef62020-06-03 01:43:33 +020025#include "common.h"
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020026
27#if defined(MBEDTLS_ECJPAKE_C)
28
29#include "mbedtls/ecjpake.h"
Hanno Becker71c8e1b2018-12-14 17:09:39 +000030#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000031#include "mbedtls/error.h"
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020032
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020033#include <string.h>
34
Hanno Becker616d1ca2018-01-24 10:25:05 +000035#if !defined(MBEDTLS_ECJPAKE_ALT)
36
Hanno Becker71c8e1b2018-12-14 17:09:39 +000037/* Parameter validation macros based on platform_util.h */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010038#define ECJPAKE_VALIDATE_RET(cond) \
39 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA)
40#define ECJPAKE_VALIDATE(cond) \
41 MBEDTLS_INTERNAL_VALIDATE(cond)
Hanno Becker71c8e1b2018-12-14 17:09:39 +000042
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020043/*
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +020044 * Convert a mbedtls_ecjpake_role to identifier string
45 */
46static const char * const ecjpake_id[] = {
47 "client",
48 "server"
49};
50
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010051#define ID_MINE (ecjpake_id[ctx->role])
52#define ID_PEER (ecjpake_id[1 - ctx->role])
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +020053
54/*
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020055 * Initialize context
56 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010057void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx)
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020058{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010059 ECJPAKE_VALIDATE(ctx != NULL);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020060
61 ctx->md_info = NULL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010062 mbedtls_ecp_group_init(&ctx->grp);
Manuel Pégourié-Gonnardb7da1942015-10-19 13:35:22 +020063 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020064
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010065 mbedtls_ecp_point_init(&ctx->Xm1);
66 mbedtls_ecp_point_init(&ctx->Xm2);
67 mbedtls_ecp_point_init(&ctx->Xp1);
68 mbedtls_ecp_point_init(&ctx->Xp2);
69 mbedtls_ecp_point_init(&ctx->Xp);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020070
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010071 mbedtls_mpi_init(&ctx->xm1);
72 mbedtls_mpi_init(&ctx->xm2);
73 mbedtls_mpi_init(&ctx->s);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020074}
75
76/*
77 * Free context
78 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010079void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx)
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020080{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010081 if (ctx == NULL) {
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020082 return;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010083 }
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020084
85 ctx->md_info = NULL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010086 mbedtls_ecp_group_free(&ctx->grp);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020087
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010088 mbedtls_ecp_point_free(&ctx->Xm1);
89 mbedtls_ecp_point_free(&ctx->Xm2);
90 mbedtls_ecp_point_free(&ctx->Xp1);
91 mbedtls_ecp_point_free(&ctx->Xp2);
92 mbedtls_ecp_point_free(&ctx->Xp);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020093
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010094 mbedtls_mpi_free(&ctx->xm1);
95 mbedtls_mpi_free(&ctx->xm2);
96 mbedtls_mpi_free(&ctx->s);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020097}
98
99/*
100 * Setup context
101 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100102int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx,
103 mbedtls_ecjpake_role role,
104 mbedtls_md_type_t hash,
105 mbedtls_ecp_group_id curve,
106 const unsigned char *secret,
107 size_t len)
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200108{
Janos Follath24eed8d2019-11-22 13:21:35 +0000109 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker185e5162018-12-19 09:48:50 +0000110
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100111 ECJPAKE_VALIDATE_RET(ctx != NULL);
112 ECJPAKE_VALIDATE_RET(role == MBEDTLS_ECJPAKE_CLIENT ||
113 role == MBEDTLS_ECJPAKE_SERVER);
114 ECJPAKE_VALIDATE_RET(secret != NULL || len == 0);
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200115
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200116 ctx->role = role;
117
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100118 if ((ctx->md_info = mbedtls_md_info_from_type(hash)) == NULL) {
119 return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
120 }
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200121
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100122 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200123
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100124 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200125
126cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 if (ret != 0) {
128 mbedtls_ecjpake_free(ctx);
129 }
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200130
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100131 return ret;
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200132}
133
134/*
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200135 * Check if context is ready for use
136 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100137int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx)
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200138{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100139 ECJPAKE_VALIDATE_RET(ctx != NULL);
Hanno Becker71c8e1b2018-12-14 17:09:39 +0000140
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100141 if (ctx->md_info == NULL ||
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200142 ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100143 ctx->s.p == NULL) {
144 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200145 }
146
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100147 return 0;
Manuel Pégourié-Gonnardb813acc2015-09-15 15:34:09 +0200148}
149
150/*
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200151 * Write a point plus its length to a buffer
152 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100153static int ecjpake_write_len_point(unsigned char **p,
154 const unsigned char *end,
155 const mbedtls_ecp_group *grp,
156 const int pf,
157 const mbedtls_ecp_point *P)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200158{
Janos Follath24eed8d2019-11-22 13:21:35 +0000159 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200160 size_t len;
161
162 /* Need at least 4 for length plus 1 for point */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100163 if (end < *p || end - *p < 5) {
164 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
165 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200166
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100167 ret = mbedtls_ecp_point_write_binary(grp, P, pf,
168 &len, *p + 4, end - (*p + 4));
169 if (ret != 0) {
170 return ret;
171 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200172
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100173 MBEDTLS_PUT_UINT32_BE(len, *p, 0);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200174
175 *p += 4 + len;
176
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100177 return 0;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200178}
179
180/*
181 * Size of the temporary buffer for ecjpake_hash:
Manuel Pégourié-Gonnard4b20c0e2015-10-20 16:16:38 +0200182 * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200183 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100184#define ECJPAKE_HASH_BUF_LEN (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200185
186/*
187 * Compute hash for ZKP (7.4.2.2.2.1)
188 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100189static int ecjpake_hash(const mbedtls_md_info_t *md_info,
190 const mbedtls_ecp_group *grp,
191 const int pf,
192 const mbedtls_ecp_point *G,
193 const mbedtls_ecp_point *V,
194 const mbedtls_ecp_point *X,
195 const char *id,
196 mbedtls_mpi *h)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200197{
Janos Follath24eed8d2019-11-22 13:21:35 +0000198 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200199 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
200 unsigned char *p = buf;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100201 const unsigned char *end = buf + sizeof(buf);
202 const size_t id_len = strlen(id);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200203 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
204
205 /* Write things to temporary buffer */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100206 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, G));
207 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, V));
208 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, X));
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200209
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100210 if (end - p < 4) {
211 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
212 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200213
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100214 MBEDTLS_PUT_UINT32_BE(id_len, p, 0);
Joe Subbiania651e6f2021-08-23 11:35:25 +0100215 p += 4;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200216
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100217 if (end < p || (size_t) (end - p) < id_len) {
218 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
219 }
Manuel Pégourié-Gonnard4b20c0e2015-10-20 16:16:38 +0200220
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100221 memcpy(p, id, id_len);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200222 p += id_len;
223
224 /* Compute hash */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100225 MBEDTLS_MPI_CHK(mbedtls_md(md_info, buf, p - buf, hash));
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200226
227 /* Turn it into an integer mod n */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100228 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(h, hash,
229 mbedtls_md_get_size(md_info)));
230 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(h, h, &grp->N));
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200231
232cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100233 return ret;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200234}
235
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200236/*
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200237 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
238 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100239static int ecjpake_zkp_read(const mbedtls_md_info_t *md_info,
240 const mbedtls_ecp_group *grp,
241 const int pf,
242 const mbedtls_ecp_point *G,
243 const mbedtls_ecp_point *X,
244 const char *id,
245 const unsigned char **p,
246 const unsigned char *end)
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200247{
Janos Follath24eed8d2019-11-22 13:21:35 +0000248 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200249 mbedtls_ecp_point V, VV;
250 mbedtls_mpi r, h;
251 size_t r_len;
252
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100253 mbedtls_ecp_point_init(&V);
254 mbedtls_ecp_point_init(&VV);
255 mbedtls_mpi_init(&r);
256 mbedtls_mpi_init(&h);
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200257
258 /*
259 * struct {
260 * ECPoint V;
261 * opaque r<1..2^8-1>;
262 * } ECSchnorrZKP;
263 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100264 if (end < *p) {
265 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
266 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200267
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100268 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, end - *p));
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200269
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100270 if (end < *p || (size_t) (end - *p) < 1) {
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200271 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
272 goto cleanup;
273 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200274
275 r_len = *(*p)++;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200276
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100277 if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) {
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200278 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
279 goto cleanup;
280 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200281
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100282 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200283 *p += r_len;
284
285 /*
286 * Verification
287 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100288 MBEDTLS_MPI_CHK(ecjpake_hash(md_info, grp, pf, G, &V, X, id, &h));
289 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd((mbedtls_ecp_group *) grp,
290 &VV, &h, X, &r, G));
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200291
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100292 if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200293 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
294 goto cleanup;
295 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200296
297cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100298 mbedtls_ecp_point_free(&V);
299 mbedtls_ecp_point_free(&VV);
300 mbedtls_mpi_free(&r);
301 mbedtls_mpi_free(&h);
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200302
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100303 return ret;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200304}
305
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200306/*
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200307 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
308 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100309static int ecjpake_zkp_write(const mbedtls_md_info_t *md_info,
310 const mbedtls_ecp_group *grp,
311 const int pf,
312 const mbedtls_ecp_point *G,
313 const mbedtls_mpi *x,
314 const mbedtls_ecp_point *X,
315 const char *id,
316 unsigned char **p,
317 const unsigned char *end,
318 int (*f_rng)(void *, unsigned char *, size_t),
319 void *p_rng)
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200320{
Janos Follath24eed8d2019-11-22 13:21:35 +0000321 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200322 mbedtls_ecp_point V;
323 mbedtls_mpi v;
324 mbedtls_mpi h; /* later recycled to hold r */
325 size_t len;
326
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100327 if (end < *p) {
328 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
329 }
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200330
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100331 mbedtls_ecp_point_init(&V);
332 mbedtls_mpi_init(&v);
333 mbedtls_mpi_init(&h);
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200334
335 /* Compute signature */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100336 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp,
337 G, &v, &V, f_rng, p_rng));
338 MBEDTLS_MPI_CHK(ecjpake_hash(md_info, grp, pf, G, &V, X, id, &h));
339 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&h, &h, x)); /* x*h */
340 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&h, &v, &h)); /* v - x*h */
341 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&h, &h, &grp->N)); /* r */
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200342
343 /* Write it out */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100344 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
345 pf, &len, *p, end - *p));
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200346 *p += len;
347
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100348 len = mbedtls_mpi_size(&h); /* actually r */
349 if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) {
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200350 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
351 goto cleanup;
352 }
353
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100354 *(*p)++ = MBEDTLS_BYTE_0(len);
355 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len)); /* r */
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200356 *p += len;
357
358cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100359 mbedtls_ecp_point_free(&V);
360 mbedtls_mpi_free(&v);
361 mbedtls_mpi_free(&h);
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200362
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100363 return ret;
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200364}
365
366/*
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200367 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
368 * Output: verified public key X
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200369 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100370static int ecjpake_kkp_read(const mbedtls_md_info_t *md_info,
371 const mbedtls_ecp_group *grp,
372 const int pf,
373 const mbedtls_ecp_point *G,
374 mbedtls_ecp_point *X,
375 const char *id,
376 const unsigned char **p,
377 const unsigned char *end)
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200378{
Janos Follath24eed8d2019-11-22 13:21:35 +0000379 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200380
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100381 if (end < *p) {
382 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
383 }
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200384
385 /*
386 * struct {
387 * ECPoint X;
388 * ECSchnorrZKP zkp;
389 * } ECJPAKEKeyKP;
390 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100391 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, end - *p));
392 if (mbedtls_ecp_is_zero(X)) {
Manuel Pégourié-Gonnard30590952015-08-17 10:37:40 +0200393 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
394 goto cleanup;
395 }
396
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100397 MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_info, grp, pf, G, X, id, p, end));
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200398
399cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100400 return ret;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200401}
402
403/*
404 * Generate an ECJPAKEKeyKP
405 * Output: the serialized structure, plus private/public key pair
406 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100407static int ecjpake_kkp_write(const mbedtls_md_info_t *md_info,
408 const mbedtls_ecp_group *grp,
409 const int pf,
410 const mbedtls_ecp_point *G,
411 mbedtls_mpi *x,
412 mbedtls_ecp_point *X,
413 const char *id,
414 unsigned char **p,
415 const unsigned char *end,
416 int (*f_rng)(void *, unsigned char *, size_t),
417 void *p_rng)
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200418{
Janos Follath24eed8d2019-11-22 13:21:35 +0000419 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200420 size_t len;
421
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100422 if (end < *p) {
423 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
424 }
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200425
426 /* Generate key (7.4.2.3.1) and write it out */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100427 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, G, x, X,
428 f_rng, p_rng));
429 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, X,
430 pf, &len, *p, end - *p));
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200431 *p += len;
432
433 /* Generate and write proof */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100434 MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_info, grp, pf, G, x, X, id,
435 p, end, f_rng, p_rng));
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200436
437cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100438 return ret;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200439}
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200440
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200441/*
442 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
Shaun Case0e7791f2021-12-20 21:14:10 -0800443 * Outputs: verified peer public keys Xa, Xb
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200444 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100445static int ecjpake_kkpp_read(const mbedtls_md_info_t *md_info,
446 const mbedtls_ecp_group *grp,
447 const int pf,
448 const mbedtls_ecp_point *G,
449 mbedtls_ecp_point *Xa,
450 mbedtls_ecp_point *Xb,
451 const char *id,
452 const unsigned char *buf,
453 size_t len)
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200454{
Janos Follath24eed8d2019-11-22 13:21:35 +0000455 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200456 const unsigned char *p = buf;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200457 const unsigned char *end = buf + len;
458
459 /*
460 * struct {
461 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
462 * } ECJPAKEKeyKPPairList;
463 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100464 MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_info, grp, pf, G, Xa, id, &p, end));
465 MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_info, grp, pf, G, Xb, id, &p, end));
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200466
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100467 if (p != end) {
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200468 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100469 }
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200470
471cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100472 return ret;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200473}
474
475/*
476 * Generate a ECJPAKEKeyKPPairList
477 * Outputs: the serialized structure, plus two private/public key pairs
478 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100479static int ecjpake_kkpp_write(const mbedtls_md_info_t *md_info,
480 const mbedtls_ecp_group *grp,
481 const int pf,
482 const mbedtls_ecp_point *G,
483 mbedtls_mpi *xm1,
484 mbedtls_ecp_point *Xa,
485 mbedtls_mpi *xm2,
486 mbedtls_ecp_point *Xb,
487 const char *id,
488 unsigned char *buf,
489 size_t len,
490 size_t *olen,
491 int (*f_rng)(void *, unsigned char *, size_t),
492 void *p_rng)
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200493{
Janos Follath24eed8d2019-11-22 13:21:35 +0000494 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200495 unsigned char *p = buf;
496 const unsigned char *end = buf + len;
497
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100498 MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_info, grp, pf, G, xm1, Xa, id,
499 &p, end, f_rng, p_rng));
500 MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_info, grp, pf, G, xm2, Xb, id,
501 &p, end, f_rng, p_rng));
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200502
503 *olen = p - buf;
504
505cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100506 return ret;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200507}
508
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200509/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200510 * Read and process the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200511 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100512int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
513 const unsigned char *buf,
514 size_t len)
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200515{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100516 ECJPAKE_VALIDATE_RET(ctx != NULL);
517 ECJPAKE_VALIDATE_RET(buf != NULL);
Hanno Becker71c8e1b2018-12-14 17:09:39 +0000518
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100519 return ecjpake_kkpp_read(ctx->md_info, &ctx->grp, ctx->point_format,
520 &ctx->grp.G,
521 &ctx->Xp1, &ctx->Xp2, ID_PEER,
522 buf, len);
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200523}
524
525/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200526 * Generate and write the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200527 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100528int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx,
529 unsigned char *buf, size_t len, size_t *olen,
530 int (*f_rng)(void *, unsigned char *, size_t),
531 void *p_rng)
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200532{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100533 ECJPAKE_VALIDATE_RET(ctx != NULL);
534 ECJPAKE_VALIDATE_RET(buf != NULL);
535 ECJPAKE_VALIDATE_RET(olen != NULL);
536 ECJPAKE_VALIDATE_RET(f_rng != NULL);
Hanno Becker71c8e1b2018-12-14 17:09:39 +0000537
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100538 return ecjpake_kkpp_write(ctx->md_info, &ctx->grp, ctx->point_format,
539 &ctx->grp.G,
540 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
541 ID_MINE, buf, len, olen, f_rng, p_rng);
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200542}
543
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200544/*
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200545 * Compute the sum of three points R = A + B + C
546 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100547static int ecjpake_ecp_add3(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
548 const mbedtls_ecp_point *A,
549 const mbedtls_ecp_point *B,
550 const mbedtls_ecp_point *C)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200551{
Janos Follath24eed8d2019-11-22 13:21:35 +0000552 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200553 mbedtls_mpi one;
554
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100555 mbedtls_mpi_init(&one);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200556
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100557 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
558 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, A, &one, B));
559 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, R, &one, C));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200560
561cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100562 mbedtls_mpi_free(&one);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200563
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100564 return ret;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200565}
566
567/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200568 * 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 +0200569 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100570int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
571 const unsigned char *buf,
572 size_t len)
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200573{
Janos Follath24eed8d2019-11-22 13:21:35 +0000574 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200575 const unsigned char *p = buf;
576 const unsigned char *end = buf + len;
577 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200578 mbedtls_ecp_point G; /* C: GB, S: GA */
Hanno Becker185e5162018-12-19 09:48:50 +0000579
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100580 ECJPAKE_VALIDATE_RET(ctx != NULL);
581 ECJPAKE_VALIDATE_RET(buf != NULL);
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200582
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100583 mbedtls_ecp_group_init(&grp);
584 mbedtls_ecp_point_init(&G);
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200585
586 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200587 * Server: GA = X3 + X4 + X1 (7.4.2.6.1)
588 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
589 * Unified: G = Xm1 + Xm2 + Xp1
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200590 * We need that before parsing in order to check Xp as we read it
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200591 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100592 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
593 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200594
595 /*
596 * struct {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200597 * ECParameters curve_params; // only client reading server msg
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200598 * ECJPAKEKeyKP ecjpake_key_kp;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200599 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200600 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100601 if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) {
602 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_group(&grp, &p, len));
603 if (grp.id != ctx->grp.id) {
Manuel Pégourié-Gonnardd9802af2015-08-17 12:47:38 +0200604 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
605 goto cleanup;
606 }
607 }
608
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100609 MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_info, &ctx->grp,
610 ctx->point_format,
611 &G, &ctx->Xp, ID_PEER, &p, end));
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200612
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100613 if (p != end) {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200614 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
615 goto cleanup;
616 }
617
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200618cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100619 mbedtls_ecp_group_free(&grp);
620 mbedtls_ecp_point_free(&G);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200621
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100622 return ret;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200623}
624
625/*
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200626 * Compute R = +/- X * S mod N, taking care not to leak S
627 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100628static int ecjpake_mul_secret(mbedtls_mpi *R, int sign,
629 const mbedtls_mpi *X,
630 const mbedtls_mpi *S,
631 const mbedtls_mpi *N,
632 int (*f_rng)(void *, unsigned char *, size_t),
633 void *p_rng)
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200634{
Janos Follath24eed8d2019-11-22 13:21:35 +0000635 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200636 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
637
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100638 mbedtls_mpi_init(&b);
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200639
640 /* b = s + rnd-128-bit * N */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100641 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&b, 16, f_rng, p_rng));
642 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&b, &b, N));
643 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&b, &b, S));
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200644
645 /* R = sign * X * b mod N */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100646 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200647 R->s *= sign;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100648 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200649
650cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100651 mbedtls_mpi_free(&b);
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200652
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100653 return ret;
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200654}
655
656/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200657 * 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 +0200658 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100659int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx,
660 unsigned char *buf, size_t len, size_t *olen,
661 int (*f_rng)(void *, unsigned char *, size_t),
662 void *p_rng)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200663{
Janos Follath24eed8d2019-11-22 13:21:35 +0000664 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200665 mbedtls_ecp_point G; /* C: GA, S: GB */
666 mbedtls_ecp_point Xm; /* C: Xc, S: Xs */
667 mbedtls_mpi xm; /* C: xc, S: xs */
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200668 unsigned char *p = buf;
669 const unsigned char *end = buf + len;
670 size_t ec_len;
Hanno Becker185e5162018-12-19 09:48:50 +0000671
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100672 ECJPAKE_VALIDATE_RET(ctx != NULL);
673 ECJPAKE_VALIDATE_RET(buf != NULL);
674 ECJPAKE_VALIDATE_RET(olen != NULL);
675 ECJPAKE_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200676
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100677 mbedtls_ecp_point_init(&G);
678 mbedtls_ecp_point_init(&Xm);
679 mbedtls_mpi_init(&xm);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200680
681 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200682 * 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 +0200683 *
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200684 * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA
685 * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB
686 * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200687 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100688 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
689 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1));
690 MBEDTLS_MPI_CHK(ecjpake_mul_secret(&xm, 1, &ctx->xm2, &ctx->s,
691 &ctx->grp.N, f_rng, p_rng));
692 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &Xm, &xm, &G, f_rng, p_rng));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200693
694 /*
695 * Now write things out
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200696 *
697 * struct {
698 * ECParameters curve_params; // only server writing its message
699 * ECJPAKEKeyKP ecjpake_key_kp;
700 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200701 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100702 if (ctx->role == MBEDTLS_ECJPAKE_SERVER) {
703 if (end < p) {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200704 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
705 goto cleanup;
706 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100707 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len,
708 p, end - p));
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200709 p += ec_len;
710 }
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200711
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100712 if (end < p) {
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200713 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
714 goto cleanup;
715 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100716 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm,
717 ctx->point_format, &ec_len, p, end - p));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200718 p += ec_len;
719
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100720 MBEDTLS_MPI_CHK(ecjpake_zkp_write(ctx->md_info, &ctx->grp,
721 ctx->point_format,
722 &G, &xm, &Xm, ID_MINE,
723 &p, end, f_rng, p_rng));
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200724
725 *olen = p - buf;
726
727cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100728 mbedtls_ecp_point_free(&G);
729 mbedtls_ecp_point_free(&Xm);
730 mbedtls_mpi_free(&xm);
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200731
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100732 return ret;
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200733}
734
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200735/*
736 * Derive PMS (7.4.2.7 / 7.4.2.8)
737 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100738int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx,
739 unsigned char *buf, size_t len, size_t *olen,
740 int (*f_rng)(void *, unsigned char *, size_t),
741 void *p_rng)
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200742{
Janos Follath24eed8d2019-11-22 13:21:35 +0000743 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200744 mbedtls_ecp_point K;
745 mbedtls_mpi m_xm2_s, one;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200746 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
747 size_t x_bytes;
Hanno Becker185e5162018-12-19 09:48:50 +0000748
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100749 ECJPAKE_VALIDATE_RET(ctx != NULL);
750 ECJPAKE_VALIDATE_RET(buf != NULL);
751 ECJPAKE_VALIDATE_RET(olen != NULL);
752 ECJPAKE_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200753
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100754 *olen = mbedtls_md_get_size(ctx->md_info);
755 if (len < *olen) {
756 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
757 }
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200758
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100759 mbedtls_ecp_point_init(&K);
760 mbedtls_mpi_init(&m_xm2_s);
761 mbedtls_mpi_init(&one);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200762
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100763 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200764
765 /*
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200766 * Client: K = ( Xs - X4 * x2 * s ) * x2
767 * Server: K = ( Xc - X2 * x4 * s ) * x4
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200768 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200769 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100770 MBEDTLS_MPI_CHK(ecjpake_mul_secret(&m_xm2_s, -1, &ctx->xm2, &ctx->s,
771 &ctx->grp.N, f_rng, p_rng));
772 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&ctx->grp, &K,
773 &one, &ctx->Xp,
774 &m_xm2_s, &ctx->Xp2));
775 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &K, &ctx->xm2, &K,
776 f_rng, p_rng));
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200777
778 /* PMS = SHA-256( K.X ) */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100779 x_bytes = (ctx->grp.pbits + 7) / 8;
780 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K.X, kx, x_bytes));
781 MBEDTLS_MPI_CHK(mbedtls_md(ctx->md_info, kx, x_bytes, buf));
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200782
783cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100784 mbedtls_ecp_point_free(&K);
785 mbedtls_mpi_free(&m_xm2_s);
786 mbedtls_mpi_free(&one);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200787
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100788 return ret;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200789}
790
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200791#undef ID_MINE
792#undef ID_PEER
793
Hanno Becker616d1ca2018-01-24 10:25:05 +0000794#endif /* ! MBEDTLS_ECJPAKE_ALT */
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200795
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200796#if defined(MBEDTLS_SELF_TEST)
797
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200798#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200799
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200800#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
801 !defined(MBEDTLS_SHA256_C)
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100802int mbedtls_ecjpake_self_test(int verbose)
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200803{
804 (void) verbose;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100805 return 0;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200806}
807#else
808
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200809static const unsigned char ecjpake_test_password[] = {
810 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
811 0x65, 0x73, 0x74
812};
813
Steven Cooreman64f27732021-01-11 17:20:10 +0100814#if !defined(MBEDTLS_ECJPAKE_ALT)
815
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200816static const unsigned char ecjpake_test_x1[] = {
817 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
818 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
819 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
820};
821
822static const unsigned char ecjpake_test_x2[] = {
823 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
824 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
825 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
826};
827
828static const unsigned char ecjpake_test_x3[] = {
829 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
830 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
831 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
832};
833
834static const unsigned char ecjpake_test_x4[] = {
835 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
836 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
837 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
838};
839
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200840static const unsigned char ecjpake_test_cli_one[] = {
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200841 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
842 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
843 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
844 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
845 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
846 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
847 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
848 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
849 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
850 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
851 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
852 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
853 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200854 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
855 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
856 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
857 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
858 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
859 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
860 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
861 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
862 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
863 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
864 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
865 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
866 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
867 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
868 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200869};
870
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200871static const unsigned char ecjpake_test_srv_one[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200872 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
873 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
874 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
875 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
876 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
877 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
878 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
879 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
880 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
881 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
882 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
883 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
884 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
885 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
886 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
887 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
888 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
889 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
890 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
891 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
892 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
893 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
894 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
895 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
896 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
897 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
898 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
899 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
900};
901
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200902static const unsigned char ecjpake_test_srv_two[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200903 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
904 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
905 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
906 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
907 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
908 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
909 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
910 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
911 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
912 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
913 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
914 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
915 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
916 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
917};
918
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200919static const unsigned char ecjpake_test_cli_two[] = {
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200920 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
921 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
922 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
923 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
924 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
925 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
926 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
927 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
928 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
929 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
930 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
931 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
932 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
933 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
934};
935
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200936static const unsigned char ecjpake_test_pms[] = {
937 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
938 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
939 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
940};
941
Antonin Décimo36e89b52019-01-23 15:24:37 +0100942/* Load my private keys and generate the corresponding public keys */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100943static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
944 const unsigned char *xm1, size_t len1,
945 const unsigned char *xm2, size_t len2)
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200946{
Janos Follath24eed8d2019-11-22 13:21:35 +0000947 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200948
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100949 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm1, xm1, len1));
950 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm2, xm2, len2));
951 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm1, &ctx->xm1,
952 &ctx->grp.G, NULL, NULL));
953 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm2, &ctx->xm2,
954 &ctx->grp.G, NULL, NULL));
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200955
956cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100957 return ret;
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200958}
959
Steven Cooreman64f27732021-01-11 17:20:10 +0100960#endif /* ! MBEDTLS_ECJPAKE_ALT */
961
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200962/* For tests we don't need a secure RNG;
963 * use the LGC from Numerical Recipes for simplicity */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100964static int ecjpake_lgc(void *p, unsigned char *out, size_t len)
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200965{
966 static uint32_t x = 42;
967 (void) p;
968
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100969 while (len > 0) {
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200970 size_t use_len = len > 4 ? 4 : len;
971 x = 1664525 * x + 1013904223;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100972 memcpy(out, &x, use_len);
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200973 out += use_len;
974 len -= use_len;
975 }
976
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100977 return 0;
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200978}
979
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100980#define TEST_ASSERT(x) \
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200981 do { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100982 if (x) \
983 ret = 0; \
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200984 else \
985 { \
986 ret = 1; \
987 goto cleanup; \
988 } \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100989 } while (0)
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200990
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200991/*
992 * Checkup routine
993 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100994int mbedtls_ecjpake_self_test(int verbose)
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200995{
Janos Follath24eed8d2019-11-22 13:21:35 +0000996 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200997 mbedtls_ecjpake_context cli;
998 mbedtls_ecjpake_context srv;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200999 unsigned char buf[512], pms[32];
1000 size_t len, pmslen;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001001
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001002 mbedtls_ecjpake_init(&cli);
1003 mbedtls_ecjpake_init(&srv);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001004
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001005 if (verbose != 0) {
1006 mbedtls_printf(" ECJPAKE test #0 (setup): ");
1007 }
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +02001008
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001009 TEST_ASSERT(mbedtls_ecjpake_setup(&cli, MBEDTLS_ECJPAKE_CLIENT,
1010 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1011 ecjpake_test_password,
1012 sizeof(ecjpake_test_password)) == 0);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001013
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001014 TEST_ASSERT(mbedtls_ecjpake_setup(&srv, MBEDTLS_ECJPAKE_SERVER,
1015 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1016 ecjpake_test_password,
1017 sizeof(ecjpake_test_password)) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001018
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001019 if (verbose != 0) {
1020 mbedtls_printf("passed\n");
1021 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001022
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001023 if (verbose != 0) {
1024 mbedtls_printf(" ECJPAKE test #1 (random handshake): ");
1025 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001026
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001027 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
1028 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001029
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001030 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001031
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001032 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1033 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001034
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001035 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001036
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001037 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1038 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +02001039
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001040 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +02001041
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001042 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1043 pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001044
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001045 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1046 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +02001047
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001048 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +02001049
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001050 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1051 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001052
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001053 TEST_ASSERT(len == pmslen);
1054 TEST_ASSERT(memcmp(buf, pms, len) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001055
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001056 if (verbose != 0) {
1057 mbedtls_printf("passed\n");
1058 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001059
Steven Cooreman64f27732021-01-11 17:20:10 +01001060#if !defined(MBEDTLS_ECJPAKE_ALT)
1061 /* 'reference handshake' tests can only be run against implementations
1062 * for which we have 100% control over how the random ephemeral keys
1063 * are generated. This is only the case for the internal mbed TLS
1064 * implementation, so these tests are skipped in case the internal
1065 * implementation is swapped out for an alternative one. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001066 if (verbose != 0) {
1067 mbedtls_printf(" ECJPAKE test #2 (reference handshake): ");
1068 }
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001069
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001070 /* Simulate generation of round one */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001071 MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1072 ecjpake_test_x1, sizeof(ecjpake_test_x1),
1073 ecjpake_test_x2, sizeof(ecjpake_test_x2)));
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001074
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001075 MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1076 ecjpake_test_x3, sizeof(ecjpake_test_x3),
1077 ecjpake_test_x4, sizeof(ecjpake_test_x4)));
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001078
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001079 /* Read round one */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001080 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1081 ecjpake_test_cli_one,
1082 sizeof(ecjpake_test_cli_one)) == 0);
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001083
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001084 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1085 ecjpake_test_srv_one,
1086 sizeof(ecjpake_test_srv_one)) == 0);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001087
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001088 /* Skip generation of round two, read round two */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001089 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1090 ecjpake_test_srv_two,
1091 sizeof(ecjpake_test_srv_two)) == 0);
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +02001092
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001093 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1094 ecjpake_test_cli_two,
1095 sizeof(ecjpake_test_cli_two)) == 0);
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +02001096
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001097 /* Server derives PMS */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001098 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1099 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001100
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001101 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1102 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001103
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001104 memset(buf, 0, len); /* Avoid interferences with next step */
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001105
1106 /* Client derives PMS */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001107 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1108 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001109
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001110 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1111 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001112
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001113 if (verbose != 0) {
1114 mbedtls_printf("passed\n");
1115 }
Steven Cooreman64f27732021-01-11 17:20:10 +01001116#endif /* ! MBEDTLS_ECJPAKE_ALT */
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +02001117
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001118cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001119 mbedtls_ecjpake_free(&cli);
1120 mbedtls_ecjpake_free(&srv);
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001121
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001122 if (ret != 0) {
1123 if (verbose != 0) {
1124 mbedtls_printf("failed\n");
1125 }
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001126
1127 ret = 1;
1128 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001129
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001130 if (verbose != 0) {
1131 mbedtls_printf("\n");
1132 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001133
Gilles Peskine1b6c09a2023-01-11 14:52:35 +01001134 return ret;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001135}
1136
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +02001137#undef TEST_ASSERT
1138
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001139#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1140
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001141#endif /* MBEDTLS_SELF_TEST */
1142
1143#endif /* MBEDTLS_ECJPAKE_C */