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