xref: /optee_os/lib/libmbedtls/mbedtls/library/ecjpake.c (revision b0563631928755fe864b97785160fb3088e9efdc)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  Elliptic curve J-PAKE
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander  */
7817466cbSJens Wiklander 
8817466cbSJens Wiklander /*
9817466cbSJens Wiklander  * References in the code are to the Thread v1.0 Specification,
10817466cbSJens Wiklander  * available to members of the Thread Group http://threadgroup.org/
11817466cbSJens Wiklander  */
12817466cbSJens Wiklander 
137901324dSJerome Forissier #include "common.h"
14817466cbSJens Wiklander 
15817466cbSJens Wiklander #if defined(MBEDTLS_ECJPAKE_C)
16817466cbSJens Wiklander 
17817466cbSJens Wiklander #include "mbedtls/ecjpake.h"
183d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
1911fa71b9SJerome Forissier #include "mbedtls/error.h"
20817466cbSJens Wiklander 
21817466cbSJens Wiklander #include <string.h>
22817466cbSJens Wiklander 
233d3b0591SJens Wiklander #if !defined(MBEDTLS_ECJPAKE_ALT)
243d3b0591SJens Wiklander 
25817466cbSJens Wiklander /*
26817466cbSJens Wiklander  * Convert a mbedtls_ecjpake_role to identifier string
27817466cbSJens Wiklander  */
28817466cbSJens Wiklander static const char * const ecjpake_id[] = {
29817466cbSJens Wiklander     "client",
30817466cbSJens Wiklander     "server"
31817466cbSJens Wiklander };
32817466cbSJens Wiklander 
33817466cbSJens Wiklander #define ID_MINE     (ecjpake_id[ctx->role])
34817466cbSJens Wiklander #define ID_PEER     (ecjpake_id[1 - ctx->role])
35817466cbSJens Wiklander 
3632b31808SJens Wiklander /**
3732b31808SJens Wiklander  * Helper to Compute a hash from md_type
3832b31808SJens Wiklander  */
mbedtls_ecjpake_compute_hash(mbedtls_md_type_t md_type,const unsigned char * input,size_t ilen,unsigned char * output)3932b31808SJens Wiklander static int mbedtls_ecjpake_compute_hash(mbedtls_md_type_t md_type,
4032b31808SJens Wiklander                                         const unsigned char *input, size_t ilen,
4132b31808SJens Wiklander                                         unsigned char *output)
4232b31808SJens Wiklander {
4332b31808SJens Wiklander     return mbedtls_md(mbedtls_md_info_from_type(md_type),
4432b31808SJens Wiklander                       input, ilen, output);
4532b31808SJens Wiklander }
4632b31808SJens Wiklander 
47817466cbSJens Wiklander /*
48817466cbSJens Wiklander  * Initialize context
49817466cbSJens Wiklander  */
mbedtls_ecjpake_init(mbedtls_ecjpake_context * ctx)50817466cbSJens Wiklander void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx)
51817466cbSJens Wiklander {
5232b31808SJens Wiklander     ctx->md_type = MBEDTLS_MD_NONE;
53817466cbSJens Wiklander     mbedtls_ecp_group_init(&ctx->grp);
54817466cbSJens Wiklander     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
55817466cbSJens Wiklander 
56817466cbSJens Wiklander     mbedtls_ecp_point_init(&ctx->Xm1);
57817466cbSJens Wiklander     mbedtls_ecp_point_init(&ctx->Xm2);
58817466cbSJens Wiklander     mbedtls_ecp_point_init(&ctx->Xp1);
59817466cbSJens Wiklander     mbedtls_ecp_point_init(&ctx->Xp2);
60817466cbSJens Wiklander     mbedtls_ecp_point_init(&ctx->Xp);
61817466cbSJens Wiklander 
62817466cbSJens Wiklander     mbedtls_mpi_init(&ctx->xm1);
63817466cbSJens Wiklander     mbedtls_mpi_init(&ctx->xm2);
64817466cbSJens Wiklander     mbedtls_mpi_init(&ctx->s);
65817466cbSJens Wiklander }
66817466cbSJens Wiklander 
67817466cbSJens Wiklander /*
68817466cbSJens Wiklander  * Free context
69817466cbSJens Wiklander  */
mbedtls_ecjpake_free(mbedtls_ecjpake_context * ctx)70817466cbSJens Wiklander void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx)
71817466cbSJens Wiklander {
7232b31808SJens Wiklander     if (ctx == NULL) {
73817466cbSJens Wiklander         return;
7432b31808SJens Wiklander     }
75817466cbSJens Wiklander 
7632b31808SJens Wiklander     ctx->md_type = MBEDTLS_MD_NONE;
77817466cbSJens Wiklander     mbedtls_ecp_group_free(&ctx->grp);
78817466cbSJens Wiklander 
79817466cbSJens Wiklander     mbedtls_ecp_point_free(&ctx->Xm1);
80817466cbSJens Wiklander     mbedtls_ecp_point_free(&ctx->Xm2);
81817466cbSJens Wiklander     mbedtls_ecp_point_free(&ctx->Xp1);
82817466cbSJens Wiklander     mbedtls_ecp_point_free(&ctx->Xp2);
83817466cbSJens Wiklander     mbedtls_ecp_point_free(&ctx->Xp);
84817466cbSJens Wiklander 
85817466cbSJens Wiklander     mbedtls_mpi_free(&ctx->xm1);
86817466cbSJens Wiklander     mbedtls_mpi_free(&ctx->xm2);
87817466cbSJens Wiklander     mbedtls_mpi_free(&ctx->s);
88817466cbSJens Wiklander }
89817466cbSJens Wiklander 
90817466cbSJens Wiklander /*
91817466cbSJens Wiklander  * Setup context
92817466cbSJens Wiklander  */
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)93817466cbSJens Wiklander int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx,
94817466cbSJens Wiklander                           mbedtls_ecjpake_role role,
95817466cbSJens Wiklander                           mbedtls_md_type_t hash,
96817466cbSJens Wiklander                           mbedtls_ecp_group_id curve,
97817466cbSJens Wiklander                           const unsigned char *secret,
98817466cbSJens Wiklander                           size_t len)
99817466cbSJens Wiklander {
10011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
101817466cbSJens Wiklander 
10232b31808SJens Wiklander     if (role != MBEDTLS_ECJPAKE_CLIENT && role != MBEDTLS_ECJPAKE_SERVER) {
10332b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
10432b31808SJens Wiklander     }
1053d3b0591SJens Wiklander 
106817466cbSJens Wiklander     ctx->role = role;
107817466cbSJens Wiklander 
10832b31808SJens Wiklander     if ((mbedtls_md_info_from_type(hash)) == NULL) {
10932b31808SJens Wiklander         return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
11032b31808SJens Wiklander     }
11132b31808SJens Wiklander 
11232b31808SJens Wiklander     ctx->md_type = hash;
113817466cbSJens Wiklander 
114817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
115817466cbSJens Wiklander 
116817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
117817466cbSJens Wiklander 
118817466cbSJens Wiklander cleanup:
11932b31808SJens Wiklander     if (ret != 0) {
120817466cbSJens Wiklander         mbedtls_ecjpake_free(ctx);
12132b31808SJens Wiklander     }
122817466cbSJens Wiklander 
12332b31808SJens Wiklander     return ret;
12432b31808SJens Wiklander }
12532b31808SJens Wiklander 
mbedtls_ecjpake_set_point_format(mbedtls_ecjpake_context * ctx,int point_format)12632b31808SJens Wiklander int mbedtls_ecjpake_set_point_format(mbedtls_ecjpake_context *ctx,
12732b31808SJens Wiklander                                      int point_format)
12832b31808SJens Wiklander {
12932b31808SJens Wiklander     switch (point_format) {
13032b31808SJens Wiklander         case MBEDTLS_ECP_PF_UNCOMPRESSED:
13132b31808SJens Wiklander         case MBEDTLS_ECP_PF_COMPRESSED:
13232b31808SJens Wiklander             ctx->point_format = point_format;
13332b31808SJens Wiklander             return 0;
13432b31808SJens Wiklander         default:
13532b31808SJens Wiklander             return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
13632b31808SJens Wiklander     }
137817466cbSJens Wiklander }
138817466cbSJens Wiklander 
139817466cbSJens Wiklander /*
140817466cbSJens Wiklander  * Check if context is ready for use
141817466cbSJens Wiklander  */
mbedtls_ecjpake_check(const mbedtls_ecjpake_context * ctx)142817466cbSJens Wiklander int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx)
143817466cbSJens Wiklander {
14432b31808SJens Wiklander     if (ctx->md_type == MBEDTLS_MD_NONE ||
145817466cbSJens Wiklander         ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
14632b31808SJens Wiklander         ctx->s.p == NULL) {
14732b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
148817466cbSJens Wiklander     }
149817466cbSJens Wiklander 
15032b31808SJens Wiklander     return 0;
151817466cbSJens Wiklander }
152817466cbSJens Wiklander 
153817466cbSJens Wiklander /*
154817466cbSJens Wiklander  * Write a point plus its length to a buffer
155817466cbSJens Wiklander  */
ecjpake_write_len_point(unsigned char ** p,const unsigned char * end,const mbedtls_ecp_group * grp,const int pf,const mbedtls_ecp_point * P)156817466cbSJens Wiklander static int ecjpake_write_len_point(unsigned char **p,
157817466cbSJens Wiklander                                    const unsigned char *end,
158817466cbSJens Wiklander                                    const mbedtls_ecp_group *grp,
159817466cbSJens Wiklander                                    const int pf,
160817466cbSJens Wiklander                                    const mbedtls_ecp_point *P)
161817466cbSJens Wiklander {
16211fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
163817466cbSJens Wiklander     size_t len;
164817466cbSJens Wiklander 
165817466cbSJens Wiklander     /* Need at least 4 for length plus 1 for point */
16632b31808SJens Wiklander     if (end < *p || end - *p < 5) {
16732b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
16832b31808SJens Wiklander     }
169817466cbSJens Wiklander 
170817466cbSJens Wiklander     ret = mbedtls_ecp_point_write_binary(grp, P, pf,
171*b0563631STom Van Eyck                                          &len, *p + 4, (size_t) (end - (*p + 4)));
17232b31808SJens Wiklander     if (ret != 0) {
17332b31808SJens Wiklander         return ret;
17432b31808SJens Wiklander     }
175817466cbSJens Wiklander 
176039e02dfSJerome Forissier     MBEDTLS_PUT_UINT32_BE(len, *p, 0);
177817466cbSJens Wiklander 
178817466cbSJens Wiklander     *p += 4 + len;
179817466cbSJens Wiklander 
18032b31808SJens Wiklander     return 0;
181817466cbSJens Wiklander }
182817466cbSJens Wiklander 
183817466cbSJens Wiklander /*
184817466cbSJens Wiklander  * Size of the temporary buffer for ecjpake_hash:
185817466cbSJens Wiklander  * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
186817466cbSJens Wiklander  */
187817466cbSJens Wiklander #define ECJPAKE_HASH_BUF_LEN    (3 * (4 + MBEDTLS_ECP_MAX_PT_LEN) + 4 + 6)
188817466cbSJens Wiklander 
189817466cbSJens Wiklander /*
190817466cbSJens Wiklander  * Compute hash for ZKP (7.4.2.2.2.1)
191817466cbSJens Wiklander  */
ecjpake_hash(const mbedtls_md_type_t md_type,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)19232b31808SJens Wiklander static int ecjpake_hash(const mbedtls_md_type_t md_type,
193817466cbSJens Wiklander                         const mbedtls_ecp_group *grp,
194817466cbSJens Wiklander                         const int pf,
195817466cbSJens Wiklander                         const mbedtls_ecp_point *G,
196817466cbSJens Wiklander                         const mbedtls_ecp_point *V,
197817466cbSJens Wiklander                         const mbedtls_ecp_point *X,
198817466cbSJens Wiklander                         const char *id,
199817466cbSJens Wiklander                         mbedtls_mpi *h)
200817466cbSJens Wiklander {
20111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
202817466cbSJens Wiklander     unsigned char buf[ECJPAKE_HASH_BUF_LEN];
203817466cbSJens Wiklander     unsigned char *p = buf;
204817466cbSJens Wiklander     const unsigned char *end = buf + sizeof(buf);
205817466cbSJens Wiklander     const size_t id_len = strlen(id);
206*b0563631STom Van Eyck     unsigned char hash[MBEDTLS_MD_MAX_SIZE];
207817466cbSJens Wiklander 
208817466cbSJens Wiklander     /* Write things to temporary buffer */
209817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, G));
210817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, V));
211817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, X));
212817466cbSJens Wiklander 
21332b31808SJens Wiklander     if (end - p < 4) {
21432b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
21532b31808SJens Wiklander     }
216817466cbSJens Wiklander 
217039e02dfSJerome Forissier     MBEDTLS_PUT_UINT32_BE(id_len, p, 0);
218039e02dfSJerome Forissier     p += 4;
219817466cbSJens Wiklander 
22032b31808SJens Wiklander     if (end < p || (size_t) (end - p) < id_len) {
22132b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
22232b31808SJens Wiklander     }
223817466cbSJens Wiklander 
224817466cbSJens Wiklander     memcpy(p, id, id_len);
225817466cbSJens Wiklander     p += id_len;
226817466cbSJens Wiklander 
227817466cbSJens Wiklander     /* Compute hash */
22832b31808SJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecjpake_compute_hash(md_type,
229*b0563631STom Van Eyck                                                  buf, (size_t) (p - buf), hash));
230817466cbSJens Wiklander 
231817466cbSJens Wiklander     /* Turn it into an integer mod n */
232817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(h, hash,
233*b0563631STom Van Eyck                                             mbedtls_md_get_size_from_type(md_type)));
234817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(h, h, &grp->N));
235817466cbSJens Wiklander 
236817466cbSJens Wiklander cleanup:
23732b31808SJens Wiklander     return ret;
238817466cbSJens Wiklander }
239817466cbSJens Wiklander 
240817466cbSJens Wiklander /*
241817466cbSJens Wiklander  * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
242817466cbSJens Wiklander  */
ecjpake_zkp_read(const mbedtls_md_type_t md_type,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)24332b31808SJens Wiklander static int ecjpake_zkp_read(const mbedtls_md_type_t md_type,
244817466cbSJens Wiklander                             const mbedtls_ecp_group *grp,
245817466cbSJens Wiklander                             const int pf,
246817466cbSJens Wiklander                             const mbedtls_ecp_point *G,
247817466cbSJens Wiklander                             const mbedtls_ecp_point *X,
248817466cbSJens Wiklander                             const char *id,
249817466cbSJens Wiklander                             const unsigned char **p,
250817466cbSJens Wiklander                             const unsigned char *end)
251817466cbSJens Wiklander {
25211fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
253817466cbSJens Wiklander     mbedtls_ecp_point V, VV;
254817466cbSJens Wiklander     mbedtls_mpi r, h;
255817466cbSJens Wiklander     size_t r_len;
256817466cbSJens Wiklander 
257817466cbSJens Wiklander     mbedtls_ecp_point_init(&V);
258817466cbSJens Wiklander     mbedtls_ecp_point_init(&VV);
259817466cbSJens Wiklander     mbedtls_mpi_init(&r);
260817466cbSJens Wiklander     mbedtls_mpi_init(&h);
261817466cbSJens Wiklander 
262817466cbSJens Wiklander     /*
263817466cbSJens Wiklander      * struct {
264817466cbSJens Wiklander      *     ECPoint V;
265817466cbSJens Wiklander      *     opaque r<1..2^8-1>;
266817466cbSJens Wiklander      * } ECSchnorrZKP;
267817466cbSJens Wiklander      */
26832b31808SJens Wiklander     if (end < *p) {
26932b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
27032b31808SJens Wiklander     }
271817466cbSJens Wiklander 
272*b0563631STom Van Eyck     MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, (size_t) (end - *p)));
273817466cbSJens Wiklander 
27432b31808SJens Wiklander     if (end < *p || (size_t) (end - *p) < 1) {
275817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
276817466cbSJens Wiklander         goto cleanup;
277817466cbSJens Wiklander     }
278817466cbSJens Wiklander 
279817466cbSJens Wiklander     r_len = *(*p)++;
280817466cbSJens Wiklander 
28132b31808SJens Wiklander     if (end < *p || (size_t) (end - *p) < r_len || r_len == 0) {
282817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
283817466cbSJens Wiklander         goto cleanup;
284817466cbSJens Wiklander     }
285817466cbSJens Wiklander 
286817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
287817466cbSJens Wiklander     *p += r_len;
288817466cbSJens Wiklander 
289817466cbSJens Wiklander     /*
290817466cbSJens Wiklander      * Verification
291817466cbSJens Wiklander      */
29232b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_hash(md_type, grp, pf, G, &V, X, id, &h));
293817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_muladd((mbedtls_ecp_group *) grp,
294817466cbSJens Wiklander                                        &VV, &h, X, &r, G));
295817466cbSJens Wiklander 
29632b31808SJens Wiklander     if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
297817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
298817466cbSJens Wiklander         goto cleanup;
299817466cbSJens Wiklander     }
300817466cbSJens Wiklander 
301817466cbSJens Wiklander cleanup:
302817466cbSJens Wiklander     mbedtls_ecp_point_free(&V);
303817466cbSJens Wiklander     mbedtls_ecp_point_free(&VV);
304817466cbSJens Wiklander     mbedtls_mpi_free(&r);
305817466cbSJens Wiklander     mbedtls_mpi_free(&h);
306817466cbSJens Wiklander 
30732b31808SJens Wiklander     return ret;
308817466cbSJens Wiklander }
309817466cbSJens Wiklander 
310817466cbSJens Wiklander /*
311817466cbSJens Wiklander  * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
312817466cbSJens Wiklander  */
ecjpake_zkp_write(const mbedtls_md_type_t md_type,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)31332b31808SJens Wiklander static int ecjpake_zkp_write(const mbedtls_md_type_t md_type,
314817466cbSJens Wiklander                              const mbedtls_ecp_group *grp,
315817466cbSJens Wiklander                              const int pf,
316817466cbSJens Wiklander                              const mbedtls_ecp_point *G,
317817466cbSJens Wiklander                              const mbedtls_mpi *x,
318817466cbSJens Wiklander                              const mbedtls_ecp_point *X,
319817466cbSJens Wiklander                              const char *id,
320817466cbSJens Wiklander                              unsigned char **p,
321817466cbSJens Wiklander                              const unsigned char *end,
322817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
323817466cbSJens Wiklander                              void *p_rng)
324817466cbSJens Wiklander {
32511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
326817466cbSJens Wiklander     mbedtls_ecp_point V;
327817466cbSJens Wiklander     mbedtls_mpi v;
328817466cbSJens Wiklander     mbedtls_mpi h; /* later recycled to hold r */
329817466cbSJens Wiklander     size_t len;
330817466cbSJens Wiklander 
33132b31808SJens Wiklander     if (end < *p) {
33232b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
33332b31808SJens Wiklander     }
334817466cbSJens Wiklander 
335817466cbSJens Wiklander     mbedtls_ecp_point_init(&V);
336817466cbSJens Wiklander     mbedtls_mpi_init(&v);
337817466cbSJens Wiklander     mbedtls_mpi_init(&h);
338817466cbSJens Wiklander 
339817466cbSJens Wiklander     /* Compute signature */
340817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp,
341817466cbSJens Wiklander                                                  G, &v, &V, f_rng, p_rng));
34232b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_hash(md_type, grp, pf, G, &V, X, id, &h));
343817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&h, &h, x));     /* x*h */
344817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&h, &v, &h));     /* v - x*h */
345817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&h, &h, &grp->N));     /* r */
346817466cbSJens Wiklander 
347817466cbSJens Wiklander     /* Write it out */
348817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
349*b0563631STom Van Eyck                                                 pf, &len, *p, (size_t) (end - *p)));
350817466cbSJens Wiklander     *p += len;
351817466cbSJens Wiklander 
352817466cbSJens Wiklander     len = mbedtls_mpi_size(&h);   /* actually r */
35332b31808SJens Wiklander     if (end < *p || (size_t) (end - *p) < 1 + len || len > 255) {
354817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
355817466cbSJens Wiklander         goto cleanup;
356817466cbSJens Wiklander     }
357817466cbSJens Wiklander 
358039e02dfSJerome Forissier     *(*p)++ = MBEDTLS_BYTE_0(len);
359817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len));     /* r */
360817466cbSJens Wiklander     *p += len;
361817466cbSJens Wiklander 
362817466cbSJens Wiklander cleanup:
363817466cbSJens Wiklander     mbedtls_ecp_point_free(&V);
364817466cbSJens Wiklander     mbedtls_mpi_free(&v);
365817466cbSJens Wiklander     mbedtls_mpi_free(&h);
366817466cbSJens Wiklander 
36732b31808SJens Wiklander     return ret;
368817466cbSJens Wiklander }
369817466cbSJens Wiklander 
370817466cbSJens Wiklander /*
371817466cbSJens Wiklander  * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
372817466cbSJens Wiklander  * Output: verified public key X
373817466cbSJens Wiklander  */
ecjpake_kkp_read(const mbedtls_md_type_t md_type,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)37432b31808SJens Wiklander static int ecjpake_kkp_read(const mbedtls_md_type_t md_type,
375817466cbSJens Wiklander                             const mbedtls_ecp_group *grp,
376817466cbSJens Wiklander                             const int pf,
377817466cbSJens Wiklander                             const mbedtls_ecp_point *G,
378817466cbSJens Wiklander                             mbedtls_ecp_point *X,
379817466cbSJens Wiklander                             const char *id,
380817466cbSJens Wiklander                             const unsigned char **p,
381817466cbSJens Wiklander                             const unsigned char *end)
382817466cbSJens Wiklander {
38311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
384817466cbSJens Wiklander 
38532b31808SJens Wiklander     if (end < *p) {
38632b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
38732b31808SJens Wiklander     }
388817466cbSJens Wiklander 
389817466cbSJens Wiklander     /*
390817466cbSJens Wiklander      * struct {
391817466cbSJens Wiklander      *     ECPoint X;
392817466cbSJens Wiklander      *     ECSchnorrZKP zkp;
393817466cbSJens Wiklander      * } ECJPAKEKeyKP;
394817466cbSJens Wiklander      */
395*b0563631STom Van Eyck     MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, (size_t) (end - *p)));
39632b31808SJens Wiklander     if (mbedtls_ecp_is_zero(X)) {
397817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_INVALID_KEY;
398817466cbSJens Wiklander         goto cleanup;
399817466cbSJens Wiklander     }
400817466cbSJens Wiklander 
40132b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_type, grp, pf, G, X, id, p, end));
402817466cbSJens Wiklander 
403817466cbSJens Wiklander cleanup:
40432b31808SJens Wiklander     return ret;
405817466cbSJens Wiklander }
406817466cbSJens Wiklander 
407817466cbSJens Wiklander /*
408817466cbSJens Wiklander  * Generate an ECJPAKEKeyKP
409817466cbSJens Wiklander  * Output: the serialized structure, plus private/public key pair
410817466cbSJens Wiklander  */
ecjpake_kkp_write(const mbedtls_md_type_t md_type,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)41132b31808SJens Wiklander static int ecjpake_kkp_write(const mbedtls_md_type_t md_type,
412817466cbSJens Wiklander                              const mbedtls_ecp_group *grp,
413817466cbSJens Wiklander                              const int pf,
414817466cbSJens Wiklander                              const mbedtls_ecp_point *G,
415817466cbSJens Wiklander                              mbedtls_mpi *x,
416817466cbSJens Wiklander                              mbedtls_ecp_point *X,
417817466cbSJens Wiklander                              const char *id,
418817466cbSJens Wiklander                              unsigned char **p,
419817466cbSJens Wiklander                              const unsigned char *end,
420817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
421817466cbSJens Wiklander                              void *p_rng)
422817466cbSJens Wiklander {
42311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
424817466cbSJens Wiklander     size_t len;
425817466cbSJens Wiklander 
42632b31808SJens Wiklander     if (end < *p) {
42732b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
42832b31808SJens Wiklander     }
429817466cbSJens Wiklander 
430817466cbSJens Wiklander     /* Generate key (7.4.2.3.1) and write it out */
431817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, G, x, X,
432817466cbSJens Wiklander                                                  f_rng, p_rng));
433817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, X,
434*b0563631STom Van Eyck                                                 pf, &len, *p, (size_t) (end - *p)));
435817466cbSJens Wiklander     *p += len;
436817466cbSJens Wiklander 
437817466cbSJens Wiklander     /* Generate and write proof */
43832b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_type, grp, pf, G, x, X, id,
439817466cbSJens Wiklander                                       p, end, f_rng, p_rng));
440817466cbSJens Wiklander 
441817466cbSJens Wiklander cleanup:
44232b31808SJens Wiklander     return ret;
443817466cbSJens Wiklander }
444817466cbSJens Wiklander 
445817466cbSJens Wiklander /*
446817466cbSJens Wiklander  * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
447039e02dfSJerome Forissier  * Outputs: verified peer public keys Xa, Xb
448817466cbSJens Wiklander  */
ecjpake_kkpp_read(const mbedtls_md_type_t md_type,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)44932b31808SJens Wiklander static int ecjpake_kkpp_read(const mbedtls_md_type_t md_type,
450817466cbSJens Wiklander                              const mbedtls_ecp_group *grp,
451817466cbSJens Wiklander                              const int pf,
452817466cbSJens Wiklander                              const mbedtls_ecp_point *G,
453817466cbSJens Wiklander                              mbedtls_ecp_point *Xa,
454817466cbSJens Wiklander                              mbedtls_ecp_point *Xb,
455817466cbSJens Wiklander                              const char *id,
456817466cbSJens Wiklander                              const unsigned char *buf,
457817466cbSJens Wiklander                              size_t len)
458817466cbSJens Wiklander {
45911fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
460817466cbSJens Wiklander     const unsigned char *p = buf;
461817466cbSJens Wiklander     const unsigned char *end = buf + len;
462817466cbSJens Wiklander 
463817466cbSJens Wiklander     /*
464817466cbSJens Wiklander      * struct {
465817466cbSJens Wiklander      *     ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
466817466cbSJens Wiklander      * } ECJPAKEKeyKPPairList;
467817466cbSJens Wiklander      */
46832b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_type, grp, pf, G, Xa, id, &p, end));
46932b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_type, grp, pf, G, Xb, id, &p, end));
470817466cbSJens Wiklander 
47132b31808SJens Wiklander     if (p != end) {
472817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
47332b31808SJens Wiklander     }
474817466cbSJens Wiklander 
475817466cbSJens Wiklander cleanup:
47632b31808SJens Wiklander     return ret;
477817466cbSJens Wiklander }
478817466cbSJens Wiklander 
479817466cbSJens Wiklander /*
480817466cbSJens Wiklander  * Generate a ECJPAKEKeyKPPairList
481817466cbSJens Wiklander  * Outputs: the serialized structure, plus two private/public key pairs
482817466cbSJens Wiklander  */
ecjpake_kkpp_write(const mbedtls_md_type_t md_type,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)48332b31808SJens Wiklander static int ecjpake_kkpp_write(const mbedtls_md_type_t md_type,
484817466cbSJens Wiklander                               const mbedtls_ecp_group *grp,
485817466cbSJens Wiklander                               const int pf,
486817466cbSJens Wiklander                               const mbedtls_ecp_point *G,
487817466cbSJens Wiklander                               mbedtls_mpi *xm1,
488817466cbSJens Wiklander                               mbedtls_ecp_point *Xa,
489817466cbSJens Wiklander                               mbedtls_mpi *xm2,
490817466cbSJens Wiklander                               mbedtls_ecp_point *Xb,
491817466cbSJens Wiklander                               const char *id,
492817466cbSJens Wiklander                               unsigned char *buf,
493817466cbSJens Wiklander                               size_t len,
494817466cbSJens Wiklander                               size_t *olen,
495817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
496817466cbSJens Wiklander                               void *p_rng)
497817466cbSJens Wiklander {
49811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
499817466cbSJens Wiklander     unsigned char *p = buf;
500817466cbSJens Wiklander     const unsigned char *end = buf + len;
501817466cbSJens Wiklander 
50232b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_type, grp, pf, G, xm1, Xa, id,
503817466cbSJens Wiklander                                       &p, end, f_rng, p_rng));
50432b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_type, grp, pf, G, xm2, Xb, id,
505817466cbSJens Wiklander                                       &p, end, f_rng, p_rng));
506817466cbSJens Wiklander 
507*b0563631STom Van Eyck     *olen = (size_t) (p - buf);
508817466cbSJens Wiklander 
509817466cbSJens Wiklander cleanup:
51032b31808SJens Wiklander     return ret;
511817466cbSJens Wiklander }
512817466cbSJens Wiklander 
513817466cbSJens Wiklander /*
514817466cbSJens Wiklander  * Read and process the first round message
515817466cbSJens Wiklander  */
mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context * ctx,const unsigned char * buf,size_t len)516817466cbSJens Wiklander int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
517817466cbSJens Wiklander                                    const unsigned char *buf,
518817466cbSJens Wiklander                                    size_t len)
519817466cbSJens Wiklander {
52032b31808SJens Wiklander     return ecjpake_kkpp_read(ctx->md_type, &ctx->grp, ctx->point_format,
521817466cbSJens Wiklander                              &ctx->grp.G,
522817466cbSJens Wiklander                              &ctx->Xp1, &ctx->Xp2, ID_PEER,
52332b31808SJens Wiklander                              buf, len);
524817466cbSJens Wiklander }
525817466cbSJens Wiklander 
526817466cbSJens Wiklander /*
527817466cbSJens Wiklander  * Generate and write the first round message
528817466cbSJens Wiklander  */
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)529817466cbSJens Wiklander int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx,
530817466cbSJens Wiklander                                     unsigned char *buf, size_t len, size_t *olen,
531817466cbSJens Wiklander                                     int (*f_rng)(void *, unsigned char *, size_t),
532817466cbSJens Wiklander                                     void *p_rng)
533817466cbSJens Wiklander {
53432b31808SJens Wiklander     return ecjpake_kkpp_write(ctx->md_type, &ctx->grp, ctx->point_format,
535817466cbSJens Wiklander                               &ctx->grp.G,
536817466cbSJens Wiklander                               &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
53732b31808SJens Wiklander                               ID_MINE, buf, len, olen, f_rng, p_rng);
538817466cbSJens Wiklander }
539817466cbSJens Wiklander 
540817466cbSJens Wiklander /*
541817466cbSJens Wiklander  * Compute the sum of three points R = A + B + C
542817466cbSJens Wiklander  */
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)543817466cbSJens Wiklander static int ecjpake_ecp_add3(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
544817466cbSJens Wiklander                             const mbedtls_ecp_point *A,
545817466cbSJens Wiklander                             const mbedtls_ecp_point *B,
546817466cbSJens Wiklander                             const mbedtls_ecp_point *C)
547817466cbSJens Wiklander {
54811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
549817466cbSJens Wiklander     mbedtls_mpi one;
550817466cbSJens Wiklander 
551817466cbSJens Wiklander     mbedtls_mpi_init(&one);
552817466cbSJens Wiklander 
553817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
554817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, A, &one, B));
555817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, R, &one, C));
556817466cbSJens Wiklander 
557817466cbSJens Wiklander cleanup:
558817466cbSJens Wiklander     mbedtls_mpi_free(&one);
559817466cbSJens Wiklander 
56032b31808SJens Wiklander     return ret;
561817466cbSJens Wiklander }
562817466cbSJens Wiklander 
563817466cbSJens Wiklander /*
564817466cbSJens Wiklander  * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
565817466cbSJens Wiklander  */
mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context * ctx,const unsigned char * buf,size_t len)566817466cbSJens Wiklander int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
567817466cbSJens Wiklander                                    const unsigned char *buf,
568817466cbSJens Wiklander                                    size_t len)
569817466cbSJens Wiklander {
57011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
571817466cbSJens Wiklander     const unsigned char *p = buf;
572817466cbSJens Wiklander     const unsigned char *end = buf + len;
573817466cbSJens Wiklander     mbedtls_ecp_group grp;
574817466cbSJens Wiklander     mbedtls_ecp_point G;    /* C: GB, S: GA */
575817466cbSJens Wiklander 
576817466cbSJens Wiklander     mbedtls_ecp_group_init(&grp);
577817466cbSJens Wiklander     mbedtls_ecp_point_init(&G);
578817466cbSJens Wiklander 
579817466cbSJens Wiklander     /*
580817466cbSJens Wiklander      * Server: GA = X3  + X4  + X1      (7.4.2.6.1)
581817466cbSJens Wiklander      * Client: GB = X1  + X2  + X3      (7.4.2.5.1)
582817466cbSJens Wiklander      * Unified: G = Xm1 + Xm2 + Xp1
583817466cbSJens Wiklander      * We need that before parsing in order to check Xp as we read it
584817466cbSJens Wiklander      */
585817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
586817466cbSJens Wiklander                                      &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
587817466cbSJens Wiklander 
588817466cbSJens Wiklander     /*
589817466cbSJens Wiklander      * struct {
590817466cbSJens Wiklander      *     ECParameters curve_params;   // only client reading server msg
591817466cbSJens Wiklander      *     ECJPAKEKeyKP ecjpake_key_kp;
592817466cbSJens Wiklander      * } Client/ServerECJPAKEParams;
593817466cbSJens Wiklander      */
59432b31808SJens Wiklander     if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) {
595817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_group(&grp, &p, len));
59632b31808SJens Wiklander         if (grp.id != ctx->grp.id) {
597817466cbSJens Wiklander             ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
598817466cbSJens Wiklander             goto cleanup;
599817466cbSJens Wiklander         }
600817466cbSJens Wiklander     }
601817466cbSJens Wiklander 
60232b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_type, &ctx->grp,
603817466cbSJens Wiklander                                      ctx->point_format,
604817466cbSJens Wiklander                                      &G, &ctx->Xp, ID_PEER, &p, end));
605817466cbSJens Wiklander 
60632b31808SJens Wiklander     if (p != end) {
607817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
608817466cbSJens Wiklander         goto cleanup;
609817466cbSJens Wiklander     }
610817466cbSJens Wiklander 
611817466cbSJens Wiklander cleanup:
612817466cbSJens Wiklander     mbedtls_ecp_group_free(&grp);
613817466cbSJens Wiklander     mbedtls_ecp_point_free(&G);
614817466cbSJens Wiklander 
61532b31808SJens Wiklander     return ret;
616817466cbSJens Wiklander }
617817466cbSJens Wiklander 
618817466cbSJens Wiklander /*
619817466cbSJens Wiklander  * Compute R = +/- X * S mod N, taking care not to leak S
620817466cbSJens Wiklander  */
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)621817466cbSJens Wiklander static int ecjpake_mul_secret(mbedtls_mpi *R, int sign,
622817466cbSJens Wiklander                               const mbedtls_mpi *X,
623817466cbSJens Wiklander                               const mbedtls_mpi *S,
624817466cbSJens Wiklander                               const mbedtls_mpi *N,
625817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
626817466cbSJens Wiklander                               void *p_rng)
627817466cbSJens Wiklander {
62811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
629817466cbSJens Wiklander     mbedtls_mpi b; /* Blinding value, then s + N * blinding */
630817466cbSJens Wiklander 
631817466cbSJens Wiklander     mbedtls_mpi_init(&b);
632817466cbSJens Wiklander 
633817466cbSJens Wiklander     /* b = s + rnd-128-bit * N */
634817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&b, 16, f_rng, p_rng));
635817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&b, &b, N));
636817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&b, &b, S));
637817466cbSJens Wiklander 
638817466cbSJens Wiklander     /* R = sign * X * b mod N */
639817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
640817466cbSJens Wiklander     R->s *= sign;
641817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
642817466cbSJens Wiklander 
643817466cbSJens Wiklander cleanup:
644817466cbSJens Wiklander     mbedtls_mpi_free(&b);
645817466cbSJens Wiklander 
64632b31808SJens Wiklander     return ret;
647817466cbSJens Wiklander }
648817466cbSJens Wiklander 
649817466cbSJens Wiklander /*
650817466cbSJens Wiklander  * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
651817466cbSJens Wiklander  */
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)652817466cbSJens Wiklander int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx,
653817466cbSJens Wiklander                                     unsigned char *buf, size_t len, size_t *olen,
654817466cbSJens Wiklander                                     int (*f_rng)(void *, unsigned char *, size_t),
655817466cbSJens Wiklander                                     void *p_rng)
656817466cbSJens Wiklander {
65711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
658817466cbSJens Wiklander     mbedtls_ecp_point G;    /* C: GA, S: GB */
659817466cbSJens Wiklander     mbedtls_ecp_point Xm;   /* C: Xc, S: Xs */
660817466cbSJens Wiklander     mbedtls_mpi xm;         /* C: xc, S: xs */
661817466cbSJens Wiklander     unsigned char *p = buf;
662817466cbSJens Wiklander     const unsigned char *end = buf + len;
663817466cbSJens Wiklander     size_t ec_len;
664817466cbSJens Wiklander 
665817466cbSJens Wiklander     mbedtls_ecp_point_init(&G);
666817466cbSJens Wiklander     mbedtls_ecp_point_init(&Xm);
667817466cbSJens Wiklander     mbedtls_mpi_init(&xm);
668817466cbSJens Wiklander 
669817466cbSJens Wiklander     /*
670817466cbSJens Wiklander      * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
671817466cbSJens Wiklander      *
672817466cbSJens Wiklander      * Client:  GA = X1  + X3  + X4  | xs = x2  * s | Xc = xc * GA
673817466cbSJens Wiklander      * Server:  GB = X3  + X1  + X2  | xs = x4  * s | Xs = xs * GB
674817466cbSJens Wiklander      * Unified: G  = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
675817466cbSJens Wiklander      */
676817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
677817466cbSJens Wiklander                                      &ctx->Xp1, &ctx->Xp2, &ctx->Xm1));
678817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_mul_secret(&xm, 1, &ctx->xm2, &ctx->s,
679817466cbSJens Wiklander                                        &ctx->grp.N, f_rng, p_rng));
680817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &Xm, &xm, &G, f_rng, p_rng));
681817466cbSJens Wiklander 
682817466cbSJens Wiklander     /*
683817466cbSJens Wiklander      * Now write things out
684817466cbSJens Wiklander      *
685817466cbSJens Wiklander      * struct {
686817466cbSJens Wiklander      *     ECParameters curve_params;   // only server writing its message
687817466cbSJens Wiklander      *     ECJPAKEKeyKP ecjpake_key_kp;
688817466cbSJens Wiklander      * } Client/ServerECJPAKEParams;
689817466cbSJens Wiklander      */
69032b31808SJens Wiklander     if (ctx->role == MBEDTLS_ECJPAKE_SERVER) {
69132b31808SJens Wiklander         if (end < p) {
692817466cbSJens Wiklander             ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
693817466cbSJens Wiklander             goto cleanup;
694817466cbSJens Wiklander         }
695817466cbSJens Wiklander         MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len,
696*b0563631STom Van Eyck                                                     p, (size_t) (end - p)));
697817466cbSJens Wiklander         p += ec_len;
698817466cbSJens Wiklander     }
699817466cbSJens Wiklander 
70032b31808SJens Wiklander     if (end < p) {
701817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
702817466cbSJens Wiklander         goto cleanup;
703817466cbSJens Wiklander     }
704817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm,
705*b0563631STom Van Eyck                                                 ctx->point_format, &ec_len, p, (size_t) (end - p)));
706817466cbSJens Wiklander     p += ec_len;
707817466cbSJens Wiklander 
70832b31808SJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_zkp_write(ctx->md_type, &ctx->grp,
709817466cbSJens Wiklander                                       ctx->point_format,
710817466cbSJens Wiklander                                       &G, &xm, &Xm, ID_MINE,
711817466cbSJens Wiklander                                       &p, end, f_rng, p_rng));
712817466cbSJens Wiklander 
713*b0563631STom Van Eyck     *olen = (size_t) (p - buf);
714817466cbSJens Wiklander 
715817466cbSJens Wiklander cleanup:
716817466cbSJens Wiklander     mbedtls_ecp_point_free(&G);
717817466cbSJens Wiklander     mbedtls_ecp_point_free(&Xm);
718817466cbSJens Wiklander     mbedtls_mpi_free(&xm);
719817466cbSJens Wiklander 
72032b31808SJens Wiklander     return ret;
721817466cbSJens Wiklander }
722817466cbSJens Wiklander 
723817466cbSJens Wiklander /*
724817466cbSJens Wiklander  * Derive PMS (7.4.2.7 / 7.4.2.8)
725817466cbSJens Wiklander  */
mbedtls_ecjpake_derive_k(mbedtls_ecjpake_context * ctx,mbedtls_ecp_point * K,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)72632b31808SJens Wiklander static int mbedtls_ecjpake_derive_k(mbedtls_ecjpake_context *ctx,
72732b31808SJens Wiklander                                     mbedtls_ecp_point *K,
728817466cbSJens Wiklander                                     int (*f_rng)(void *, unsigned char *, size_t),
729817466cbSJens Wiklander                                     void *p_rng)
730817466cbSJens Wiklander {
73111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
732817466cbSJens Wiklander     mbedtls_mpi m_xm2_s, one;
733817466cbSJens Wiklander 
734817466cbSJens Wiklander     mbedtls_mpi_init(&m_xm2_s);
735817466cbSJens Wiklander     mbedtls_mpi_init(&one);
736817466cbSJens Wiklander 
737817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
738817466cbSJens Wiklander 
739817466cbSJens Wiklander     /*
740817466cbSJens Wiklander      * Client:  K = ( Xs - X4  * x2  * s ) * x2
741817466cbSJens Wiklander      * Server:  K = ( Xc - X2  * x4  * s ) * x4
742817466cbSJens Wiklander      * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
743817466cbSJens Wiklander      */
744817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_mul_secret(&m_xm2_s, -1, &ctx->xm2, &ctx->s,
745817466cbSJens Wiklander                                        &ctx->grp.N, f_rng, p_rng));
74632b31808SJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&ctx->grp, K,
747817466cbSJens Wiklander                                        &one, &ctx->Xp,
748817466cbSJens Wiklander                                        &m_xm2_s, &ctx->Xp2));
74932b31808SJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, K, &ctx->xm2, K,
750817466cbSJens Wiklander                                     f_rng, p_rng));
751817466cbSJens Wiklander 
75232b31808SJens Wiklander cleanup:
75332b31808SJens Wiklander     mbedtls_mpi_free(&m_xm2_s);
75432b31808SJens Wiklander     mbedtls_mpi_free(&one);
75532b31808SJens Wiklander 
75632b31808SJens Wiklander     return ret;
75732b31808SJens Wiklander }
75832b31808SJens Wiklander 
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)75932b31808SJens Wiklander int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx,
76032b31808SJens Wiklander                                   unsigned char *buf, size_t len, size_t *olen,
76132b31808SJens Wiklander                                   int (*f_rng)(void *, unsigned char *, size_t),
76232b31808SJens Wiklander                                   void *p_rng)
76332b31808SJens Wiklander {
76432b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
76532b31808SJens Wiklander     mbedtls_ecp_point K;
76632b31808SJens Wiklander     unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
76732b31808SJens Wiklander     size_t x_bytes;
76832b31808SJens Wiklander 
769*b0563631STom Van Eyck     *olen = mbedtls_md_get_size_from_type(ctx->md_type);
77032b31808SJens Wiklander     if (len < *olen) {
77132b31808SJens Wiklander         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
77232b31808SJens Wiklander     }
77332b31808SJens Wiklander 
77432b31808SJens Wiklander     mbedtls_ecp_point_init(&K);
77532b31808SJens Wiklander 
77632b31808SJens Wiklander     ret = mbedtls_ecjpake_derive_k(ctx, &K, f_rng, p_rng);
77732b31808SJens Wiklander     if (ret) {
77832b31808SJens Wiklander         goto cleanup;
77932b31808SJens Wiklander     }
78032b31808SJens Wiklander 
781817466cbSJens Wiklander     /* PMS = SHA-256( K.X ) */
782817466cbSJens Wiklander     x_bytes = (ctx->grp.pbits + 7) / 8;
783817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K.X, kx, x_bytes));
78432b31808SJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecjpake_compute_hash(ctx->md_type,
78532b31808SJens Wiklander                                                  kx, x_bytes, buf));
786817466cbSJens Wiklander 
787817466cbSJens Wiklander cleanup:
788817466cbSJens Wiklander     mbedtls_ecp_point_free(&K);
789817466cbSJens Wiklander 
79032b31808SJens Wiklander     return ret;
79132b31808SJens Wiklander }
79232b31808SJens Wiklander 
mbedtls_ecjpake_write_shared_key(mbedtls_ecjpake_context * ctx,unsigned char * buf,size_t len,size_t * olen,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)79332b31808SJens Wiklander int mbedtls_ecjpake_write_shared_key(mbedtls_ecjpake_context *ctx,
79432b31808SJens Wiklander                                      unsigned char *buf, size_t len, size_t *olen,
79532b31808SJens Wiklander                                      int (*f_rng)(void *, unsigned char *, size_t),
79632b31808SJens Wiklander                                      void *p_rng)
79732b31808SJens Wiklander {
79832b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
79932b31808SJens Wiklander     mbedtls_ecp_point K;
80032b31808SJens Wiklander 
80132b31808SJens Wiklander     mbedtls_ecp_point_init(&K);
80232b31808SJens Wiklander 
80332b31808SJens Wiklander     ret = mbedtls_ecjpake_derive_k(ctx, &K, f_rng, p_rng);
80432b31808SJens Wiklander     if (ret) {
80532b31808SJens Wiklander         goto cleanup;
80632b31808SJens Wiklander     }
80732b31808SJens Wiklander 
80832b31808SJens Wiklander     ret = mbedtls_ecp_point_write_binary(&ctx->grp, &K, ctx->point_format,
80932b31808SJens Wiklander                                          olen, buf, len);
81032b31808SJens Wiklander     if (ret != 0) {
81132b31808SJens Wiklander         goto cleanup;
81232b31808SJens Wiklander     }
81332b31808SJens Wiklander 
81432b31808SJens Wiklander cleanup:
81532b31808SJens Wiklander     mbedtls_ecp_point_free(&K);
81632b31808SJens Wiklander 
81732b31808SJens Wiklander     return ret;
818817466cbSJens Wiklander }
819817466cbSJens Wiklander 
820817466cbSJens Wiklander #undef ID_MINE
821817466cbSJens Wiklander #undef ID_PEER
822817466cbSJens Wiklander 
8233d3b0591SJens Wiklander #endif /* ! MBEDTLS_ECJPAKE_ALT */
824817466cbSJens Wiklander 
825817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
826817466cbSJens Wiklander 
827817466cbSJens Wiklander #include "mbedtls/platform.h"
828817466cbSJens Wiklander 
829817466cbSJens Wiklander #if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
830*b0563631STom Van Eyck     !defined(MBEDTLS_MD_CAN_SHA256)
mbedtls_ecjpake_self_test(int verbose)831817466cbSJens Wiklander int mbedtls_ecjpake_self_test(int verbose)
832817466cbSJens Wiklander {
833817466cbSJens Wiklander     (void) verbose;
83432b31808SJens Wiklander     return 0;
835817466cbSJens Wiklander }
836817466cbSJens Wiklander #else
837817466cbSJens Wiklander 
838817466cbSJens Wiklander static const unsigned char ecjpake_test_password[] = {
839817466cbSJens Wiklander     0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
840817466cbSJens Wiklander     0x65, 0x73, 0x74
841817466cbSJens Wiklander };
842817466cbSJens Wiklander 
8437901324dSJerome Forissier #if !defined(MBEDTLS_ECJPAKE_ALT)
8447901324dSJerome Forissier 
845817466cbSJens Wiklander static const unsigned char ecjpake_test_x1[] = {
846817466cbSJens Wiklander     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
847817466cbSJens Wiklander     0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
848817466cbSJens Wiklander     0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
849817466cbSJens Wiklander };
850817466cbSJens Wiklander 
851817466cbSJens Wiklander static const unsigned char ecjpake_test_x2[] = {
852817466cbSJens Wiklander     0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
853817466cbSJens Wiklander     0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
854817466cbSJens Wiklander     0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
855817466cbSJens Wiklander };
856817466cbSJens Wiklander 
857817466cbSJens Wiklander static const unsigned char ecjpake_test_x3[] = {
858817466cbSJens Wiklander     0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
859817466cbSJens Wiklander     0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
860817466cbSJens Wiklander     0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
861817466cbSJens Wiklander };
862817466cbSJens Wiklander 
863817466cbSJens Wiklander static const unsigned char ecjpake_test_x4[] = {
864817466cbSJens Wiklander     0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
865817466cbSJens Wiklander     0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
866817466cbSJens Wiklander     0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
867817466cbSJens Wiklander };
868817466cbSJens Wiklander 
869817466cbSJens Wiklander static const unsigned char ecjpake_test_cli_one[] = {
870817466cbSJens Wiklander     0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
871817466cbSJens Wiklander     0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
872817466cbSJens Wiklander     0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
873817466cbSJens Wiklander     0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
874817466cbSJens Wiklander     0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
875817466cbSJens Wiklander     0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
876817466cbSJens Wiklander     0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
877817466cbSJens Wiklander     0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
878817466cbSJens Wiklander     0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
879817466cbSJens Wiklander     0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
880817466cbSJens Wiklander     0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
881817466cbSJens Wiklander     0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
882817466cbSJens Wiklander     0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
883817466cbSJens Wiklander     0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
884817466cbSJens Wiklander     0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
885817466cbSJens Wiklander     0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
886817466cbSJens Wiklander     0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
887817466cbSJens Wiklander     0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
888817466cbSJens Wiklander     0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
889817466cbSJens Wiklander     0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
890817466cbSJens Wiklander     0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
891817466cbSJens Wiklander     0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
892817466cbSJens Wiklander     0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
893817466cbSJens Wiklander     0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
894817466cbSJens Wiklander     0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
895817466cbSJens Wiklander     0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
896817466cbSJens Wiklander     0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
897817466cbSJens Wiklander     0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
898817466cbSJens Wiklander };
899817466cbSJens Wiklander 
900817466cbSJens Wiklander static const unsigned char ecjpake_test_srv_one[] = {
901817466cbSJens Wiklander     0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
902817466cbSJens Wiklander     0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
903817466cbSJens Wiklander     0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
904817466cbSJens Wiklander     0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
905817466cbSJens Wiklander     0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
906817466cbSJens Wiklander     0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
907817466cbSJens Wiklander     0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
908817466cbSJens Wiklander     0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
909817466cbSJens Wiklander     0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
910817466cbSJens Wiklander     0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
911817466cbSJens Wiklander     0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
912817466cbSJens Wiklander     0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
913817466cbSJens Wiklander     0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
914817466cbSJens Wiklander     0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
915817466cbSJens Wiklander     0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
916817466cbSJens Wiklander     0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
917817466cbSJens Wiklander     0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
918817466cbSJens Wiklander     0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
919817466cbSJens Wiklander     0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
920817466cbSJens Wiklander     0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
921817466cbSJens Wiklander     0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
922817466cbSJens Wiklander     0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
923817466cbSJens Wiklander     0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
924817466cbSJens Wiklander     0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
925817466cbSJens Wiklander     0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
926817466cbSJens Wiklander     0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
927817466cbSJens Wiklander     0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
928817466cbSJens Wiklander     0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
929817466cbSJens Wiklander };
930817466cbSJens Wiklander 
931817466cbSJens Wiklander static const unsigned char ecjpake_test_srv_two[] = {
932817466cbSJens Wiklander     0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
933817466cbSJens Wiklander     0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
934817466cbSJens Wiklander     0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
935817466cbSJens Wiklander     0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
936817466cbSJens Wiklander     0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
937817466cbSJens Wiklander     0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
938817466cbSJens Wiklander     0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
939817466cbSJens Wiklander     0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
940817466cbSJens Wiklander     0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
941817466cbSJens Wiklander     0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
942817466cbSJens Wiklander     0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
943817466cbSJens Wiklander     0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
944817466cbSJens Wiklander     0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
945817466cbSJens Wiklander     0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
946817466cbSJens Wiklander };
947817466cbSJens Wiklander 
948817466cbSJens Wiklander static const unsigned char ecjpake_test_cli_two[] = {
949817466cbSJens Wiklander     0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
950817466cbSJens Wiklander     0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
951817466cbSJens Wiklander     0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
952817466cbSJens Wiklander     0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
953817466cbSJens Wiklander     0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
954817466cbSJens Wiklander     0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
955817466cbSJens Wiklander     0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
956817466cbSJens Wiklander     0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
957817466cbSJens Wiklander     0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
958817466cbSJens Wiklander     0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
959817466cbSJens Wiklander     0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
960817466cbSJens Wiklander     0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
961817466cbSJens Wiklander     0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
962817466cbSJens Wiklander     0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
963817466cbSJens Wiklander };
964817466cbSJens Wiklander 
96532b31808SJens Wiklander static const unsigned char ecjpake_test_shared_key[] = {
96632b31808SJens Wiklander     0x04, 0x01, 0xab, 0xe9, 0xf2, 0xc7, 0x3a, 0x99, 0x14, 0xcb, 0x1f, 0x80,
96732b31808SJens Wiklander     0xfb, 0x9d, 0xdb, 0x7e, 0x00, 0x12, 0xa8, 0x9c, 0x2f, 0x39, 0x27, 0x79,
96832b31808SJens Wiklander     0xf9, 0x64, 0x40, 0x14, 0x75, 0xea, 0xc1, 0x31, 0x28, 0x43, 0x8f, 0xe1,
96932b31808SJens Wiklander     0x12, 0x41, 0xd6, 0xc1, 0xe5, 0x5f, 0x7b, 0x80, 0x88, 0x94, 0xc9, 0xc0,
97032b31808SJens Wiklander     0x27, 0xa3, 0x34, 0x41, 0xf5, 0xcb, 0xa1, 0xfe, 0x6c, 0xc7, 0xe6, 0x12,
97132b31808SJens Wiklander     0x17, 0xc3, 0xde, 0x27, 0xb4,
97232b31808SJens Wiklander };
97332b31808SJens Wiklander 
974817466cbSJens Wiklander static const unsigned char ecjpake_test_pms[] = {
975817466cbSJens Wiklander     0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
976817466cbSJens Wiklander     0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
977817466cbSJens Wiklander     0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
978817466cbSJens Wiklander };
979817466cbSJens Wiklander 
98032b31808SJens Wiklander /*
98132b31808SJens Wiklander  * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!!
98232b31808SJens Wiklander  *
98332b31808SJens Wiklander  * This is the linear congruential generator from numerical recipes,
98432b31808SJens Wiklander  * except we only use the low byte as the output. See
98532b31808SJens Wiklander  * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
98632b31808SJens Wiklander  */
self_test_rng(void * ctx,unsigned char * out,size_t len)98732b31808SJens Wiklander static int self_test_rng(void *ctx, unsigned char *out, size_t len)
98832b31808SJens Wiklander {
98932b31808SJens Wiklander     static uint32_t state = 42;
99032b31808SJens Wiklander 
99132b31808SJens Wiklander     (void) ctx;
99232b31808SJens Wiklander 
99332b31808SJens Wiklander     for (size_t i = 0; i < len; i++) {
99432b31808SJens Wiklander         state = state * 1664525u + 1013904223u;
99532b31808SJens Wiklander         out[i] = (unsigned char) state;
99632b31808SJens Wiklander     }
99732b31808SJens Wiklander 
99832b31808SJens Wiklander     return 0;
99932b31808SJens Wiklander }
100032b31808SJens Wiklander 
10015b25c76aSJerome Forissier /* 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)1002817466cbSJens Wiklander static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
1003817466cbSJens Wiklander                              const unsigned char *xm1, size_t len1,
1004817466cbSJens Wiklander                              const unsigned char *xm2, size_t len2)
1005817466cbSJens Wiklander {
100611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1007817466cbSJens Wiklander 
1008817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm1, xm1, len1));
1009817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm2, xm2, len2));
1010817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm1, &ctx->xm1,
101132b31808SJens Wiklander                                     &ctx->grp.G, self_test_rng, NULL));
1012817466cbSJens Wiklander     MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm2, &ctx->xm2,
101332b31808SJens Wiklander                                     &ctx->grp.G, self_test_rng, NULL));
1014817466cbSJens Wiklander 
1015817466cbSJens Wiklander cleanup:
101632b31808SJens Wiklander     return ret;
1017817466cbSJens Wiklander }
1018817466cbSJens Wiklander 
10197901324dSJerome Forissier #endif /* ! MBEDTLS_ECJPAKE_ALT */
10207901324dSJerome Forissier 
1021817466cbSJens Wiklander /* For tests we don't need a secure RNG;
1022817466cbSJens Wiklander  * use the LGC from Numerical Recipes for simplicity */
ecjpake_lgc(void * p,unsigned char * out,size_t len)1023817466cbSJens Wiklander static int ecjpake_lgc(void *p, unsigned char *out, size_t len)
1024817466cbSJens Wiklander {
1025817466cbSJens Wiklander     static uint32_t x = 42;
1026817466cbSJens Wiklander     (void) p;
1027817466cbSJens Wiklander 
102832b31808SJens Wiklander     while (len > 0) {
1029817466cbSJens Wiklander         size_t use_len = len > 4 ? 4 : len;
1030817466cbSJens Wiklander         x = 1664525 * x + 1013904223;
1031817466cbSJens Wiklander         memcpy(out, &x, use_len);
1032817466cbSJens Wiklander         out += use_len;
1033817466cbSJens Wiklander         len -= use_len;
1034817466cbSJens Wiklander     }
1035817466cbSJens Wiklander 
103632b31808SJens Wiklander     return 0;
1037817466cbSJens Wiklander }
1038817466cbSJens Wiklander 
1039817466cbSJens Wiklander #define TEST_ASSERT(x)    \
1040817466cbSJens Wiklander     do {                    \
1041817466cbSJens Wiklander         if (x)             \
1042817466cbSJens Wiklander         ret = 0;        \
1043817466cbSJens Wiklander         else                \
1044817466cbSJens Wiklander         {                   \
1045817466cbSJens Wiklander             ret = 1;        \
1046817466cbSJens Wiklander             goto cleanup;   \
1047817466cbSJens Wiklander         }                   \
1048817466cbSJens Wiklander     } while (0)
1049817466cbSJens Wiklander 
1050817466cbSJens Wiklander /*
1051817466cbSJens Wiklander  * Checkup routine
1052817466cbSJens Wiklander  */
mbedtls_ecjpake_self_test(int verbose)1053817466cbSJens Wiklander int mbedtls_ecjpake_self_test(int verbose)
1054817466cbSJens Wiklander {
105511fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1056817466cbSJens Wiklander     mbedtls_ecjpake_context cli;
1057817466cbSJens Wiklander     mbedtls_ecjpake_context srv;
1058817466cbSJens Wiklander     unsigned char buf[512], pms[32];
1059817466cbSJens Wiklander     size_t len, pmslen;
1060817466cbSJens Wiklander 
1061817466cbSJens Wiklander     mbedtls_ecjpake_init(&cli);
1062817466cbSJens Wiklander     mbedtls_ecjpake_init(&srv);
1063817466cbSJens Wiklander 
106432b31808SJens Wiklander     if (verbose != 0) {
1065817466cbSJens Wiklander         mbedtls_printf("  ECJPAKE test #0 (setup): ");
106632b31808SJens Wiklander     }
1067817466cbSJens Wiklander 
1068817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_setup(&cli, MBEDTLS_ECJPAKE_CLIENT,
1069817466cbSJens Wiklander                                       MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1070817466cbSJens Wiklander                                       ecjpake_test_password,
1071817466cbSJens Wiklander                                       sizeof(ecjpake_test_password)) == 0);
1072817466cbSJens Wiklander 
1073817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_setup(&srv, MBEDTLS_ECJPAKE_SERVER,
1074817466cbSJens Wiklander                                       MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1075817466cbSJens Wiklander                                       ecjpake_test_password,
1076817466cbSJens Wiklander                                       sizeof(ecjpake_test_password)) == 0);
1077817466cbSJens Wiklander 
107832b31808SJens Wiklander     if (verbose != 0) {
1079817466cbSJens Wiklander         mbedtls_printf("passed\n");
108032b31808SJens Wiklander     }
1081817466cbSJens Wiklander 
108232b31808SJens Wiklander     if (verbose != 0) {
1083817466cbSJens Wiklander         mbedtls_printf("  ECJPAKE test #1 (random handshake): ");
108432b31808SJens Wiklander     }
1085817466cbSJens Wiklander 
1086817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
1087817466cbSJens Wiklander                                                 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1088817466cbSJens Wiklander 
1089817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
1090817466cbSJens Wiklander 
1091817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1092817466cbSJens Wiklander                                                 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1093817466cbSJens Wiklander 
1094817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
1095817466cbSJens Wiklander 
1096817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1097817466cbSJens Wiklander                                                 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1098817466cbSJens Wiklander 
1099817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
1100817466cbSJens Wiklander 
1101817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1102817466cbSJens Wiklander                                               pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
1103817466cbSJens Wiklander 
1104817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1105817466cbSJens Wiklander                                                 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1106817466cbSJens Wiklander 
1107817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
1108817466cbSJens Wiklander 
1109817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1110817466cbSJens Wiklander                                               buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1111817466cbSJens Wiklander 
1112817466cbSJens Wiklander     TEST_ASSERT(len == pmslen);
1113817466cbSJens Wiklander     TEST_ASSERT(memcmp(buf, pms, len) == 0);
1114817466cbSJens Wiklander 
111532b31808SJens Wiklander     if (verbose != 0) {
1116817466cbSJens Wiklander         mbedtls_printf("passed\n");
111732b31808SJens Wiklander     }
1118817466cbSJens Wiklander 
11197901324dSJerome Forissier #if !defined(MBEDTLS_ECJPAKE_ALT)
11207901324dSJerome Forissier     /* 'reference handshake' tests can only be run against implementations
11217901324dSJerome Forissier      * for which we have 100% control over how the random ephemeral keys
1122*b0563631STom Van Eyck      * are generated. This is only the case for the internal Mbed TLS
11237901324dSJerome Forissier      * implementation, so these tests are skipped in case the internal
11247901324dSJerome Forissier      * implementation is swapped out for an alternative one. */
112532b31808SJens Wiklander     if (verbose != 0) {
1126817466cbSJens Wiklander         mbedtls_printf("  ECJPAKE test #2 (reference handshake): ");
112732b31808SJens Wiklander     }
1128817466cbSJens Wiklander 
1129817466cbSJens Wiklander     /* Simulate generation of round one */
1130817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1131817466cbSJens Wiklander                                       ecjpake_test_x1, sizeof(ecjpake_test_x1),
1132817466cbSJens Wiklander                                       ecjpake_test_x2, sizeof(ecjpake_test_x2)));
1133817466cbSJens Wiklander 
1134817466cbSJens Wiklander     MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1135817466cbSJens Wiklander                                       ecjpake_test_x3, sizeof(ecjpake_test_x3),
1136817466cbSJens Wiklander                                       ecjpake_test_x4, sizeof(ecjpake_test_x4)));
1137817466cbSJens Wiklander 
1138817466cbSJens Wiklander     /* Read round one */
1139817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1140817466cbSJens Wiklander                                                ecjpake_test_cli_one,
1141817466cbSJens Wiklander                                                sizeof(ecjpake_test_cli_one)) == 0);
1142817466cbSJens Wiklander 
1143817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1144817466cbSJens Wiklander                                                ecjpake_test_srv_one,
1145817466cbSJens Wiklander                                                sizeof(ecjpake_test_srv_one)) == 0);
1146817466cbSJens Wiklander 
1147817466cbSJens Wiklander     /* Skip generation of round two, read round two */
1148817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1149817466cbSJens Wiklander                                                ecjpake_test_srv_two,
1150817466cbSJens Wiklander                                                sizeof(ecjpake_test_srv_two)) == 0);
1151817466cbSJens Wiklander 
1152817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1153817466cbSJens Wiklander                                                ecjpake_test_cli_two,
1154817466cbSJens Wiklander                                                sizeof(ecjpake_test_cli_two)) == 0);
1155817466cbSJens Wiklander 
1156817466cbSJens Wiklander     /* Server derives PMS */
1157817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1158817466cbSJens Wiklander                                               buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1159817466cbSJens Wiklander 
1160817466cbSJens Wiklander     TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1161817466cbSJens Wiklander     TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1162817466cbSJens Wiklander 
116332b31808SJens Wiklander     /* Server derives K as unsigned binary data */
116432b31808SJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_write_shared_key(&srv,
116532b31808SJens Wiklander                                                  buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
116632b31808SJens Wiklander 
116732b31808SJens Wiklander     TEST_ASSERT(len == sizeof(ecjpake_test_shared_key));
116832b31808SJens Wiklander     TEST_ASSERT(memcmp(buf, ecjpake_test_shared_key, len) == 0);
116932b31808SJens Wiklander 
1170817466cbSJens Wiklander     memset(buf, 0, len);   /* Avoid interferences with next step */
1171817466cbSJens Wiklander 
1172817466cbSJens Wiklander     /* Client derives PMS */
1173817466cbSJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1174817466cbSJens Wiklander                                               buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1175817466cbSJens Wiklander 
1176817466cbSJens Wiklander     TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1177817466cbSJens Wiklander     TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1178817466cbSJens Wiklander 
117932b31808SJens Wiklander     /* Client derives K as unsigned binary data */
118032b31808SJens Wiklander     TEST_ASSERT(mbedtls_ecjpake_write_shared_key(&cli,
118132b31808SJens Wiklander                                                  buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
118232b31808SJens Wiklander 
118332b31808SJens Wiklander     TEST_ASSERT(len == sizeof(ecjpake_test_shared_key));
118432b31808SJens Wiklander     TEST_ASSERT(memcmp(buf, ecjpake_test_shared_key, len) == 0);
118532b31808SJens Wiklander 
118632b31808SJens Wiklander     if (verbose != 0) {
1187817466cbSJens Wiklander         mbedtls_printf("passed\n");
118832b31808SJens Wiklander     }
11897901324dSJerome Forissier #endif /* ! MBEDTLS_ECJPAKE_ALT */
1190817466cbSJens Wiklander 
1191817466cbSJens Wiklander cleanup:
1192817466cbSJens Wiklander     mbedtls_ecjpake_free(&cli);
1193817466cbSJens Wiklander     mbedtls_ecjpake_free(&srv);
1194817466cbSJens Wiklander 
119532b31808SJens Wiklander     if (ret != 0) {
119632b31808SJens Wiklander         if (verbose != 0) {
1197817466cbSJens Wiklander             mbedtls_printf("failed\n");
119832b31808SJens Wiklander         }
1199817466cbSJens Wiklander 
1200817466cbSJens Wiklander         ret = 1;
1201817466cbSJens Wiklander     }
1202817466cbSJens Wiklander 
120332b31808SJens Wiklander     if (verbose != 0) {
1204817466cbSJens Wiklander         mbedtls_printf("\n");
120532b31808SJens Wiklander     }
1206817466cbSJens Wiklander 
120732b31808SJens Wiklander     return ret;
1208817466cbSJens Wiklander }
1209817466cbSJens Wiklander 
1210817466cbSJens Wiklander #undef TEST_ASSERT
1211817466cbSJens Wiklander 
1212*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_MD_CAN_SHA256 */
1213817466cbSJens Wiklander 
1214817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
1215817466cbSJens Wiklander 
1216817466cbSJens Wiklander #endif /* MBEDTLS_ECJPAKE_C */
1217