blob: 8a8f0e29a03d8e59ea6dcc16a776eb16505d03a6 [file] [log] [blame]
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001/*
2 * Elliptic curve J-PAKE
3 *
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
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 * This file is part of mbed TLS (https://tls.mbed.org)
20 */
21
22/*
Manuel Pégourié-Gonnard6b798b92015-08-14 11:18:30 +020023 * References in the code are to the Thread v1.0 Specification,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +020024 * available to members of the Thread Group http://threadgroup.org/
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020025 */
26
27#if !defined(MBEDTLS_CONFIG_FILE)
28#include "mbedtls/config.h"
29#else
30#include MBEDTLS_CONFIG_FILE
31#endif
32
33#if defined(MBEDTLS_ECJPAKE_C)
34
35#include "mbedtls/ecjpake.h"
36
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020037#include <string.h>
38
39/*
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +020040 * Convert a mbedtls_ecjpake_role to identifier string
41 */
42static const char * const ecjpake_id[] = {
43 "client",
44 "server"
45};
46
47#define ID_MINE ( ecjpake_id[ ctx->role ] )
48#define ID_PEER ( ecjpake_id[ 1 - ctx->role ] )
49
50/*
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020051 * Initialize context
52 */
53void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx )
54{
55 if( ctx == NULL )
56 return;
57
58 ctx->md_info = NULL;
59 mbedtls_ecp_group_init( &ctx->grp );
60
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020061 mbedtls_ecp_point_init( &ctx->Xm1 );
62 mbedtls_ecp_point_init( &ctx->Xm2 );
63 mbedtls_ecp_point_init( &ctx->Xp1 );
64 mbedtls_ecp_point_init( &ctx->Xp2 );
65 mbedtls_ecp_point_init( &ctx->Xp );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020066
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020067 mbedtls_mpi_init( &ctx->xm1 );
68 mbedtls_mpi_init( &ctx->xm2 );
69 mbedtls_mpi_init( &ctx->s );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020070}
71
72/*
73 * Free context
74 */
75void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx )
76{
77 if( ctx == NULL )
78 return;
79
80 ctx->md_info = NULL;
81 mbedtls_ecp_group_free( &ctx->grp );
82
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020083 mbedtls_ecp_point_free( &ctx->Xm1 );
84 mbedtls_ecp_point_free( &ctx->Xm2 );
85 mbedtls_ecp_point_free( &ctx->Xp1 );
86 mbedtls_ecp_point_free( &ctx->Xp2 );
87 mbedtls_ecp_point_free( &ctx->Xp );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020088
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020089 mbedtls_mpi_free( &ctx->xm1 );
90 mbedtls_mpi_free( &ctx->xm2 );
91 mbedtls_mpi_free( &ctx->s );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020092}
93
94/*
95 * Setup context
96 */
97int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +020098 mbedtls_ecjpake_role role,
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020099 mbedtls_md_type_t hash,
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200100 mbedtls_ecp_group_id curve,
101 const unsigned char *secret,
102 size_t len )
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200103{
104 int ret;
105
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200106 ctx->role = role;
107
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200108 if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL )
109 return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE );
110
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200111 MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, curve ) );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200112
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200113 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->s, secret, len ) );
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200114
115cleanup:
116 if( ret != 0 )
117 mbedtls_ecjpake_free( ctx );
118
119 return( ret );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200120}
121
122/*
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200123 * Write a point plus its length to a buffer
124 */
125static int ecjpake_write_len_point( unsigned char **p,
126 const unsigned char *end,
127 const mbedtls_ecp_group *grp,
128 const mbedtls_ecp_point *P )
129{
130 int ret;
131 size_t len;
132
133 /* Need at least 4 for length plus 1 for point */
134 if( end < *p || end - *p < 5 )
135 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
136
137 ret = mbedtls_ecp_point_write_binary( grp, P, MBEDTLS_ECP_PF_UNCOMPRESSED,
138 &len, *p + 4, end - ( *p + 4 ) );
139 if( ret != 0 )
140 return( ret );
141
142 (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF );
143 (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF );
144 (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF );
145 (*p)[3] = (unsigned char)( ( len ) & 0xFF );
146
147 *p += 4 + len;
148
149 return( 0 );
150}
151
152/*
153 * Size of the temporary buffer for ecjpake_hash:
154 * 3 EC points plus their length, plus ID (6 bytes)
155 */
156#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 6 )
157
158/*
159 * Compute hash for ZKP (7.4.2.2.2.1)
160 */
161static int ecjpake_hash( const mbedtls_md_info_t *md_info,
162 const mbedtls_ecp_group *grp,
163 const mbedtls_ecp_point *G,
164 const mbedtls_ecp_point *V,
165 const mbedtls_ecp_point *X,
166 const char *id,
167 mbedtls_mpi *h )
168{
169 int ret;
170 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
171 unsigned char *p = buf;
172 const unsigned char *end = buf + sizeof( buf );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200173 const size_t id_len = strlen( id );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200174 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
175
176 /* Write things to temporary buffer */
177 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, G ) );
178 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, V ) );
179 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, X ) );
180
181 if( end < p || (size_t)( end - p ) < id_len )
182 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
183
184 *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF );
185 *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF );
186 *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF );
187 *p++ = (unsigned char)( ( id_len ) & 0xFF );
188
189 memcpy( p, id, id_len );
190 p += id_len;
191
192 /* Compute hash */
193 mbedtls_md( md_info, buf, p - buf, hash );
194
195 /* Turn it into an integer mod n */
196 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash,
197 mbedtls_md_get_size( md_info ) ) );
198 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) );
199
200cleanup:
201 return( ret );
202}
203
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200204/*
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200205 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
206 */
207static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info,
208 const mbedtls_ecp_group *grp,
209 const mbedtls_ecp_point *G,
210 const mbedtls_ecp_point *X,
211 const char *id,
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200212 const unsigned char **p,
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200213 const unsigned char *end )
214{
215 int ret;
216 mbedtls_ecp_point V, VV;
217 mbedtls_mpi r, h;
218 size_t r_len;
219
220 mbedtls_ecp_point_init( &V );
221 mbedtls_ecp_point_init( &VV );
222 mbedtls_mpi_init( &r );
223 mbedtls_mpi_init( &h );
224
225 /*
226 * struct {
227 * ECPoint V;
228 * opaque r<1..2^8-1>;
229 * } ECSchnorrZKP;
230 */
231 if( end < *p )
232 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
233
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200234 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200235
236 if( end < *p || (size_t)( end - *p ) < 1 )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200237 {
238 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
239 goto cleanup;
240 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200241
242 r_len = *(*p)++;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200243
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200244 if( end < *p || (size_t)( end - *p ) < r_len )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200245 {
246 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
247 goto cleanup;
248 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200249
250 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) );
251 *p += r_len;
252
253 /*
254 * Verification
255 */
256 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
257 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp,
258 &VV, &h, X, &r, G ) );
259
260 if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200261 {
262 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
263 goto cleanup;
264 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200265
266cleanup:
267 mbedtls_ecp_point_free( &V );
268 mbedtls_ecp_point_free( &VV );
269 mbedtls_mpi_free( &r );
270 mbedtls_mpi_free( &h );
271
272 return( ret );
273}
274
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200275/*
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200276 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
277 */
278static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info,
279 const mbedtls_ecp_group *grp,
280 const mbedtls_ecp_point *G,
281 const mbedtls_mpi *x,
282 const mbedtls_ecp_point *X,
283 const char *id,
284 unsigned char **p,
285 const unsigned char *end,
286 int (*f_rng)(void *, unsigned char *, size_t),
287 void *p_rng )
288{
289 int ret;
290 mbedtls_ecp_point V;
291 mbedtls_mpi v;
292 mbedtls_mpi h; /* later recycled to hold r */
293 size_t len;
294
295 if( end < *p )
296 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
297
298 mbedtls_ecp_point_init( &V );
299 mbedtls_mpi_init( &v );
300 mbedtls_mpi_init( &h );
301
302 /* Compute signature */
303 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp,
304 G, &v, &V, f_rng, p_rng ) );
305 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
306 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */
307 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */
308 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */
309
310 /* Write it out */
311 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V,
312 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
313 *p += len;
314
315 len = mbedtls_mpi_size( &h ); /* actually r */
316 if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 )
317 {
318 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
319 goto cleanup;
320 }
321
322 *(*p)++ = (unsigned char)( len & 0xFF );
323 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */
324 *p += len;
325
326cleanup:
327 mbedtls_ecp_point_free( &V );
328 mbedtls_mpi_free( &v );
329 mbedtls_mpi_free( &h );
330
331 return( ret );
332}
333
334/*
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200335 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
336 * Output: verified public key X
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200337 */
338static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info,
339 const mbedtls_ecp_group *grp,
340 const mbedtls_ecp_point *G,
341 mbedtls_ecp_point *X,
342 const char *id,
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200343 const unsigned char **p,
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200344 const unsigned char *end )
345{
346 int ret;
347
348 if( end < *p )
349 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
350
351 /*
352 * struct {
353 * ECPoint X;
354 * ECSchnorrZKP zkp;
355 * } ECJPAKEKeyKP;
356 */
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200357 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) );
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200358 MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, G, X, id, p, end ) );
359
360cleanup:
361 return( ret );
362}
363
364/*
365 * Generate an ECJPAKEKeyKP
366 * Output: the serialized structure, plus private/public key pair
367 */
368static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info,
369 const mbedtls_ecp_group *grp,
370 const mbedtls_ecp_point *G,
371 mbedtls_mpi *x,
372 mbedtls_ecp_point *X,
373 const char *id,
374 unsigned char **p,
375 const unsigned char *end,
376 int (*f_rng)(void *, unsigned char *, size_t),
377 void *p_rng )
378{
379 int ret;
380 size_t len;
381
382 if( end < *p )
383 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
384
385 /* Generate key (7.4.2.3.1) and write it out */
386 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X,
387 f_rng, p_rng ) );
388 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X,
389 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
390 *p += len;
391
392 /* Generate and write proof */
393 MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, G, x, X, id,
394 p, end, f_rng, p_rng ) );
395
396cleanup:
397 return( ret );
398}
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200399
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200400/*
401 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
402 * Ouputs: verified peer public keys Xa, Xb
403 */
404static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info,
405 const mbedtls_ecp_group *grp,
406 const mbedtls_ecp_point *G,
407 mbedtls_ecp_point *Xa,
408 mbedtls_ecp_point *Xb,
409 const char *id,
410 const unsigned char *buf,
411 size_t len )
412{
413 int ret;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200414 const unsigned char *p = buf;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200415 const unsigned char *end = buf + len;
416
417 /*
418 * struct {
419 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
420 * } ECJPAKEKeyKPPairList;
421 */
422 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, G, Xa, id, &p, end ) );
423 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, G, Xb, id, &p, end ) );
424
425 if( p != end )
426 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
427
428cleanup:
429 return( ret );
430}
431
432/*
433 * Generate a ECJPAKEKeyKPPairList
434 * Outputs: the serialized structure, plus two private/public key pairs
435 */
436static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info,
437 const mbedtls_ecp_group *grp,
438 const mbedtls_ecp_point *G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200439 mbedtls_mpi *xm1,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200440 mbedtls_ecp_point *Xa,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200441 mbedtls_mpi *xm2,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200442 mbedtls_ecp_point *Xb,
443 const char *id,
444 unsigned char *buf,
445 size_t len,
446 size_t *olen,
447 int (*f_rng)(void *, unsigned char *, size_t),
448 void *p_rng )
449{
450 int ret;
451 unsigned char *p = buf;
452 const unsigned char *end = buf + len;
453
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200454 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, G, xm1, Xa, id,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200455 &p, end, f_rng, p_rng ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200456 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, G, xm2, Xb, id,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200457 &p, end, f_rng, p_rng ) );
458
459 *olen = p - buf;
460
461cleanup:
462 return( ret );
463}
464
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200465/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200466 * Read and process the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200467 */
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200468int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx,
469 const unsigned char *buf,
470 size_t len )
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200471{
472 return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200473 &ctx->Xp1, &ctx->Xp2, ID_PEER,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200474 buf, len ) );
475}
476
477/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200478 * Generate and write the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200479 */
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200480int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200481 unsigned char *buf, size_t len, size_t *olen,
482 int (*f_rng)(void *, unsigned char *, size_t),
483 void *p_rng )
484{
485 return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200486 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200487 ID_MINE, buf, len, olen, f_rng, p_rng ) );
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200488}
489
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200490/*
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200491 * Compute the sum of three points R = A + B + C
492 */
493static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
494 const mbedtls_ecp_point *A,
495 const mbedtls_ecp_point *B,
496 const mbedtls_ecp_point *C )
497{
498 int ret;
499 mbedtls_mpi one;
500
501 mbedtls_mpi_init( &one );
502
503 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
504 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) );
505 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) );
506
507cleanup:
508 mbedtls_mpi_free( &one );
509
510 return( ret );
511}
512
513/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200514 * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6)
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200515 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200516int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200517 const unsigned char *buf,
518 size_t len )
519{
520 int ret;
521 const unsigned char *p = buf;
522 const unsigned char *end = buf + len;
523 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200524 mbedtls_ecp_point G; /* C: GB, S: GA */
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200525
526 mbedtls_ecp_group_init( &grp );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200527 mbedtls_ecp_point_init( &G );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200528
529 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200530 * Server: GA = X3 + X4 + X1 (7.4.2.6.1)
531 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
532 * Unified: G = Xm1 + Xm2 + Xp1
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200533 * We need that before parsing in order to check Xp as we read it
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200534 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200535 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200536 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200537
538 /*
539 * struct {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200540 * ECParameters curve_params; // only client reading server msg
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200541 * ECJPAKEKeyKP ecjpake_key_kp;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200542 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200543 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200544 if( ctx->role == MBEDTLS_ECJPAKE_CLIENT )
545 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200546 MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200547 &G, &ctx->Xp, ID_PEER, &p, end ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200548
549 if( p != end )
550 {
551 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
552 goto cleanup;
553 }
554
555 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200556 * Xs already checked, only thing left to check is the group,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200557 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200558 if( ctx->role == MBEDTLS_ECJPAKE_CLIENT && grp.id != ctx->grp.id )
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200559 {
560 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
561 goto cleanup;
562 }
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200563cleanup:
564 mbedtls_ecp_group_free( &grp );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200565 mbedtls_ecp_point_free( &G );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200566
567 return( ret );
568}
569
570/*
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200571 * Compute R = +/- X * S mod N, taking care not to leak S
572 */
573static int ecjpake_mul_secret( mbedtls_mpi *R, int sign,
574 const mbedtls_mpi *X,
575 const mbedtls_mpi *S,
576 const mbedtls_mpi *N,
577 int (*f_rng)(void *, unsigned char *, size_t),
578 void *p_rng )
579{
580 int ret;
581 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
582
583 mbedtls_mpi_init( &b );
584
585 /* b = s + rnd-128-bit * N */
586 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &b, 16, f_rng, p_rng ) );
587 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &b, &b, N ) );
588 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &b, &b, S ) );
589
590 /* R = sign * X * b mod N */
591 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( R, X, &b ) );
592 R->s *= sign;
593 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( R, R, N ) );
594
595cleanup:
596 mbedtls_mpi_free( &b );
597
598 return( ret );
599}
600
601/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200602 * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200603 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200604int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200605 unsigned char *buf, size_t len, size_t *olen,
606 int (*f_rng)(void *, unsigned char *, size_t),
607 void *p_rng )
608{
609 int ret;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200610 mbedtls_ecp_point G; /* C: GA, S: GB */
611 mbedtls_ecp_point Xm; /* C: Xc, S: Xs */
612 mbedtls_mpi xm; /* C: xc, S: xs */
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200613 unsigned char *p = buf;
614 const unsigned char *end = buf + len;
615 size_t ec_len;
616
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200617 mbedtls_ecp_point_init( &G );
618 mbedtls_ecp_point_init( &Xm );
619 mbedtls_mpi_init( &xm );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200620
621 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200622 * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1)
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200623 *
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200624 * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA
625 * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB
626 * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200627 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200628 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200629 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) );
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200630 MBEDTLS_MPI_CHK( ecjpake_mul_secret( &xm, 1, &ctx->xm2, &ctx->s,
631 &ctx->grp.N, f_rng, p_rng ) );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200632 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200633
634 /*
635 * Now write things out
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200636 *
637 * struct {
638 * ECParameters curve_params; // only server writing its message
639 * ECJPAKEKeyKP ecjpake_key_kp;
640 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200641 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200642 if( ctx->role == MBEDTLS_ECJPAKE_SERVER )
643 {
644 if( end < p )
645 {
646 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
647 goto cleanup;
648 }
649 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len,
650 p, end - p ) );
651 p += ec_len;
652 }
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200653
654 if( end < p )
655 {
656 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
657 goto cleanup;
658 }
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200659 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200660 MBEDTLS_ECP_PF_UNCOMPRESSED, &ec_len, p, end - p ) );
661 p += ec_len;
662
663 MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200664 &G, &xm, &Xm, ID_MINE,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200665 &p, end, f_rng, p_rng ) );
666
667 *olen = p - buf;
668
669cleanup:
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200670 mbedtls_ecp_point_free( &G );
671 mbedtls_ecp_point_free( &Xm );
672 mbedtls_mpi_free( &xm );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200673
674 return( ret );
675}
676
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200677/*
678 * Derive PMS (7.4.2.7 / 7.4.2.8)
679 */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200680int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200681 unsigned char *buf, size_t len, size_t *olen,
682 int (*f_rng)(void *, unsigned char *, size_t),
683 void *p_rng )
684{
685 int ret;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200686 mbedtls_ecp_point K;
687 mbedtls_mpi m_xm2_s, one;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200688 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
689 size_t x_bytes;
690
691 *olen = mbedtls_md_get_size( ctx->md_info );
692 if( len < *olen )
693 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
694
695 mbedtls_ecp_point_init( &K );
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200696 mbedtls_mpi_init( &m_xm2_s );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200697 mbedtls_mpi_init( &one );
698
699 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200700
701 /*
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200702 * Client: K = ( Xs - X4 * x2 * s ) * x2
703 * Server: K = ( Xc - X2 * x4 * s ) * x4
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200704 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200705 */
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200706 MBEDTLS_MPI_CHK( ecjpake_mul_secret( &m_xm2_s, -1, &ctx->xm2, &ctx->s,
707 &ctx->grp.N, f_rng, p_rng ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200708 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K,
709 &one, &ctx->Xp,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200710 &m_xm2_s, &ctx->Xp2 ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200711 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200712 f_rng, p_rng ) );
713
714 /* PMS = SHA-256( K.X ) */
715 x_bytes = ( ctx->grp.pbits + 7 ) / 8;
716 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) );
717 MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) );
718
719cleanup:
720 mbedtls_ecp_point_free( &K );
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200721 mbedtls_mpi_free( &m_xm2_s );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200722 mbedtls_mpi_free( &one );
723
724 return( ret );
725}
726
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200727#undef ID_MINE
728#undef ID_PEER
729
730
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200731#if defined(MBEDTLS_SELF_TEST)
732
733#if defined(MBEDTLS_PLATFORM_C)
734#include "mbedtls/platform.h"
735#else
736#include <stdio.h>
737#define mbedtls_printf printf
738#endif
739
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200740#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
741 !defined(MBEDTLS_SHA256_C)
742int mbedtls_ecjpake_self_test( int verbose )
743{
744 (void) verbose;
745 return( 0 );
746}
747#else
748
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200749static const unsigned char ecjpake_test_password[] = {
750 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
751 0x65, 0x73, 0x74
752};
753
754static const unsigned char ecjpake_test_x1[] = {
755 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
756 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
757 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
758};
759
760static const unsigned char ecjpake_test_x2[] = {
761 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
762 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
763 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
764};
765
766static const unsigned char ecjpake_test_x3[] = {
767 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
768 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
769 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
770};
771
772static const unsigned char ecjpake_test_x4[] = {
773 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
774 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
775 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
776};
777
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200778static const unsigned char ecjpake_test_cli_one[] = {
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200779 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
780 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
781 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
782 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
783 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
784 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
785 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
786 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
787 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
788 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
789 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
790 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
791 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200792 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
793 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
794 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
795 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
796 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
797 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
798 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
799 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
800 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
801 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
802 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
803 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
804 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
805 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
806 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200807};
808
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200809static const unsigned char ecjpake_test_srv_one[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200810 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
811 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
812 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
813 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
814 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
815 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
816 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
817 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
818 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
819 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
820 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
821 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
822 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
823 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
824 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
825 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
826 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
827 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
828 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
829 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
830 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
831 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
832 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
833 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
834 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
835 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
836 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
837 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
838};
839
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200840static const unsigned char ecjpake_test_srv_two[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200841 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
842 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
843 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
844 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
845 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
846 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
847 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
848 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
849 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
850 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
851 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
852 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
853 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
854 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
855};
856
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200857static const unsigned char ecjpake_test_cli_two[] = {
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200858 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
859 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
860 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
861 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
862 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
863 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
864 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
865 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
866 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
867 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
868 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
869 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
870 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
871 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
872};
873
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200874static const unsigned char ecjpake_test_pms[] = {
875 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
876 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
877 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
878};
879
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200880/* Load my private keys and generate the correponding public keys */
881static int ecjpake_test_load( mbedtls_ecjpake_context *ctx,
882 const unsigned char *xm1, size_t len1,
883 const unsigned char *xm2, size_t len2 )
884{
885 int ret;
886
887 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) );
888 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) );
889 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1,
890 &ctx->grp.G, NULL, NULL ) );
891 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2,
892 &ctx->grp.G, NULL, NULL ) );
893
894cleanup:
895 return( ret );
896}
897
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200898/* For tests we don't need a secure RNG;
899 * use the LGC from Numerical Recipes for simplicity */
900static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
901{
902 static uint32_t x = 42;
903 (void) p;
904
905 while( len > 0 )
906 {
907 size_t use_len = len > 4 ? 4 : len;
908 x = 1664525 * x + 1013904223;
909 memcpy( out, &x, use_len );
910 out += use_len;
911 len -= use_len;
912 }
913
914 return( 0 );
915}
916
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200917#define TEST_ASSERT( x ) \
918 do { \
919 if( x ) \
920 ret = 0; \
921 else \
922 { \
923 ret = 1; \
924 goto cleanup; \
925 } \
926 } while( 0 )
927
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200928/*
929 * Checkup routine
930 */
931int mbedtls_ecjpake_self_test( int verbose )
932{
933 int ret;
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200934 mbedtls_ecjpake_context cli;
935 mbedtls_ecjpake_context srv;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200936 unsigned char buf[512], pms[32];
937 size_t len, pmslen;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200938
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200939 mbedtls_ecjpake_init( &cli );
940 mbedtls_ecjpake_init( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200941
942 if( verbose != 0 )
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200943 mbedtls_printf( " ECJPAKE test #0 (setup): " );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200944
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200945 TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200946 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
947 ecjpake_test_password,
948 sizeof( ecjpake_test_password ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200949
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200950 TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200951 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
952 ecjpake_test_password,
953 sizeof( ecjpake_test_password ) ) == 0 );
954
955 if( verbose != 0 )
956 mbedtls_printf( "passed\n" );
957
958 if( verbose != 0 )
959 mbedtls_printf( " ECJPAKE test #1 (random handshake): " );
960
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200961 TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200962 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
963
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200964 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200965
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200966 TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200967 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
968
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200969 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200970
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200971 TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200972 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
973
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200974 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200975
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200976 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200977 pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 );
978
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200979 TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli,
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200980 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
981
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200982 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200983
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200984 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200985 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
986
987 TEST_ASSERT( len == pmslen );
988 TEST_ASSERT( memcmp( buf, pms, len ) == 0 );
989
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200990 if( verbose != 0 )
991 mbedtls_printf( "passed\n" );
992
993 if( verbose != 0 )
994 mbedtls_printf( " ECJPAKE test #2 (reference handshake): " );
995
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200996 /* Simulate generation of round one */
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200997 MBEDTLS_MPI_CHK( ecjpake_test_load( &cli,
998 ecjpake_test_x1, sizeof( ecjpake_test_x1 ),
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200999 ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001000
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +02001001 MBEDTLS_MPI_CHK( ecjpake_test_load( &srv,
1002 ecjpake_test_x3, sizeof( ecjpake_test_x3 ),
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001003 ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001004
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001005 /* Read round one */
1006 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv,
1007 ecjpake_test_cli_one,
1008 sizeof( ecjpake_test_cli_one ) ) == 0 );
1009
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +02001010 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001011 ecjpake_test_srv_one,
1012 sizeof( ecjpake_test_srv_one ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001013
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001014 /* Skip generation of round two, read round two */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +02001015 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001016 ecjpake_test_srv_two,
1017 sizeof( ecjpake_test_srv_two ) ) == 0 );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +02001018
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +02001019 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001020 ecjpake_test_cli_two,
1021 sizeof( ecjpake_test_cli_two ) ) == 0 );
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +02001022
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001023 /* Server derives PMS */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +02001024 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001025 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1026
1027 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1028 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1029
1030 memset( buf, 0, len ); /* Avoid interferences with next step */
1031
1032 /* Client derives PMS */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +02001033 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001034 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1035
1036 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1037 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1038
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +02001039 if( verbose != 0 )
1040 mbedtls_printf( "passed\n" );
1041
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001042cleanup:
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001043 mbedtls_ecjpake_free( &cli );
1044 mbedtls_ecjpake_free( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001045
1046 if( ret != 0 )
1047 {
1048 if( verbose != 0 )
1049 mbedtls_printf( "failed\n" );
1050
1051 ret = 1;
1052 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001053
1054 if( verbose != 0 )
1055 mbedtls_printf( "\n" );
1056
1057 return( ret );
1058}
1059
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +02001060#undef TEST_ASSERT
1061
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001062#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1063
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001064#endif /* MBEDTLS_SELF_TEST */
1065
1066#endif /* MBEDTLS_ECJPAKE_C */