blob: 8aa58477c8f8dcb99fbbf1a4fedd66487947da8b [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 ) );
114 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->s, &ctx->s, &ctx->grp.N ) );
115
116cleanup:
117 if( ret != 0 )
118 mbedtls_ecjpake_free( ctx );
119
120 return( ret );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200121}
122
123/*
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200124 * Write a point plus its length to a buffer
125 */
126static int ecjpake_write_len_point( unsigned char **p,
127 const unsigned char *end,
128 const mbedtls_ecp_group *grp,
129 const mbedtls_ecp_point *P )
130{
131 int ret;
132 size_t len;
133
134 /* Need at least 4 for length plus 1 for point */
135 if( end < *p || end - *p < 5 )
136 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
137
138 ret = mbedtls_ecp_point_write_binary( grp, P, MBEDTLS_ECP_PF_UNCOMPRESSED,
139 &len, *p + 4, end - ( *p + 4 ) );
140 if( ret != 0 )
141 return( ret );
142
143 (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF );
144 (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF );
145 (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF );
146 (*p)[3] = (unsigned char)( ( len ) & 0xFF );
147
148 *p += 4 + len;
149
150 return( 0 );
151}
152
153/*
154 * Size of the temporary buffer for ecjpake_hash:
155 * 3 EC points plus their length, plus ID (6 bytes)
156 */
157#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 6 )
158
159/*
160 * Compute hash for ZKP (7.4.2.2.2.1)
161 */
162static int ecjpake_hash( const mbedtls_md_info_t *md_info,
163 const mbedtls_ecp_group *grp,
164 const mbedtls_ecp_point *G,
165 const mbedtls_ecp_point *V,
166 const mbedtls_ecp_point *X,
167 const char *id,
168 mbedtls_mpi *h )
169{
170 int ret;
171 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
172 unsigned char *p = buf;
173 const unsigned char *end = buf + sizeof( buf );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200174 const size_t id_len = strlen( id );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200175 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
176
177 /* Write things to temporary buffer */
178 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, G ) );
179 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, V ) );
180 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, X ) );
181
182 if( end < p || (size_t)( end - p ) < id_len )
183 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
184
185 *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF );
186 *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF );
187 *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF );
188 *p++ = (unsigned char)( ( id_len ) & 0xFF );
189
190 memcpy( p, id, id_len );
191 p += id_len;
192
193 /* Compute hash */
194 mbedtls_md( md_info, buf, p - buf, hash );
195
196 /* Turn it into an integer mod n */
197 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash,
198 mbedtls_md_get_size( md_info ) ) );
199 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) );
200
201cleanup:
202 return( ret );
203}
204
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200205/*
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200206 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
207 */
208static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info,
209 const mbedtls_ecp_group *grp,
210 const mbedtls_ecp_point *G,
211 const mbedtls_ecp_point *X,
212 const char *id,
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200213 const unsigned char **p,
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200214 const unsigned char *end )
215{
216 int ret;
217 mbedtls_ecp_point V, VV;
218 mbedtls_mpi r, h;
219 size_t r_len;
220
221 mbedtls_ecp_point_init( &V );
222 mbedtls_ecp_point_init( &VV );
223 mbedtls_mpi_init( &r );
224 mbedtls_mpi_init( &h );
225
226 /*
227 * struct {
228 * ECPoint V;
229 * opaque r<1..2^8-1>;
230 * } ECSchnorrZKP;
231 */
232 if( end < *p )
233 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
234
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200235 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200236
237 if( end < *p || (size_t)( end - *p ) < 1 )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200238 {
239 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
240 goto cleanup;
241 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200242
243 r_len = *(*p)++;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200244
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200245 if( end < *p || (size_t)( end - *p ) < r_len )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200246 {
247 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
248 goto cleanup;
249 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200250
251 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) );
252 *p += r_len;
253
254 /*
255 * Verification
256 */
257 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
258 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp,
259 &VV, &h, X, &r, G ) );
260
261 if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200262 {
263 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
264 goto cleanup;
265 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200266
267cleanup:
268 mbedtls_ecp_point_free( &V );
269 mbedtls_ecp_point_free( &VV );
270 mbedtls_mpi_free( &r );
271 mbedtls_mpi_free( &h );
272
273 return( ret );
274}
275
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200276/*
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200277 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
278 */
279static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info,
280 const mbedtls_ecp_group *grp,
281 const mbedtls_ecp_point *G,
282 const mbedtls_mpi *x,
283 const mbedtls_ecp_point *X,
284 const char *id,
285 unsigned char **p,
286 const unsigned char *end,
287 int (*f_rng)(void *, unsigned char *, size_t),
288 void *p_rng )
289{
290 int ret;
291 mbedtls_ecp_point V;
292 mbedtls_mpi v;
293 mbedtls_mpi h; /* later recycled to hold r */
294 size_t len;
295
296 if( end < *p )
297 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
298
299 mbedtls_ecp_point_init( &V );
300 mbedtls_mpi_init( &v );
301 mbedtls_mpi_init( &h );
302
303 /* Compute signature */
304 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp,
305 G, &v, &V, f_rng, p_rng ) );
306 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
307 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */
308 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */
309 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */
310
311 /* Write it out */
312 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V,
313 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
314 *p += len;
315
316 len = mbedtls_mpi_size( &h ); /* actually r */
317 if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 )
318 {
319 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
320 goto cleanup;
321 }
322
323 *(*p)++ = (unsigned char)( len & 0xFF );
324 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */
325 *p += len;
326
327cleanup:
328 mbedtls_ecp_point_free( &V );
329 mbedtls_mpi_free( &v );
330 mbedtls_mpi_free( &h );
331
332 return( ret );
333}
334
335/*
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200336 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
337 * Output: verified public key X
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200338 */
339static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info,
340 const mbedtls_ecp_group *grp,
341 const mbedtls_ecp_point *G,
342 mbedtls_ecp_point *X,
343 const char *id,
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200344 const unsigned char **p,
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200345 const unsigned char *end )
346{
347 int ret;
348
349 if( end < *p )
350 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
351
352 /*
353 * struct {
354 * ECPoint X;
355 * ECSchnorrZKP zkp;
356 * } ECJPAKEKeyKP;
357 */
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200358 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) );
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200359 MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, G, X, id, p, end ) );
360
361cleanup:
362 return( ret );
363}
364
365/*
366 * Generate an ECJPAKEKeyKP
367 * Output: the serialized structure, plus private/public key pair
368 */
369static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info,
370 const mbedtls_ecp_group *grp,
371 const mbedtls_ecp_point *G,
372 mbedtls_mpi *x,
373 mbedtls_ecp_point *X,
374 const char *id,
375 unsigned char **p,
376 const unsigned char *end,
377 int (*f_rng)(void *, unsigned char *, size_t),
378 void *p_rng )
379{
380 int ret;
381 size_t len;
382
383 if( end < *p )
384 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
385
386 /* Generate key (7.4.2.3.1) and write it out */
387 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X,
388 f_rng, p_rng ) );
389 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X,
390 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
391 *p += len;
392
393 /* Generate and write proof */
394 MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, G, x, X, id,
395 p, end, f_rng, p_rng ) );
396
397cleanup:
398 return( ret );
399}
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200400
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200401/*
402 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
403 * Ouputs: verified peer public keys Xa, Xb
404 */
405static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info,
406 const mbedtls_ecp_group *grp,
407 const mbedtls_ecp_point *G,
408 mbedtls_ecp_point *Xa,
409 mbedtls_ecp_point *Xb,
410 const char *id,
411 const unsigned char *buf,
412 size_t len )
413{
414 int ret;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200415 const unsigned char *p = buf;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200416 const unsigned char *end = buf + len;
417
418 /*
419 * struct {
420 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
421 * } ECJPAKEKeyKPPairList;
422 */
423 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, G, Xa, id, &p, end ) );
424 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, G, Xb, id, &p, end ) );
425
426 if( p != end )
427 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
428
429cleanup:
430 return( ret );
431}
432
433/*
434 * Generate a ECJPAKEKeyKPPairList
435 * Outputs: the serialized structure, plus two private/public key pairs
436 */
437static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info,
438 const mbedtls_ecp_group *grp,
439 const mbedtls_ecp_point *G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200440 mbedtls_mpi *xm1,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200441 mbedtls_ecp_point *Xa,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200442 mbedtls_mpi *xm2,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200443 mbedtls_ecp_point *Xb,
444 const char *id,
445 unsigned char *buf,
446 size_t len,
447 size_t *olen,
448 int (*f_rng)(void *, unsigned char *, size_t),
449 void *p_rng )
450{
451 int ret;
452 unsigned char *p = buf;
453 const unsigned char *end = buf + len;
454
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200455 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, G, xm1, Xa, id,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200456 &p, end, f_rng, p_rng ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200457 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, G, xm2, Xb, id,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200458 &p, end, f_rng, p_rng ) );
459
460 *olen = p - buf;
461
462cleanup:
463 return( ret );
464}
465
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200466/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200467 * Read and process the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200468 */
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200469int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx,
470 const unsigned char *buf,
471 size_t len )
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200472{
473 return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200474 &ctx->Xp1, &ctx->Xp2, ID_PEER,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200475 buf, len ) );
476}
477
478/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200479 * Generate and write the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200480 */
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200481int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200482 unsigned char *buf, size_t len, size_t *olen,
483 int (*f_rng)(void *, unsigned char *, size_t),
484 void *p_rng )
485{
486 return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200487 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200488 ID_MINE, buf, len, olen, f_rng, p_rng ) );
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200489}
490
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200491/*
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200492 * Compute the sum of three points R = A + B + C
493 */
494static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
495 const mbedtls_ecp_point *A,
496 const mbedtls_ecp_point *B,
497 const mbedtls_ecp_point *C )
498{
499 int ret;
500 mbedtls_mpi one;
501
502 mbedtls_mpi_init( &one );
503
504 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
505 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) );
506 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) );
507
508cleanup:
509 mbedtls_mpi_free( &one );
510
511 return( ret );
512}
513
514/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200515 * 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 +0200516 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200517int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200518 const unsigned char *buf,
519 size_t len )
520{
521 int ret;
522 const unsigned char *p = buf;
523 const unsigned char *end = buf + len;
524 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200525 mbedtls_ecp_point G; /* C: GB, S: GA */
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200526
527 mbedtls_ecp_group_init( &grp );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200528 mbedtls_ecp_point_init( &G );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200529
530 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200531 * Server: GA = X3 + X4 + X1 (7.4.2.6.1)
532 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
533 * Unified: G = Xm1 + Xm2 + Xp1
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200534 * We need that before parsing in order to check Xp as we read it
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200535 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200536 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200537 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200538
539 /*
540 * struct {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200541 * ECParameters curve_params; // only client reading server msg
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200542 * ECJPAKEKeyKP ecjpake_key_kp;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200543 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200544 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200545 if( ctx->role == MBEDTLS_ECJPAKE_CLIENT )
546 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200547 MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200548 &G, &ctx->Xp, ID_PEER, &p, end ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200549
550 if( p != end )
551 {
552 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
553 goto cleanup;
554 }
555
556 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200557 * Xs already checked, only thing left to check is the group,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200558 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200559 if( ctx->role == MBEDTLS_ECJPAKE_CLIENT && grp.id != ctx->grp.id )
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200560 {
561 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
562 goto cleanup;
563 }
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200564cleanup:
565 mbedtls_ecp_group_free( &grp );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200566 mbedtls_ecp_point_free( &G );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200567
568 return( ret );
569}
570
571/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200572 * 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 +0200573 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200574int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200575 unsigned char *buf, size_t len, size_t *olen,
576 int (*f_rng)(void *, unsigned char *, size_t),
577 void *p_rng )
578{
579 int ret;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200580 mbedtls_ecp_point G; /* C: GA, S: GB */
581 mbedtls_ecp_point Xm; /* C: Xc, S: Xs */
582 mbedtls_mpi xm; /* C: xc, S: xs */
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200583 unsigned char *p = buf;
584 const unsigned char *end = buf + len;
585 size_t ec_len;
586
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200587 mbedtls_ecp_point_init( &G );
588 mbedtls_ecp_point_init( &Xm );
589 mbedtls_mpi_init( &xm );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200590
591 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200592 * 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 +0200593 *
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200594 * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA
595 * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB
596 * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200597 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200598 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200599 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200600 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &xm, &ctx->xm2, &ctx->s ) );
601 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &xm, &xm, &ctx->grp.N ) );
602 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200603
604 /*
605 * Now write things out
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200606 *
607 * struct {
608 * ECParameters curve_params; // only server writing its message
609 * ECJPAKEKeyKP ecjpake_key_kp;
610 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200611 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200612 if( ctx->role == MBEDTLS_ECJPAKE_SERVER )
613 {
614 if( end < p )
615 {
616 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
617 goto cleanup;
618 }
619 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len,
620 p, end - p ) );
621 p += ec_len;
622 }
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200623
624 if( end < p )
625 {
626 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
627 goto cleanup;
628 }
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200629 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200630 MBEDTLS_ECP_PF_UNCOMPRESSED, &ec_len, p, end - p ) );
631 p += ec_len;
632
633 MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200634 &G, &xm, &Xm, ID_MINE,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200635 &p, end, f_rng, p_rng ) );
636
637 *olen = p - buf;
638
639cleanup:
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200640 mbedtls_ecp_point_free( &G );
641 mbedtls_ecp_point_free( &Xm );
642 mbedtls_mpi_free( &xm );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200643
644 return( ret );
645}
646
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200647/*
648 * Derive PMS (7.4.2.7 / 7.4.2.8)
649 */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200650int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200651 unsigned char *buf, size_t len, size_t *olen,
652 int (*f_rng)(void *, unsigned char *, size_t),
653 void *p_rng )
654{
655 int ret;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200656 mbedtls_ecp_point K;
657 mbedtls_mpi m_xm2_s, one;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200658 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
659 size_t x_bytes;
660
661 *olen = mbedtls_md_get_size( ctx->md_info );
662 if( len < *olen )
663 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
664
665 mbedtls_ecp_point_init( &K );
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200666 mbedtls_mpi_init( &m_xm2_s );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200667 mbedtls_mpi_init( &one );
668
669 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200670
671 /*
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200672 * Client: K = ( Xs - X4 * x2 * s ) * x2
673 * Server: K = ( Xc - X2 * x4 * s ) * x4
674 * Unified: K = ( Xp - Xp2 * xm2 * x ) * xm2
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200675 */
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200676 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &m_xm2_s, &ctx->xm2, &ctx->s ) );
677 m_xm2_s.s *= -1;
678 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &m_xm2_s, &m_xm2_s, &ctx->grp.N ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200679
680 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K,
681 &one, &ctx->Xp,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200682 &m_xm2_s, &ctx->Xp2 ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200683 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200684 f_rng, p_rng ) );
685
686 /* PMS = SHA-256( K.X ) */
687 x_bytes = ( ctx->grp.pbits + 7 ) / 8;
688 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) );
689 MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) );
690
691cleanup:
692 mbedtls_ecp_point_free( &K );
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200693 mbedtls_mpi_free( &m_xm2_s );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200694 mbedtls_mpi_free( &one );
695
696 return( ret );
697}
698
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200699#undef ID_MINE
700#undef ID_PEER
701
702
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200703#if defined(MBEDTLS_SELF_TEST)
704
705#if defined(MBEDTLS_PLATFORM_C)
706#include "mbedtls/platform.h"
707#else
708#include <stdio.h>
709#define mbedtls_printf printf
710#endif
711
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200712#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
713 !defined(MBEDTLS_SHA256_C)
714int mbedtls_ecjpake_self_test( int verbose )
715{
716 (void) verbose;
717 return( 0 );
718}
719#else
720
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200721static const unsigned char ecjpake_test_password[] = {
722 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
723 0x65, 0x73, 0x74
724};
725
726static const unsigned char ecjpake_test_x1[] = {
727 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
728 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
729 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
730};
731
732static const unsigned char ecjpake_test_x2[] = {
733 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
734 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
735 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
736};
737
738static const unsigned char ecjpake_test_x3[] = {
739 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
740 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
741 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
742};
743
744static const unsigned char ecjpake_test_x4[] = {
745 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
746 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
747 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
748};
749
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200750static const unsigned char ecjpake_test_cli_one[] = {
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200751 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
752 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
753 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
754 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
755 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
756 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
757 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
758 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
759 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
760 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
761 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
762 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
763 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200764 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
765 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
766 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
767 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
768 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
769 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
770 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
771 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
772 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
773 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
774 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
775 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
776 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
777 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
778 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200779};
780
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200781static const unsigned char ecjpake_test_srv_one[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200782 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
783 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
784 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
785 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
786 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
787 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
788 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
789 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
790 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
791 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
792 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
793 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
794 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
795 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
796 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
797 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
798 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
799 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
800 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
801 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
802 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
803 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
804 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
805 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
806 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
807 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
808 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
809 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
810};
811
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200812static const unsigned char ecjpake_test_srv_two[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200813 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
814 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
815 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
816 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
817 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
818 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
819 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
820 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
821 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
822 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
823 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
824 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
825 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
826 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
827};
828
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200829static const unsigned char ecjpake_test_cli_two[] = {
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200830 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
831 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
832 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
833 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
834 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
835 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
836 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
837 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
838 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
839 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
840 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
841 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
842 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
843 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
844};
845
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200846static const unsigned char ecjpake_test_pms[] = {
847 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
848 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
849 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
850};
851
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200852/* Load my private keys and generate the correponding public keys */
853static int ecjpake_test_load( mbedtls_ecjpake_context *ctx,
854 const unsigned char *xm1, size_t len1,
855 const unsigned char *xm2, size_t len2 )
856{
857 int ret;
858
859 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) );
860 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) );
861 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1,
862 &ctx->grp.G, NULL, NULL ) );
863 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2,
864 &ctx->grp.G, NULL, NULL ) );
865
866cleanup:
867 return( ret );
868}
869
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200870/* For tests we don't need a secure RNG;
871 * use the LGC from Numerical Recipes for simplicity */
872static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
873{
874 static uint32_t x = 42;
875 (void) p;
876
877 while( len > 0 )
878 {
879 size_t use_len = len > 4 ? 4 : len;
880 x = 1664525 * x + 1013904223;
881 memcpy( out, &x, use_len );
882 out += use_len;
883 len -= use_len;
884 }
885
886 return( 0 );
887}
888
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200889#define TEST_ASSERT( x ) \
890 do { \
891 if( x ) \
892 ret = 0; \
893 else \
894 { \
895 ret = 1; \
896 goto cleanup; \
897 } \
898 } while( 0 )
899
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200900/*
901 * Checkup routine
902 */
903int mbedtls_ecjpake_self_test( int verbose )
904{
905 int ret;
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200906 mbedtls_ecjpake_context cli;
907 mbedtls_ecjpake_context srv;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200908 unsigned char buf[512], pms[32];
909 size_t len, pmslen;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200910
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200911 mbedtls_ecjpake_init( &cli );
912 mbedtls_ecjpake_init( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200913
914 if( verbose != 0 )
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200915 mbedtls_printf( " ECJPAKE test #0 (setup): " );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200916
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200917 TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200918 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
919 ecjpake_test_password,
920 sizeof( ecjpake_test_password ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200921
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200922 TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200923 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
924 ecjpake_test_password,
925 sizeof( ecjpake_test_password ) ) == 0 );
926
927 if( verbose != 0 )
928 mbedtls_printf( "passed\n" );
929
930 if( verbose != 0 )
931 mbedtls_printf( " ECJPAKE test #1 (random handshake): " );
932
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200933 TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200934 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
935
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200936 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200937
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200938 TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200939 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
940
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200941 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200942
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200943 TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200944 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
945
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200946 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200947
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200948 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200949 pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 );
950
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200951 TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli,
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200952 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
953
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200954 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200955
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200956 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200957 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
958
959 TEST_ASSERT( len == pmslen );
960 TEST_ASSERT( memcmp( buf, pms, len ) == 0 );
961
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200962 if( verbose != 0 )
963 mbedtls_printf( "passed\n" );
964
965 if( verbose != 0 )
966 mbedtls_printf( " ECJPAKE test #2 (reference handshake): " );
967
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200968 /* Simulate generation of round one */
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200969 MBEDTLS_MPI_CHK( ecjpake_test_load( &cli,
970 ecjpake_test_x1, sizeof( ecjpake_test_x1 ),
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200971 ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200972
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200973 MBEDTLS_MPI_CHK( ecjpake_test_load( &srv,
974 ecjpake_test_x3, sizeof( ecjpake_test_x3 ),
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200975 ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200976
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200977 /* Read round one */
978 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv,
979 ecjpake_test_cli_one,
980 sizeof( ecjpake_test_cli_one ) ) == 0 );
981
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200982 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200983 ecjpake_test_srv_one,
984 sizeof( ecjpake_test_srv_one ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200985
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200986 /* Skip generation of round two, read round two */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200987 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200988 ecjpake_test_srv_two,
989 sizeof( ecjpake_test_srv_two ) ) == 0 );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200990
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200991 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200992 ecjpake_test_cli_two,
993 sizeof( ecjpake_test_cli_two ) ) == 0 );
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200994
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200995 /* Server derives PMS */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200996 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200997 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
998
999 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1000 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1001
1002 memset( buf, 0, len ); /* Avoid interferences with next step */
1003
1004 /* Client derives PMS */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +02001005 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001006 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1007
1008 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1009 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1010
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +02001011 if( verbose != 0 )
1012 mbedtls_printf( "passed\n" );
1013
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001014cleanup:
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001015 mbedtls_ecjpake_free( &cli );
1016 mbedtls_ecjpake_free( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001017
1018 if( ret != 0 )
1019 {
1020 if( verbose != 0 )
1021 mbedtls_printf( "failed\n" );
1022
1023 ret = 1;
1024 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001025
1026 if( verbose != 0 )
1027 mbedtls_printf( "\n" );
1028
1029 return( ret );
1030}
1031
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +02001032#undef TEST_ASSERT
1033
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001034#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1035
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001036#endif /* MBEDTLS_SELF_TEST */
1037
1038#endif /* MBEDTLS_ECJPAKE_C */