blob: f5863bc4c894732c3df39f65fd2566d82241a34f [file] [log] [blame]
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001/*
2 * Elliptic curve J-PAKE
3 *
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * This file is part of mbed TLS (https://tls.mbed.org)
20 */
21
22/*
Manuel Pégourié-Gonnard6b798b92015-08-14 11:18:30 +020023 * References in the code are to the Thread v1.0 Specification,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +020024 * available to members of the Thread Group http://threadgroup.org/
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +020025 */
26
27#if !defined(MBEDTLS_CONFIG_FILE)
28#include "mbedtls/config.h"
29#else
30#include MBEDTLS_CONFIG_FILE
31#endif
32
33#if defined(MBEDTLS_ECJPAKE_C)
34
35#include "mbedtls/ecjpake.h"
36
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020037#include <string.h>
38
39/*
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +020040 * Convert a mbedtls_ecjpake_role to identifier string
41 */
42static const char * const ecjpake_id[] = {
43 "client",
44 "server"
45};
46
47#define ID_MINE ( ecjpake_id[ ctx->role ] )
48#define ID_PEER ( ecjpake_id[ 1 - ctx->role ] )
49
50/*
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020051 * Initialize context
52 */
53void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx )
54{
55 if( ctx == NULL )
56 return;
57
58 ctx->md_info = NULL;
59 mbedtls_ecp_group_init( &ctx->grp );
60
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020061 mbedtls_ecp_point_init( &ctx->Xm1 );
62 mbedtls_ecp_point_init( &ctx->Xm2 );
63 mbedtls_ecp_point_init( &ctx->Xp1 );
64 mbedtls_ecp_point_init( &ctx->Xp2 );
65 mbedtls_ecp_point_init( &ctx->Xp );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020066
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020067 mbedtls_mpi_init( &ctx->xm1 );
68 mbedtls_mpi_init( &ctx->xm2 );
69 mbedtls_mpi_init( &ctx->s );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020070}
71
72/*
73 * Free context
74 */
75void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx )
76{
77 if( ctx == NULL )
78 return;
79
80 ctx->md_info = NULL;
81 mbedtls_ecp_group_free( &ctx->grp );
82
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020083 mbedtls_ecp_point_free( &ctx->Xm1 );
84 mbedtls_ecp_point_free( &ctx->Xm2 );
85 mbedtls_ecp_point_free( &ctx->Xp1 );
86 mbedtls_ecp_point_free( &ctx->Xp2 );
87 mbedtls_ecp_point_free( &ctx->Xp );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020088
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +020089 mbedtls_mpi_free( &ctx->xm1 );
90 mbedtls_mpi_free( &ctx->xm2 );
91 mbedtls_mpi_free( &ctx->s );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020092}
93
94/*
95 * Setup context
96 */
97int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +020098 mbedtls_ecjpake_role role,
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +020099 mbedtls_md_type_t hash,
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200100 mbedtls_ecp_group_id curve,
101 const unsigned char *secret,
102 size_t len )
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200103{
104 int ret;
105
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200106 ctx->role = role;
107
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200108 if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL )
109 return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE );
110
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200111 MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, curve ) );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200112
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200113 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->s, secret, len ) );
Manuel Pégourié-Gonnard23dcbe32015-08-13 09:37:00 +0200114
115cleanup:
116 if( ret != 0 )
117 mbedtls_ecjpake_free( ctx );
118
119 return( ret );
Manuel Pégourié-Gonnard7af8bc12015-08-12 16:58:50 +0200120}
121
122/*
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200123 * Write a point plus its length to a buffer
124 */
125static int ecjpake_write_len_point( unsigned char **p,
126 const unsigned char *end,
127 const mbedtls_ecp_group *grp,
128 const mbedtls_ecp_point *P )
129{
130 int ret;
131 size_t len;
132
133 /* Need at least 4 for length plus 1 for point */
134 if( end < *p || end - *p < 5 )
135 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
136
137 ret = mbedtls_ecp_point_write_binary( grp, P, MBEDTLS_ECP_PF_UNCOMPRESSED,
138 &len, *p + 4, end - ( *p + 4 ) );
139 if( ret != 0 )
140 return( ret );
141
142 (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF );
143 (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF );
144 (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF );
145 (*p)[3] = (unsigned char)( ( len ) & 0xFF );
146
147 *p += 4 + len;
148
149 return( 0 );
150}
151
152/*
153 * Size of the temporary buffer for ecjpake_hash:
154 * 3 EC points plus their length, plus ID (6 bytes)
155 */
156#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 6 )
157
158/*
159 * Compute hash for ZKP (7.4.2.2.2.1)
160 */
161static int ecjpake_hash( const mbedtls_md_info_t *md_info,
162 const mbedtls_ecp_group *grp,
163 const mbedtls_ecp_point *G,
164 const mbedtls_ecp_point *V,
165 const mbedtls_ecp_point *X,
166 const char *id,
167 mbedtls_mpi *h )
168{
169 int ret;
170 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
171 unsigned char *p = buf;
172 const unsigned char *end = buf + sizeof( buf );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200173 const size_t id_len = strlen( id );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200174 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
175
176 /* Write things to temporary buffer */
177 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, G ) );
178 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, V ) );
179 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, X ) );
180
181 if( end < p || (size_t)( end - p ) < id_len )
182 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
183
184 *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF );
185 *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF );
186 *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF );
187 *p++ = (unsigned char)( ( id_len ) & 0xFF );
188
189 memcpy( p, id, id_len );
190 p += id_len;
191
192 /* Compute hash */
193 mbedtls_md( md_info, buf, p - buf, hash );
194
195 /* Turn it into an integer mod n */
196 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash,
197 mbedtls_md_get_size( md_info ) ) );
198 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) );
199
200cleanup:
201 return( ret );
202}
203
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200204/*
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200205 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
206 */
207static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info,
208 const mbedtls_ecp_group *grp,
209 const mbedtls_ecp_point *G,
210 const mbedtls_ecp_point *X,
211 const char *id,
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200212 const unsigned char **p,
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200213 const unsigned char *end )
214{
215 int ret;
216 mbedtls_ecp_point V, VV;
217 mbedtls_mpi r, h;
218 size_t r_len;
219
220 mbedtls_ecp_point_init( &V );
221 mbedtls_ecp_point_init( &VV );
222 mbedtls_mpi_init( &r );
223 mbedtls_mpi_init( &h );
224
225 /*
226 * struct {
227 * ECPoint V;
228 * opaque r<1..2^8-1>;
229 * } ECSchnorrZKP;
230 */
231 if( end < *p )
232 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
233
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200234 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200235
236 if( end < *p || (size_t)( end - *p ) < 1 )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200237 {
238 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
239 goto cleanup;
240 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200241
242 r_len = *(*p)++;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200243
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200244 if( end < *p || (size_t)( end - *p ) < r_len )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200245 {
246 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
247 goto cleanup;
248 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200249
250 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) );
251 *p += r_len;
252
253 /*
254 * Verification
255 */
256 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
257 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp,
258 &VV, &h, X, &r, G ) );
259
260 if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 )
Manuel Pégourié-Gonnard4f2cd952015-08-12 11:17:55 +0200261 {
262 ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
263 goto cleanup;
264 }
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200265
266cleanup:
267 mbedtls_ecp_point_free( &V );
268 mbedtls_ecp_point_free( &VV );
269 mbedtls_mpi_free( &r );
270 mbedtls_mpi_free( &h );
271
272 return( ret );
273}
274
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200275/*
Manuel Pégourié-Gonnard3aed1852015-08-12 14:53:56 +0200276 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
277 */
278static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info,
279 const mbedtls_ecp_group *grp,
280 const mbedtls_ecp_point *G,
281 const mbedtls_mpi *x,
282 const mbedtls_ecp_point *X,
283 const char *id,
284 unsigned char **p,
285 const unsigned char *end,
286 int (*f_rng)(void *, unsigned char *, size_t),
287 void *p_rng )
288{
289 int ret;
290 mbedtls_ecp_point V;
291 mbedtls_mpi v;
292 mbedtls_mpi h; /* later recycled to hold r */
293 size_t len;
294
295 if( end < *p )
296 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
297
298 mbedtls_ecp_point_init( &V );
299 mbedtls_mpi_init( &v );
300 mbedtls_mpi_init( &h );
301
302 /* Compute signature */
303 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp,
304 G, &v, &V, f_rng, p_rng ) );
305 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
306 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */
307 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */
308 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */
309
310 /* Write it out */
311 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V,
312 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
313 *p += len;
314
315 len = mbedtls_mpi_size( &h ); /* actually r */
316 if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 )
317 {
318 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
319 goto cleanup;
320 }
321
322 *(*p)++ = (unsigned char)( len & 0xFF );
323 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */
324 *p += len;
325
326cleanup:
327 mbedtls_ecp_point_free( &V );
328 mbedtls_mpi_free( &v );
329 mbedtls_mpi_free( &h );
330
331 return( ret );
332}
333
334/*
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200335 * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof
336 * Output: verified public key X
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200337 */
338static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info,
339 const mbedtls_ecp_group *grp,
340 const mbedtls_ecp_point *G,
341 mbedtls_ecp_point *X,
342 const char *id,
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200343 const unsigned char **p,
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200344 const unsigned char *end )
345{
346 int ret;
347
348 if( end < *p )
349 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
350
351 /*
352 * struct {
353 * ECPoint X;
354 * ECSchnorrZKP zkp;
355 * } ECJPAKEKeyKP;
356 */
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200357 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) );
Manuel Pégourié-Gonnard30590952015-08-17 10:37:40 +0200358 if( mbedtls_ecp_is_zero( X ) )
359 {
360 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
361 goto cleanup;
362 }
363
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200364 MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, G, X, id, p, end ) );
365
366cleanup:
367 return( ret );
368}
369
370/*
371 * Generate an ECJPAKEKeyKP
372 * Output: the serialized structure, plus private/public key pair
373 */
374static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info,
375 const mbedtls_ecp_group *grp,
376 const mbedtls_ecp_point *G,
377 mbedtls_mpi *x,
378 mbedtls_ecp_point *X,
379 const char *id,
380 unsigned char **p,
381 const unsigned char *end,
382 int (*f_rng)(void *, unsigned char *, size_t),
383 void *p_rng )
384{
385 int ret;
386 size_t len;
387
388 if( end < *p )
389 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
390
391 /* Generate key (7.4.2.3.1) and write it out */
392 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X,
393 f_rng, p_rng ) );
394 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X,
395 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
396 *p += len;
397
398 /* Generate and write proof */
399 MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, G, x, X, id,
400 p, end, f_rng, p_rng ) );
401
402cleanup:
403 return( ret );
404}
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200405
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200406/*
407 * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs
408 * Ouputs: verified peer public keys Xa, Xb
409 */
410static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info,
411 const mbedtls_ecp_group *grp,
412 const mbedtls_ecp_point *G,
413 mbedtls_ecp_point *Xa,
414 mbedtls_ecp_point *Xb,
415 const char *id,
416 const unsigned char *buf,
417 size_t len )
418{
419 int ret;
Manuel Pégourié-Gonnard9028c5a2015-08-12 14:51:36 +0200420 const unsigned char *p = buf;
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200421 const unsigned char *end = buf + len;
422
423 /*
424 * struct {
425 * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2];
426 * } ECJPAKEKeyKPPairList;
427 */
428 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, G, Xa, id, &p, end ) );
429 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, G, Xb, id, &p, end ) );
430
431 if( p != end )
432 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
433
434cleanup:
435 return( ret );
436}
437
438/*
439 * Generate a ECJPAKEKeyKPPairList
440 * Outputs: the serialized structure, plus two private/public key pairs
441 */
442static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info,
443 const mbedtls_ecp_group *grp,
444 const mbedtls_ecp_point *G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200445 mbedtls_mpi *xm1,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200446 mbedtls_ecp_point *Xa,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200447 mbedtls_mpi *xm2,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200448 mbedtls_ecp_point *Xb,
449 const char *id,
450 unsigned char *buf,
451 size_t len,
452 size_t *olen,
453 int (*f_rng)(void *, unsigned char *, size_t),
454 void *p_rng )
455{
456 int ret;
457 unsigned char *p = buf;
458 const unsigned char *end = buf + len;
459
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200460 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, G, xm1, Xa, id,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200461 &p, end, f_rng, p_rng ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200462 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, G, xm2, Xb, id,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200463 &p, end, f_rng, p_rng ) );
464
465 *olen = p - buf;
466
467cleanup:
468 return( ret );
469}
470
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200471/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200472 * Read and process the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200473 */
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200474int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx,
475 const unsigned char *buf,
476 size_t len )
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200477{
478 return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200479 &ctx->Xp1, &ctx->Xp2, ID_PEER,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200480 buf, len ) );
481}
482
483/*
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200484 * Generate and write the first round message
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200485 */
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200486int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200487 unsigned char *buf, size_t len, size_t *olen,
488 int (*f_rng)(void *, unsigned char *, size_t),
489 void *p_rng )
490{
491 return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, &ctx->grp.G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200492 &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2,
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200493 ID_MINE, buf, len, olen, f_rng, p_rng ) );
Manuel Pégourié-Gonnard4e8bc782015-08-12 20:50:31 +0200494}
495
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200496/*
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200497 * Compute the sum of three points R = A + B + C
498 */
499static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
500 const mbedtls_ecp_point *A,
501 const mbedtls_ecp_point *B,
502 const mbedtls_ecp_point *C )
503{
504 int ret;
505 mbedtls_mpi one;
506
507 mbedtls_mpi_init( &one );
508
509 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
510 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) );
511 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) );
512
513cleanup:
514 mbedtls_mpi_free( &one );
515
516 return( ret );
517}
518
519/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200520 * 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 +0200521 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200522int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200523 const unsigned char *buf,
524 size_t len )
525{
526 int ret;
527 const unsigned char *p = buf;
528 const unsigned char *end = buf + len;
529 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200530 mbedtls_ecp_point G; /* C: GB, S: GA */
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200531
532 mbedtls_ecp_group_init( &grp );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200533 mbedtls_ecp_point_init( &G );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200534
535 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200536 * Server: GA = X3 + X4 + X1 (7.4.2.6.1)
537 * Client: GB = X1 + X2 + X3 (7.4.2.5.1)
538 * Unified: G = Xm1 + Xm2 + Xp1
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200539 * We need that before parsing in order to check Xp as we read it
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200540 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200541 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200542 &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200543
544 /*
545 * struct {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200546 * ECParameters curve_params; // only client reading server msg
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200547 * ECJPAKEKeyKP ecjpake_key_kp;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200548 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200549 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200550 if( ctx->role == MBEDTLS_ECJPAKE_CLIENT )
Manuel Pégourié-Gonnardd9802af2015-08-17 12:47:38 +0200551 {
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200552 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) );
Manuel Pégourié-Gonnardd9802af2015-08-17 12:47:38 +0200553 if( grp.id != ctx->grp.id )
554 {
555 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
556 goto cleanup;
557 }
558 }
559
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200560 MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200561 &G, &ctx->Xp, ID_PEER, &p, end ) );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200562
563 if( p != end )
564 {
565 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
566 goto cleanup;
567 }
568
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200569cleanup:
570 mbedtls_ecp_group_free( &grp );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200571 mbedtls_ecp_point_free( &G );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200572
573 return( ret );
574}
575
576/*
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200577 * Compute R = +/- X * S mod N, taking care not to leak S
578 */
579static int ecjpake_mul_secret( mbedtls_mpi *R, int sign,
580 const mbedtls_mpi *X,
581 const mbedtls_mpi *S,
582 const mbedtls_mpi *N,
583 int (*f_rng)(void *, unsigned char *, size_t),
584 void *p_rng )
585{
586 int ret;
587 mbedtls_mpi b; /* Blinding value, then s + N * blinding */
588
589 mbedtls_mpi_init( &b );
590
591 /* b = s + rnd-128-bit * N */
592 MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &b, 16, f_rng, p_rng ) );
593 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &b, &b, N ) );
594 MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &b, &b, S ) );
595
596 /* R = sign * X * b mod N */
597 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( R, X, &b ) );
598 R->s *= sign;
599 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( R, R, N ) );
600
601cleanup:
602 mbedtls_mpi_free( &b );
603
604 return( ret );
605}
606
607/*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200608 * 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 +0200609 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200610int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200611 unsigned char *buf, size_t len, size_t *olen,
612 int (*f_rng)(void *, unsigned char *, size_t),
613 void *p_rng )
614{
615 int ret;
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200616 mbedtls_ecp_point G; /* C: GA, S: GB */
617 mbedtls_ecp_point Xm; /* C: Xc, S: Xs */
618 mbedtls_mpi xm; /* C: xc, S: xs */
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200619 unsigned char *p = buf;
620 const unsigned char *end = buf + len;
621 size_t ec_len;
622
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200623 mbedtls_ecp_point_init( &G );
624 mbedtls_ecp_point_init( &Xm );
625 mbedtls_mpi_init( &xm );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200626
627 /*
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200628 * 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 +0200629 *
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200630 * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA
631 * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB
632 * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200633 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200634 MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G,
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200635 &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) );
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200636 MBEDTLS_MPI_CHK( ecjpake_mul_secret( &xm, 1, &ctx->xm2, &ctx->s,
637 &ctx->grp.N, f_rng, p_rng ) );
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200638 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200639
640 /*
641 * Now write things out
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200642 *
643 * struct {
644 * ECParameters curve_params; // only server writing its message
645 * ECJPAKEKeyKP ecjpake_key_kp;
646 * } Client/ServerECJPAKEParams;
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200647 */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200648 if( ctx->role == MBEDTLS_ECJPAKE_SERVER )
649 {
650 if( end < p )
651 {
652 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
653 goto cleanup;
654 }
655 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len,
656 p, end - p ) );
657 p += ec_len;
658 }
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200659
660 if( end < p )
661 {
662 ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
663 goto cleanup;
664 }
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200665 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200666 MBEDTLS_ECP_PF_UNCOMPRESSED, &ec_len, p, end - p ) );
667 p += ec_len;
668
669 MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp,
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200670 &G, &xm, &Xm, ID_MINE,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200671 &p, end, f_rng, p_rng ) );
672
673 *olen = p - buf;
674
675cleanup:
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200676 mbedtls_ecp_point_free( &G );
677 mbedtls_ecp_point_free( &Xm );
678 mbedtls_mpi_free( &xm );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200679
680 return( ret );
681}
682
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200683/*
684 * Derive PMS (7.4.2.7 / 7.4.2.8)
685 */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200686int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200687 unsigned char *buf, size_t len, size_t *olen,
688 int (*f_rng)(void *, unsigned char *, size_t),
689 void *p_rng )
690{
691 int ret;
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200692 mbedtls_ecp_point K;
693 mbedtls_mpi m_xm2_s, one;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200694 unsigned char kx[MBEDTLS_ECP_MAX_BYTES];
695 size_t x_bytes;
696
697 *olen = mbedtls_md_get_size( ctx->md_info );
698 if( len < *olen )
699 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
700
701 mbedtls_ecp_point_init( &K );
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200702 mbedtls_mpi_init( &m_xm2_s );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200703 mbedtls_mpi_init( &one );
704
705 MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200706
707 /*
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200708 * Client: K = ( Xs - X4 * x2 * s ) * x2
709 * Server: K = ( Xc - X2 * x4 * s ) * x4
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200710 * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200711 */
Manuel Pégourié-Gonnardd0d8a932015-08-14 15:14:50 +0200712 MBEDTLS_MPI_CHK( ecjpake_mul_secret( &m_xm2_s, -1, &ctx->xm2, &ctx->s,
713 &ctx->grp.N, f_rng, p_rng ) );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200714 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K,
715 &one, &ctx->Xp,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200716 &m_xm2_s, &ctx->Xp2 ) );
Manuel Pégourié-Gonnardce456762015-08-14 11:54:35 +0200717 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200718 f_rng, p_rng ) );
719
720 /* PMS = SHA-256( K.X ) */
721 x_bytes = ( ctx->grp.pbits + 7 ) / 8;
722 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) );
723 MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) );
724
725cleanup:
726 mbedtls_ecp_point_free( &K );
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200727 mbedtls_mpi_free( &m_xm2_s );
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200728 mbedtls_mpi_free( &one );
729
730 return( ret );
731}
732
Manuel Pégourié-Gonnarde0ad57b2015-08-14 11:10:39 +0200733#undef ID_MINE
734#undef ID_PEER
735
736
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200737#if defined(MBEDTLS_SELF_TEST)
738
739#if defined(MBEDTLS_PLATFORM_C)
740#include "mbedtls/platform.h"
741#else
742#include <stdio.h>
743#define mbedtls_printf printf
744#endif
745
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200746#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
747 !defined(MBEDTLS_SHA256_C)
748int mbedtls_ecjpake_self_test( int verbose )
749{
750 (void) verbose;
751 return( 0 );
752}
753#else
754
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200755static const unsigned char ecjpake_test_password[] = {
756 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74,
757 0x65, 0x73, 0x74
758};
759
760static const unsigned char ecjpake_test_x1[] = {
761 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
762 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
763 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21
764};
765
766static const unsigned char ecjpake_test_x2[] = {
767 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
768 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
769 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
770};
771
772static const unsigned char ecjpake_test_x3[] = {
773 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
774 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
775 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81
776};
777
778static const unsigned char ecjpake_test_x4[] = {
779 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
780 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
781 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1
782};
783
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200784static const unsigned char ecjpake_test_cli_one[] = {
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200785 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
786 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
787 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
788 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
789 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
790 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
791 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
792 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
793 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
794 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
795 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
796 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
797 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
Manuel Pégourié-Gonnard082767f2015-08-12 14:43:57 +0200798 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e,
799 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62,
800 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5,
801 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb,
802 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35,
803 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0,
804 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb,
805 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47,
806 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39,
807 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97,
808 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40,
809 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d,
810 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa,
811 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d,
812 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200813};
814
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200815static const unsigned char ecjpake_test_srv_one[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200816 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb,
817 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18,
818 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47,
819 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f,
820 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7,
821 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d,
822 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64,
823 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36,
824 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2,
825 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec,
826 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16,
827 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96,
828 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3,
829 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19,
830 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f,
831 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8,
832 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7,
833 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea,
834 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5,
835 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6,
836 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31,
837 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d,
838 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8,
839 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee,
840 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84,
841 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f,
842 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80,
843 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12
844};
845
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200846static const unsigned char ecjpake_test_srv_two[] = {
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200847 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23,
848 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c,
849 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f,
850 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca,
851 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26,
852 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55,
853 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38,
854 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6,
855 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9,
856 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4,
857 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2,
858 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8,
859 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd,
860 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c
861};
862
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +0200863static const unsigned char ecjpake_test_cli_two[] = {
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +0200864 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46,
865 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb,
866 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72,
867 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce,
868 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98,
869 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31,
870 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15,
871 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36,
872 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8,
873 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45,
874 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d,
875 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58,
876 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82,
877 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c
878};
879
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200880static const unsigned char ecjpake_test_pms[] = {
881 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7,
882 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9,
883 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
884};
885
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +0200886/* Load my private keys and generate the correponding public keys */
887static int ecjpake_test_load( mbedtls_ecjpake_context *ctx,
888 const unsigned char *xm1, size_t len1,
889 const unsigned char *xm2, size_t len2 )
890{
891 int ret;
892
893 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) );
894 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) );
895 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1,
896 &ctx->grp.G, NULL, NULL ) );
897 MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2,
898 &ctx->grp.G, NULL, NULL ) );
899
900cleanup:
901 return( ret );
902}
903
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200904/* For tests we don't need a secure RNG;
905 * use the LGC from Numerical Recipes for simplicity */
906static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
907{
908 static uint32_t x = 42;
909 (void) p;
910
911 while( len > 0 )
912 {
913 size_t use_len = len > 4 ? 4 : len;
914 x = 1664525 * x + 1013904223;
915 memcpy( out, &x, use_len );
916 out += use_len;
917 len -= use_len;
918 }
919
920 return( 0 );
921}
922
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200923#define TEST_ASSERT( x ) \
924 do { \
925 if( x ) \
926 ret = 0; \
927 else \
928 { \
929 ret = 1; \
930 goto cleanup; \
931 } \
932 } while( 0 )
933
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200934/*
935 * Checkup routine
936 */
937int mbedtls_ecjpake_self_test( int verbose )
938{
939 int ret;
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200940 mbedtls_ecjpake_context cli;
941 mbedtls_ecjpake_context srv;
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200942 unsigned char buf[512], pms[32];
943 size_t len, pmslen;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200944
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200945 mbedtls_ecjpake_init( &cli );
946 mbedtls_ecjpake_init( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200947
948 if( verbose != 0 )
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200949 mbedtls_printf( " ECJPAKE test #0 (setup): " );
Manuel Pégourié-Gonnardcb7cd032015-08-13 10:09:10 +0200950
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200951 TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200952 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
953 ecjpake_test_password,
954 sizeof( ecjpake_test_password ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200955
Manuel Pégourié-Gonnard64493912015-08-13 20:19:51 +0200956 TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200957 MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1,
958 ecjpake_test_password,
959 sizeof( ecjpake_test_password ) ) == 0 );
960
961 if( verbose != 0 )
962 mbedtls_printf( "passed\n" );
963
964 if( verbose != 0 )
965 mbedtls_printf( " ECJPAKE test #1 (random handshake): " );
966
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200967 TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200968 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
969
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200970 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200971
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200972 TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv,
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200973 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
974
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +0200975 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200976
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200977 TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv,
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200978 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
979
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200980 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 );
Manuel Pégourié-Gonnardbed9e412015-08-13 18:53:59 +0200981
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200982 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200983 pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 );
984
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200985 TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli,
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200986 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
987
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +0200988 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 );
Manuel Pégourié-Gonnard614bd5e2015-08-13 20:19:16 +0200989
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +0200990 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +0200991 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
992
993 TEST_ASSERT( len == pmslen );
994 TEST_ASSERT( memcmp( buf, pms, len ) == 0 );
995
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +0200996 if( verbose != 0 )
997 mbedtls_printf( "passed\n" );
998
999 if( verbose != 0 )
1000 mbedtls_printf( " ECJPAKE test #2 (reference handshake): " );
1001
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001002 /* Simulate generation of round one */
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +02001003 MBEDTLS_MPI_CHK( ecjpake_test_load( &cli,
1004 ecjpake_test_x1, sizeof( ecjpake_test_x1 ),
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001005 ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001006
Manuel Pégourié-Gonnarde2d3a4e2015-08-14 12:03:04 +02001007 MBEDTLS_MPI_CHK( ecjpake_test_load( &srv,
1008 ecjpake_test_x3, sizeof( ecjpake_test_x3 ),
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001009 ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) );
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001010
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001011 /* Read round one */
1012 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv,
1013 ecjpake_test_cli_one,
1014 sizeof( ecjpake_test_cli_one ) ) == 0 );
1015
Manuel Pégourié-Gonnardd8204a72015-08-14 13:36:55 +02001016 TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001017 ecjpake_test_srv_one,
1018 sizeof( ecjpake_test_srv_one ) ) == 0 );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001019
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001020 /* Skip generation of round two, read round two */
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +02001021 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001022 ecjpake_test_srv_two,
1023 sizeof( ecjpake_test_srv_two ) ) == 0 );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +02001024
Manuel Pégourié-Gonnarde1927102015-08-14 14:20:48 +02001025 TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv,
Manuel Pégourié-Gonnardc9070812015-08-14 14:48:50 +02001026 ecjpake_test_cli_two,
1027 sizeof( ecjpake_test_cli_two ) ) == 0 );
Manuel Pégourié-Gonnardec0eece2015-08-13 19:13:20 +02001028
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001029 /* Server derives PMS */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +02001030 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001031 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1032
1033 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1034 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1035
1036 memset( buf, 0, len ); /* Avoid interferences with next step */
1037
1038 /* Client derives PMS */
Manuel Pégourié-Gonnardf7368c92015-08-14 14:33:05 +02001039 TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli,
Manuel Pégourié-Gonnard5f188292015-08-14 10:52:39 +02001040 buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 );
1041
1042 TEST_ASSERT( len == sizeof( ecjpake_test_pms ) );
1043 TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 );
1044
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +02001045 if( verbose != 0 )
1046 mbedtls_printf( "passed\n" );
1047
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001048cleanup:
Manuel Pégourié-Gonnard8d31e802015-08-13 14:44:57 +02001049 mbedtls_ecjpake_free( &cli );
1050 mbedtls_ecjpake_free( &srv );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001051
1052 if( ret != 0 )
1053 {
1054 if( verbose != 0 )
1055 mbedtls_printf( "failed\n" );
1056
1057 ret = 1;
1058 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001059
1060 if( verbose != 0 )
1061 mbedtls_printf( "\n" );
1062
1063 return( ret );
1064}
1065
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +02001066#undef TEST_ASSERT
1067
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +02001068#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
1069
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +02001070#endif /* MBEDTLS_SELF_TEST */
1071
1072#endif /* MBEDTLS_ECJPAKE_C */