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