blob: 57afb45f0e03112808df96caf01cd29f52547e6b [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é-Gonnard8489f172015-08-07 17:47:39 +020023 * We implement EC-JPAKE as defined in Chapter 7.4 of the Thread v1.0
24 * Specification. References below are to this document.
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/*
40 * Write a point plus its length to a buffer
41 */
42static int ecjpake_write_len_point( unsigned char **p,
43 const unsigned char *end,
44 const mbedtls_ecp_group *grp,
45 const mbedtls_ecp_point *P )
46{
47 int ret;
48 size_t len;
49
50 /* Need at least 4 for length plus 1 for point */
51 if( end < *p || end - *p < 5 )
52 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
53
54 ret = mbedtls_ecp_point_write_binary( grp, P, MBEDTLS_ECP_PF_UNCOMPRESSED,
55 &len, *p + 4, end - ( *p + 4 ) );
56 if( ret != 0 )
57 return( ret );
58
59 (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF );
60 (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF );
61 (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF );
62 (*p)[3] = (unsigned char)( ( len ) & 0xFF );
63
64 *p += 4 + len;
65
66 return( 0 );
67}
68
69/*
70 * Size of the temporary buffer for ecjpake_hash:
71 * 3 EC points plus their length, plus ID (6 bytes)
72 */
73#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 6 )
74
75/*
76 * Compute hash for ZKP (7.4.2.2.2.1)
77 */
78static int ecjpake_hash( const mbedtls_md_info_t *md_info,
79 const mbedtls_ecp_group *grp,
80 const mbedtls_ecp_point *G,
81 const mbedtls_ecp_point *V,
82 const mbedtls_ecp_point *X,
83 const char *id,
84 mbedtls_mpi *h )
85{
86 int ret;
87 unsigned char buf[ECJPAKE_HASH_BUF_LEN];
88 unsigned char *p = buf;
89 const unsigned char *end = buf + sizeof( buf );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +020090 const size_t id_len = strlen( id );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +020091 unsigned char hash[MBEDTLS_MD_MAX_SIZE];
92
93 /* Write things to temporary buffer */
94 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, G ) );
95 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, V ) );
96 MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, X ) );
97
98 if( end < p || (size_t)( end - p ) < id_len )
99 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
100
101 *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF );
102 *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF );
103 *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF );
104 *p++ = (unsigned char)( ( id_len ) & 0xFF );
105
106 memcpy( p, id, id_len );
107 p += id_len;
108
109 /* Compute hash */
110 mbedtls_md( md_info, buf, p - buf, hash );
111
112 /* Turn it into an integer mod n */
113 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash,
114 mbedtls_md_get_size( md_info ) ) );
115 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) );
116
117cleanup:
118 return( ret );
119}
120
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200121/*
122 * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2)
123 */
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200124static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info,
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200125 const mbedtls_ecp_group *grp,
126 const mbedtls_ecp_point *G,
127 const mbedtls_mpi *x,
128 const mbedtls_ecp_point *X,
129 const char *id,
130 unsigned char **p,
131 const unsigned char *end,
132 int (*f_rng)(void *, unsigned char *, size_t),
133 void *p_rng )
134{
135 int ret;
136 mbedtls_ecp_point V;
137 mbedtls_mpi v;
138 mbedtls_mpi h; /* later recycled to hold r */
139 size_t len;
140
141 if( end < *p )
142 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
143
144 mbedtls_ecp_point_init( &V );
145 mbedtls_mpi_init( &v );
146 mbedtls_mpi_init( &h );
147
148 /* Compute signature */
Manuel Pégourié-Gonnardc6181952015-08-11 14:33:51 +0200149 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp,
150 G, &v, &V, f_rng, p_rng ) );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200151 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
152 MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */
153 MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */
154 MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */
155
156 /* Write it out */
157 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V,
158 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
159 *p += len;
160
161 len = mbedtls_mpi_size( &h ); /* actually r */
162 if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 )
163 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
164
165 *(*p)++ = (unsigned char)( len & 0xFF );
166 MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */
167 *p += len;
168
169cleanup:
170 mbedtls_ecp_point_free( &V );
171 mbedtls_mpi_free( &v );
172 mbedtls_mpi_free( &h );
173
174 return( ret );
175}
176
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200177/*
178 * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3)
179 */
180static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info,
181 const mbedtls_ecp_group *grp,
182 const mbedtls_ecp_point *G,
183 const mbedtls_ecp_point *X,
184 const char *id,
185 unsigned char **p,
186 const unsigned char *end )
187{
188 int ret;
189 mbedtls_ecp_point V, VV;
190 mbedtls_mpi r, h;
191 size_t r_len;
192
193 mbedtls_ecp_point_init( &V );
194 mbedtls_ecp_point_init( &VV );
195 mbedtls_mpi_init( &r );
196 mbedtls_mpi_init( &h );
197
198 /*
199 * struct {
200 * ECPoint V;
201 * opaque r<1..2^8-1>;
202 * } ECSchnorrZKP;
203 */
204 if( end < *p )
205 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
206
207 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V,
208 (const unsigned char **) p, end - *p ) );
209
210 if( end < *p || (size_t)( end - *p ) < 1 )
211 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
212
213 r_len = *(*p)++;
214 if( end < *p || (size_t)( end - *p ) < r_len )
215 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
216
217 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) );
218 *p += r_len;
219
220 /*
221 * Verification
222 */
223 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, G, &V, X, id, &h ) );
224 MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp,
225 &VV, &h, X, &r, G ) );
226
227 if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 )
228 return( MBEDTLS_ERR_ECP_VERIFY_FAILED );
229
230cleanup:
231 mbedtls_ecp_point_free( &V );
232 mbedtls_ecp_point_free( &VV );
233 mbedtls_mpi_free( &r );
234 mbedtls_mpi_free( &h );
235
236 return( ret );
237}
238
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200239/*
240 * Parse verify a ECJPAKEKeyKP (7.4.2.2.1)
241 * Output: public key X
242 */
243static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info,
244 const mbedtls_ecp_group *grp,
245 const mbedtls_ecp_point *G,
246 mbedtls_ecp_point *X,
247 const char *id,
248 unsigned char **p,
249 const unsigned char *end )
250{
251 int ret;
252
253 if( end < *p )
254 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
255
256 /*
257 * struct {
258 * ECPoint X;
259 * ECSchnorrZKP zkp;
260 * } ECJPAKEKeyKP;
261 */
262 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X,
263 (const unsigned char **) p, end - *p ) );
264 MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, G, X, id, p, end ) );
265
266cleanup:
267 return( ret );
268}
269
270/*
271 * Generate an ECJPAKEKeyKP
272 * Output: the serialized structure, plus private/public key pair
273 */
274static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info,
275 const mbedtls_ecp_group *grp,
276 const mbedtls_ecp_point *G,
277 mbedtls_mpi *x,
278 mbedtls_ecp_point *X,
279 const char *id,
280 unsigned char **p,
281 const unsigned char *end,
282 int (*f_rng)(void *, unsigned char *, size_t),
283 void *p_rng )
284{
285 int ret;
286 size_t len;
287
288 if( end < *p )
289 return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
290
291 /* Generate key (7.4.2.3.1) and write it out */
292 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X,
293 f_rng, p_rng ) );
294 MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X,
295 MBEDTLS_ECP_PF_UNCOMPRESSED, &len, *p, end - *p ) );
296 *p += len;
297
298 /* Generate and write proof */
299 MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, G, x, X, id,
300 p, end, f_rng, p_rng ) );
301
302cleanup:
303 return( ret );
304}
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200305
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200306#if defined(MBEDTLS_SELF_TEST)
307
308#if defined(MBEDTLS_PLATFORM_C)
309#include "mbedtls/platform.h"
310#else
311#include <stdio.h>
312#define mbedtls_printf printf
313#endif
314
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200315#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
316 !defined(MBEDTLS_SHA256_C)
317int mbedtls_ecjpake_self_test( int verbose )
318{
319 (void) verbose;
320 return( 0 );
321}
322#else
323
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200324static const unsigned char ecjpake_test_kkp[] = {
325 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19,
326 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44,
327 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad,
328 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62,
329 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9,
330 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d,
331 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e,
332 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e,
333 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73,
334 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22,
335 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce,
336 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00,
337 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b,
338 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200339};
340
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200341/* For tests we don't need a secure RNG;
342 * use the LGC from Numerical Recipes for simplicity */
343static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
344{
345 static uint32_t x = 42;
346 (void) p;
347
348 while( len > 0 )
349 {
350 size_t use_len = len > 4 ? 4 : len;
351 x = 1664525 * x + 1013904223;
352 memcpy( out, &x, use_len );
353 out += use_len;
354 len -= use_len;
355 }
356
357 return( 0 );
358}
359
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200360#define TEST_ASSERT( x ) \
361 do { \
362 if( x ) \
363 ret = 0; \
364 else \
365 { \
366 ret = 1; \
367 goto cleanup; \
368 } \
369 } while( 0 )
370
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200371/*
372 * Checkup routine
373 */
374int mbedtls_ecjpake_self_test( int verbose )
375{
376 int ret;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200377 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200378 mbedtls_ecp_point X;
379 mbedtls_mpi x;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200380 const mbedtls_md_info_t *md_info;
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200381 unsigned char buf[1000];
382 unsigned char *p;
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200383 const unsigned char *end;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200384
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200385 mbedtls_ecp_group_init( &grp );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200386 mbedtls_ecp_point_init( &X );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200387 mbedtls_mpi_init( &x );
388
389 /* Common to all tests */
390 md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
391 MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP256R1 ) );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200392
393 if( verbose != 0 )
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200394 mbedtls_printf( " ECJPAKE test #1 (kkp read): " );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200395
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200396 p = (unsigned char *) ecjpake_test_kkp;
397 end = ecjpake_test_kkp + sizeof( ecjpake_test_kkp );
398 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, &grp, &grp.G, &X, "client",
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200399 &p, end ) );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200400
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200401 TEST_ASSERT( p == end );
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200402
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200403 /* Corrupt proof */
404 memcpy( buf, ecjpake_test_kkp, sizeof( ecjpake_test_kkp ) );
405 buf[sizeof( ecjpake_test_kkp ) - 1]--;
406 p = buf;
407 end = buf + sizeof( ecjpake_test_kkp );
408 ret = ecjpake_kkp_read( md_info, &grp, &grp.G, &X, "client", &p, end );
409
410 TEST_ASSERT( ret == MBEDTLS_ERR_ECP_VERIFY_FAILED );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200411
412 if( verbose != 0 )
413 mbedtls_printf( "passed\n" );
414
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200415 if( verbose != 0 )
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200416 mbedtls_printf( " ECJPAKE test #2 (kkp write/read): " );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200417
418 p = buf;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200419 MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, &grp, &grp.G, &x, &X, "client",
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200420 &p, buf + sizeof( buf ),
421 ecjpake_lgc, NULL ) );
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200422 end = p;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200423 p = buf;
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200424 MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, &grp, &grp.G, &X, "client",
425 &p, end ) );
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200426
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200427 if( verbose != 0 )
428 mbedtls_printf( "passed\n" );
429
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200430cleanup:
431 mbedtls_ecp_group_free( &grp );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200432 mbedtls_ecp_point_free( &X );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200433 mbedtls_mpi_free( &x );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200434
435 if( ret != 0 )
436 {
437 if( verbose != 0 )
438 mbedtls_printf( "failed\n" );
439
440 ret = 1;
441 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200442
443 if( verbose != 0 )
444 mbedtls_printf( "\n" );
445
446 return( ret );
447}
448
Manuel Pégourié-Gonnardb1b250b2015-08-12 11:01:58 +0200449#undef TEST_ASSERT
450
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200451#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
452
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200453#endif /* MBEDTLS_SELF_TEST */
454
455#endif /* MBEDTLS_ECJPAKE_C */