1/*
2 * Elliptic curve J-PAKE
3 *
4 * Copyright The Mbed TLS Contributors
5 * 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.
18 */
19
20/*
21 * References in the code are to the Thread v1.0 Specification,
22 * available to members of the Thread Group http://threadgroup.org/
23 */
24
25#include "common.h"
26
27#if defined(MBEDTLS_ECJPAKE_C)
28
29#include "mbedtls/ecjpake.h"
30#include "mbedtls/platform_util.h"
31#include "mbedtls/error.h"
32
33#include <string.h>
34
35#if !defined(MBEDTLS_ECJPAKE_ALT)
36
37/* Parameter validation macros based on platform_util.h */
38#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)
42
43/*
44 * Convert a mbedtls_ecjpake_role to identifier string
45 */
46static const char * const ecjpake_id[] = {
47 "client",
48 "server"
49};
50
51#define ID_MINE (ecjpake_id[ctx->role])
52#define ID_PEER (ecjpake_id[1 - ctx->role])
53
54/*
55 * Initialize context
56 */
57void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx)
58{
59 ECJPAKE_VALIDATE(ctx != NULL);
60
61 ctx->md_info = NULL;
62 mbedtls_ecp_group_init(&ctx->grp);
63 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
64
65 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);
70
71 mbedtls_mpi_init(&ctx->xm1);
72 mbedtls_mpi_init(&ctx->xm2);
73 mbedtls_mpi_init(&ctx->s);
74}
75
76/*
77 * Free context
78 */
79void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx)
80{
81 if (ctx == NULL) {
82 return;
83 }
84
85 ctx->md_info = NULL;
86 mbedtls_ecp_group_free(&ctx->grp);
87
88 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);
93
94 mbedtls_mpi_free(&ctx->xm1);
95 mbedtls_mpi_free(&ctx->xm2);
96 mbedtls_mpi_free(&ctx->s);
97}
98
99/*
100 * Setup context
101 */
102int 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)
108{
109 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
110
111 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);
115
116 ctx->role = role;
117
118 if ((ctx->md_info = mbedtls_md_info_from_type(hash)) == NULL) {
119 return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
120 }
121
122 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
123
124 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
125
126cleanup:
127 if (ret != 0) {
128 mbedtls_ecjpake_free(ctx);
129 }
130
131 return ret;
132}
133
134/*
135 * Check if context is ready for use
136 */
137int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx)
138{
139 ECJPAKE_VALIDATE_RET(ctx != NULL);
140
141 if (ctx->md_info == NULL ||
142 ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
143 ctx->s.p == NULL) {
144 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
145 }
146
147 return 0;
148}
149
150/*
151 * Write a point plus its length to a buffer
152 */
153static 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)
158{
159 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
160 size_t len;
161
162 /* Need at least 4 for length plus 1 for point */
163 if (end < *p || end - *p < 5) {
164 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
165 }
166
167 ret = mbedtls_ecp_point_write_binary(grp, P, pf,
168 &len, *p + 4, end - (*p + 4));
169 if (ret != 0) {
170 return ret;
171 }
172
173 MBEDTLS_PUT_UINT32_BE(len, *p, 0);
174
175 *p += 4 + len;
176
177 return 0;
178}
179
180/*
181 * Size of the temporary buffer for ecjpake_hash:
182 * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
183 */
184#define ECJPAKE_HASH_BUF_LEN (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6)
185
186/*
187 * Compute hash for ZKP (7.4.2.2.2.1)
188 */
189static 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)
197{
198 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
199 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
200 unsigned char *p = buf;
201 const unsigned char *end = buf + sizeof(buf);
202 const size_t id_len = strlen(id);
203 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
204
205 /* Write things to temporary buffer */
206 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));
209
210 if (end - p < 4) {
211 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
212 }
213
214 MBEDTLS_PUT_UINT32_BE(id_len, p, 0);
215 p += 4;
216
217 if (end < p || (size_t) (end - p) < id_len) {
218 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
219 }
220
221 memcpy(p, id, id_len);
222 p += id_len;
223
224 /* Compute hash */
225 MBEDTLS_MPI_CHK(mbedtls_md(md_info, buf, p - buf, hash));
226
227 /* Turn it into an integer mod n */
228 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));
231
232cleanup:
233 return ret;
234}
235
236/*
237 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
238 */
239static 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)
247{
248 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
249 mbedtls_ecp_point V, VV;
250 mbedtls_mpi r, h;
251 size_t r_len;
252
253 mbedtls_ecp_point_init(&V);
254 mbedtls_ecp_point_init(&VV);
255 mbedtls_mpi_init(&r);
256 mbedtls_mpi_init(&h);
257
258 /*
259 * struct {
260 * ECPoint V;
261 * opaque r<1..2^8-1>;
262 * } ECSchnorrZKP;
263 */
264 if (end < *p) {
265 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
266 }
267
268 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, end - *p));
269
270 if (end < *p || (size_t) (end - *p) < 1) {
271 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
272 goto cleanup;
273 }
274
275 r_len = *(*p)++;
276
277 if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) {
278 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
279 goto cleanup;
280 }
281
282 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
283 *p += r_len;
284
285 /*
286 * Verification
287 */
288 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));
291
292 if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
293 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
294 goto cleanup;
295 }
296
297cleanup:
298 mbedtls_ecp_point_free(&V);
299 mbedtls_ecp_point_free(&VV);
300 mbedtls_mpi_free(&r);
301 mbedtls_mpi_free(&h);
302
303 return ret;
304}
305
306/*
307 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
308 */
309static 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)
320{
321 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
322 mbedtls_ecp_point V;
323 mbedtls_mpi v;
324 mbedtls_mpi h; /* later recycled to hold r */
325 size_t len;
326
327 if (end < *p) {
328 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
329 }
330
331 mbedtls_ecp_point_init(&V);
332 mbedtls_mpi_init(&v);
333 mbedtls_mpi_init(&h);
334
335 /* Compute signature */
336 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 */
342
343 /* Write it out */
344 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
345 pf, &len, *p, end - *p));
346 *p += len;
347
348 len = mbedtls_mpi_size(&h); /* actually r */
349 if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) {
350 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
351 goto cleanup;
352 }
353
354 *(*p)++ = MBEDTLS_BYTE_0(len);
355 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len)); /* r */
356 *p += len;
357
358cleanup:
359 mbedtls_ecp_point_free(&V);
360 mbedtls_mpi_free(&v);
361 mbedtls_mpi_free(&h);
362
363 return ret;
364}
365
366/*
367 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
368 * Output: verified public key X
369 */
370static 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)
378{
379 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
380
381 if (end < *p) {
382 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
383 }
384
385 /*
386 * struct {
387 * ECPoint X;
388 * ECSchnorrZKP zkp;
389 * } ECJPAKEKeyKP;
390 */
391 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, end - *p));
392 if (mbedtls_ecp_is_zero(X)) {
393 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
394 goto cleanup;
395 }
396
397 MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_info, grp, pf, G, X, id, p, end));
398
399cleanup:
400 return ret;
401}
402
403/*
404 * Generate an ECJPAKEKeyKP
405 * Output: the serialized structure, plus private/public key pair
406 */
407static 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)
418{
419 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
420 size_t len;
421
422 if (end < *p) {
423 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
424 }
425
426 /* Generate key (7.4.2.3.1) and write it out */
427 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));
431 *p += len;
432
433 /* Generate and write proof */
434 MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_info, grp, pf, G, x, X, id,
435 p, end, f_rng, p_rng));
436
437cleanup:
438 return ret;
439}
440
441/*
442 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
443 * Outputs: verified peer public keys Xa, Xb
444 */
445static 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)
454{
455 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
456 const unsigned char *p = buf;
457 const unsigned char *end = buf + len;
458
459 /*
460 * struct {
461 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
462 * } ECJPAKEKeyKPPairList;
463 */
464 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));
466
467 if (p != end) {
468 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
469 }
470
471cleanup:
472 return ret;
473}
474
475/*
476 * Generate a ECJPAKEKeyKPPairList
477 * Outputs: the serialized structure, plus two private/public key pairs
478 */
479static 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)
493{
494 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
495 unsigned char *p = buf;
496 const unsigned char *end = buf + len;
497
498 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));
502
503 *olen = p - buf;
504
505cleanup:
506 return ret;
507}
508
509/*
510 * Read and process the first round message
511 */
512int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
513 const unsigned char *buf,
514 size_t len)
515{
516 ECJPAKE_VALIDATE_RET(ctx != NULL);
517 ECJPAKE_VALIDATE_RET(buf != NULL);
518
519 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);
523}
524
525/*
526 * Generate and write the first round message
527 */
528int 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)
532{
533 ECJPAKE_VALIDATE_RET(ctx != NULL);
534 ECJPAKE_VALIDATE_RET(buf != NULL);
535 ECJPAKE_VALIDATE_RET(olen != NULL);
536 ECJPAKE_VALIDATE_RET(f_rng != NULL);
537
538 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);
542}
543
544/*
545 * Compute the sum of three points R = A + B + C
546 */
547static 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)
551{
552 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
553 mbedtls_mpi one;
554
555 mbedtls_mpi_init(&one);
556
557 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));
560
561cleanup:
562 mbedtls_mpi_free(&one);
563
564 return ret;
565}
566
567/*
568 * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
569 */
570int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
571 const unsigned char *buf,
572 size_t len)
573{
574 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
575 const unsigned char *p = buf;
576 const unsigned char *end = buf + len;
577 mbedtls_ecp_group grp;
578 mbedtls_ecp_point G; /* C: GB, S: GA */
579
580 ECJPAKE_VALIDATE_RET(ctx != NULL);
581 ECJPAKE_VALIDATE_RET(buf != NULL);
582
583 mbedtls_ecp_group_init(&grp);
584 mbedtls_ecp_point_init(&G);
585
586 /*
587 * 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
590 * We need that before parsing in order to check Xp as we read it
591 */
592 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
593 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
594
595 /*
596 * struct {
597 * ECParameters curve_params; // only client reading server msg
598 * ECJPAKEKeyKP ecjpake_key_kp;
599 * } Client/ServerECJPAKEParams;
600 */
601 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) {
604 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
605 goto cleanup;
606 }
607 }
608
609 MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_info, &ctx->grp,
610 ctx->point_format,
611 &G, &ctx->Xp, ID_PEER, &p, end));
612
613 if (p != end) {
614 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
615 goto cleanup;
616 }
617
618cleanup:
619 mbedtls_ecp_group_free(&grp);
620 mbedtls_ecp_point_free(&G);
621
622 return ret;
623}
624
625/*
626 * Compute R = +/- X * S mod N, taking care not to leak S
627 */
628static 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)
634{
635 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
636 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
637
638 mbedtls_mpi_init(&b);
639
640 /* b = s + rnd-128-bit * N */
641 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));
644
645 /* R = sign * X * b mod N */
646 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
647 R->s *= sign;
648 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
649
650cleanup:
651 mbedtls_mpi_free(&b);
652
653 return ret;
654}
655
656/*
657 * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
658 */
659int 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)
663{
664 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
665 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 */
668 unsigned char *p = buf;
669 const unsigned char *end = buf + len;
670 size_t ec_len;
671
672 ECJPAKE_VALIDATE_RET(ctx != NULL);
673 ECJPAKE_VALIDATE_RET(buf != NULL);
674 ECJPAKE_VALIDATE_RET(olen != NULL);
675 ECJPAKE_VALIDATE_RET(f_rng != NULL);
676
677 mbedtls_ecp_point_init(&G);
678 mbedtls_ecp_point_init(&Xm);
679 mbedtls_mpi_init(&xm);
680
681 /*
682 * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
683 *
684 * 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
687 */
688 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));
693
694 /*
695 * Now write things out
696 *
697 * struct {
698 * ECParameters curve_params; // only server writing its message
699 * ECJPAKEKeyKP ecjpake_key_kp;
700 * } Client/ServerECJPAKEParams;
701 */
702 if (ctx->role == MBEDTLS_ECJPAKE_SERVER) {
703 if (end < p) {
704 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
705 goto cleanup;
706 }
707 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len,
708 p, end - p));
709 p += ec_len;
710 }
711
712 if (end < p) {
713 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
714 goto cleanup;
715 }
716 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm,
717 ctx->point_format, &ec_len, p, end - p));
718 p += ec_len;
719
720 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));
724
725 *olen = p - buf;
726
727cleanup:
728 mbedtls_ecp_point_free(&G);
729 mbedtls_ecp_point_free(&Xm);
730 mbedtls_mpi_free(&xm);
731
732 return ret;
733}
734
735/*
736 * Derive PMS (7.4.2.7 / 7.4.2.8)
737 */
738int 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)
742{
743 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
744 mbedtls_ecp_point K;
745 mbedtls_mpi m_xm2_s, one;
746 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
747 size_t x_bytes;
748
749 ECJPAKE_VALIDATE_RET(ctx != NULL);
750 ECJPAKE_VALIDATE_RET(buf != NULL);
751 ECJPAKE_VALIDATE_RET(olen != NULL);
752 ECJPAKE_VALIDATE_RET(f_rng != NULL);
753
754 *olen = mbedtls_md_get_size(ctx->md_info);
755 if (len < *olen) {
756 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
757 }
758
759 mbedtls_ecp_point_init(&K);
760 mbedtls_mpi_init(&m_xm2_s);
761 mbedtls_mpi_init(&one);
762
763 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
764
765 /*
766 * Client: K = ( Xs - X4 * x2 * s ) * x2
767 * Server: K = ( Xc - X2 * x4 * s ) * x4
768 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
769 */
770 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));
777
778 /* PMS = SHA-256( K.X ) */
779 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));
782
783cleanup:
784 mbedtls_ecp_point_free(&K);
785 mbedtls_mpi_free(&m_xm2_s);
786 mbedtls_mpi_free(&one);
787
788 return ret;
789}
790
791#undef ID_MINE
792#undef ID_PEER
793
794#endif /* ! MBEDTLS_ECJPAKE_ALT */
795
796#if defined(MBEDTLS_SELF_TEST)
797
798#include "mbedtls/platform.h"
799
800#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
801 !defined(MBEDTLS_SHA256_C)
802int mbedtls_ecjpake_self_test(int verbose)
803{
804 (void) verbose;
805 return 0;
806}
807#else
808
809static 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
814#if !defined(MBEDTLS_ECJPAKE_ALT)
815
816static 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
840static const unsigned char ecjpake_test_cli_one[] = {
841 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,
854 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
869};
870
871static const unsigned char ecjpake_test_srv_one[] = {
872 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
902static const unsigned char ecjpake_test_srv_two[] = {
903 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
919static const unsigned char ecjpake_test_cli_two[] = {
920 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
936static 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
942/* Load my private keys and generate the corresponding public keys */
943static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
944 const unsigned char *xm1, size_t len1,
945 const unsigned char *xm2, size_t len2)
946{
947 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
948
949 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));
955
956cleanup:
957 return ret;
958}
959
960#endif /* ! MBEDTLS_ECJPAKE_ALT */
961
962/* For tests we don't need a secure RNG;
963 * use the LGC from Numerical Recipes for simplicity */
964static int ecjpake_lgc(void *p, unsigned char *out, size_t len)
965{
966 static uint32_t x = 42;
967 (void) p;
968
969 while (len > 0) {
970 size_t use_len = len > 4 ? 4 : len;
971 x = 1664525 * x + 1013904223;
972 memcpy(out, &x, use_len);
973 out += use_len;
974 len -= use_len;
975 }
976
977 return 0;
978}
979
980#define TEST_ASSERT(x) \
981 do { \
982 if (x) \
983 ret = 0; \
984 else \
985 { \
986 ret = 1; \
987 goto cleanup; \
988 } \
989 } while (0)
990
991/*
992 * Checkup routine
993 */
994int mbedtls_ecjpake_self_test(int verbose)
995{
996 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
997 mbedtls_ecjpake_context cli;
998 mbedtls_ecjpake_context srv;
999 unsigned char buf[512], pms[32];
1000 size_t len, pmslen;
1001
1002 mbedtls_ecjpake_init(&cli);
1003 mbedtls_ecjpake_init(&srv);
1004
1005 if (verbose != 0) {
1006 mbedtls_printf(" ECJPAKE test #0 (setup): ");
1007 }
1008
1009 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);
1013
1014 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);
1018
1019 if (verbose != 0) {
1020 mbedtls_printf("passed\n");
1021 }
1022
1023 if (verbose != 0) {
1024 mbedtls_printf(" ECJPAKE test #1 (random handshake): ");
1025 }
1026
1027 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
1028 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1029
1030 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
1031
1032 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1033 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1034
1035 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
1036
1037 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1038 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1039
1040 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
1041
1042 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1043 pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
1044
1045 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1046 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1047
1048 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
1049
1050 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1051 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1052
1053 TEST_ASSERT(len == pmslen);
1054 TEST_ASSERT(memcmp(buf, pms, len) == 0);
1055
1056 if (verbose != 0) {
1057 mbedtls_printf("passed\n");
1058 }
1059
1060#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. */
1066 if (verbose != 0) {
1067 mbedtls_printf(" ECJPAKE test #2 (reference handshake): ");
1068 }
1069
1070 /* Simulate generation of round one */
1071 MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1072 ecjpake_test_x1, sizeof(ecjpake_test_x1),
1073 ecjpake_test_x2, sizeof(ecjpake_test_x2)));
1074
1075 MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1076 ecjpake_test_x3, sizeof(ecjpake_test_x3),
1077 ecjpake_test_x4, sizeof(ecjpake_test_x4)));
1078
1079 /* Read round one */
1080 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1081 ecjpake_test_cli_one,
1082 sizeof(ecjpake_test_cli_one)) == 0);
1083
1084 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1085 ecjpake_test_srv_one,
1086 sizeof(ecjpake_test_srv_one)) == 0);
1087
1088 /* Skip generation of round two, read round two */
1089 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1090 ecjpake_test_srv_two,
1091 sizeof(ecjpake_test_srv_two)) == 0);
1092
1093 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1094 ecjpake_test_cli_two,
1095 sizeof(ecjpake_test_cli_two)) == 0);
1096
1097 /* Server derives PMS */
1098 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1099 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1100
1101 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1102 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1103
1104 memset(buf, 0, len); /* Avoid interferences with next step */
1105
1106 /* Client derives PMS */
1107 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1108 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1109
1110 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1111 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1112
1113 if (verbose != 0) {
1114 mbedtls_printf("passed\n");
1115 }
1116#endif /* ! MBEDTLS_ECJPAKE_ALT */
1117
1118cleanup:
1119 mbedtls_ecjpake_free(&cli);
1120 mbedtls_ecjpake_free(&srv);
1121
1122 if (ret != 0) {
1123 if (verbose != 0) {
1124 mbedtls_printf("failed\n");
1125 }
1126
1127 ret = 1;
1128 }
1129
1130 if (verbose != 0) {
1131 mbedtls_printf("\n");
1132 }
1133
1134 return ret;
1135}
1136
1137#undef TEST_ASSERT
1138
1139#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1140
1141#endif /* MBEDTLS_SELF_TEST */
1142
1143#endif /* MBEDTLS_ECJPAKE_C */
1144