text
[RRG-proxmark3.git] / common / mbedtls / ecjpake.c
blob5082d626f93fb5f248d5595a71d4e4fd85bbae7e
1 /*
2 * Elliptic curve J-PAKE
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * References in the code are to the Thread v1.0 Specification,
22 * available to members of the Thread Group http://threadgroup.org/
25 #include "common.h"
27 #if defined(MBEDTLS_ECJPAKE_C)
29 #include "mbedtls/ecjpake.h"
30 #include "mbedtls/platform_util.h"
31 #include "mbedtls/error.h"
33 #include <string.h>
35 #if !defined(MBEDTLS_ECJPAKE_ALT)
37 /* Parameter validation macros based on platform_util.h */
38 #define ECJPAKE_VALIDATE_RET( cond ) \
39 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
40 #define ECJPAKE_VALIDATE( cond ) \
41 MBEDTLS_INTERNAL_VALIDATE( cond )
44 * Convert a mbedtls_ecjpake_role to identifier string
46 static const char *const ecjpake_id[] = {
47 "client",
48 "server"
51 #define ID_MINE ( ecjpake_id[ ctx->role ] )
52 #define ID_PEER ( ecjpake_id[ 1 - ctx->role ] )
55 * Initialize context
57 void mbedtls_ecjpake_init(mbedtls_ecjpake_context *ctx) {
58 ECJPAKE_VALIDATE(ctx != NULL);
60 ctx->md_info = NULL;
61 mbedtls_ecp_group_init(&ctx->grp);
62 ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
64 mbedtls_ecp_point_init(&ctx->Xm1);
65 mbedtls_ecp_point_init(&ctx->Xm2);
66 mbedtls_ecp_point_init(&ctx->Xp1);
67 mbedtls_ecp_point_init(&ctx->Xp2);
68 mbedtls_ecp_point_init(&ctx->Xp);
70 mbedtls_mpi_init(&ctx->xm1);
71 mbedtls_mpi_init(&ctx->xm2);
72 mbedtls_mpi_init(&ctx->s);
76 * Free context
78 void mbedtls_ecjpake_free(mbedtls_ecjpake_context *ctx) {
79 if (ctx == NULL)
80 return;
82 ctx->md_info = NULL;
83 mbedtls_ecp_group_free(&ctx->grp);
85 mbedtls_ecp_point_free(&ctx->Xm1);
86 mbedtls_ecp_point_free(&ctx->Xm2);
87 mbedtls_ecp_point_free(&ctx->Xp1);
88 mbedtls_ecp_point_free(&ctx->Xp2);
89 mbedtls_ecp_point_free(&ctx->Xp);
91 mbedtls_mpi_free(&ctx->xm1);
92 mbedtls_mpi_free(&ctx->xm2);
93 mbedtls_mpi_free(&ctx->s);
97 * Setup context
99 int mbedtls_ecjpake_setup(mbedtls_ecjpake_context *ctx,
100 mbedtls_ecjpake_role role,
101 mbedtls_md_type_t hash,
102 mbedtls_ecp_group_id curve,
103 const unsigned char *secret,
104 size_t len) {
105 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
107 ECJPAKE_VALIDATE_RET(ctx != NULL);
108 ECJPAKE_VALIDATE_RET(role == MBEDTLS_ECJPAKE_CLIENT ||
109 role == MBEDTLS_ECJPAKE_SERVER);
110 ECJPAKE_VALIDATE_RET(secret != NULL || len == 0);
112 ctx->role = role;
114 if ((ctx->md_info = mbedtls_md_info_from_type(hash)) == NULL)
115 return (MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE);
117 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&ctx->grp, curve));
119 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->s, secret, len));
121 cleanup:
122 if (ret != 0)
123 mbedtls_ecjpake_free(ctx);
125 return (ret);
129 * Check if context is ready for use
131 int mbedtls_ecjpake_check(const mbedtls_ecjpake_context *ctx) {
132 ECJPAKE_VALIDATE_RET(ctx != NULL);
134 if (ctx->md_info == NULL ||
135 ctx->grp.id == MBEDTLS_ECP_DP_NONE ||
136 ctx->s.p == NULL) {
137 return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
140 return (0);
144 * Write a point plus its length to a buffer
146 static int ecjpake_write_len_point(unsigned char **p,
147 const unsigned char *end,
148 const mbedtls_ecp_group *grp,
149 const int pf,
150 const mbedtls_ecp_point *P) {
151 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
152 size_t len;
154 /* Need at least 4 for length plus 1 for point */
155 if (end < *p || end - *p < 5)
156 return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
158 ret = mbedtls_ecp_point_write_binary(grp, P, pf,
159 &len, *p + 4, end - (*p + 4));
160 if (ret != 0)
161 return (ret);
163 (*p)[0] = (unsigned char)((len >> 24) & 0xFF);
164 (*p)[1] = (unsigned char)((len >> 16) & 0xFF);
165 (*p)[2] = (unsigned char)((len >> 8) & 0xFF);
166 (*p)[3] = (unsigned char)((len) & 0xFF);
168 *p += 4 + len;
170 return (0);
174 * Size of the temporary buffer for ecjpake_hash:
175 * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
177 #define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 4 + 6 )
180 * Compute hash for ZKP (7.4.2.2.2.1)
182 static int ecjpake_hash(const mbedtls_md_info_t *md_info,
183 const mbedtls_ecp_group *grp,
184 const int pf,
185 const mbedtls_ecp_point *G,
186 const mbedtls_ecp_point *V,
187 const mbedtls_ecp_point *X,
188 const char *id,
189 mbedtls_mpi *h) {
190 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
191 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
192 unsigned char *p = buf;
193 const unsigned char *end = buf + sizeof(buf);
194 const size_t id_len = strlen(id);
195 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
197 /* Write things to temporary buffer */
198 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, G));
199 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, V));
200 MBEDTLS_MPI_CHK(ecjpake_write_len_point(&p, end, grp, pf, X));
202 if (end - p < 4)
203 return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
205 *p++ = (unsigned char)((id_len >> 24) & 0xFF);
206 *p++ = (unsigned char)((id_len >> 16) & 0xFF);
207 *p++ = (unsigned char)((id_len >> 8) & 0xFF);
208 *p++ = (unsigned char)((id_len) & 0xFF);
210 if (end < p || (size_t)(end - p) < id_len)
211 return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
213 memcpy(p, id, id_len);
214 p += id_len;
216 /* Compute hash */
217 MBEDTLS_MPI_CHK(mbedtls_md(md_info, buf, p - buf, hash));
219 /* Turn it into an integer mod n */
220 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(h, hash,
221 mbedtls_md_get_size(md_info)));
222 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(h, h, &grp->N));
224 cleanup:
225 return (ret);
229 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
231 static int ecjpake_zkp_read(const mbedtls_md_info_t *md_info,
232 const mbedtls_ecp_group *grp,
233 const int pf,
234 const mbedtls_ecp_point *G,
235 const mbedtls_ecp_point *X,
236 const char *id,
237 const unsigned char **p,
238 const unsigned char *end) {
239 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
240 mbedtls_ecp_point V, VV;
241 mbedtls_mpi r, h;
242 size_t r_len;
244 mbedtls_ecp_point_init(&V);
245 mbedtls_ecp_point_init(&VV);
246 mbedtls_mpi_init(&r);
247 mbedtls_mpi_init(&h);
250 * struct {
251 * ECPoint V;
252 * opaque r<1..2^8-1>;
253 * } ECSchnorrZKP;
255 if (end < *p)
256 return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
258 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, &V, p, end - *p));
260 if (end < *p || (size_t)(end - *p) < 1) {
261 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
262 goto cleanup;
265 r_len = *(*p)++;
267 if (end < *p || (size_t)(end - *p) < r_len) {
268 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
269 goto cleanup;
272 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r, *p, r_len));
273 *p += r_len;
276 * Verification
278 MBEDTLS_MPI_CHK(ecjpake_hash(md_info, grp, pf, G, &V, X, id, &h));
279 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd((mbedtls_ecp_group *) grp,
280 &VV, &h, X, &r, G));
282 if (mbedtls_ecp_point_cmp(&VV, &V) != 0) {
283 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
284 goto cleanup;
287 cleanup:
288 mbedtls_ecp_point_free(&V);
289 mbedtls_ecp_point_free(&VV);
290 mbedtls_mpi_free(&r);
291 mbedtls_mpi_free(&h);
293 return (ret);
297 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
299 static int ecjpake_zkp_write(const mbedtls_md_info_t *md_info,
300 const mbedtls_ecp_group *grp,
301 const int pf,
302 const mbedtls_ecp_point *G,
303 const mbedtls_mpi *x,
304 const mbedtls_ecp_point *X,
305 const char *id,
306 unsigned char **p,
307 const unsigned char *end,
308 int (*f_rng)(void *, unsigned char *, size_t),
309 void *p_rng) {
310 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
311 mbedtls_ecp_point V;
312 mbedtls_mpi v;
313 mbedtls_mpi h; /* later recycled to hold r */
314 size_t len;
316 if (end < *p)
317 return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
319 mbedtls_ecp_point_init(&V);
320 mbedtls_mpi_init(&v);
321 mbedtls_mpi_init(&h);
323 /* Compute signature */
324 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp,
325 G, &v, &V, f_rng, p_rng));
326 MBEDTLS_MPI_CHK(ecjpake_hash(md_info, grp, pf, G, &V, X, id, &h));
327 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&h, &h, x)); /* x*h */
328 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&h, &v, &h)); /* v - x*h */
329 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&h, &h, &grp->N)); /* r */
331 /* Write it out */
332 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, &V,
333 pf, &len, *p, end - *p));
334 *p += len;
336 len = mbedtls_mpi_size(&h); /* actually r */
337 if (end < *p || (size_t)(end - *p) < 1 + len || len > 255) {
338 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
339 goto cleanup;
342 *(*p)++ = (unsigned char)(len & 0xFF);
343 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, *p, len)); /* r */
344 *p += len;
346 cleanup:
347 mbedtls_ecp_point_free(&V);
348 mbedtls_mpi_free(&v);
349 mbedtls_mpi_free(&h);
351 return (ret);
355 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
356 * Output: verified public key X
358 static int ecjpake_kkp_read(const mbedtls_md_info_t *md_info,
359 const mbedtls_ecp_group *grp,
360 const int pf,
361 const mbedtls_ecp_point *G,
362 mbedtls_ecp_point *X,
363 const char *id,
364 const unsigned char **p,
365 const unsigned char *end) {
366 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
368 if (end < *p)
369 return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
372 * struct {
373 * ECPoint X;
374 * ECSchnorrZKP zkp;
375 * } ECJPAKEKeyKP;
377 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_point(grp, X, p, end - *p));
378 if (mbedtls_ecp_is_zero(X)) {
379 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
380 goto cleanup;
383 MBEDTLS_MPI_CHK(ecjpake_zkp_read(md_info, grp, pf, G, X, id, p, end));
385 cleanup:
386 return (ret);
390 * Generate an ECJPAKEKeyKP
391 * Output: the serialized structure, plus private/public key pair
393 static int ecjpake_kkp_write(const mbedtls_md_info_t *md_info,
394 const mbedtls_ecp_group *grp,
395 const int pf,
396 const mbedtls_ecp_point *G,
397 mbedtls_mpi *x,
398 mbedtls_ecp_point *X,
399 const char *id,
400 unsigned char **p,
401 const unsigned char *end,
402 int (*f_rng)(void *, unsigned char *, size_t),
403 void *p_rng) {
404 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
405 size_t len;
407 if (end < *p)
408 return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
410 /* Generate key (7.4.2.3.1) and write it out */
411 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_keypair_base((mbedtls_ecp_group *) grp, G, x, X,
412 f_rng, p_rng));
413 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(grp, X,
414 pf, &len, *p, end - *p));
415 *p += len;
417 /* Generate and write proof */
418 MBEDTLS_MPI_CHK(ecjpake_zkp_write(md_info, grp, pf, G, x, X, id,
419 p, end, f_rng, p_rng));
421 cleanup:
422 return (ret);
426 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
427 * Ouputs: verified peer public keys Xa, Xb
429 static int ecjpake_kkpp_read(const mbedtls_md_info_t *md_info,
430 const mbedtls_ecp_group *grp,
431 const int pf,
432 const mbedtls_ecp_point *G,
433 mbedtls_ecp_point *Xa,
434 mbedtls_ecp_point *Xb,
435 const char *id,
436 const unsigned char *buf,
437 size_t len) {
438 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
439 const unsigned char *p = buf;
440 const unsigned char *end = buf + len;
443 * struct {
444 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
445 * } ECJPAKEKeyKPPairList;
447 MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_info, grp, pf, G, Xa, id, &p, end));
448 MBEDTLS_MPI_CHK(ecjpake_kkp_read(md_info, grp, pf, G, Xb, id, &p, end));
450 if (p != end)
451 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
453 cleanup:
454 return (ret);
458 * Generate a ECJPAKEKeyKPPairList
459 * Outputs: the serialized structure, plus two private/public key pairs
461 static int ecjpake_kkpp_write(const mbedtls_md_info_t *md_info,
462 const mbedtls_ecp_group *grp,
463 const int pf,
464 const mbedtls_ecp_point *G,
465 mbedtls_mpi *xm1,
466 mbedtls_ecp_point *Xa,
467 mbedtls_mpi *xm2,
468 mbedtls_ecp_point *Xb,
469 const char *id,
470 unsigned char *buf,
471 size_t len,
472 size_t *olen,
473 int (*f_rng)(void *, unsigned char *, size_t),
474 void *p_rng) {
475 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
476 unsigned char *p = buf;
477 const unsigned char *end = buf + len;
479 MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_info, grp, pf, G, xm1, Xa, id,
480 &p, end, f_rng, p_rng));
481 MBEDTLS_MPI_CHK(ecjpake_kkp_write(md_info, grp, pf, G, xm2, Xb, id,
482 &p, end, f_rng, p_rng));
484 *olen = p - buf;
486 cleanup:
487 return (ret);
491 * Read and process the first round message
493 int mbedtls_ecjpake_read_round_one(mbedtls_ecjpake_context *ctx,
494 const unsigned char *buf,
495 size_t len) {
496 ECJPAKE_VALIDATE_RET(ctx != NULL);
497 ECJPAKE_VALIDATE_RET(buf != NULL);
499 return (ecjpake_kkpp_read(ctx->md_info, &ctx->grp, ctx->point_format,
500 &ctx->grp.G,
501 &ctx->Xp1, &ctx->Xp2, ID_PEER,
502 buf, len));
506 * Generate and write the first round message
508 int mbedtls_ecjpake_write_round_one(mbedtls_ecjpake_context *ctx,
509 unsigned char *buf, size_t len, size_t *olen,
510 int (*f_rng)(void *, unsigned char *, size_t),
511 void *p_rng) {
512 ECJPAKE_VALIDATE_RET(ctx != NULL);
513 ECJPAKE_VALIDATE_RET(buf != NULL);
514 ECJPAKE_VALIDATE_RET(olen != NULL);
515 ECJPAKE_VALIDATE_RET(f_rng != NULL);
517 return (ecjpake_kkpp_write(ctx->md_info, &ctx->grp, ctx->point_format,
518 &ctx->grp.G,
519 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
520 ID_MINE, buf, len, olen, f_rng, p_rng));
524 * Compute the sum of three points R = A + B + C
526 static int ecjpake_ecp_add3(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
527 const mbedtls_ecp_point *A,
528 const mbedtls_ecp_point *B,
529 const mbedtls_ecp_point *C) {
530 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
531 mbedtls_mpi one;
533 mbedtls_mpi_init(&one);
535 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
536 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, A, &one, B));
537 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(grp, R, &one, R, &one, C));
539 cleanup:
540 mbedtls_mpi_free(&one);
542 return (ret);
546 * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
548 int mbedtls_ecjpake_read_round_two(mbedtls_ecjpake_context *ctx,
549 const unsigned char *buf,
550 size_t len) {
551 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
552 const unsigned char *p = buf;
553 const unsigned char *end = buf + len;
554 mbedtls_ecp_group grp;
555 mbedtls_ecp_point G; /* C: GB, S: GA */
557 ECJPAKE_VALIDATE_RET(ctx != NULL);
558 ECJPAKE_VALIDATE_RET(buf != NULL);
560 mbedtls_ecp_group_init(&grp);
561 mbedtls_ecp_point_init(&G);
564 * Server: GA = X3 + X4 + X1 (7.4.2.6.1)
565 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
566 * Unified: G = Xm1 + Xm2 + Xp1
567 * We need that before parsing in order to check Xp as we read it
569 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
570 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1));
573 * struct {
574 * ECParameters curve_params; // only client reading server msg
575 * ECJPAKEKeyKP ecjpake_key_kp;
576 * } Client/ServerECJPAKEParams;
578 if (ctx->role == MBEDTLS_ECJPAKE_CLIENT) {
579 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_read_group(&grp, &p, len));
580 if (grp.id != ctx->grp.id) {
581 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
582 goto cleanup;
586 MBEDTLS_MPI_CHK(ecjpake_kkp_read(ctx->md_info, &ctx->grp,
587 ctx->point_format,
588 &G, &ctx->Xp, ID_PEER, &p, end));
590 if (p != end) {
591 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
592 goto cleanup;
595 cleanup:
596 mbedtls_ecp_group_free(&grp);
597 mbedtls_ecp_point_free(&G);
599 return (ret);
603 * Compute R = +/- X * S mod N, taking care not to leak S
605 static int ecjpake_mul_secret(mbedtls_mpi *R, int sign,
606 const mbedtls_mpi *X,
607 const mbedtls_mpi *S,
608 const mbedtls_mpi *N,
609 int (*f_rng)(void *, unsigned char *, size_t),
610 void *p_rng) {
611 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
612 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
614 mbedtls_mpi_init(&b);
616 /* b = s + rnd-128-bit * N */
617 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&b, 16, f_rng, p_rng));
618 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&b, &b, N));
619 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&b, &b, S));
621 /* R = sign * X * b mod N */
622 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(R, X, &b));
623 R->s *= sign;
624 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(R, R, N));
626 cleanup:
627 mbedtls_mpi_free(&b);
629 return (ret);
633 * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
635 int mbedtls_ecjpake_write_round_two(mbedtls_ecjpake_context *ctx,
636 unsigned char *buf, size_t len, size_t *olen,
637 int (*f_rng)(void *, unsigned char *, size_t),
638 void *p_rng) {
639 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
640 mbedtls_ecp_point G; /* C: GA, S: GB */
641 mbedtls_ecp_point Xm; /* C: Xc, S: Xs */
642 mbedtls_mpi xm; /* C: xc, S: xs */
643 unsigned char *p = buf;
644 const unsigned char *end = buf + len;
645 size_t ec_len;
647 ECJPAKE_VALIDATE_RET(ctx != NULL);
648 ECJPAKE_VALIDATE_RET(buf != NULL);
649 ECJPAKE_VALIDATE_RET(olen != NULL);
650 ECJPAKE_VALIDATE_RET(f_rng != NULL);
652 mbedtls_ecp_point_init(&G);
653 mbedtls_ecp_point_init(&Xm);
654 mbedtls_mpi_init(&xm);
657 * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
659 * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA
660 * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB
661 * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
663 MBEDTLS_MPI_CHK(ecjpake_ecp_add3(&ctx->grp, &G,
664 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1));
665 MBEDTLS_MPI_CHK(ecjpake_mul_secret(&xm, 1, &ctx->xm2, &ctx->s,
666 &ctx->grp.N, f_rng, p_rng));
667 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &Xm, &xm, &G, f_rng, p_rng));
670 * Now write things out
672 * struct {
673 * ECParameters curve_params; // only server writing its message
674 * ECJPAKEKeyKP ecjpake_key_kp;
675 * } Client/ServerECJPAKEParams;
677 if (ctx->role == MBEDTLS_ECJPAKE_SERVER) {
678 if (end < p) {
679 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
680 goto cleanup;
682 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_group(&ctx->grp, &ec_len,
683 p, end - p));
684 p += ec_len;
687 if (end < p) {
688 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
689 goto cleanup;
691 MBEDTLS_MPI_CHK(mbedtls_ecp_tls_write_point(&ctx->grp, &Xm,
692 ctx->point_format, &ec_len, p, end - p));
693 p += ec_len;
695 MBEDTLS_MPI_CHK(ecjpake_zkp_write(ctx->md_info, &ctx->grp,
696 ctx->point_format,
697 &G, &xm, &Xm, ID_MINE,
698 &p, end, f_rng, p_rng));
700 *olen = p - buf;
702 cleanup:
703 mbedtls_ecp_point_free(&G);
704 mbedtls_ecp_point_free(&Xm);
705 mbedtls_mpi_free(&xm);
707 return (ret);
711 * Derive PMS (7.4.2.7 / 7.4.2.8)
713 int mbedtls_ecjpake_derive_secret(mbedtls_ecjpake_context *ctx,
714 unsigned char *buf, size_t len, size_t *olen,
715 int (*f_rng)(void *, unsigned char *, size_t),
716 void *p_rng) {
717 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
718 mbedtls_ecp_point K;
719 mbedtls_mpi m_xm2_s, one;
720 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
721 size_t x_bytes;
723 ECJPAKE_VALIDATE_RET(ctx != NULL);
724 ECJPAKE_VALIDATE_RET(buf != NULL);
725 ECJPAKE_VALIDATE_RET(olen != NULL);
726 ECJPAKE_VALIDATE_RET(f_rng != NULL);
728 *olen = mbedtls_md_get_size(ctx->md_info);
729 if (len < *olen)
730 return (MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
732 mbedtls_ecp_point_init(&K);
733 mbedtls_mpi_init(&m_xm2_s);
734 mbedtls_mpi_init(&one);
736 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1));
739 * Client: K = ( Xs - X4 * x2 * s ) * x2
740 * Server: K = ( Xc - X2 * x4 * s ) * x4
741 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
743 MBEDTLS_MPI_CHK(ecjpake_mul_secret(&m_xm2_s, -1, &ctx->xm2, &ctx->s,
744 &ctx->grp.N, f_rng, p_rng));
745 MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&ctx->grp, &K,
746 &one, &ctx->Xp,
747 &m_xm2_s, &ctx->Xp2));
748 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &K, &ctx->xm2, &K,
749 f_rng, p_rng));
751 /* PMS = SHA-256( K.X ) */
752 x_bytes = (ctx->grp.pbits + 7) / 8;
753 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&K.X, kx, x_bytes));
754 MBEDTLS_MPI_CHK(mbedtls_md(ctx->md_info, kx, x_bytes, buf));
756 cleanup:
757 mbedtls_ecp_point_free(&K);
758 mbedtls_mpi_free(&m_xm2_s);
759 mbedtls_mpi_free(&one);
761 return (ret);
764 #undef ID_MINE
765 #undef ID_PEER
767 #endif /* ! MBEDTLS_ECJPAKE_ALT */
769 #if defined(MBEDTLS_SELF_TEST)
771 #if defined(MBEDTLS_PLATFORM_C)
772 #include "mbedtls/platform.h"
773 #else
774 #include <stdio.h>
775 #define mbedtls_printf printf
776 #endif
778 #if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
779 !defined(MBEDTLS_SHA256_C)
780 int mbedtls_ecjpake_self_test(int verbose) {
781 (void) verbose;
782 return (0);
784 #else
786 static const unsigned char ecjpake_test_password[] = {
787 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
788 0x65, 0x73, 0x74
791 #if !defined(MBEDTLS_ECJPAKE_ALT)
793 static const unsigned char ecjpake_test_x1[] = {
794 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
795 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
796 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
799 static const unsigned char ecjpake_test_x2[] = {
800 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
801 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
802 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
805 static const unsigned char ecjpake_test_x3[] = {
806 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
807 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
808 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
811 static const unsigned char ecjpake_test_x4[] = {
812 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
813 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
814 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
817 static const unsigned char ecjpake_test_cli_one[] = {
818 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
819 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
820 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
821 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
822 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
823 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
824 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
825 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
826 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
827 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
828 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
829 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
830 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
831 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
832 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
833 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
834 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
835 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
836 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
837 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
838 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
839 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
840 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
841 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
842 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
843 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
844 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
845 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
848 static const unsigned char ecjpake_test_srv_one[] = {
849 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
850 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
851 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
852 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
853 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
854 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
855 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
856 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
857 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
858 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
859 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
860 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
861 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
862 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
863 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
864 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
865 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
866 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
867 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
868 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
869 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
870 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
871 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
872 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
873 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
874 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
875 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
876 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
879 static const unsigned char ecjpake_test_srv_two[] = {
880 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
881 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
882 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
883 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
884 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
885 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
886 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
887 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
888 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
889 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
890 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
891 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
892 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
893 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
896 static const unsigned char ecjpake_test_cli_two[] = {
897 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
898 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
899 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
900 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
901 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
902 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
903 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
904 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
905 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
906 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
907 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
908 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
909 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
910 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
913 static const unsigned char ecjpake_test_pms[] = {
914 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
915 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
916 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
919 /* Load my private keys and generate the corresponding public keys */
920 static int ecjpake_test_load(mbedtls_ecjpake_context *ctx,
921 const unsigned char *xm1, size_t len1,
922 const unsigned char *xm2, size_t len2) {
923 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
925 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm1, xm1, len1));
926 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ctx->xm2, xm2, len2));
927 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm1, &ctx->xm1,
928 &ctx->grp.G, NULL, NULL));
929 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&ctx->grp, &ctx->Xm2, &ctx->xm2,
930 &ctx->grp.G, NULL, NULL));
932 cleanup:
933 return (ret);
936 #endif /* ! MBEDTLS_ECJPAKE_ALT */
938 /* For tests we don't need a secure RNG;
939 * use the LGC from Numerical Recipes for simplicity */
940 static int ecjpake_lgc(void *p, unsigned char *out, size_t len) {
941 static uint32_t x = 42;
942 (void) p;
944 while (len > 0) {
945 size_t use_len = len > 4 ? 4 : len;
946 x = 1664525 * x + 1013904223;
947 memcpy(out, &x, use_len);
948 out += use_len;
949 len -= use_len;
952 return (0);
955 #define TEST_ASSERT( x ) \
956 do { \
957 if( x ) \
958 ret = 0; \
959 else \
961 ret = 1; \
962 goto cleanup; \
964 } while( 0 )
967 * Checkup routine
969 int mbedtls_ecjpake_self_test(int verbose) {
970 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
971 mbedtls_ecjpake_context cli;
972 mbedtls_ecjpake_context srv;
973 unsigned char buf[512], pms[32];
974 size_t len, pmslen;
976 mbedtls_ecjpake_init(&cli);
977 mbedtls_ecjpake_init(&srv);
979 if (verbose != 0)
980 mbedtls_printf(" ECJPAKE test #0 (setup): ");
982 TEST_ASSERT(mbedtls_ecjpake_setup(&cli, MBEDTLS_ECJPAKE_CLIENT,
983 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
984 ecjpake_test_password,
985 sizeof(ecjpake_test_password)) == 0);
987 TEST_ASSERT(mbedtls_ecjpake_setup(&srv, MBEDTLS_ECJPAKE_SERVER,
988 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
989 ecjpake_test_password,
990 sizeof(ecjpake_test_password)) == 0);
992 if (verbose != 0)
993 mbedtls_printf("passed\n");
995 if (verbose != 0)
996 mbedtls_printf(" ECJPAKE test #1 (random handshake): ");
998 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&cli,
999 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1001 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv, buf, len) == 0);
1003 TEST_ASSERT(mbedtls_ecjpake_write_round_one(&srv,
1004 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1006 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli, buf, len) == 0);
1008 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&srv,
1009 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1011 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli, buf, len) == 0);
1013 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1014 pms, sizeof(pms), &pmslen, ecjpake_lgc, NULL) == 0);
1016 TEST_ASSERT(mbedtls_ecjpake_write_round_two(&cli,
1017 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1019 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv, buf, len) == 0);
1021 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1022 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1024 TEST_ASSERT(len == pmslen);
1025 TEST_ASSERT(memcmp(buf, pms, len) == 0);
1027 if (verbose != 0)
1028 mbedtls_printf("passed\n");
1030 #if !defined(MBEDTLS_ECJPAKE_ALT)
1031 /* 'reference handshake' tests can only be run against implementations
1032 * for which we have 100% control over how the random ephemeral keys
1033 * are generated. This is only the case for the internal mbed TLS
1034 * implementation, so these tests are skipped in case the internal
1035 * implementation is swapped out for an alternative one. */
1036 if (verbose != 0)
1037 mbedtls_printf(" ECJPAKE test #2 (reference handshake): ");
1039 /* Simulate generation of round one */
1040 MBEDTLS_MPI_CHK(ecjpake_test_load(&cli,
1041 ecjpake_test_x1, sizeof(ecjpake_test_x1),
1042 ecjpake_test_x2, sizeof(ecjpake_test_x2)));
1044 MBEDTLS_MPI_CHK(ecjpake_test_load(&srv,
1045 ecjpake_test_x3, sizeof(ecjpake_test_x3),
1046 ecjpake_test_x4, sizeof(ecjpake_test_x4)));
1048 /* Read round one */
1049 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&srv,
1050 ecjpake_test_cli_one,
1051 sizeof(ecjpake_test_cli_one)) == 0);
1053 TEST_ASSERT(mbedtls_ecjpake_read_round_one(&cli,
1054 ecjpake_test_srv_one,
1055 sizeof(ecjpake_test_srv_one)) == 0);
1057 /* Skip generation of round two, read round two */
1058 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&cli,
1059 ecjpake_test_srv_two,
1060 sizeof(ecjpake_test_srv_two)) == 0);
1062 TEST_ASSERT(mbedtls_ecjpake_read_round_two(&srv,
1063 ecjpake_test_cli_two,
1064 sizeof(ecjpake_test_cli_two)) == 0);
1066 /* Server derives PMS */
1067 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&srv,
1068 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1070 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1071 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1073 memset(buf, 0, len); /* Avoid interferences with next step */
1075 /* Client derives PMS */
1076 TEST_ASSERT(mbedtls_ecjpake_derive_secret(&cli,
1077 buf, sizeof(buf), &len, ecjpake_lgc, NULL) == 0);
1079 TEST_ASSERT(len == sizeof(ecjpake_test_pms));
1080 TEST_ASSERT(memcmp(buf, ecjpake_test_pms, len) == 0);
1082 if (verbose != 0)
1083 mbedtls_printf("passed\n");
1084 #endif /* ! MBEDTLS_ECJPAKE_ALT */
1086 cleanup:
1087 mbedtls_ecjpake_free(&cli);
1088 mbedtls_ecjpake_free(&srv);
1090 if (ret != 0) {
1091 if (verbose != 0)
1092 mbedtls_printf("failed\n");
1094 ret = 1;
1097 if (verbose != 0)
1098 mbedtls_printf("\n");
1100 return (ret);
1103 #undef TEST_ASSERT
1105 #endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1107 #endif /* MBEDTLS_SELF_TEST */
1109 #endif /* MBEDTLS_ECJPAKE_C */