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