blob: 6f61433717e7c50f1318a57f3a11c1fc9e14b0d3 [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
239
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200240#if defined(MBEDTLS_SELF_TEST)
241
242#if defined(MBEDTLS_PLATFORM_C)
243#include "mbedtls/platform.h"
244#else
245#include <stdio.h>
246#define mbedtls_printf printf
247#endif
248
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200249#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
250 !defined(MBEDTLS_SHA256_C)
251int mbedtls_ecjpake_self_test( int verbose )
252{
253 (void) verbose;
254 return( 0 );
255}
256#else
257
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200258static const unsigned char ecjpake_test_X[] = {
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200259 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19, 0x33,
260 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44, 0xe5,
261 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad, 0xa7,
262 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62, 0x1f,
263 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9, 0x06,
264 0x07, 0x31, 0xf6, 0x94, 0xa4
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200265};
266
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200267static const unsigned char ecjpake_test_zkp[] = {
268 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d, 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce,
269 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e, 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66,
270 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e, 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0,
271 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73, 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24,
272 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22, 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d,
273 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce, 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29,
274 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00, 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8,
275 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b, 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e,
276 0x98, 0x34, 0x58
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200277};
278
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200279/* For tests we don't need a secure RNG;
280 * use the LGC from Numerical Recipes for simplicity */
281static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
282{
283 static uint32_t x = 42;
284 (void) p;
285
286 while( len > 0 )
287 {
288 size_t use_len = len > 4 ? 4 : len;
289 x = 1664525 * x + 1013904223;
290 memcpy( out, &x, use_len );
291 out += use_len;
292 len -= use_len;
293 }
294
295 return( 0 );
296}
297
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200298/*
299 * Checkup routine
300 */
301int mbedtls_ecjpake_self_test( int verbose )
302{
303 int ret;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200304 mbedtls_ecp_group grp;
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200305 mbedtls_ecp_point X;
306 mbedtls_mpi x;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200307 const mbedtls_md_info_t *md_info;
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200308 unsigned char buf[1000];
309 unsigned char *p;
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200310 const unsigned char *end;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200311
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200312 mbedtls_ecp_group_init( &grp );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200313 mbedtls_ecp_point_init( &X );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200314 mbedtls_mpi_init( &x );
315
316 /* Common to all tests */
317 md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
318 MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP256R1 ) );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200319
320 if( verbose != 0 )
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200321 mbedtls_printf( " ECJPAKE test #1 (zkp read): " );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200322
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200323 MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( &grp, &X,
324 ecjpake_test_X,
325 sizeof( ecjpake_test_X ) ) );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200326
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200327 p = (unsigned char *) ecjpake_test_zkp;
328 end = ecjpake_test_zkp + sizeof( ecjpake_test_zkp );
329 MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, &grp, &grp.G, &X, "client",
330 &p, end ) );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200331
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200332 /* Corrupt proof */
333 memcpy( buf, ecjpake_test_zkp, sizeof( ecjpake_test_zkp ) );
334 buf[sizeof( ecjpake_test_zkp ) - 1]--;
335 p = buf;
336 end = buf + sizeof( ecjpake_test_zkp );
337 ret = ecjpake_zkp_read( md_info, &grp, &grp.G, &X, "client", &p, end );
338
339 if( ret != MBEDTLS_ERR_ECP_VERIFY_FAILED )
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200340 {
341 ret = 1;
342 goto cleanup;
343 }
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200344 ret = 0;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200345
346 if( verbose != 0 )
347 mbedtls_printf( "passed\n" );
348
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200349 if( verbose != 0 )
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200350 mbedtls_printf( " ECJPAKE test #2 (zkp write/read): " );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200351
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200352 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( &grp, &grp.G, &x, &X,
Manuel Pégourié-Gonnardc6181952015-08-11 14:33:51 +0200353 ecjpake_lgc, NULL ) );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200354
355 p = buf;
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200356 MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, &grp, &grp.G, &x, &X, "client",
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200357 &p, buf + sizeof( buf ),
358 ecjpake_lgc, NULL ) );
359
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200360 p = buf;
Manuel Pégourié-Gonnard967cd712015-08-12 10:09:55 +0200361 MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, &grp, &grp.G, &X, "client",
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200362 &p, buf + sizeof( buf ) ) );
363
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200364 if( verbose != 0 )
365 mbedtls_printf( "passed\n" );
366
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200367cleanup:
368 mbedtls_ecp_group_free( &grp );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200369 mbedtls_ecp_point_free( &X );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200370 mbedtls_mpi_free( &x );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200371
372 if( ret != 0 )
373 {
374 if( verbose != 0 )
375 mbedtls_printf( "failed\n" );
376
377 ret = 1;
378 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200379
380 if( verbose != 0 )
381 mbedtls_printf( "\n" );
382
383 return( ret );
384}
385
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200386#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
387
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200388#endif /* MBEDTLS_SELF_TEST */
389
390#endif /* MBEDTLS_ECJPAKE_C */