mbedtls ported to mbed-classic

Fork of mbedtls by Christopher Haster

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ecjpake.c Source File

ecjpake.c

00001 /*
00002  *  Elliptic curve J-PAKE
00003  *
00004  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  *
00019  *  This file is part of mbed TLS (https://tls.mbed.org)
00020  */
00021 
00022 /*
00023  * References in the code are to the Thread v1.0 Specification,
00024  * available to members of the Thread Group http://threadgroup.org/
00025  */
00026 
00027 #if !defined(MBEDTLS_CONFIG_FILE)
00028 #include "mbedtls/config.h"
00029 #else
00030 #include MBEDTLS_CONFIG_FILE
00031 #endif
00032 
00033 #if defined(MBEDTLS_ECJPAKE_C)
00034 
00035 #include "mbedtls/ecjpake.h"
00036 
00037 #include <string.h>
00038 
00039 /*
00040  * Convert a mbedtls_ecjpake_role to identifier string
00041  */
00042 static const char * const ecjpake_id[] = {
00043     "client",
00044     "server"
00045 };
00046 
00047 #define ID_MINE     ( ecjpake_id[ ctx->role ] )
00048 #define ID_PEER     ( ecjpake_id[ 1 - ctx->role ] )
00049 
00050 /*
00051  * Initialize context
00052  */
00053 void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx )
00054 {
00055     if( ctx == NULL )
00056         return;
00057 
00058     ctx->md_info = NULL;
00059     mbedtls_ecp_group_init( &ctx->grp );
00060     ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
00061 
00062     mbedtls_ecp_point_init( &ctx->Xm1 );
00063     mbedtls_ecp_point_init( &ctx->Xm2 );
00064     mbedtls_ecp_point_init( &ctx->Xp1 );
00065     mbedtls_ecp_point_init( &ctx->Xp2 );
00066     mbedtls_ecp_point_init( &ctx->Xp  );
00067 
00068     mbedtls_mpi_init( &ctx->xm1 );
00069     mbedtls_mpi_init( &ctx->xm2 );
00070     mbedtls_mpi_init( &ctx->s   );
00071 }
00072 
00073 /*
00074  * Free context
00075  */
00076 void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx )
00077 {
00078     if( ctx == NULL )
00079         return;
00080 
00081     ctx->md_info = NULL;
00082     mbedtls_ecp_group_free( &ctx->grp );
00083 
00084     mbedtls_ecp_point_free( &ctx->Xm1 );
00085     mbedtls_ecp_point_free( &ctx->Xm2 );
00086     mbedtls_ecp_point_free( &ctx->Xp1 );
00087     mbedtls_ecp_point_free( &ctx->Xp2 );
00088     mbedtls_ecp_point_free( &ctx->Xp  );
00089 
00090     mbedtls_mpi_free( &ctx->xm1 );
00091     mbedtls_mpi_free( &ctx->xm2 );
00092     mbedtls_mpi_free( &ctx->s   );
00093 }
00094 
00095 /*
00096  * Setup context
00097  */
00098 int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx,
00099                            mbedtls_ecjpake_role role,
00100                            mbedtls_md_type_t hash,
00101                            mbedtls_ecp_group_id curve,
00102                            const unsigned char *secret,
00103                            size_t len )
00104 {
00105     int ret;
00106 
00107     ctx->role = role;
00108 
00109     if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL )
00110         return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE );
00111 
00112     MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, curve ) );
00113 
00114     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->s, secret, len ) );
00115 
00116 cleanup:
00117     if( ret != 0 )
00118         mbedtls_ecjpake_free( ctx );
00119 
00120     return( ret );
00121 }
00122 
00123 /*
00124  * Check if context is ready for use
00125  */
00126 int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx )
00127 {
00128     if( ctx->md_info == NULL ||
00129         ctx->grp.id  == MBEDTLS_ECP_DP_NONE ||
00130         ctx->s.p  == NULL )
00131     {
00132         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
00133     }
00134 
00135     return( 0 );
00136 }
00137 
00138 /*
00139  * Write a point plus its length to a buffer
00140  */
00141 static int ecjpake_write_len_point( unsigned char **p,
00142                                     const unsigned char *end,
00143                                     const mbedtls_ecp_group *grp,
00144                                     const int pf,
00145                                     const mbedtls_ecp_point *P )
00146 {
00147     int ret;
00148     size_t len;
00149 
00150     /* Need at least 4 for length plus 1 for point */
00151     if( end < *p || end - *p < 5 )
00152         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
00153 
00154     ret = mbedtls_ecp_point_write_binary( grp, P, pf,
00155                                           &len, *p + 4, end - ( *p + 4 ) );
00156     if( ret != 0 )
00157         return( ret );
00158 
00159     (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF );
00160     (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF );
00161     (*p)[2] = (unsigned char)( ( len >>  8 ) & 0xFF );
00162     (*p)[3] = (unsigned char)( ( len       ) & 0xFF );
00163 
00164     *p += 4 + len;
00165 
00166     return( 0 );
00167 }
00168 
00169 /*
00170  * Size of the temporary buffer for ecjpake_hash:
00171  * 3 EC points plus their length, plus ID and its length (4 + 6 bytes)
00172  */
00173 #define ECJPAKE_HASH_BUF_LEN    ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 4 + 6 )
00174 
00175 /*
00176  * Compute hash for ZKP (7.4.2.2.2.1)
00177  */
00178 static int ecjpake_hash( const mbedtls_md_info_t *md_info,
00179                          const mbedtls_ecp_group *grp,
00180                          const int pf,
00181                          const mbedtls_ecp_point *G,
00182                          const mbedtls_ecp_point *V,
00183                          const mbedtls_ecp_point *X,
00184                          const char *id,
00185                          mbedtls_mpi *h )
00186 {
00187     int ret;
00188     unsigned char buf[ECJPAKE_HASH_BUF_LEN];
00189     unsigned char *p = buf;
00190     const unsigned char *end = buf + sizeof( buf );
00191     const size_t id_len = strlen( id );
00192     unsigned char hash[MBEDTLS_MD_MAX_SIZE];
00193 
00194     /* Write things to temporary buffer */
00195     MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, G ) );
00196     MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, V ) );
00197     MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, X ) );
00198 
00199     if( end - p < 4 )
00200         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
00201 
00202     *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF );
00203     *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF );
00204     *p++ = (unsigned char)( ( id_len >>  8 ) & 0xFF );
00205     *p++ = (unsigned char)( ( id_len       ) & 0xFF );
00206 
00207     if( end < p || (size_t)( end - p ) < id_len )
00208         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
00209 
00210     memcpy( p, id, id_len );
00211     p += id_len;
00212 
00213     /* Compute hash */
00214     mbedtls_md( md_info, buf, p - buf, hash );
00215 
00216     /* Turn it into an integer mod n */
00217     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash,
00218                                         mbedtls_md_get_size( md_info ) ) );
00219     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N  ) );
00220 
00221 cleanup:
00222     return( ret );
00223 }
00224 
00225 /*
00226  * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
00227  */
00228 static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info,
00229                              const mbedtls_ecp_group *grp,
00230                              const int pf,
00231                              const mbedtls_ecp_point *G,
00232                              const mbedtls_ecp_point *X,
00233                              const char *id,
00234                              const unsigned char **p,
00235                              const unsigned char *end )
00236 {
00237     int ret;
00238     mbedtls_ecp_point V, VV;
00239     mbedtls_mpi r, h;
00240     size_t r_len;
00241 
00242     mbedtls_ecp_point_init( &V );
00243     mbedtls_ecp_point_init( &VV );
00244     mbedtls_mpi_init( &r );
00245     mbedtls_mpi_init( &h );
00246 
00247     /*
00248      * struct {
00249      *     ECPoint V;
00250      *     opaque r<1..2^8-1>;
00251      * } ECSchnorrZKP;
00252      */
00253     if( end < *p )
00254         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
00255 
00256     MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) );
00257 
00258     if( end < *p || (size_t)( end - *p ) < 1 )
00259     {
00260         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
00261         goto cleanup;
00262     }
00263 
00264     r_len = *(*p)++;
00265 
00266     if( end < *p || (size_t)( end - *p ) < r_len )
00267     {
00268         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
00269         goto cleanup;
00270     }
00271 
00272     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) );
00273     *p += r_len;
00274 
00275     /*
00276      * Verification
00277      */
00278     MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) );
00279     MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp,
00280                      &VV, &h, X, &r, G ) );
00281 
00282     if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 )
00283     {
00284         ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
00285         goto cleanup;
00286     }
00287 
00288 cleanup:
00289     mbedtls_ecp_point_free( &V );
00290     mbedtls_ecp_point_free( &VV );
00291     mbedtls_mpi_free( &r );
00292     mbedtls_mpi_free( &h );
00293 
00294     return( ret );
00295 }
00296 
00297 /*
00298  * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
00299  */
00300 static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info,
00301                               const mbedtls_ecp_group *grp,
00302                               const int pf, 
00303                               const mbedtls_ecp_point *G,
00304                               const mbedtls_mpi *x,
00305                               const mbedtls_ecp_point *X,
00306                               const char *id,
00307                               unsigned char **p,
00308                               const unsigned char *end,
00309                               int (*f_rng)(void *, unsigned char *, size_t),
00310                               void *p_rng )
00311 {
00312     int ret;
00313     mbedtls_ecp_point V;
00314     mbedtls_mpi v;
00315     mbedtls_mpi h; /* later recycled to hold r */
00316     size_t len;
00317 
00318     if( end < *p )
00319         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
00320 
00321     mbedtls_ecp_point_init( &V );
00322     mbedtls_mpi_init( &v );
00323     mbedtls_mpi_init( &h );
00324 
00325     /* Compute signature */
00326     MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp,
00327                                                    G, &v, &V, f_rng, p_rng ) );
00328     MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) );
00329     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */
00330     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */
00331     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N  ) ); /* r */
00332 
00333     /* Write it out */
00334     MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V,
00335                 pf, &len, *p, end - *p ) );
00336     *p += len;
00337 
00338     len = mbedtls_mpi_size( &h ); /* actually r */
00339     if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 )
00340     {
00341         ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
00342         goto cleanup;
00343     }
00344 
00345     *(*p)++ = (unsigned char)( len & 0xFF );
00346     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */
00347     *p += len;
00348 
00349 cleanup:
00350     mbedtls_ecp_point_free( &V );
00351     mbedtls_mpi_free( &v );
00352     mbedtls_mpi_free( &h );
00353 
00354     return( ret );
00355 }
00356 
00357 /*
00358  * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
00359  * Output: verified public key X
00360  */
00361 static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info,
00362                              const mbedtls_ecp_group *grp,
00363                              const int pf,
00364                              const mbedtls_ecp_point *G,
00365                              mbedtls_ecp_point *X,
00366                              const char *id,
00367                              const unsigned char **p,
00368                              const unsigned char *end )
00369 {
00370     int ret;
00371 
00372     if( end < *p )
00373         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
00374 
00375     /*
00376      * struct {
00377      *     ECPoint X;
00378      *     ECSchnorrZKP zkp;
00379      * } ECJPAKEKeyKP;
00380      */
00381     MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) );
00382     if( mbedtls_ecp_is_zero( X ) )
00383     {
00384         ret = MBEDTLS_ERR_ECP_INVALID_KEY;
00385         goto cleanup;
00386     }
00387 
00388     MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, pf, G, X, id, p, end ) );
00389 
00390 cleanup:
00391     return( ret );
00392 }
00393 
00394 /*
00395  * Generate an ECJPAKEKeyKP
00396  * Output: the serialized structure, plus private/public key pair
00397  */
00398 static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info,
00399                               const mbedtls_ecp_group *grp,
00400                               const int pf,
00401                               const mbedtls_ecp_point *G,
00402                               mbedtls_mpi *x,
00403                               mbedtls_ecp_point *X,
00404                               const char *id,
00405                               unsigned char **p,
00406                               const unsigned char *end,
00407                               int (*f_rng)(void *, unsigned char *, size_t),
00408                               void *p_rng )
00409 {
00410     int ret;
00411     size_t len;
00412 
00413     if( end < *p )
00414         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
00415 
00416     /* Generate key (7.4.2.3.1) and write it out */
00417     MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X,
00418                                                    f_rng, p_rng ) );
00419     MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X,
00420                 pf, &len, *p, end - *p ) );
00421     *p += len;
00422 
00423     /* Generate and write proof */
00424     MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, pf, G, x, X, id,
00425                                         p, end, f_rng, p_rng ) );
00426 
00427 cleanup:
00428     return( ret );
00429 }
00430 
00431 /*
00432  * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
00433  * Ouputs: verified peer public keys Xa, Xb
00434  */
00435 static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info,
00436                               const mbedtls_ecp_group *grp,
00437                               const int pf,
00438                               const mbedtls_ecp_point *G,
00439                               mbedtls_ecp_point *Xa,
00440                               mbedtls_ecp_point *Xb,
00441                               const char *id,
00442                               const unsigned char *buf,
00443                               size_t len )
00444 {
00445     int ret;
00446     const unsigned char *p = buf;
00447     const unsigned char *end = buf + len;
00448 
00449     /*
00450      * struct {
00451      *     ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
00452      * } ECJPAKEKeyKPPairList;
00453      */
00454     MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xa, id, &p, end ) );
00455     MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xb, id, &p, end ) );
00456 
00457     if( p != end )
00458         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
00459 
00460 cleanup:
00461     return( ret );
00462 }
00463 
00464 /*
00465  * Generate a ECJPAKEKeyKPPairList
00466  * Outputs: the serialized structure, plus two private/public key pairs
00467  */
00468 static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info,
00469                                const mbedtls_ecp_group *grp,
00470                                const int pf,
00471                                const mbedtls_ecp_point *G,
00472                                mbedtls_mpi *xm1,
00473                                mbedtls_ecp_point *Xa,
00474                                mbedtls_mpi *xm2,
00475                                mbedtls_ecp_point *Xb,
00476                                const char *id,
00477                                unsigned char *buf,
00478                                size_t len,
00479                                size_t *olen,
00480                                int (*f_rng)(void *, unsigned char *, size_t),
00481                                void *p_rng )
00482 {
00483     int ret;
00484     unsigned char *p = buf;
00485     const unsigned char *end = buf + len;
00486 
00487     MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm1, Xa, id,
00488                 &p, end, f_rng, p_rng ) );
00489     MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm2, Xb, id,
00490                 &p, end, f_rng, p_rng ) );
00491 
00492     *olen = p - buf;
00493 
00494 cleanup:
00495     return( ret );
00496 }
00497 
00498 /*
00499  * Read and process the first round message
00500  */
00501 int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx,
00502                                     const unsigned char *buf,
00503                                     size_t len )
00504 {
00505     return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format,
00506                                &ctx->grp.G ,
00507                                &ctx->Xp1, &ctx->Xp2, ID_PEER,
00508                                buf, len ) );
00509 }
00510 
00511 /*
00512  * Generate and write the first round message
00513  */
00514 int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx,
00515                             unsigned char *buf, size_t len, size_t *olen,
00516                             int (*f_rng)(void *, unsigned char *, size_t),
00517                             void *p_rng )
00518 {
00519     return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format,
00520                                 &ctx->grp.G ,
00521                                 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
00522                                 ID_MINE, buf, len, olen, f_rng, p_rng ) );
00523 }
00524 
00525 /*
00526  * Compute the sum of three points R = A + B + C
00527  */
00528 static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
00529                              const mbedtls_ecp_point *A,
00530                              const mbedtls_ecp_point *B,
00531                              const mbedtls_ecp_point *C )
00532 {
00533     int ret;
00534     mbedtls_mpi one;
00535 
00536     mbedtls_mpi_init( &one );
00537 
00538     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
00539     MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) );
00540     MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) );
00541 
00542 cleanup:
00543     mbedtls_mpi_free( &one );
00544 
00545     return( ret );
00546 }
00547 
00548 /*
00549  * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
00550  */
00551 int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx,
00552                                             const unsigned char *buf,
00553                                             size_t len )
00554 {
00555     int ret;
00556     const unsigned char *p = buf;
00557     const unsigned char *end = buf + len;
00558     mbedtls_ecp_group grp;
00559     mbedtls_ecp_point G;    /* C: GB, S: GA */
00560 
00561     mbedtls_ecp_group_init( &grp );
00562     mbedtls_ecp_point_init( &G );
00563 
00564     /*
00565      * Server: GA = X3  + X4  + X1      (7.4.2.6.1)
00566      * Client: GB = X1  + X2  + X3      (7.4.2.5.1)
00567      * Unified: G = Xm1 + Xm2 + Xp1
00568      * We need that before parsing in order to check Xp as we read it
00569      */
00570     MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
00571                                        &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) );
00572 
00573     /*
00574      * struct {
00575      *     ECParameters curve_params;   // only client reading server msg
00576      *     ECJPAKEKeyKP ecjpake_key_kp;
00577      * } Client/ServerECJPAKEParams;
00578      */
00579     if( ctx->role == MBEDTLS_ECJPAKE_CLIENT )
00580     {
00581         MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) );
00582         if( grp.id  != ctx->grp.id  )
00583         {
00584             ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
00585             goto cleanup;
00586         }
00587     }
00588 
00589     MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp,
00590                             ctx->point_format,
00591                             &G, &ctx->Xp, ID_PEER, &p, end ) );
00592 
00593     if( p != end )
00594     {
00595         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
00596         goto cleanup;
00597     }
00598 
00599 cleanup:
00600     mbedtls_ecp_group_free( &grp );
00601     mbedtls_ecp_point_free( &G );
00602 
00603     return( ret );
00604 }
00605 
00606 /*
00607  * Compute R = +/- X * S mod N, taking care not to leak S
00608  */
00609 static int ecjpake_mul_secret( mbedtls_mpi *R, int sign,
00610                                const mbedtls_mpi *X,
00611                                const mbedtls_mpi *S,
00612                                const mbedtls_mpi *N,
00613                                int (*f_rng)(void *, unsigned char *, size_t),
00614                                void *p_rng )
00615 {
00616     int ret;
00617     mbedtls_mpi b; /* Blinding value, then s + N * blinding */
00618 
00619     mbedtls_mpi_init( &b );
00620 
00621     /* b = s + rnd-128-bit * N */
00622     MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &b, 16, f_rng, p_rng ) );
00623     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &b, &b, N ) );
00624     MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &b, &b, S ) );
00625 
00626     /* R = sign * X * b mod N */
00627     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( R, X, &b ) );
00628     R->s  *= sign;
00629     MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( R, R, N ) );
00630 
00631 cleanup:
00632     mbedtls_mpi_free( &b );
00633 
00634     return( ret );
00635 }
00636 
00637 /*
00638  * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
00639  */
00640 int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx,
00641                             unsigned char *buf, size_t len, size_t *olen,
00642                             int (*f_rng)(void *, unsigned char *, size_t),
00643                             void *p_rng )
00644 {
00645     int ret;
00646     mbedtls_ecp_point G;    /* C: GA, S: GB */
00647     mbedtls_ecp_point Xm;   /* C: Xc, S: Xs */
00648     mbedtls_mpi xm;         /* C: xc, S: xs */
00649     unsigned char *p = buf;
00650     const unsigned char *end = buf + len;
00651     size_t ec_len;
00652 
00653     mbedtls_ecp_point_init( &G );
00654     mbedtls_ecp_point_init( &Xm );
00655     mbedtls_mpi_init( &xm );
00656 
00657     /*
00658      * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
00659      *
00660      * Client:  GA = X1  + X3  + X4  | xs = x2  * s | Xc = xc * GA
00661      * Server:  GB = X3  + X1  + X2  | xs = x4  * s | Xs = xs * GB
00662      * Unified: G  = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
00663      */
00664     MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
00665                                        &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) );
00666     MBEDTLS_MPI_CHK( ecjpake_mul_secret( &xm, 1, &ctx->xm2, &ctx->s,
00667                                          &ctx->grp.N , f_rng, p_rng ) );
00668     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) );
00669 
00670     /*
00671      * Now write things out
00672      *
00673      * struct {
00674      *     ECParameters curve_params;   // only server writing its message
00675      *     ECJPAKEKeyKP ecjpake_key_kp;
00676      * } Client/ServerECJPAKEParams;
00677      */
00678     if( ctx->role == MBEDTLS_ECJPAKE_SERVER )
00679     {
00680         if( end < p )
00681         {
00682             ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
00683             goto cleanup;
00684         }
00685         MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len,
00686                                                       p, end - p ) );
00687         p += ec_len;
00688     }
00689 
00690     if( end < p )
00691     {
00692         ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
00693         goto cleanup;
00694     }
00695     MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm,
00696                      ctx->point_format, &ec_len, p, end - p ) );
00697     p += ec_len;
00698 
00699     MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp,
00700                                         ctx->point_format,
00701                                         &G, &xm, &Xm, ID_MINE,
00702                                         &p, end, f_rng, p_rng ) );
00703 
00704     *olen = p - buf;
00705 
00706 cleanup:
00707     mbedtls_ecp_point_free( &G );
00708     mbedtls_ecp_point_free( &Xm );
00709     mbedtls_mpi_free( &xm );
00710 
00711     return( ret );
00712 }
00713 
00714 /*
00715  * Derive PMS (7.4.2.7 / 7.4.2.8)
00716  */
00717 int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx,
00718                             unsigned char *buf, size_t len, size_t *olen,
00719                             int (*f_rng)(void *, unsigned char *, size_t),
00720                             void *p_rng )
00721 {
00722     int ret;
00723     mbedtls_ecp_point K;
00724     mbedtls_mpi m_xm2_s, one;
00725     unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
00726     size_t x_bytes;
00727 
00728     *olen = mbedtls_md_get_size( ctx->md_info );
00729     if( len < *olen )
00730         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
00731 
00732     mbedtls_ecp_point_init( &K );
00733     mbedtls_mpi_init( &m_xm2_s );
00734     mbedtls_mpi_init( &one );
00735 
00736     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
00737 
00738     /*
00739      * Client:  K = ( Xs - X4  * x2  * s ) * x2
00740      * Server:  K = ( Xc - X2  * x4  * s ) * x4
00741      * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
00742      */
00743     MBEDTLS_MPI_CHK( ecjpake_mul_secret( &m_xm2_s, -1, &ctx->xm2, &ctx->s,
00744                                          &ctx->grp.N , f_rng, p_rng ) );
00745     MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K,
00746                                          &one, &ctx->Xp,
00747                                          &m_xm2_s, &ctx->Xp2 ) );
00748     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K,
00749                                       f_rng, p_rng ) );
00750 
00751     /* PMS = SHA-256( K.X ) */
00752     x_bytes = ( ctx->grp.pbits  + 7 ) / 8;
00753     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X , kx, x_bytes ) );
00754     MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) );
00755 
00756 cleanup:
00757     mbedtls_ecp_point_free( &K );
00758     mbedtls_mpi_free( &m_xm2_s );
00759     mbedtls_mpi_free( &one );
00760 
00761     return( ret );
00762 }
00763 
00764 #undef ID_MINE
00765 #undef ID_PEER
00766 
00767 
00768 #if defined(MBEDTLS_SELF_TEST)
00769 
00770 #if defined(MBEDTLS_PLATFORM_C)
00771 #include "mbedtls/platform.h"
00772 #else
00773 #include <stdio.h>
00774 #define mbedtls_printf     printf
00775 #endif
00776 
00777 #if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
00778     !defined(MBEDTLS_SHA256_C)
00779 int mbedtls_ecjpake_self_test( int verbose )
00780 {
00781     (void) verbose;
00782     return( 0 );
00783 }
00784 #else
00785 
00786 static const unsigned char ecjpake_test_password[] = {
00787     0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
00788     0x65, 0x73, 0x74
00789 };
00790 
00791 static const unsigned char ecjpake_test_x1[] = {
00792     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
00793     0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
00794     0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
00795 };
00796 
00797 static const unsigned char ecjpake_test_x2[] = {
00798     0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
00799     0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
00800     0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
00801 };
00802 
00803 static const unsigned char ecjpake_test_x3[] = {
00804     0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
00805     0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
00806     0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
00807 };
00808 
00809 static const unsigned char ecjpake_test_x4[] = {
00810     0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
00811     0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
00812     0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
00813 };
00814 
00815 static const unsigned char ecjpake_test_cli_one[] = {
00816     0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
00817     0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
00818     0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
00819     0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
00820     0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
00821     0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
00822     0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
00823     0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
00824     0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
00825     0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
00826     0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
00827     0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
00828     0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
00829     0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
00830     0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
00831     0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
00832     0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
00833     0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
00834     0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
00835     0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
00836     0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
00837     0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
00838     0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
00839     0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
00840     0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
00841     0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
00842     0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
00843     0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
00844 };
00845 
00846 static const unsigned char ecjpake_test_srv_one[] = {
00847     0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
00848     0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
00849     0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
00850     0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
00851     0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
00852     0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
00853     0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
00854     0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
00855     0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
00856     0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
00857     0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
00858     0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
00859     0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
00860     0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
00861     0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
00862     0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
00863     0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
00864     0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
00865     0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
00866     0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
00867     0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
00868     0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
00869     0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
00870     0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
00871     0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
00872     0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
00873     0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
00874     0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
00875 };
00876 
00877 static const unsigned char ecjpake_test_srv_two[] = {
00878     0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
00879     0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
00880     0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
00881     0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
00882     0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
00883     0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
00884     0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
00885     0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
00886     0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
00887     0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
00888     0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
00889     0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
00890     0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
00891     0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
00892 };
00893 
00894 static const unsigned char ecjpake_test_cli_two[] = {
00895     0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
00896     0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
00897     0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
00898     0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
00899     0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
00900     0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
00901     0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
00902     0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
00903     0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
00904     0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
00905     0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
00906     0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
00907     0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
00908     0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
00909 };
00910 
00911 static const unsigned char ecjpake_test_pms[] = {
00912     0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
00913     0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
00914     0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
00915 };
00916 
00917 /* Load my private keys and generate the correponding public keys */
00918 static int ecjpake_test_load( mbedtls_ecjpake_context *ctx,
00919                               const unsigned char *xm1, size_t len1,
00920                               const unsigned char *xm2, size_t len2 )
00921 {
00922     int ret;
00923 
00924     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) );
00925     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) );
00926     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1,
00927                                       &ctx->grp.G , NULL, NULL ) );
00928     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2,
00929                                       &ctx->grp.G , NULL, NULL ) );
00930 
00931 cleanup:
00932     return( ret );
00933 }
00934 
00935 /* For tests we don't need a secure RNG;
00936  * use the LGC from Numerical Recipes for simplicity */
00937 static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
00938 {
00939     static uint32_t x = 42;
00940     (void) p;
00941 
00942     while( len > 0 )
00943     {
00944         size_t use_len = len > 4 ? 4 : len;
00945         x = 1664525 * x + 1013904223;
00946         memcpy( out, &x, use_len );
00947         out += use_len;
00948         len -= use_len;
00949     }
00950 
00951     return( 0 );
00952 }
00953 
00954 #define TEST_ASSERT( x )    \
00955     do {                    \
00956         if( x )             \
00957             ret = 0;        \
00958         else                \
00959         {                   \
00960             ret = 1;        \
00961             goto cleanup;   \
00962         }                   \
00963     } while( 0 )
00964 
00965 /*
00966  * Checkup routine
00967  */
00968 int mbedtls_ecjpake_self_test( int verbose )
00969 {
00970     int ret;
00971     mbedtls_ecjpake_context cli;
00972     mbedtls_ecjpake_context srv;
00973     unsigned char buf[512], pms[32];
00974     size_t len, pmslen;
00975 
00976     mbedtls_ecjpake_init( &cli );
00977     mbedtls_ecjpake_init( &srv );
00978 
00979     if( verbose != 0 )
00980         mbedtls_printf( "  ECJPAKE test #0 (setup): " );
00981 
00982     TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT,
00983                     MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1 ,
00984                     ecjpake_test_password,
00985             sizeof( ecjpake_test_password ) ) == 0 );
00986 
00987     TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER,
00988                     MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1 ,
00989                     ecjpake_test_password,
00990             sizeof( ecjpake_test_password ) ) == 0 );
00991 
00992     if( verbose != 0 )
00993         mbedtls_printf( "passed\n" );
00994 
00995     if( verbose != 0 )
00996         mbedtls_printf( "  ECJPAKE test #1 (random handshake): " );
00997 
00998     TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli,
00999                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01000 
01001     TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 );
01002 
01003     TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv,
01004                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01005 
01006     TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 );
01007 
01008     TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv,
01009                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01010 
01011     TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 );
01012 
01013     TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
01014                  pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 );
01015 
01016     TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli,
01017                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01018 
01019     TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 );
01020 
01021     TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
01022                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01023 
01024     TEST_ASSERT( len == pmslen );
01025     TEST_ASSERT( memcmp( buf, pms, len ) == 0 );
01026 
01027     if( verbose != 0 )
01028         mbedtls_printf( "passed\n" );
01029 
01030     if( verbose != 0 )
01031         mbedtls_printf( "  ECJPAKE test #2 (reference handshake): " );
01032 
01033     /* Simulate generation of round one */
01034     MBEDTLS_MPI_CHK( ecjpake_test_load( &cli,
01035                 ecjpake_test_x1, sizeof( ecjpake_test_x1 ),
01036                 ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) );
01037 
01038     MBEDTLS_MPI_CHK( ecjpake_test_load( &srv,
01039                 ecjpake_test_x3, sizeof( ecjpake_test_x3 ),
01040                 ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) );
01041 
01042     /* Read round one */
01043     TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv,
01044                                     ecjpake_test_cli_one,
01045                             sizeof( ecjpake_test_cli_one ) ) == 0 );
01046 
01047     TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli,
01048                                     ecjpake_test_srv_one,
01049                             sizeof( ecjpake_test_srv_one ) ) == 0 );
01050 
01051     /* Skip generation of round two, read round two */
01052     TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli,
01053                                     ecjpake_test_srv_two,
01054                             sizeof( ecjpake_test_srv_two ) ) == 0 );
01055 
01056     TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv,
01057                                     ecjpake_test_cli_two,
01058                             sizeof( ecjpake_test_cli_two ) ) == 0 );
01059 
01060     /* Server derives PMS */
01061     TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
01062                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01063 
01064     TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
01065     TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
01066 
01067     memset( buf, 0, len ); /* Avoid interferences with next step */
01068 
01069     /* Client derives PMS */
01070     TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
01071                  buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
01072 
01073     TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
01074     TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
01075 
01076     if( verbose != 0 )
01077         mbedtls_printf( "passed\n" );
01078 
01079 cleanup:
01080     mbedtls_ecjpake_free( &cli );
01081     mbedtls_ecjpake_free( &srv );
01082 
01083     if( ret != 0 )
01084     {
01085         if( verbose != 0 )
01086             mbedtls_printf( "failed\n" );
01087 
01088         ret = 1;
01089     }
01090 
01091     if( verbose != 0 )
01092         mbedtls_printf( "\n" );
01093 
01094     return( ret );
01095 }
01096 
01097 #undef TEST_ASSERT
01098 
01099 #endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
01100 
01101 #endif /* MBEDTLS_SELF_TEST */
01102 
01103 #endif /* MBEDTLS_ECJPAKE_C */