blob: 7dc780ca934b0bd1d3c8434cf05741e2287b357c [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 */
124static int ecjpake_write_zkp( const mbedtls_md_info_t *md_info,
125 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 */
149 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( (mbedtls_ecp_group *) grp,
150 &v, &V, f_rng, p_rng ) ); /* TODO: wrong base point! */
151 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é-Gonnard4d8685b2015-08-05 15:44:42 +0200177#if defined(MBEDTLS_SELF_TEST)
178
179#if defined(MBEDTLS_PLATFORM_C)
180#include "mbedtls/platform.h"
181#else
182#include <stdio.h>
183#define mbedtls_printf printf
184#endif
185
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200186#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
187 !defined(MBEDTLS_SHA256_C)
188int mbedtls_ecjpake_self_test( int verbose )
189{
190 (void) verbose;
191 return( 0 );
192}
193#else
194
195static const unsigned char ecjpake_test_G[] = {
196 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
197 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33,
198 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42,
199 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e,
200 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40,
201 0x68, 0x37, 0xbf, 0x51, 0xf5
202};
203
204static const unsigned char ecjpake_test_V[] = {
205 0x04, 0xfa, 0x9a, 0x24, 0x9d, 0x73, 0x6e, 0x30, 0x28, 0xd1, 0x2d, 0xf1,
206 0xdc, 0xfa, 0x22, 0xd1, 0xed, 0x62, 0x82, 0xbf, 0xab, 0x27, 0x7c, 0x7c,
207 0x52, 0x56, 0xf3, 0xfd, 0x38, 0x07, 0xa5, 0xae, 0xe0, 0x72, 0xfb, 0x4d,
208 0x9c, 0x2b, 0xd6, 0xa4, 0x70, 0xf7, 0xb4, 0xd0, 0xbd, 0xfb, 0x4a, 0x94,
209 0x96, 0xcf, 0xcd, 0xd3, 0x53, 0xf9, 0x90, 0x3c, 0x0a, 0x69, 0xa4, 0x4b,
210 0x18, 0xc6, 0xd2, 0x9b, 0xb8
211};
212
213static const unsigned char ecjpake_test_X[] = {
214 0x04, 0x52, 0xa4, 0xda, 0x90, 0xa5, 0x15, 0x7f, 0xc0, 0xe5, 0x1f, 0x79,
215 0x4b, 0xe3, 0xbb, 0x3f, 0x1d, 0xf8, 0xdf, 0xb1, 0xe3, 0x18, 0xa8, 0x10,
216 0xf2, 0x05, 0x2e, 0x64, 0xa8, 0xe8, 0x35, 0x64, 0xe8, 0xe2, 0x8c, 0x17,
217 0x15, 0xab, 0xf7, 0x8d, 0x1f, 0x8b, 0x18, 0x99, 0x6d, 0x6a, 0xb7, 0xbd,
218 0xcc, 0xbe, 0x52, 0x08, 0x1a, 0x3a, 0xe7, 0x65, 0x4b, 0xdf, 0x66, 0x62,
219 0xf5, 0x74, 0xe0, 0xfd, 0x80
220};
221
222static const unsigned char ecjpake_test_h[] = {
223 0xec, 0xf3, 0x24, 0x46, 0x16, 0xce, 0xa5, 0x34, 0x58, 0x46, 0xd2, 0x45,
224 0xba, 0x27, 0x63, 0x36, 0x50, 0xc4, 0x70, 0x3d, 0x56, 0x0c, 0x7a, 0x7c,
225 0x51, 0x69, 0xfe, 0xa7, 0xa3, 0xf7, 0x79, 0x10
226};
227
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200228/* For tests we don't need a secure RNG;
229 * use the LGC from Numerical Recipes for simplicity */
230static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
231{
232 static uint32_t x = 42;
233 (void) p;
234
235 while( len > 0 )
236 {
237 size_t use_len = len > 4 ? 4 : len;
238 x = 1664525 * x + 1013904223;
239 memcpy( out, &x, use_len );
240 out += use_len;
241 len -= use_len;
242 }
243
244 return( 0 );
245}
246
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200247/*
248 * Checkup routine
249 */
250int mbedtls_ecjpake_self_test( int verbose )
251{
252 int ret;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200253 mbedtls_ecp_group grp;
254 mbedtls_ecp_point G, V, X;
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200255 mbedtls_mpi x, h, h_ref;
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200256 const mbedtls_md_info_t *md_info;
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200257 unsigned char buf[1000];
258 unsigned char *p;
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200259
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200260 mbedtls_ecp_group_init( &grp );
261 mbedtls_ecp_point_init( &G );
262 mbedtls_ecp_point_init( &V );
263 mbedtls_ecp_point_init( &X );
264 mbedtls_mpi_init( &h_ref );
265 mbedtls_mpi_init( &h );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200266 mbedtls_mpi_init( &x );
267
268 /* Common to all tests */
269 md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
270 MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP256R1 ) );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200271
272 if( verbose != 0 )
273 mbedtls_printf( " ECJPAKE test #1 (hash): " );
274
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200275 MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( &grp, &G, ecjpake_test_G,
276 sizeof( ecjpake_test_G ) ) );
277 MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( &grp, &V, ecjpake_test_V,
278 sizeof( ecjpake_test_V ) ) );
279 MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( &grp, &X, ecjpake_test_X,
280 sizeof( ecjpake_test_X ) ) );
281 MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &h_ref, ecjpake_test_h,
282 sizeof( ecjpake_test_h ) ) );
283
284 MBEDTLS_MPI_CHK( ecjpake_hash( md_info, &grp, &G, &V, &X, "client", &h ) );
285
286 if( mbedtls_mpi_cmp_mpi( &h, &h_ref ) != 0 )
287 {
288 ret = 1;
289 goto cleanup;
290 }
291
292 if( verbose != 0 )
293 mbedtls_printf( "passed\n" );
294
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200295 if( verbose != 0 )
296 mbedtls_printf( " ECJPAKE test #2 (zkp, WIP): " );
297
298 MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( &grp, &x, &X,
299 ecjpake_lgc, NULL ) );
300
301 p = buf;
302 MBEDTLS_MPI_CHK( ecjpake_write_zkp( md_info, &grp, &G, &x, &X, "client",
303 &p, buf + sizeof( buf ),
304 ecjpake_lgc, NULL ) );
305
306 if( verbose != 0 )
307 mbedtls_printf( "passed\n" );
308
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200309cleanup:
310 mbedtls_ecp_group_free( &grp );
311 mbedtls_ecp_point_free( &G );
312 mbedtls_ecp_point_free( &V );
313 mbedtls_ecp_point_free( &X );
314 mbedtls_mpi_free( &h_ref );
315 mbedtls_mpi_free( &h );
Manuel Pégourié-Gonnard8489f172015-08-07 17:47:39 +0200316 mbedtls_mpi_free( &x );
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200317
318 if( ret != 0 )
319 {
320 if( verbose != 0 )
321 mbedtls_printf( "failed\n" );
322
323 ret = 1;
324 }
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200325
326 if( verbose != 0 )
327 mbedtls_printf( "\n" );
328
329 return( ret );
330}
331
Manuel Pégourié-Gonnard3dbf2fb2015-08-06 17:24:39 +0200332#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */
333
Manuel Pégourié-Gonnard4d8685b2015-08-05 15:44:42 +0200334#endif /* MBEDTLS_SELF_TEST */
335
336#endif /* MBEDTLS_ECJPAKE_C */