blob: 031ec34ce95c7c0d9a712eb62b2785110969bd62 [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,
24 * available from 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/*
467 * Read the contents of the ClientHello extension
468 */
469int mbedtls_ecjpake_tls_read_client_ext( mbedtls_ecjpake_context *ctx,
470 const unsigned char *buf,
471 size_t len )
472{
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/*
479 * Read the contents of the ServerHello extension
480 */
481int mbedtls_ecjpake_tls_read_server_ext( mbedtls_ecjpake_context *ctx,
482 const unsigned char *buf,
483 size_t len )
484{
485 return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200486 &ctx->Xp1, &ctx->Xp2, ID_PEER,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200487 buf, len ) );
488}
489
490/*
491 * Generate the contents of the ClientHello extension
492 */
493int mbedtls_ecjpake_tls_write_client_ext( mbedtls_ecjpake_context *ctx,
494 unsigned char *buf, size_t len, size_t *olen,
495 int (*f_rng)(void *, unsigned char *, size_t),
496 void *p_rng )
497{
498 return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200499 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200500 ID_MINE, buf, len, olen, f_rng, p_rng ) );
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200501}
502
503/*
504 * Generate the contents of the ServerHello extension
505 */
506int mbedtls_ecjpake_tls_write_server_ext( mbedtls_ecjpake_context *ctx,
507 unsigned char *buf, size_t len, size_t *olen,
508 int (*f_rng)(void *, unsigned char *, size_t),
509 void *p_rng )
510{
511 return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200512 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200513 ID_MINE, buf, len, olen, f_rng, p_rng ) );
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200514}
515
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200516/*
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200517 * Compute the sum of three points R = A + B + C
518 */
519static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
520 const mbedtls_ecp_point *A,
521 const mbedtls_ecp_point *B,
522 const mbedtls_ecp_point *C )
523{
524 int ret;
525 mbedtls_mpi one;
526
527 mbedtls_mpi_init( &one );
528
529 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
530 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) );
531 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) );
532
533cleanup:
534 mbedtls_mpi_free( &one );
535
536 return( ret );
537}
538
539/*
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200540 * Read and process ServerECJPAKEParams (7.4.2.5)
541 */
542int mbedtls_ecjpake_tls_read_server_params( mbedtls_ecjpake_context *ctx,
543 const unsigned char *buf,
544 size_t len )
545{
546 int ret;
547 const unsigned char *p = buf;
548 const unsigned char *end = buf + len;
549 mbedtls_ecp_group grp;
550 mbedtls_ecp_point GB;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200551
552 mbedtls_ecp_group_init( &grp );
553 mbedtls_ecp_point_init( &GB );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200554
555 /*
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200556 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
557 * Unified: GB = Xm1 + Xm2 + Xp1
558 * We need that before parsing in order to check Xp as we read it
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200559 */
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200560 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &GB,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200561 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200562
563 /*
564 * struct {
565 * ECParameters curve_params;
566 * ECJPAKEKeyKP ecjpake_key_kp;
567 * } ServerECJPAKEParams;
568 */
569 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) );
570 MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200571 &GB, &ctx->Xp, ID_PEER, &p, end ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200572
573 if( p != end )
574 {
575 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
576 goto cleanup;
577 }
578
579 /*
580 * Xs already checked, only thing left to check is the group
581 */
582 if( grp.id != ctx->grp.id )
583 {
584 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
585 goto cleanup;
586 }
587
588cleanup:
589 mbedtls_ecp_group_free( &grp );
590 mbedtls_ecp_point_free( &GB );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200591
592 return( ret );
593}
594
595/*
596 * Generate and write ServerECJPAKEParams (7.4.2.5)
597 */
598int mbedtls_ecjpake_tls_write_server_params( mbedtls_ecjpake_context *ctx,
599 unsigned char *buf, size_t len, size_t *olen,
600 int (*f_rng)(void *, unsigned char *, size_t),
601 void *p_rng )
602{
603 int ret;
604 mbedtls_ecp_point GB, Xs;
605 mbedtls_mpi xs;
606 unsigned char *p = buf;
607 const unsigned char *end = buf + len;
608 size_t ec_len;
609
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200610 if( end < p )
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200611 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
612
613 mbedtls_ecp_point_init( &GB );
614 mbedtls_ecp_point_init( &Xs );
615 mbedtls_mpi_init( &xs );
616
617 /*
618 * First generate private/public key pair (7.4.2.5.1)
619 *
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200620 * Server: GB = X1 + X2 + X3
621 * Unified:
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200622 * xs = x4 * s mod n
623 * Xs = xs * GB
624 */
625 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &GB,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200626 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) );
627 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &xs, &ctx->xm2, &ctx->s ) );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200628 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &xs, &xs, &ctx->grp.N ) );
629 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xs, &xs, &GB, f_rng, p_rng ) );
630
631 /*
632 * Now write things out
633 */
634 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len,
635 p, end - p ) );
636 p += ec_len;
637
638 if( end < p )
639 {
640 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
641 goto cleanup;
642 }
643 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xs,
644 MBEDTLS_ECP_PF_UNCOMPRESSED, &ec_len, p, end - p ) );
645 p += ec_len;
646
647 MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200648 &GB, &xs, &Xs, ID_MINE,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200649 &p, end, f_rng, p_rng ) );
650
651 *olen = p - buf;
652
653cleanup:
654 mbedtls_ecp_point_free( &GB );
655 mbedtls_ecp_point_free( &Xs );
656 mbedtls_mpi_free( &xs );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200657
658 return( ret );
659}
660
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200661/*
662 * Read and process ClientECJPAKEParams (7.4.2.6)
663 */
664int mbedtls_ecjpake_tls_read_client_params( mbedtls_ecjpake_context *ctx,
665 const unsigned char *buf,
666 size_t len )
667{
668 int ret;
669 const unsigned char *p = buf;
670 const unsigned char *end = buf + len;
671 mbedtls_ecp_group grp;
672 mbedtls_ecp_point GA;
673
674 mbedtls_ecp_group_init( &grp );
675 mbedtls_ecp_point_init( &GA );
676
677 /*
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200678 * Server: GA = X1 + X3 + X4 (7.4.2.6.1)
679 * Unified: G = Xp1 + Xm1 + Xm2
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200680 * We need that before parsing in order to check Xc as we read it
681 */
682 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &GA,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200683 &ctx->Xp1, &ctx->Xm1, &ctx->Xm2 ) );
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200684
685 /*
686 * struct {
687 * ECJPAKEKeyKP ecjpake_key_kp;
688 * } CLientECJPAKEParams;
689 */
690 MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200691 &GA, &ctx->Xp, ID_PEER, &p, end ) );
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200692
693 if( p != end )
694 {
695 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
696 goto cleanup;
697 }
698
699cleanup:
700 mbedtls_ecp_group_free( &grp );
701 mbedtls_ecp_point_free( &GA );
702
703 return( ret );
704}
705
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200706/*
707 * Generate and write ClientECJPAKEParams (7.4.2.6)
708 */
709int mbedtls_ecjpake_tls_write_client_params( mbedtls_ecjpake_context *ctx,
710 unsigned char *buf, size_t len, size_t *olen,
711 int (*f_rng)(void *, unsigned char *, size_t),
712 void *p_rng )
713{
714 int ret;
715 mbedtls_ecp_point GA, Xc;
716 mbedtls_mpi xc;
717 unsigned char *p = buf;
718 const unsigned char *end = buf + len;
719 size_t ec_len;
720
721 if( end < p )
722 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
723
724 mbedtls_ecp_point_init( &GA );
725 mbedtls_ecp_point_init( &Xc );
726 mbedtls_mpi_init( &xc );
727
728 /*
729 * First generate private/public key pair (7.4.2.6.1)
730 *
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200731 * Client: GA = X1 + X3 + X4
732 * Unified: G = Xm1 + Xp1 + Xp2
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200733 * xc = x2 * s mod n
734 * Xc = xc * GA
735 */
736 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &GA,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200737 &ctx->Xm1, &ctx->Xp1, &ctx->Xp2 ) );
738 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &xc, &ctx->xm2, &ctx->s ) );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200739 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &xc, &xc, &ctx->grp.N ) );
740 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xc, &xc, &GA, f_rng, p_rng ) );
741
742 /*
743 * Now write things out
744 */
745 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xc,
746 MBEDTLS_ECP_PF_UNCOMPRESSED, &ec_len, p, end - p ) );
747 p += ec_len;
748
749 MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200750 &GA, &xc, &Xc, ID_MINE,
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200751 &p, end, f_rng, p_rng ) );
752
753 *olen = p - buf;
754
755cleanup:
756 mbedtls_ecp_point_free( &GA );
757 mbedtls_ecp_point_free( &Xc );
758 mbedtls_mpi_free( &xc );
759
760 return( ret );
761}
762
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200763/*
764 * Derive PMS (7.4.2.7 / 7.4.2.8)
765 */
766int mbedtls_ecjpake_tls_derive_pms( mbedtls_ecjpake_context *ctx,
767 unsigned char *buf, size_t len, size_t *olen,
768 int (*f_rng)(void *, unsigned char *, size_t),
769 void *p_rng )
770{
771 int ret;
772 mbedtls_ecp_point K, *X42;
773 mbedtls_mpi xbs, one;
774 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
775 size_t x_bytes;
776
777 *olen = mbedtls_md_get_size( ctx->md_info );
778 if( len < *olen )
779 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
780
781 mbedtls_ecp_point_init( &K );
782 mbedtls_mpi_init( &xbs );
783 mbedtls_mpi_init( &one );
784
785 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200786 X42 = ctx->role == MBEDTLS_ECJPAKE_CLIENT ? &ctx->Xp2 : &ctx->Xp2;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200787
788 /*
789 * Client: K = ( Xs - X4 * x2 * s ) * x2
790 * Server: K = ( Xc - X2 * x4 * s ) * x4
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200791 * Unified: K = ( Xp - X42 * xm2 * x ) * xm2
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200792 */
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200793 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &xbs, &ctx->xm2, &ctx->s ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200794 xbs.s *= -1;
795 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &xbs, &xbs, &ctx->grp.N ) );
796
797 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K,
798 &one, &ctx->Xp,
799 &xbs, X42 ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200800 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200801 f_rng, p_rng ) );
802
803 /* PMS = SHA-256( K.X ) */
804 x_bytes = ( ctx->grp.pbits + 7 ) / 8;
805 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) );
806 MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) );
807
808cleanup:
809 mbedtls_ecp_point_free( &K );
810 mbedtls_mpi_free( &xbs );
811 mbedtls_mpi_free( &one );
812
813 return( ret );
814}
815
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200816#undef ID_MINE
817#undef ID_PEER
818
819
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200820#if defined(MBEDTLS_SELF_TEST)
821
822#if defined(MBEDTLS_PLATFORM_C)
823#include "mbedtls/platform.h"
824#else
825#include <stdio.h>
826#define mbedtls_printf printf
827#endif
828
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200829#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
830 !defined(MBEDTLS_SHA256_C)
831int mbedtls_ecjpake_self_test( int verbose )
832{
833 (void) verbose;
834 return( 0 );
835}
836#else
837
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200838static const unsigned char ecjpake_test_password[] = {
839 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
840 0x65, 0x73, 0x74
841};
842
843static const unsigned char ecjpake_test_x1[] = {
844 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
845 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
846 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
847};
848
849static const unsigned char ecjpake_test_x2[] = {
850 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
851 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
852 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
853};
854
855static const unsigned char ecjpake_test_x3[] = {
856 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
857 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
858 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
859};
860
861static const unsigned char ecjpake_test_x4[] = {
862 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
863 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
864 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
865};
866
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200867static const unsigned char ecjpake_test_cli_ext[] = {
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200868 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
869 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
870 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
871 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
872 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
873 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
874 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
875 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
876 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
877 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
878 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
879 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
880 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200881 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
882 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
883 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
884 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
885 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
886 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
887 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
888 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
889 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
890 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
891 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
892 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
893 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
894 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
895 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200896};
897
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200898static const unsigned char ecjpake_test_srv_ext[] = {
899 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
900 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
901 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
902 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
903 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
904 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
905 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
906 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
907 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
908 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
909 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
910 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
911 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
912 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
913 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
914 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
915 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
916 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
917 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
918 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
919 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
920 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
921 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
922 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
923 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
924 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
925 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
926 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
927};
928
929static const unsigned char ecjpake_test_srv_kx[] = {
930 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
931 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
932 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
933 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
934 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
935 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
936 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
937 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
938 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
939 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
940 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
941 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
942 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
943 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
944};
945
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200946static const unsigned char ecjpake_test_cli_kx[] = {
947 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
948 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
949 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
950 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
951 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
952 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
953 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
954 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
955 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
956 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
957 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
958 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
959 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
960 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
961};
962
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200963static const unsigned char ecjpake_test_pms[] = {
964 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
965 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
966 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
967};
968
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200969/* For tests we don't need a secure RNG;
970 * use the LGC from Numerical Recipes for simplicity */
971static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
972{
973 static uint32_t x = 42;
974 (void) p;
975
976 while( len > 0 )
977 {
978 size_t use_len = len > 4 ? 4 : len;
979 x = 1664525 * x + 1013904223;
980 memcpy( out, &x, use_len );
981 out += use_len;
982 len -= use_len;
983 }
984
985 return( 0 );
986}
987
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200988#define TEST_ASSERT( x ) \
989 do { \
990 if( x ) \
991 ret = 0; \
992 else \
993 { \
994 ret = 1; \
995 goto cleanup; \
996 } \
997 } while( 0 )
998
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200999/*
1000 * Checkup routine
1001 */
1002int mbedtls_ecjpake_self_test( int verbose )
1003{
1004 int ret;
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001005 mbedtls_ecjpake_context cli;
1006 mbedtls_ecjpake_context srv;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001007 unsigned char buf[512], pms[32];
1008 size_t len, pmslen;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001009
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001010 mbedtls_ecjpake_init( &cli );
1011 mbedtls_ecjpake_init( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001012
1013 if( verbose != 0 )
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001014 mbedtls_printf( " ECJPAKE test #0 (setup): " );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +02001015
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +02001016 TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001017 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1018 ecjpake_test_password,
1019 sizeof( ecjpake_test_password ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001020
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +02001021 TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001022 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
1023 ecjpake_test_password,
1024 sizeof( ecjpake_test_password ) ) == 0 );
1025
1026 if( verbose != 0 )
1027 mbedtls_printf( "passed\n" );
1028
1029 if( verbose != 0 )
1030 mbedtls_printf( " ECJPAKE test #1 (random handshake): " );
1031
1032 TEST_ASSERT( mbedtls_ecjpake_tls_write_client_ext( &cli,
1033 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1034
1035 TEST_ASSERT( mbedtls_ecjpake_tls_read_client_ext( &srv, buf, len ) == 0 );
1036
1037 TEST_ASSERT( mbedtls_ecjpake_tls_write_server_ext( &srv,
1038 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1039
1040 TEST_ASSERT( mbedtls_ecjpake_tls_read_server_ext( &cli, buf, len ) == 0 );
1041
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +02001042 TEST_ASSERT( mbedtls_ecjpake_tls_write_server_params( &srv,
1043 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1044
1045 TEST_ASSERT( mbedtls_ecjpake_tls_read_server_params( &cli, buf, len ) == 0 );
1046
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001047 TEST_ASSERT( mbedtls_ecjpake_tls_derive_pms( &cli,
1048 pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 );
1049
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +02001050 TEST_ASSERT( mbedtls_ecjpake_tls_write_client_params( &cli,
1051 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1052
1053 TEST_ASSERT( mbedtls_ecjpake_tls_read_client_params( &srv, buf, len ) == 0 );
1054
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001055 TEST_ASSERT( mbedtls_ecjpake_tls_derive_pms( &srv,
1056 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1057
1058 TEST_ASSERT( len == pmslen );
1059 TEST_ASSERT( memcmp( buf, pms, len ) == 0 );
1060
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001061 if( verbose != 0 )
1062 mbedtls_printf( "passed\n" );
1063
1064 if( verbose != 0 )
1065 mbedtls_printf( " ECJPAKE test #2 (reference handshake): " );
1066
1067 /* Simulate key generation on client, skip writing client_ext */
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001068 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &cli.xm1,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001069 ecjpake_test_x1, sizeof( ecjpake_test_x1 ) ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001070 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &cli.xm2,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001071 ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001072 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &cli.grp, &cli.Xm1, &cli.xm1,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001073 &cli.grp.G, NULL, NULL ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001074 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &cli.grp, &cli.Xm2, &cli.xm2,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001075 &cli.grp.G, NULL, NULL ) );
1076
1077 /* Server reads client ext */
1078 TEST_ASSERT( mbedtls_ecjpake_tls_read_client_ext( &srv,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +02001079 ecjpake_test_cli_ext,
1080 sizeof( ecjpake_test_cli_ext ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001081
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001082 /* Simulate key generation on server, skip writing server_ext */
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001083 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &srv.xm1,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001084 ecjpake_test_x3, sizeof( ecjpake_test_x3 ) ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001085 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &srv.xm2,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001086 ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001087 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &srv.grp, &srv.Xm1, &srv.xm1,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001088 &srv.grp.G, NULL, NULL ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +02001089 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &srv.grp, &srv.Xm2, &srv.xm2,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001090 &srv.grp.G, NULL, NULL ) );
1091
1092 /* Client reads server ext and key exchange */
1093 TEST_ASSERT( mbedtls_ecjpake_tls_read_server_ext( &cli,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +02001094 ecjpake_test_srv_ext,
1095 sizeof( ecjpake_test_srv_ext ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001096
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001097 TEST_ASSERT( mbedtls_ecjpake_tls_read_server_params( &cli,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +02001098 ecjpake_test_srv_kx,
1099 sizeof( ecjpake_test_srv_kx ) ) == 0 );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +02001100
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +02001101 /* Server reads client key exchange */
1102 TEST_ASSERT( mbedtls_ecjpake_tls_read_client_params( &srv,
1103 ecjpake_test_cli_kx,
1104 sizeof( ecjpake_test_cli_kx ) ) == 0 );
1105
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001106 /* Server derives PMS */
1107 TEST_ASSERT( mbedtls_ecjpake_tls_derive_pms( &srv,
1108 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1109
1110 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1111 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1112
1113 memset( buf, 0, len ); /* Avoid interferences with next step */
1114
1115 /* Client derives PMS */
1116 TEST_ASSERT( mbedtls_ecjpake_tls_derive_pms( &cli,
1117 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1118
1119 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1120 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1121
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +02001122 if( verbose != 0 )
1123 mbedtls_printf( "passed\n" );
1124
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001125cleanup:
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001126 mbedtls_ecjpake_free( &cli );
1127 mbedtls_ecjpake_free( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001128
1129 if( ret != 0 )
1130 {
1131 if( verbose != 0 )
1132 mbedtls_printf( "failed\n" );
1133
1134 ret = 1;
1135 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001136
1137 if( verbose != 0 )
1138 mbedtls_printf( "\n" );
1139
1140 return( ret );
1141}
1142
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +02001143#undef TEST_ASSERT
1144
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001145#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1146
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001147#endif /* MBEDTLS_SELF_TEST */
1148
1149#endif /* MBEDTLS_ECJPAKE_C */