xref: /optee_os/lib/libmbedtls/mbedtls/library/ecjpake.c (revision 817466cb476de705a8e3dabe1ef165fe27a18c2f)
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