1 /*
2 * Elliptic curve J-PAKE
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7
8 /*
9 * References in the code are to the Thread v1.0 Specification,
10 * available to members of the Thread Group http://threadgroup.org/
11 */
12
13 #include "common.h"
14
15 #if defined(MBEDTLS_ECJPAKE_C)
16
17 #include "mbedtls/ecjpake.h"
18 #include "mbedtls/platform_util.h"
19 #include "mbedtls/error.h"
20
21 #include <string.h>
22
23 #if !defined(MBEDTLS_ECJPAKE_ALT)
24
25 /* Parameter validation macros based on platform_util.h */
26 #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)
30
31 /*
32 * Convert a mbedtls_ecjpake_role to identifier string
33 */
34 static const char * const ecjpake_id[] = {
35 "client",
36 "server"
37 };
38
39 #define ID_MINE (ecjpake_id[ctx->role])
40 #define ID_PEER (ecjpake_id[1 - ctx->role])
41
42 /*
43 * Initialize context
44 */
mbedtls_ecjpake_init(mbedtls_ecjpake_context * ctx)45 void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx)
46 {
47 ECJPAKE_VALIDATE(ctx != NULL);
48
49 ctx->md_info = NULL;
50 mbedtls_ecp_group_init(&ctx->grp);
51 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
52
53 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);
58
59 mbedtls_mpi_init(&ctx->xm1);
60 mbedtls_mpi_init(&ctx->xm2);
61 mbedtls_mpi_init(&ctx->s);
62 }
63
64 /*
65 * Free context
66 */
mbedtls_ecjpake_free(mbedtls_ecjpake_context * ctx)67 void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx)
68 {
69 if (ctx == NULL) {
70 return;
71 }
72
73 ctx->md_info = NULL;
74 mbedtls_ecp_group_free(&ctx->grp);
75
76 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);
81
82 mbedtls_mpi_free(&ctx->xm1);
83 mbedtls_mpi_free(&ctx->xm2);
84 mbedtls_mpi_free(&ctx->s);
85 }
86
87 /*
88 * Setup context
89 */
mbedtls_ecjpake_setup(mbedtls_ecjpake_context * ctx,mbedtls_ecjpake_role role,mbedtls_md_type_t hash,mbedtls_ecp_group_id curve,const unsigned char * secret,size_t len)90 int 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)
96 {
97 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
98
99 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);
103
104 ctx->role = role;
105
106 if ((ctx->md_info = mbedtls_md_info_from_type(hash)) == NULL) {
107 return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
108 }
109
110 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
111
112 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
113
114 cleanup:
115 if (ret != 0) {
116 mbedtls_ecjpake_free(ctx);
117 }
118
119 return ret;
120 }
121
122 /*
123 * Check if context is ready for use
124 */
mbedtls_ecjpake_check(const mbedtls_ecjpake_context * ctx)125 int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx)
126 {
127 ECJPAKE_VALIDATE_RET(ctx != NULL);
128
129 if (ctx->md_info == NULL ||
130 ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
131 ctx->s.p == NULL) {
132 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
133 }
134
135 return 0;
136 }
137
138 /*
139 * Write a point plus its length to a buffer
140 */
ecjpake_write_len_point(unsigned char ** p,const unsigned char * end,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * P)141 static 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)
146 {
147 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
148 size_t len;
149
150 /* Need at least 4 for length plus 1 for point */
151 if (end < *p || end - *p < 5) {
152 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
153 }
154
155 ret = mbedtls_ecp_point_write_binary(grp, P, pf,
156 &len, *p + 4, end - (*p + 4));
157 if (ret != 0) {
158 return ret;
159 }
160
161 MBEDTLS_PUT_UINT32_BE(len, *p, 0);
162
163 *p += 4 + len;
164
165 return 0;
166 }
167
168 /*
169 * Size of the temporary buffer for ecjpake_hash:
170 * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
171 */
172 #define ECJPAKE_HASH_BUF_LEN (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6)
173
174 /*
175 * Compute hash for ZKP (7.4.2.2.2.1)
176 */
ecjpake_hash(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,const mbedtls_ecp_point * V,const mbedtls_ecp_point * X,const char * id,mbedtls_mpi * h)177 static 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)
185 {
186 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
187 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
188 unsigned char *p = buf;
189 const unsigned char *end = buf + sizeof(buf);
190 const size_t id_len = strlen(id);
191 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
192
193 /* Write things to temporary buffer */
194 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));
197
198 if (end - p < 4) {
199 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
200 }
201
202 MBEDTLS_PUT_UINT32_BE(id_len, p, 0);
203 p += 4;
204
205 if (end < p || (size_t) (end - p) < id_len) {
206 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
207 }
208
209 memcpy(p, id, id_len);
210 p += id_len;
211
212 /* Compute hash */
213 MBEDTLS_MPI_CHK(mbedtls_md(md_info, buf, p - buf, hash));
214
215 /* Turn it into an integer mod n */
216 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));
219
220 cleanup:
221 return ret;
222 }
223
224 /*
225 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
226 */
ecjpake_zkp_read(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,const mbedtls_ecp_point * X,const char * id,const unsigned char ** p,const unsigned char * end)227 static 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)
235 {
236 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
237 mbedtls_ecp_point V, VV;
238 mbedtls_mpi r, h;
239 size_t r_len;
240
241 mbedtls_ecp_point_init(&V);
242 mbedtls_ecp_point_init(&VV);
243 mbedtls_mpi_init(&r);
244 mbedtls_mpi_init(&h);
245
246 /*
247 * struct {
248 * ECPoint V;
249 * opaque r<1..2^8-1>;
250 * } ECSchnorrZKP;
251 */
252 if (end < *p) {
253 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
254 }
255
256 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, end - *p));
257
258 if (end < *p || (size_t) (end - *p) < 1) {
259 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
260 goto cleanup;
261 }
262
263 r_len = *(*p)++;
264
265 if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) {
266 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
267 goto cleanup;
268 }
269
270 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
271 *p += r_len;
272
273 /*
274 * Verification
275 */
276 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));
279
280 if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
281 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
282 goto cleanup;
283 }
284
285 cleanup:
286 mbedtls_ecp_point_free(&V);
287 mbedtls_ecp_point_free(&VV);
288 mbedtls_mpi_free(&r);
289 mbedtls_mpi_free(&h);
290
291 return ret;
292 }
293
294 /*
295 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
296 */
ecjpake_zkp_write(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,const mbedtls_mpi * x,const mbedtls_ecp_point * X,const char * id,unsigned char ** p,const unsigned char * end,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)297 static 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)
308 {
309 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
310 mbedtls_ecp_point V;
311 mbedtls_mpi v;
312 mbedtls_mpi h; /* later recycled to hold r */
313 size_t len;
314
315 if (end < *p) {
316 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
317 }
318
319 mbedtls_ecp_point_init(&V);
320 mbedtls_mpi_init(&v);
321 mbedtls_mpi_init(&h);
322
323 /* Compute signature */
324 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 */
330
331 /* Write it out */
332 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
333 pf, &len, *p, end - *p));
334 *p += len;
335
336 len = mbedtls_mpi_size(&h); /* actually r */
337 if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) {
338 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
339 goto cleanup;
340 }
341
342 *(*p)++ = MBEDTLS_BYTE_0(len);
343 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len)); /* r */
344 *p += len;
345
346 cleanup:
347 mbedtls_ecp_point_free(&V);
348 mbedtls_mpi_free(&v);
349 mbedtls_mpi_free(&h);
350
351 return ret;
352 }
353
354 /*
355 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
356 * Output: verified public key X
357 */
ecjpake_kkp_read(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,mbedtls_ecp_point * X,const char * id,const unsigned char ** p,const unsigned char * end)358 static 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)
366 {
367 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
368
369 if (end < *p) {
370 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
371 }
372
373 /*
374 * struct {
375 * ECPoint X;
376 * ECSchnorrZKP zkp;
377 * } ECJPAKEKeyKP;
378 */
379 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, end - *p));
380 if (mbedtls_ecp_is_zero(X)) {
381 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
382 goto cleanup;
383 }
384
385 MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_info, grp, pf, G, X, id, p, end));
386
387 cleanup:
388 return ret;
389 }
390
391 /*
392 * Generate an ECJPAKEKeyKP
393 * Output: the serialized structure, plus private/public key pair
394 */
ecjpake_kkp_write(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,mbedtls_mpi * x,mbedtls_ecp_point * X,const char * id,unsigned char ** p,const unsigned char * end,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)395 static 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)
406 {
407 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
408 size_t len;
409
410 if (end < *p) {
411 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
412 }
413
414 /* Generate key (7.4.2.3.1) and write it out */
415 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));
419 *p += len;
420
421 /* Generate and write proof */
422 MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_info, grp, pf, G, x, X, id,
423 p, end, f_rng, p_rng));
424
425 cleanup:
426 return ret;
427 }
428
429 /*
430 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
431 * Outputs: verified peer public keys Xa, Xb
432 */
ecjpake_kkpp_read(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,mbedtls_ecp_point * Xa,mbedtls_ecp_point * Xb,const char * id,const unsigned char * buf,size_t len)433 static 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)
442 {
443 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
444 const unsigned char *p = buf;
445 const unsigned char *end = buf + len;
446
447 /*
448 * struct {
449 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
450 * } ECJPAKEKeyKPPairList;
451 */
452 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));
454
455 if (p != end) {
456 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
457 }
458
459 cleanup:
460 return ret;
461 }
462
463 /*
464 * Generate a ECJPAKEKeyKPPairList
465 * Outputs: the serialized structure, plus two private/public key pairs
466 */
ecjpake_kkpp_write(const mbedtls_md_info_t * md_info,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * G,mbedtls_mpi * xm1,mbedtls_ecp_point * Xa,mbedtls_mpi * xm2,mbedtls_ecp_point * Xb,const char * id,unsigned char * buf,size_t len,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)467 static 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)
481 {
482 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
483 unsigned char *p = buf;
484 const unsigned char *end = buf + len;
485
486 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));
490
491 *olen = p - buf;
492
493 cleanup:
494 return ret;
495 }
496
497 /*
498 * Read and process the first round message
499 */
mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context * ctx,const unsigned char * buf,size_t len)500 int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
501 const unsigned char *buf,
502 size_t len)
503 {
504 ECJPAKE_VALIDATE_RET(ctx != NULL);
505 ECJPAKE_VALIDATE_RET(buf != NULL);
506
507 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);
511 }
512
513 /*
514 * Generate and write the first round message
515 */
mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context * ctx,unsigned char * buf,size_t len,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)516 int 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)
520 {
521 ECJPAKE_VALIDATE_RET(ctx != NULL);
522 ECJPAKE_VALIDATE_RET(buf != NULL);
523 ECJPAKE_VALIDATE_RET(olen != NULL);
524 ECJPAKE_VALIDATE_RET(f_rng != NULL);
525
526 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);
530 }
531
532 /*
533 * Compute the sum of three points R = A + B + C
534 */
ecjpake_ecp_add3(mbedtls_ecp_group * grp,mbedtls_ecp_point * R,const mbedtls_ecp_point * A,const mbedtls_ecp_point * B,const mbedtls_ecp_point * C)535 static 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)
539 {
540 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
541 mbedtls_mpi one;
542
543 mbedtls_mpi_init(&one);
544
545 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));
548
549 cleanup:
550 mbedtls_mpi_free(&one);
551
552 return ret;
553 }
554
555 /*
556 * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
557 */
mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context * ctx,const unsigned char * buf,size_t len)558 int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
559 const unsigned char *buf,
560 size_t len)
561 {
562 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
563 const unsigned char *p = buf;
564 const unsigned char *end = buf + len;
565 mbedtls_ecp_group grp;
566 mbedtls_ecp_point G; /* C: GB, S: GA */
567
568 ECJPAKE_VALIDATE_RET(ctx != NULL);
569 ECJPAKE_VALIDATE_RET(buf != NULL);
570
571 mbedtls_ecp_group_init(&grp);
572 mbedtls_ecp_point_init(&G);
573
574 /*
575 * 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
578 * We need that before parsing in order to check Xp as we read it
579 */
580 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
581 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
582
583 /*
584 * struct {
585 * ECParameters curve_params; // only client reading server msg
586 * ECJPAKEKeyKP ecjpake_key_kp;
587 * } Client/ServerECJPAKEParams;
588 */
589 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) {
592 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
593 goto cleanup;
594 }
595 }
596
597 MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_info, &ctx->grp,
598 ctx->point_format,
599 &G, &ctx->Xp, ID_PEER, &p, end));
600
601 if (p != end) {
602 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
603 goto cleanup;
604 }
605
606 cleanup:
607 mbedtls_ecp_group_free(&grp);
608 mbedtls_ecp_point_free(&G);
609
610 return ret;
611 }
612
613 /*
614 * Compute R = +/- X * S mod N, taking care not to leak S
615 */
ecjpake_mul_secret(mbedtls_mpi * R,int sign,const mbedtls_mpi * X,const mbedtls_mpi * S,const mbedtls_mpi * N,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)616 static 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)
622 {
623 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
624 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
625
626 mbedtls_mpi_init(&b);
627
628 /* b = s + rnd-128-bit * N */
629 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));
632
633 /* R = sign * X * b mod N */
634 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
635 R->s *= sign;
636 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
637
638 cleanup:
639 mbedtls_mpi_free(&b);
640
641 return ret;
642 }
643
644 /*
645 * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
646 */
mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context * ctx,unsigned char * buf,size_t len,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)647 int 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)
651 {
652 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
653 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 */
656 unsigned char *p = buf;
657 const unsigned char *end = buf + len;
658 size_t ec_len;
659
660 ECJPAKE_VALIDATE_RET(ctx != NULL);
661 ECJPAKE_VALIDATE_RET(buf != NULL);
662 ECJPAKE_VALIDATE_RET(olen != NULL);
663 ECJPAKE_VALIDATE_RET(f_rng != NULL);
664
665 mbedtls_ecp_point_init(&G);
666 mbedtls_ecp_point_init(&Xm);
667 mbedtls_mpi_init(&xm);
668
669 /*
670 * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
671 *
672 * 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
675 */
676 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));
681
682 /*
683 * Now write things out
684 *
685 * struct {
686 * ECParameters curve_params; // only server writing its message
687 * ECJPAKEKeyKP ecjpake_key_kp;
688 * } Client/ServerECJPAKEParams;
689 */
690 if (ctx->role == MBEDTLS_ECJPAKE_SERVER) {
691 if (end < p) {
692 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
693 goto cleanup;
694 }
695 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len,
696 p, end - p));
697 p += ec_len;
698 }
699
700 if (end < p) {
701 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
702 goto cleanup;
703 }
704 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm,
705 ctx->point_format, &ec_len, p, end - p));
706 p += ec_len;
707
708 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));
712
713 *olen = p - buf;
714
715 cleanup:
716 mbedtls_ecp_point_free(&G);
717 mbedtls_ecp_point_free(&Xm);
718 mbedtls_mpi_free(&xm);
719
720 return ret;
721 }
722
723 /*
724 * Derive PMS (7.4.2.7 / 7.4.2.8)
725 */
mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context * ctx,unsigned char * buf,size_t len,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)726 int 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)
730 {
731 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
732 mbedtls_ecp_point K;
733 mbedtls_mpi m_xm2_s, one;
734 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
735 size_t x_bytes;
736
737 ECJPAKE_VALIDATE_RET(ctx != NULL);
738 ECJPAKE_VALIDATE_RET(buf != NULL);
739 ECJPAKE_VALIDATE_RET(olen != NULL);
740 ECJPAKE_VALIDATE_RET(f_rng != NULL);
741
742 *olen = mbedtls_md_get_size(ctx->md_info);
743 if (len < *olen) {
744 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
745 }
746
747 mbedtls_ecp_point_init(&K);
748 mbedtls_mpi_init(&m_xm2_s);
749 mbedtls_mpi_init(&one);
750
751 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
752
753 /*
754 * Client: K = ( Xs - X4 * x2 * s ) * x2
755 * Server: K = ( Xc - X2 * x4 * s ) * x4
756 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
757 */
758 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));
765
766 /* PMS = SHA-256( K.X ) */
767 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));
770
771 cleanup:
772 mbedtls_ecp_point_free(&K);
773 mbedtls_mpi_free(&m_xm2_s);
774 mbedtls_mpi_free(&one);
775
776 return ret;
777 }
778
779 #undef ID_MINE
780 #undef ID_PEER
781
782 #endif /* ! MBEDTLS_ECJPAKE_ALT */
783
784 #if defined(MBEDTLS_SELF_TEST)
785
786 #include "mbedtls/platform.h"
787
788 #if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
789 !defined(MBEDTLS_SHA256_C)
mbedtls_ecjpake_self_test(int verbose)790 int mbedtls_ecjpake_self_test(int verbose)
791 {
792 (void) verbose;
793 return 0;
794 }
795 #else
796
797 static 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
802 #if !defined(MBEDTLS_ECJPAKE_ALT)
803
804 static 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
810 static 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
816 static 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
822 static 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
828 static const unsigned char ecjpake_test_cli_one[] = {
829 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,
842 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
857 };
858
859 static const unsigned char ecjpake_test_srv_one[] = {
860 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
890 static const unsigned char ecjpake_test_srv_two[] = {
891 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
907 static const unsigned char ecjpake_test_cli_two[] = {
908 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
924 static 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
930 /* Load my private keys and generate the corresponding public keys */
ecjpake_test_load(mbedtls_ecjpake_context * ctx,const unsigned char * xm1,size_t len1,const unsigned char * xm2,size_t len2)931 static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
932 const unsigned char *xm1, size_t len1,
933 const unsigned char *xm2, size_t len2)
934 {
935 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
936
937 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));
943
944 cleanup:
945 return ret;
946 }
947
948 #endif /* ! MBEDTLS_ECJPAKE_ALT */
949
950 /* For tests we don't need a secure RNG;
951 * use the LGC from Numerical Recipes for simplicity */
ecjpake_lgc(void * p,unsigned char * out,size_t len)952 static int ecjpake_lgc(void *p, unsigned char *out, size_t len)
953 {
954 static uint32_t x = 42;
955 (void) p;
956
957 while (len > 0) {
958 size_t use_len = len > 4 ? 4 : len;
959 x = 1664525 * x + 1013904223;
960 memcpy(out, &x, use_len);
961 out += use_len;
962 len -= use_len;
963 }
964
965 return 0;
966 }
967
968 #define TEST_ASSERT(x) \
969 do { \
970 if (x) \
971 ret = 0; \
972 else \
973 { \
974 ret = 1; \
975 goto cleanup; \
976 } \
977 } while (0)
978
979 /*
980 * Checkup routine
981 */
mbedtls_ecjpake_self_test(int verbose)982 int mbedtls_ecjpake_self_test(int verbose)
983 {
984 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
985 mbedtls_ecjpake_context cli;
986 mbedtls_ecjpake_context srv;
987 unsigned char buf[512], pms[32];
988 size_t len, pmslen;
989
990 mbedtls_ecjpake_init(&cli);
991 mbedtls_ecjpake_init(&srv);
992
993 if (verbose != 0) {
994 mbedtls_printf(" ECJPAKE test #0 (setup): ");
995 }
996
997 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);
1001
1002 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);
1006
1007 if (verbose != 0) {
1008 mbedtls_printf("passed\n");
1009 }
1010
1011 if (verbose != 0) {
1012 mbedtls_printf(" ECJPAKE test #1 (random handshake): ");
1013 }
1014
1015 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
1016 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1017
1018 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
1019
1020 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1021 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1022
1023 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
1024
1025 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1026 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1027
1028 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
1029
1030 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1031 pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
1032
1033 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1034 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1035
1036 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
1037
1038 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1039 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1040
1041 TEST_ASSERT(len == pmslen);
1042 TEST_ASSERT(memcmp(buf, pms, len) == 0);
1043
1044 if (verbose != 0) {
1045 mbedtls_printf("passed\n");
1046 }
1047
1048 #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
1051 * are generated. This is only the case for the internal Mbed TLS
1052 * implementation, so these tests are skipped in case the internal
1053 * implementation is swapped out for an alternative one. */
1054 if (verbose != 0) {
1055 mbedtls_printf(" ECJPAKE test #2 (reference handshake): ");
1056 }
1057
1058 /* Simulate generation of round one */
1059 MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1060 ecjpake_test_x1, sizeof(ecjpake_test_x1),
1061 ecjpake_test_x2, sizeof(ecjpake_test_x2)));
1062
1063 MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1064 ecjpake_test_x3, sizeof(ecjpake_test_x3),
1065 ecjpake_test_x4, sizeof(ecjpake_test_x4)));
1066
1067 /* Read round one */
1068 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1069 ecjpake_test_cli_one,
1070 sizeof(ecjpake_test_cli_one)) == 0);
1071
1072 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1073 ecjpake_test_srv_one,
1074 sizeof(ecjpake_test_srv_one)) == 0);
1075
1076 /* Skip generation of round two, read round two */
1077 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1078 ecjpake_test_srv_two,
1079 sizeof(ecjpake_test_srv_two)) == 0);
1080
1081 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1082 ecjpake_test_cli_two,
1083 sizeof(ecjpake_test_cli_two)) == 0);
1084
1085 /* Server derives PMS */
1086 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1087 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1088
1089 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1090 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1091
1092 memset(buf, 0, len); /* Avoid interferences with next step */
1093
1094 /* Client derives PMS */
1095 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1096 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1097
1098 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1099 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1100
1101 if (verbose != 0) {
1102 mbedtls_printf("passed\n");
1103 }
1104 #endif /* ! MBEDTLS_ECJPAKE_ALT */
1105
1106 cleanup:
1107 mbedtls_ecjpake_free(&cli);
1108 mbedtls_ecjpake_free(&srv);
1109
1110 if (ret != 0) {
1111 if (verbose != 0) {
1112 mbedtls_printf("failed\n");
1113 }
1114
1115 ret = 1;
1116 }
1117
1118 if (verbose != 0) {
1119 mbedtls_printf("\n");
1120 }
1121
1122 return ret;
1123 }
1124
1125 #undef TEST_ASSERT
1126
1127 #endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1128
1129 #endif /* MBEDTLS_SELF_TEST */
1130
1131 #endif /* MBEDTLS_ECJPAKE_C */
1132