blob: 7b865ecd234ed950c4b9421dd8a40420ec1cc9b1 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Diffie-Hellman-Merkle key exchange
3 *
Paul Bakker530927b2015-02-13 14:24:10 +01004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
Manuel Pégourié-Gonnarde12abf92015-01-28 17:13:45 +00006 * This file is part of mbed TLS (https://polarssl.org)
Paul Bakkere0ccd0a2009-01-04 16:27:10 +00007 *
Paul Bakker5121ce52009-01-03 21:22:43 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22/*
23 * Reference:
24 *
25 * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
26 */
27
Paul Bakker40e46942009-01-03 21:51:57 +000028#include "polarssl/config.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000029
Paul Bakker40e46942009-01-03 21:51:57 +000030#if defined(POLARSSL_DHM_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000031
Paul Bakker40e46942009-01-03 21:51:57 +000032#include "polarssl/dhm.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000033
Paul Bakker312da332014-06-13 17:20:13 +020034/* Implementation that should never be optimized out by the compiler */
35static void polarssl_zeroize( void *v, size_t n ) {
36 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
37}
38
Paul Bakker5121ce52009-01-03 21:22:43 +000039/*
40 * helper to validate the mpi size and import it
41 */
42static int dhm_read_bignum( mpi *X,
43 unsigned char **p,
Paul Bakkerff60ee62010-03-16 21:09:09 +000044 const unsigned char *end )
Paul Bakker5121ce52009-01-03 21:22:43 +000045{
46 int ret, n;
47
48 if( end - *p < 2 )
Paul Bakker40e46942009-01-03 21:51:57 +000049 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000050
51 n = ( (*p)[0] << 8 ) | (*p)[1];
52 (*p) += 2;
53
54 if( (int)( end - *p ) < n )
Paul Bakker40e46942009-01-03 21:51:57 +000055 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +000056
57 if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 )
Paul Bakker9d781402011-05-09 16:17:09 +000058 return( POLARSSL_ERR_DHM_READ_PARAMS_FAILED + ret );
Paul Bakker5121ce52009-01-03 21:22:43 +000059
60 (*p) += n;
61
62 return( 0 );
63}
64
65/*
Paul Bakkeraec37cb2012-04-26 18:59:59 +000066 * Verify sanity of parameter with regards to P
Paul Bakker345a6fe2011-02-28 21:20:02 +000067 *
Paul Bakkeraec37cb2012-04-26 18:59:59 +000068 * Parameter should be: 2 <= public_param <= P - 2
Paul Bakker345a6fe2011-02-28 21:20:02 +000069 *
70 * For more information on the attack, see:
71 * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
72 * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
Paul Bakkerc47840e2011-02-20 16:37:30 +000073 */
Paul Bakkeraec37cb2012-04-26 18:59:59 +000074static int dhm_check_range( const mpi *param, const mpi *P )
Paul Bakkerc47840e2011-02-20 16:37:30 +000075{
Paul Bakker345a6fe2011-02-28 21:20:02 +000076 mpi L, U;
77 int ret = POLARSSL_ERR_DHM_BAD_INPUT_DATA;
Paul Bakkerc47840e2011-02-20 16:37:30 +000078
Paul Bakker6c591fa2011-05-05 11:49:20 +000079 mpi_init( &L ); mpi_init( &U );
Paul Bakker7890e622014-04-17 12:42:41 +020080
81 MPI_CHK( mpi_lset( &L, 2 ) );
82 MPI_CHK( mpi_sub_int( &U, P, 2 ) );
Paul Bakkerc47840e2011-02-20 16:37:30 +000083
Paul Bakkeraec37cb2012-04-26 18:59:59 +000084 if( mpi_cmp_mpi( param, &L ) >= 0 &&
85 mpi_cmp_mpi( param, &U ) <= 0 )
Paul Bakkerc47840e2011-02-20 16:37:30 +000086 {
Paul Bakker345a6fe2011-02-28 21:20:02 +000087 ret = 0;
Paul Bakkerc47840e2011-02-20 16:37:30 +000088 }
89
Paul Bakker7890e622014-04-17 12:42:41 +020090cleanup:
Paul Bakker6c591fa2011-05-05 11:49:20 +000091 mpi_free( &L ); mpi_free( &U );
Paul Bakker345a6fe2011-02-28 21:20:02 +000092 return( ret );
Paul Bakkerc47840e2011-02-20 16:37:30 +000093}
94
95/*
Paul Bakker5121ce52009-01-03 21:22:43 +000096 * Parse the ServerKeyExchange parameters
97 */
98int dhm_read_params( dhm_context *ctx,
99 unsigned char **p,
Paul Bakkerff60ee62010-03-16 21:09:09 +0000100 const unsigned char *end )
Paul Bakker5121ce52009-01-03 21:22:43 +0000101{
Paul Bakker13ed9ab2012-04-16 09:43:49 +0000102 int ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000103
104 memset( ctx, 0, sizeof( dhm_context ) );
105
106 if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 ||
107 ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 ||
108 ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
109 return( ret );
110
Paul Bakker345a6fe2011-02-28 21:20:02 +0000111 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
112 return( ret );
113
Paul Bakker5121ce52009-01-03 21:22:43 +0000114 ctx->len = mpi_size( &ctx->P );
115
116 if( end - *p < 2 )
Paul Bakker40e46942009-01-03 21:51:57 +0000117 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000118
Paul Bakker5121ce52009-01-03 21:22:43 +0000119 return( 0 );
120}
121
122/*
123 * Setup and write the ServerKeyExchange parameters
124 */
125int dhm_make_params( dhm_context *ctx, int x_size,
Paul Bakker23986e52011-04-24 08:57:21 +0000126 unsigned char *output, size_t *olen,
Paul Bakkera3d195c2011-11-27 21:07:34 +0000127 int (*f_rng)(void *, unsigned char *, size_t),
128 void *p_rng )
Paul Bakker5121ce52009-01-03 21:22:43 +0000129{
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000130 int ret, count = 0;
Paul Bakker23986e52011-04-24 08:57:21 +0000131 size_t n1, n2, n3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000132 unsigned char *p;
133
Paul Bakkerb5b20f12012-09-16 15:07:49 +0000134 if( mpi_cmp_int( &ctx->P, 0 ) == 0 )
135 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
136
Paul Bakker5121ce52009-01-03 21:22:43 +0000137 /*
Paul Bakkerff7fe672010-07-18 09:45:05 +0000138 * Generate X as large as possible ( < P )
Paul Bakker5121ce52009-01-03 21:22:43 +0000139 */
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000140 do
141 {
142 mpi_fill_random( &ctx->X, x_size, f_rng, p_rng );
Paul Bakker5121ce52009-01-03 21:22:43 +0000143
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000144 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
Paul Bakker7890e622014-04-17 12:42:41 +0200145 MPI_CHK( mpi_shift_r( &ctx->X, 1 ) );
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000146
147 if( count++ > 10 )
148 return( POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED );
149 }
150 while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000151
Paul Bakkerff7fe672010-07-18 09:45:05 +0000152 /*
153 * Calculate GX = G^X mod P
154 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000155 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
156 &ctx->P , &ctx->RP ) );
157
Paul Bakker345a6fe2011-02-28 21:20:02 +0000158 if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
Paul Bakkerc47840e2011-02-20 16:37:30 +0000159 return( ret );
160
Paul Bakker5121ce52009-01-03 21:22:43 +0000161 /*
162 * export P, G, GX
163 */
164#define DHM_MPI_EXPORT(X,n) \
165 MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \
166 *p++ = (unsigned char)( n >> 8 ); \
167 *p++ = (unsigned char)( n ); p += n;
168
169 n1 = mpi_size( &ctx->P );
170 n2 = mpi_size( &ctx->G );
171 n3 = mpi_size( &ctx->GX );
172
173 p = output;
174 DHM_MPI_EXPORT( &ctx->P , n1 );
175 DHM_MPI_EXPORT( &ctx->G , n2 );
176 DHM_MPI_EXPORT( &ctx->GX, n3 );
177
178 *olen = p - output;
179
180 ctx->len = n1;
181
182cleanup:
183
184 if( ret != 0 )
Paul Bakker9d781402011-05-09 16:17:09 +0000185 return( POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED + ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000186
187 return( 0 );
188}
189
190/*
191 * Import the peer's public value G^Y
192 */
193int dhm_read_public( dhm_context *ctx,
Paul Bakker23986e52011-04-24 08:57:21 +0000194 const unsigned char *input, size_t ilen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000195{
196 int ret;
197
198 if( ctx == NULL || ilen < 1 || ilen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000199 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000200
201 if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
Paul Bakker9d781402011-05-09 16:17:09 +0000202 return( POLARSSL_ERR_DHM_READ_PUBLIC_FAILED + ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000203
204 return( 0 );
205}
206
207/*
208 * Create own private value X and export G^X
209 */
210int dhm_make_public( dhm_context *ctx, int x_size,
Paul Bakker23986e52011-04-24 08:57:21 +0000211 unsigned char *output, size_t olen,
Paul Bakkera3d195c2011-11-27 21:07:34 +0000212 int (*f_rng)(void *, unsigned char *, size_t),
213 void *p_rng )
Paul Bakker5121ce52009-01-03 21:22:43 +0000214{
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000215 int ret, count = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000216
217 if( ctx == NULL || olen < 1 || olen > ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000218 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000219
Paul Bakkerb5b20f12012-09-16 15:07:49 +0000220 if( mpi_cmp_int( &ctx->P, 0 ) == 0 )
221 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
222
Paul Bakker5121ce52009-01-03 21:22:43 +0000223 /*
224 * generate X and calculate GX = G^X mod P
225 */
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000226 do
227 {
228 mpi_fill_random( &ctx->X, x_size, f_rng, p_rng );
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000230 while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
Paul Bakker7890e622014-04-17 12:42:41 +0200231 MPI_CHK( mpi_shift_r( &ctx->X, 1 ) );
Paul Bakkeraec37cb2012-04-26 18:59:59 +0000232
233 if( count++ > 10 )
234 return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED );
235 }
236 while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
238 MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
239 &ctx->P , &ctx->RP ) );
240
Paul Bakker345a6fe2011-02-28 21:20:02 +0000241 if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
242 return( ret );
Paul Bakkerc47840e2011-02-20 16:37:30 +0000243
Paul Bakker5121ce52009-01-03 21:22:43 +0000244 MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) );
245
246cleanup:
247
248 if( ret != 0 )
Paul Bakker9d781402011-05-09 16:17:09 +0000249 return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000250
251 return( 0 );
252}
253
254/*
255 * Derive and export the shared secret (G^Y)^X mod P
256 */
257int dhm_calc_secret( dhm_context *ctx,
Paul Bakker23986e52011-04-24 08:57:21 +0000258 unsigned char *output, size_t *olen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000259{
260 int ret;
261
262 if( ctx == NULL || *olen < ctx->len )
Paul Bakker40e46942009-01-03 21:51:57 +0000263 return( POLARSSL_ERR_DHM_BAD_INPUT_DATA );
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
265 MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X,
266 &ctx->P, &ctx->RP ) );
267
Paul Bakker345a6fe2011-02-28 21:20:02 +0000268 if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
Paul Bakkerc47840e2011-02-20 16:37:30 +0000269 return( ret );
270
Paul Bakker5121ce52009-01-03 21:22:43 +0000271 *olen = mpi_size( &ctx->K );
272
273 MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) );
274
275cleanup:
276
277 if( ret != 0 )
Paul Bakker9d781402011-05-09 16:17:09 +0000278 return( POLARSSL_ERR_DHM_CALC_SECRET_FAILED + ret );
Paul Bakker5121ce52009-01-03 21:22:43 +0000279
280 return( 0 );
281}
282
283/*
284 * Free the components of a DHM key
285 */
286void dhm_free( dhm_context *ctx )
287{
Paul Bakker6c591fa2011-05-05 11:49:20 +0000288 mpi_free( &ctx->RP ); mpi_free( &ctx->K ); mpi_free( &ctx->GY );
289 mpi_free( &ctx->GX ); mpi_free( &ctx->X ); mpi_free( &ctx->G );
290 mpi_free( &ctx->P );
Paul Bakker312da332014-06-13 17:20:13 +0200291
292 polarssl_zeroize( ctx, sizeof( dhm_context ) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000293}
294
Paul Bakker40e46942009-01-03 21:51:57 +0000295#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000296
297/*
298 * Checkup routine
299 */
300int dhm_self_test( int verbose )
301{
302 return( verbose++ );
303}
304
305#endif
306
307#endif