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