xref: /third_party/mbedtls/library/ecjpake.c (revision a8e1175b)
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/*
26 * Convert a mbedtls_ecjpake_role to identifier string
27 */
28static const char * const ecjpake_id[] = {
29    "client",
30    "server"
31};
32
33#define ID_MINE     (ecjpake_id[ctx->role])
34#define ID_PEER     (ecjpake_id[1 - ctx->role])
35
36/**
37 * Helper to Compute a hash from md_type
38 */
39static int mbedtls_ecjpake_compute_hash(mbedtls_md_type_t md_type,
40                                        const unsigned char *input, size_t ilen,
41                                        unsigned char *output)
42{
43    return mbedtls_md(mbedtls_md_info_from_type(md_type),
44                      input, ilen, output);
45}
46
47/*
48 * Initialize context
49 */
50void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx)
51{
52    ctx->md_type = MBEDTLS_MD_NONE;
53    mbedtls_ecp_group_init(&ctx->grp);
54    ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
55
56    mbedtls_ecp_point_init(&ctx->Xm1);
57    mbedtls_ecp_point_init(&ctx->Xm2);
58    mbedtls_ecp_point_init(&ctx->Xp1);
59    mbedtls_ecp_point_init(&ctx->Xp2);
60    mbedtls_ecp_point_init(&ctx->Xp);
61
62    mbedtls_mpi_init(&ctx->xm1);
63    mbedtls_mpi_init(&ctx->xm2);
64    mbedtls_mpi_init(&ctx->s);
65}
66
67/*
68 * Free context
69 */
70void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx)
71{
72    if (ctx == NULL) {
73        return;
74    }
75
76    ctx->md_type = MBEDTLS_MD_NONE;
77    mbedtls_ecp_group_free(&ctx->grp);
78
79    mbedtls_ecp_point_free(&ctx->Xm1);
80    mbedtls_ecp_point_free(&ctx->Xm2);
81    mbedtls_ecp_point_free(&ctx->Xp1);
82    mbedtls_ecp_point_free(&ctx->Xp2);
83    mbedtls_ecp_point_free(&ctx->Xp);
84
85    mbedtls_mpi_free(&ctx->xm1);
86    mbedtls_mpi_free(&ctx->xm2);
87    mbedtls_mpi_free(&ctx->s);
88}
89
90/*
91 * Setup context
92 */
93int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx,
94                          mbedtls_ecjpake_role role,
95                          mbedtls_md_type_t hash,
96                          mbedtls_ecp_group_id curve,
97                          const unsigned char *secret,
98                          size_t len)
99{
100    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
101
102    if (role != MBEDTLS_ECJPAKE_CLIENT && role != MBEDTLS_ECJPAKE_SERVER) {
103        return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
104    }
105
106    ctx->role = role;
107
108    if ((mbedtls_md_info_from_type(hash)) == NULL) {
109        return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
110    }
111
112    ctx->md_type = hash;
113
114    MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
115
116    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
117
118cleanup:
119    if (ret != 0) {
120        mbedtls_ecjpake_free(ctx);
121    }
122
123    return ret;
124}
125
126int mbedtls_ecjpake_set_point_format(mbedtls_ecjpake_context *ctx,
127                                     int point_format)
128{
129    switch (point_format) {
130        case MBEDTLS_ECP_PF_UNCOMPRESSED:
131        case MBEDTLS_ECP_PF_COMPRESSED:
132            ctx->point_format = point_format;
133            return 0;
134        default:
135            return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
136    }
137}
138
139/*
140 * Check if context is ready for use
141 */
142int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx)
143{
144    if (ctx->md_type == MBEDTLS_MD_NONE ||
145        ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
146        ctx->s.p == NULL) {
147        return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
148    }
149
150    return 0;
151}
152
153/*
154 * Write a point plus its length to a buffer
155 */
156static int ecjpake_write_len_point(unsigned char **p,
157                                   const unsigned char *end,
158                                   const mbedtls_ecp_group *grp,
159                                   const int pf,
160                                   const mbedtls_ecp_point *P)
161{
162    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
163    size_t len;
164
165    /* Need at least 4 for length plus 1 for point */
166    if (end < *p || end - *p < 5) {
167        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
168    }
169
170    ret = mbedtls_ecp_point_write_binary(grp, P, pf,
171                                         &len, *p + 4, (size_t) (end - (*p + 4)));
172    if (ret != 0) {
173        return ret;
174    }
175
176    MBEDTLS_PUT_UINT32_BE(len, *p, 0);
177
178    *p += 4 + len;
179
180    return 0;
181}
182
183/*
184 * Size of the temporary buffer for ecjpake_hash:
185 * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
186 */
187#define ECJPAKE_HASH_BUF_LEN    (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6)
188
189/*
190 * Compute hash for ZKP (7.4.2.2.2.1)
191 */
192static int ecjpake_hash(const mbedtls_md_type_t md_type,
193                        const mbedtls_ecp_group *grp,
194                        const int pf,
195                        const mbedtls_ecp_point *G,
196                        const mbedtls_ecp_point *V,
197                        const mbedtls_ecp_point *X,
198                        const char *id,
199                        mbedtls_mpi *h)
200{
201    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
202    unsigned char buf[ECJPAKE_HASH_BUF_LEN];
203    unsigned char *p = buf;
204    const unsigned char *end = buf + sizeof(buf);
205    const size_t id_len = strlen(id);
206    unsigned char hash[MBEDTLS_MD_MAX_SIZE];
207
208    /* Write things to temporary buffer */
209    MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, G));
210    MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, V));
211    MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, X));
212
213    if (end - p < 4) {
214        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
215    }
216
217    MBEDTLS_PUT_UINT32_BE(id_len, p, 0);
218    p += 4;
219
220    if (end < p || (size_t) (end - p) < id_len) {
221        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
222    }
223
224    memcpy(p, id, id_len);
225    p += id_len;
226
227    /* Compute hash */
228    MBEDTLS_MPI_CHK(mbedtls_ecjpake_compute_hash(md_type,
229                                                 buf, (size_t) (p - buf), hash));
230
231    /* Turn it into an integer mod n */
232    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(h, hash,
233                                            mbedtls_md_get_size_from_type(md_type)));
234    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(h, h, &grp->N));
235
236cleanup:
237    return ret;
238}
239
240/*
241 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
242 */
243static int ecjpake_zkp_read(const mbedtls_md_type_t md_type,
244                            const mbedtls_ecp_group *grp,
245                            const int pf,
246                            const mbedtls_ecp_point *G,
247                            const mbedtls_ecp_point *X,
248                            const char *id,
249                            const unsigned char **p,
250                            const unsigned char *end)
251{
252    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
253    mbedtls_ecp_point V, VV;
254    mbedtls_mpi r, h;
255    size_t r_len;
256
257    mbedtls_ecp_point_init(&V);
258    mbedtls_ecp_point_init(&VV);
259    mbedtls_mpi_init(&r);
260    mbedtls_mpi_init(&h);
261
262    /*
263     * struct {
264     *     ECPoint V;
265     *     opaque r<1..2^8-1>;
266     * } ECSchnorrZKP;
267     */
268    if (end < *p) {
269        return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
270    }
271
272    MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, (size_t) (end - *p)));
273
274    if (end < *p || (size_t) (end - *p) < 1) {
275        ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
276        goto cleanup;
277    }
278
279    r_len = *(*p)++;
280
281    if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) {
282        ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
283        goto cleanup;
284    }
285
286    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
287    *p += r_len;
288
289    /*
290     * Verification
291     */
292    MBEDTLS_MPI_CHK(ecjpake_hash(md_type, grp, pf, G, &V, X, id, &h));
293    MBEDTLS_MPI_CHK(mbedtls_ecp_muladd((mbedtls_ecp_group *) grp,
294                                       &VV, &h, X, &r, G));
295
296    if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
297        ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
298        goto cleanup;
299    }
300
301cleanup:
302    mbedtls_ecp_point_free(&V);
303    mbedtls_ecp_point_free(&VV);
304    mbedtls_mpi_free(&r);
305    mbedtls_mpi_free(&h);
306
307    return ret;
308}
309
310/*
311 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
312 */
313static int ecjpake_zkp_write(const mbedtls_md_type_t md_type,
314                             const mbedtls_ecp_group *grp,
315                             const int pf,
316                             const mbedtls_ecp_point *G,
317                             const mbedtls_mpi *x,
318                             const mbedtls_ecp_point *X,
319                             const char *id,
320                             unsigned char **p,
321                             const unsigned char *end,
322                             int (*f_rng)(void *, unsigned char *, size_t),
323                             void *p_rng)
324{
325    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
326    mbedtls_ecp_point V;
327    mbedtls_mpi v;
328    mbedtls_mpi h; /* later recycled to hold r */
329    size_t len;
330
331    if (end < *p) {
332        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
333    }
334
335    mbedtls_ecp_point_init(&V);
336    mbedtls_mpi_init(&v);
337    mbedtls_mpi_init(&h);
338
339    /* Compute signature */
340    MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp,
341                                                 G, &v, &V, f_rng, p_rng));
342    MBEDTLS_MPI_CHK(ecjpake_hash(md_type, grp, pf, G, &V, X, id, &h));
343    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&h, &h, x));     /* x*h */
344    MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&h, &v, &h));     /* v - x*h */
345    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&h, &h, &grp->N));     /* r */
346
347    /* Write it out */
348    MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
349                                                pf, &len, *p, (size_t) (end - *p)));
350    *p += len;
351
352    len = mbedtls_mpi_size(&h);   /* actually r */
353    if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) {
354        ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
355        goto cleanup;
356    }
357
358    *(*p)++ = MBEDTLS_BYTE_0(len);
359    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len));     /* r */
360    *p += len;
361
362cleanup:
363    mbedtls_ecp_point_free(&V);
364    mbedtls_mpi_free(&v);
365    mbedtls_mpi_free(&h);
366
367    return ret;
368}
369
370/*
371 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
372 * Output: verified public key X
373 */
374static int ecjpake_kkp_read(const mbedtls_md_type_t md_type,
375                            const mbedtls_ecp_group *grp,
376                            const int pf,
377                            const mbedtls_ecp_point *G,
378                            mbedtls_ecp_point *X,
379                            const char *id,
380                            const unsigned char **p,
381                            const unsigned char *end)
382{
383    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
384
385    if (end < *p) {
386        return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
387    }
388
389    /*
390     * struct {
391     *     ECPoint X;
392     *     ECSchnorrZKP zkp;
393     * } ECJPAKEKeyKP;
394     */
395    MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, (size_t) (end - *p)));
396    if (mbedtls_ecp_is_zero(X)) {
397        ret = MBEDTLS_ERR_ECP_INVALID_KEY;
398        goto cleanup;
399    }
400
401    MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_type, grp, pf, G, X, id, p, end));
402
403cleanup:
404    return ret;
405}
406
407/*
408 * Generate an ECJPAKEKeyKP
409 * Output: the serialized structure, plus private/public key pair
410 */
411static int ecjpake_kkp_write(const mbedtls_md_type_t md_type,
412                             const mbedtls_ecp_group *grp,
413                             const int pf,
414                             const mbedtls_ecp_point *G,
415                             mbedtls_mpi *x,
416                             mbedtls_ecp_point *X,
417                             const char *id,
418                             unsigned char **p,
419                             const unsigned char *end,
420                             int (*f_rng)(void *, unsigned char *, size_t),
421                             void *p_rng)
422{
423    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
424    size_t len;
425
426    if (end < *p) {
427        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
428    }
429
430    /* Generate key (7.4.2.3.1) and write it out */
431    MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, G, x, X,
432                                                 f_rng, p_rng));
433    MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, X,
434                                                pf, &len, *p, (size_t) (end - *p)));
435    *p += len;
436
437    /* Generate and write proof */
438    MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_type, grp, pf, G, x, X, id,
439                                      p, end, f_rng, p_rng));
440
441cleanup:
442    return ret;
443}
444
445/*
446 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
447 * Outputs: verified peer public keys Xa, Xb
448 */
449static int ecjpake_kkpp_read(const mbedtls_md_type_t md_type,
450                             const mbedtls_ecp_group *grp,
451                             const int pf,
452                             const mbedtls_ecp_point *G,
453                             mbedtls_ecp_point *Xa,
454                             mbedtls_ecp_point *Xb,
455                             const char *id,
456                             const unsigned char *buf,
457                             size_t len)
458{
459    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
460    const unsigned char *p = buf;
461    const unsigned char *end = buf + len;
462
463    /*
464     * struct {
465     *     ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
466     * } ECJPAKEKeyKPPairList;
467     */
468    MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_type, grp, pf, G, Xa, id, &p, end));
469    MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_type, grp, pf, G, Xb, id, &p, end));
470
471    if (p != end) {
472        ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
473    }
474
475cleanup:
476    return ret;
477}
478
479/*
480 * Generate a ECJPAKEKeyKPPairList
481 * Outputs: the serialized structure, plus two private/public key pairs
482 */
483static int ecjpake_kkpp_write(const mbedtls_md_type_t md_type,
484                              const mbedtls_ecp_group *grp,
485                              const int pf,
486                              const mbedtls_ecp_point *G,
487                              mbedtls_mpi *xm1,
488                              mbedtls_ecp_point *Xa,
489                              mbedtls_mpi *xm2,
490                              mbedtls_ecp_point *Xb,
491                              const char *id,
492                              unsigned char *buf,
493                              size_t len,
494                              size_t *olen,
495                              int (*f_rng)(void *, unsigned char *, size_t),
496                              void *p_rng)
497{
498    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
499    unsigned char *p = buf;
500    const unsigned char *end = buf + len;
501
502    MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_type, grp, pf, G, xm1, Xa, id,
503                                      &p, end, f_rng, p_rng));
504    MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_type, grp, pf, G, xm2, Xb, id,
505                                      &p, end, f_rng, p_rng));
506
507    *olen = (size_t) (p - buf);
508
509cleanup:
510    return ret;
511}
512
513/*
514 * Read and process the first round message
515 */
516int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
517                                   const unsigned char *buf,
518                                   size_t len)
519{
520    return ecjpake_kkpp_read(ctx->md_type, &ctx->grp, ctx->point_format,
521                             &ctx->grp.G,
522                             &ctx->Xp1, &ctx->Xp2, ID_PEER,
523                             buf, len);
524}
525
526/*
527 * Generate and write the first round message
528 */
529int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx,
530                                    unsigned char *buf, size_t len, size_t *olen,
531                                    int (*f_rng)(void *, unsigned char *, size_t),
532                                    void *p_rng)
533{
534    return ecjpake_kkpp_write(ctx->md_type, &ctx->grp, ctx->point_format,
535                              &ctx->grp.G,
536                              &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
537                              ID_MINE, buf, len, olen, f_rng, p_rng);
538}
539
540/*
541 * Compute the sum of three points R = A + B + C
542 */
543static int ecjpake_ecp_add3(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
544                            const mbedtls_ecp_point *A,
545                            const mbedtls_ecp_point *B,
546                            const mbedtls_ecp_point *C)
547{
548    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
549    mbedtls_mpi one;
550
551    mbedtls_mpi_init(&one);
552
553    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
554    MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, A, &one, B));
555    MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, R, &one, C));
556
557cleanup:
558    mbedtls_mpi_free(&one);
559
560    return ret;
561}
562
563/*
564 * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
565 */
566int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
567                                   const unsigned char *buf,
568                                   size_t len)
569{
570    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
571    const unsigned char *p = buf;
572    const unsigned char *end = buf + len;
573    mbedtls_ecp_group grp;
574    mbedtls_ecp_point G;    /* C: GB, S: GA */
575
576    mbedtls_ecp_group_init(&grp);
577    mbedtls_ecp_point_init(&G);
578
579    /*
580     * Server: GA = X3  + X4  + X1      (7.4.2.6.1)
581     * Client: GB = X1  + X2  + X3      (7.4.2.5.1)
582     * Unified: G = Xm1 + Xm2 + Xp1
583     * We need that before parsing in order to check Xp as we read it
584     */
585    MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
586                                     &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
587
588    /*
589     * struct {
590     *     ECParameters curve_params;   // only client reading server msg
591     *     ECJPAKEKeyKP ecjpake_key_kp;
592     * } Client/ServerECJPAKEParams;
593     */
594    if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) {
595        MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_group(&grp, &p, len));
596        if (grp.id != ctx->grp.id) {
597            ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
598            goto cleanup;
599        }
600    }
601
602    MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_type, &ctx->grp,
603                                     ctx->point_format,
604                                     &G, &ctx->Xp, ID_PEER, &p, end));
605
606    if (p != end) {
607        ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
608        goto cleanup;
609    }
610
611cleanup:
612    mbedtls_ecp_group_free(&grp);
613    mbedtls_ecp_point_free(&G);
614
615    return ret;
616}
617
618/*
619 * Compute R = +/- X * S mod N, taking care not to leak S
620 */
621static int ecjpake_mul_secret(mbedtls_mpi *R, int sign,
622                              const mbedtls_mpi *X,
623                              const mbedtls_mpi *S,
624                              const mbedtls_mpi *N,
625                              int (*f_rng)(void *, unsigned char *, size_t),
626                              void *p_rng)
627{
628    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
629    mbedtls_mpi b; /* Blinding value, then s + N * blinding */
630
631    mbedtls_mpi_init(&b);
632
633    /* b = s + rnd-128-bit * N */
634    MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&b, 16, f_rng, p_rng));
635    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&b, &b, N));
636    MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&b, &b, S));
637
638    /* R = sign * X * b mod N */
639    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
640    R->s *= sign;
641    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
642
643cleanup:
644    mbedtls_mpi_free(&b);
645
646    return ret;
647}
648
649/*
650 * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
651 */
652int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx,
653                                    unsigned char *buf, size_t len, size_t *olen,
654                                    int (*f_rng)(void *, unsigned char *, size_t),
655                                    void *p_rng)
656{
657    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
658    mbedtls_ecp_point G;    /* C: GA, S: GB */
659    mbedtls_ecp_point Xm;   /* C: Xc, S: Xs */
660    mbedtls_mpi xm;         /* C: xc, S: xs */
661    unsigned char *p = buf;
662    const unsigned char *end = buf + len;
663    size_t ec_len;
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, (size_t) (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, (size_t) (end - p)));
706    p += ec_len;
707
708    MBEDTLS_MPI_CHK(ecjpake_zkp_write(ctx->md_type, &ctx->grp,
709                                      ctx->point_format,
710                                      &G, &xm, &Xm, ID_MINE,
711                                      &p, end, f_rng, p_rng));
712
713    *olen = (size_t) (p - buf);
714
715cleanup:
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 */
726static int mbedtls_ecjpake_derive_k(mbedtls_ecjpake_context *ctx,
727                                    mbedtls_ecp_point *K,
728                                    int (*f_rng)(void *, unsigned char *, size_t),
729                                    void *p_rng)
730{
731    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
732    mbedtls_mpi m_xm2_s, one;
733
734    mbedtls_mpi_init(&m_xm2_s);
735    mbedtls_mpi_init(&one);
736
737    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
738
739    /*
740     * Client:  K = ( Xs - X4  * x2  * s ) * x2
741     * Server:  K = ( Xc - X2  * x4  * s ) * x4
742     * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
743     */
744    MBEDTLS_MPI_CHK(ecjpake_mul_secret(&m_xm2_s, -1, &ctx->xm2, &ctx->s,
745                                       &ctx->grp.N, f_rng, p_rng));
746    MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&ctx->grp, K,
747                                       &one, &ctx->Xp,
748                                       &m_xm2_s, &ctx->Xp2));
749    MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, K, &ctx->xm2, K,
750                                    f_rng, p_rng));
751
752cleanup:
753    mbedtls_mpi_free(&m_xm2_s);
754    mbedtls_mpi_free(&one);
755
756    return ret;
757}
758
759int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx,
760                                  unsigned char *buf, size_t len, size_t *olen,
761                                  int (*f_rng)(void *, unsigned char *, size_t),
762                                  void *p_rng)
763{
764    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
765    mbedtls_ecp_point K;
766    unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
767    size_t x_bytes;
768
769    *olen = mbedtls_md_get_size_from_type(ctx->md_type);
770    if (len < *olen) {
771        return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
772    }
773
774    mbedtls_ecp_point_init(&K);
775
776    ret = mbedtls_ecjpake_derive_k(ctx, &K, f_rng, p_rng);
777    if (ret) {
778        goto cleanup;
779    }
780
781    /* PMS = SHA-256( K.X ) */
782    x_bytes = (ctx->grp.pbits + 7) / 8;
783    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K.X, kx, x_bytes));
784    MBEDTLS_MPI_CHK(mbedtls_ecjpake_compute_hash(ctx->md_type,
785                                                 kx, x_bytes, buf));
786
787cleanup:
788    mbedtls_ecp_point_free(&K);
789
790    return ret;
791}
792
793int mbedtls_ecjpake_write_shared_key(mbedtls_ecjpake_context *ctx,
794                                     unsigned char *buf, size_t len, size_t *olen,
795                                     int (*f_rng)(void *, unsigned char *, size_t),
796                                     void *p_rng)
797{
798    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
799    mbedtls_ecp_point K;
800
801    mbedtls_ecp_point_init(&K);
802
803    ret = mbedtls_ecjpake_derive_k(ctx, &K, f_rng, p_rng);
804    if (ret) {
805        goto cleanup;
806    }
807
808    ret = mbedtls_ecp_point_write_binary(&ctx->grp, &K, ctx->point_format,
809                                         olen, buf, len);
810    if (ret != 0) {
811        goto cleanup;
812    }
813
814cleanup:
815    mbedtls_ecp_point_free(&K);
816
817    return ret;
818}
819
820#undef ID_MINE
821#undef ID_PEER
822
823#endif /* ! MBEDTLS_ECJPAKE_ALT */
824
825#if defined(MBEDTLS_SELF_TEST)
826
827#include "mbedtls/platform.h"
828
829#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
830    !defined(MBEDTLS_MD_CAN_SHA256)
831int mbedtls_ecjpake_self_test(int verbose)
832{
833    (void) verbose;
834    return 0;
835}
836#else
837
838static const unsigned char ecjpake_test_password[] = {
839    0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
840    0x65, 0x73, 0x74
841};
842
843#if !defined(MBEDTLS_ECJPAKE_ALT)
844
845static const unsigned char ecjpake_test_x1[] = {
846    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
847    0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
848    0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
849};
850
851static const unsigned char ecjpake_test_x2[] = {
852    0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
853    0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
854    0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
855};
856
857static const unsigned char ecjpake_test_x3[] = {
858    0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
859    0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
860    0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
861};
862
863static const unsigned char ecjpake_test_x4[] = {
864    0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
865    0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
866    0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
867};
868
869static const unsigned char ecjpake_test_cli_one[] = {
870    0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
871    0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
872    0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
873    0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
874    0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
875    0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
876    0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
877    0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
878    0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
879    0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
880    0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
881    0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
882    0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
883    0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
884    0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
885    0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
886    0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
887    0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
888    0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
889    0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
890    0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
891    0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
892    0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
893    0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
894    0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
895    0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
896    0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
897    0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
898};
899
900static const unsigned char ecjpake_test_srv_one[] = {
901    0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
902    0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
903    0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
904    0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
905    0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
906    0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
907    0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
908    0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
909    0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
910    0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
911    0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
912    0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
913    0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
914    0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
915    0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
916    0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
917    0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
918    0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
919    0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
920    0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
921    0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
922    0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
923    0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
924    0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
925    0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
926    0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
927    0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
928    0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
929};
930
931static const unsigned char ecjpake_test_srv_two[] = {
932    0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
933    0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
934    0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
935    0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
936    0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
937    0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
938    0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
939    0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
940    0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
941    0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
942    0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
943    0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
944    0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
945    0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
946};
947
948static const unsigned char ecjpake_test_cli_two[] = {
949    0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
950    0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
951    0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
952    0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
953    0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
954    0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
955    0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
956    0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
957    0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
958    0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
959    0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
960    0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
961    0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
962    0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
963};
964
965static const unsigned char ecjpake_test_shared_key[] = {
966    0x04, 0x01, 0xab, 0xe9, 0xf2, 0xc7, 0x3a, 0x99, 0x14, 0xcb, 0x1f, 0x80,
967    0xfb, 0x9d, 0xdb, 0x7e, 0x00, 0x12, 0xa8, 0x9c, 0x2f, 0x39, 0x27, 0x79,
968    0xf9, 0x64, 0x40, 0x14, 0x75, 0xea, 0xc1, 0x31, 0x28, 0x43, 0x8f, 0xe1,
969    0x12, 0x41, 0xd6, 0xc1, 0xe5, 0x5f, 0x7b, 0x80, 0x88, 0x94, 0xc9, 0xc0,
970    0x27, 0xa3, 0x34, 0x41, 0xf5, 0xcb, 0xa1, 0xfe, 0x6c, 0xc7, 0xe6, 0x12,
971    0x17, 0xc3, 0xde, 0x27, 0xb4,
972};
973
974static const unsigned char ecjpake_test_pms[] = {
975    0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
976    0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
977    0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
978};
979
980/*
981 * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!!
982 *
983 * This is the linear congruential generator from numerical recipes,
984 * except we only use the low byte as the output. See
985 * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
986 */
987static int self_test_rng(void *ctx, unsigned char *out, size_t len)
988{
989    static uint32_t state = 42;
990
991    (void) ctx;
992
993    for (size_t i = 0; i < len; i++) {
994        state = state * 1664525u + 1013904223u;
995        out[i] = (unsigned char) state;
996    }
997
998    return 0;
999}
1000
1001/* Load my private keys and generate the corresponding public keys */
1002static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
1003                             const unsigned char *xm1, size_t len1,
1004                             const unsigned char *xm2, size_t len2)
1005{
1006    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1007
1008    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm1, xm1, len1));
1009    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm2, xm2, len2));
1010    MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm1, &ctx->xm1,
1011                                    &ctx->grp.G, self_test_rng, NULL));
1012    MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm2, &ctx->xm2,
1013                                    &ctx->grp.G, self_test_rng, NULL));
1014
1015cleanup:
1016    return ret;
1017}
1018
1019#endif /* ! MBEDTLS_ECJPAKE_ALT */
1020
1021/* For tests we don't need a secure RNG;
1022 * use the LGC from Numerical Recipes for simplicity */
1023static int ecjpake_lgc(void *p, unsigned char *out, size_t len)
1024{
1025    static uint32_t x = 42;
1026    (void) p;
1027
1028    while (len > 0) {
1029        size_t use_len = len > 4 ? 4 : len;
1030        x = 1664525 * x + 1013904223;
1031        memcpy(out, &x, use_len);
1032        out += use_len;
1033        len -= use_len;
1034    }
1035
1036    return 0;
1037}
1038
1039#define TEST_ASSERT(x)    \
1040    do {                    \
1041        if (x)             \
1042        ret = 0;        \
1043        else                \
1044        {                   \
1045            ret = 1;        \
1046            goto cleanup;   \
1047        }                   \
1048    } while (0)
1049
1050/*
1051 * Checkup routine
1052 */
1053int mbedtls_ecjpake_self_test(int verbose)
1054{
1055    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1056    mbedtls_ecjpake_context cli;
1057    mbedtls_ecjpake_context srv;
1058    unsigned char buf[512], pms[32];
1059    size_t len, pmslen;
1060
1061    mbedtls_ecjpake_init(&cli);
1062    mbedtls_ecjpake_init(&srv);
1063
1064    if (verbose != 0) {
1065        mbedtls_printf("  ECJPAKE test #0 (setup): ");
1066    }
1067
1068    TEST_ASSERT(mbedtls_ecjpake_setup(&cli, MBEDTLS_ECJPAKE_CLIENT,
1069                                      MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1070                                      ecjpake_test_password,
1071                                      sizeof(ecjpake_test_password)) == 0);
1072
1073    TEST_ASSERT(mbedtls_ecjpake_setup(&srv, MBEDTLS_ECJPAKE_SERVER,
1074                                      MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1075                                      ecjpake_test_password,
1076                                      sizeof(ecjpake_test_password)) == 0);
1077
1078    if (verbose != 0) {
1079        mbedtls_printf("passed\n");
1080    }
1081
1082    if (verbose != 0) {
1083        mbedtls_printf("  ECJPAKE test #1 (random handshake): ");
1084    }
1085
1086    TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
1087                                                buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1088
1089    TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
1090
1091    TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1092                                                buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1093
1094    TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
1095
1096    TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1097                                                buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1098
1099    TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
1100
1101    TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1102                                              pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
1103
1104    TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1105                                                buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1106
1107    TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
1108
1109    TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1110                                              buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1111
1112    TEST_ASSERT(len == pmslen);
1113    TEST_ASSERT(memcmp(buf, pms, len) == 0);
1114
1115    if (verbose != 0) {
1116        mbedtls_printf("passed\n");
1117    }
1118
1119#if !defined(MBEDTLS_ECJPAKE_ALT)
1120    /* 'reference handshake' tests can only be run against implementations
1121     * for which we have 100% control over how the random ephemeral keys
1122     * are generated. This is only the case for the internal Mbed TLS
1123     * implementation, so these tests are skipped in case the internal
1124     * implementation is swapped out for an alternative one. */
1125    if (verbose != 0) {
1126        mbedtls_printf("  ECJPAKE test #2 (reference handshake): ");
1127    }
1128
1129    /* Simulate generation of round one */
1130    MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1131                                      ecjpake_test_x1, sizeof(ecjpake_test_x1),
1132                                      ecjpake_test_x2, sizeof(ecjpake_test_x2)));
1133
1134    MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1135                                      ecjpake_test_x3, sizeof(ecjpake_test_x3),
1136                                      ecjpake_test_x4, sizeof(ecjpake_test_x4)));
1137
1138    /* Read round one */
1139    TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1140                                               ecjpake_test_cli_one,
1141                                               sizeof(ecjpake_test_cli_one)) == 0);
1142
1143    TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1144                                               ecjpake_test_srv_one,
1145                                               sizeof(ecjpake_test_srv_one)) == 0);
1146
1147    /* Skip generation of round two, read round two */
1148    TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1149                                               ecjpake_test_srv_two,
1150                                               sizeof(ecjpake_test_srv_two)) == 0);
1151
1152    TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1153                                               ecjpake_test_cli_two,
1154                                               sizeof(ecjpake_test_cli_two)) == 0);
1155
1156    /* Server derives PMS */
1157    TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1158                                              buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1159
1160    TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1161    TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1162
1163    /* Server derives K as unsigned binary data */
1164    TEST_ASSERT(mbedtls_ecjpake_write_shared_key(&srv,
1165                                                 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1166
1167    TEST_ASSERT(len == sizeof(ecjpake_test_shared_key));
1168    TEST_ASSERT(memcmp(buf, ecjpake_test_shared_key, len) == 0);
1169
1170    memset(buf, 0, len);   /* Avoid interferences with next step */
1171
1172    /* Client derives PMS */
1173    TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1174                                              buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1175
1176    TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1177    TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1178
1179    /* Client derives K as unsigned binary data */
1180    TEST_ASSERT(mbedtls_ecjpake_write_shared_key(&cli,
1181                                                 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1182
1183    TEST_ASSERT(len == sizeof(ecjpake_test_shared_key));
1184    TEST_ASSERT(memcmp(buf, ecjpake_test_shared_key, len) == 0);
1185
1186    if (verbose != 0) {
1187        mbedtls_printf("passed\n");
1188    }
1189#endif /* ! MBEDTLS_ECJPAKE_ALT */
1190
1191cleanup:
1192    mbedtls_ecjpake_free(&cli);
1193    mbedtls_ecjpake_free(&srv);
1194
1195    if (ret != 0) {
1196        if (verbose != 0) {
1197            mbedtls_printf("failed\n");
1198        }
1199
1200        ret = 1;
1201    }
1202
1203    if (verbose != 0) {
1204        mbedtls_printf("\n");
1205    }
1206
1207    return ret;
1208}
1209
1210#undef TEST_ASSERT
1211
1212#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_MD_CAN_SHA256 */
1213
1214#endif /* MBEDTLS_SELF_TEST */
1215
1216#endif /* MBEDTLS_ECJPAKE_C */
1217