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