xref: /optee_os/lib/libmbedtls/mbedtls/library/dhm.c (revision 817466cb476de705a8e3dabe1ef165fe27a18c2f)
1*817466cbSJens Wiklander /*
2*817466cbSJens Wiklander  *  Diffie-Hellman-Merkle key exchange
3*817466cbSJens Wiklander  *
4*817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5*817466cbSJens Wiklander  *  SPDX-License-Identifier: Apache-2.0
6*817466cbSJens Wiklander  *
7*817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8*817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9*817466cbSJens Wiklander  *  You may obtain a copy of the License at
10*817466cbSJens Wiklander  *
11*817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12*817466cbSJens Wiklander  *
13*817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14*817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15*817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17*817466cbSJens Wiklander  *  limitations under the License.
18*817466cbSJens Wiklander  *
19*817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20*817466cbSJens Wiklander  */
21*817466cbSJens Wiklander /*
22*817466cbSJens Wiklander  *  The following sources were referenced in the design of this implementation
23*817466cbSJens Wiklander  *  of the Diffie-Hellman-Merkle algorithm:
24*817466cbSJens Wiklander  *
25*817466cbSJens Wiklander  *  [1] Handbook of Applied Cryptography - 1997, Chapter 12
26*817466cbSJens Wiklander  *      Menezes, van Oorschot and Vanstone
27*817466cbSJens Wiklander  *
28*817466cbSJens Wiklander  */
29*817466cbSJens Wiklander 
30*817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
31*817466cbSJens Wiklander #include "mbedtls/config.h"
32*817466cbSJens Wiklander #else
33*817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
34*817466cbSJens Wiklander #endif
35*817466cbSJens Wiklander 
36*817466cbSJens Wiklander #if defined(MBEDTLS_DHM_C)
37*817466cbSJens Wiklander 
38*817466cbSJens Wiklander #include "mbedtls/dhm.h"
39*817466cbSJens Wiklander 
40*817466cbSJens Wiklander #include <string.h>
41*817466cbSJens Wiklander 
42*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
43*817466cbSJens Wiklander #include "mbedtls/pem.h"
44*817466cbSJens Wiklander #endif
45*817466cbSJens Wiklander 
46*817466cbSJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C)
47*817466cbSJens Wiklander #include "mbedtls/asn1.h"
48*817466cbSJens Wiklander #endif
49*817466cbSJens Wiklander 
50*817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
51*817466cbSJens Wiklander #include "mbedtls/platform.h"
52*817466cbSJens Wiklander #else
53*817466cbSJens Wiklander #include <stdlib.h>
54*817466cbSJens Wiklander #include <stdio.h>
55*817466cbSJens Wiklander #define mbedtls_printf     printf
56*817466cbSJens Wiklander #define mbedtls_calloc    calloc
57*817466cbSJens Wiklander #define mbedtls_free       free
58*817466cbSJens Wiklander #endif
59*817466cbSJens Wiklander 
60*817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */
61*817466cbSJens Wiklander static void mbedtls_zeroize( void *v, size_t n ) {
62*817466cbSJens Wiklander     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
63*817466cbSJens Wiklander }
64*817466cbSJens Wiklander 
65*817466cbSJens Wiklander /*
66*817466cbSJens Wiklander  * helper to validate the mbedtls_mpi size and import it
67*817466cbSJens Wiklander  */
68*817466cbSJens Wiklander static int dhm_read_bignum( mbedtls_mpi *X,
69*817466cbSJens Wiklander                             unsigned char **p,
70*817466cbSJens Wiklander                             const unsigned char *end )
71*817466cbSJens Wiklander {
72*817466cbSJens Wiklander     int ret, n;
73*817466cbSJens Wiklander 
74*817466cbSJens Wiklander     if( end - *p < 2 )
75*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
76*817466cbSJens Wiklander 
77*817466cbSJens Wiklander     n = ( (*p)[0] << 8 ) | (*p)[1];
78*817466cbSJens Wiklander     (*p) += 2;
79*817466cbSJens Wiklander 
80*817466cbSJens Wiklander     if( (int)( end - *p ) < n )
81*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
82*817466cbSJens Wiklander 
83*817466cbSJens Wiklander     if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
84*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
85*817466cbSJens Wiklander 
86*817466cbSJens Wiklander     (*p) += n;
87*817466cbSJens Wiklander 
88*817466cbSJens Wiklander     return( 0 );
89*817466cbSJens Wiklander }
90*817466cbSJens Wiklander 
91*817466cbSJens Wiklander /*
92*817466cbSJens Wiklander  * Verify sanity of parameter with regards to P
93*817466cbSJens Wiklander  *
94*817466cbSJens Wiklander  * Parameter should be: 2 <= public_param <= P - 2
95*817466cbSJens Wiklander  *
96*817466cbSJens Wiklander  * For more information on the attack, see:
97*817466cbSJens Wiklander  *  http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
98*817466cbSJens Wiklander  *  http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
99*817466cbSJens Wiklander  */
100*817466cbSJens Wiklander static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
101*817466cbSJens Wiklander {
102*817466cbSJens Wiklander     mbedtls_mpi L, U;
103*817466cbSJens Wiklander     int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
104*817466cbSJens Wiklander 
105*817466cbSJens Wiklander     mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
106*817466cbSJens Wiklander 
107*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
108*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
109*817466cbSJens Wiklander 
110*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 &&
111*817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( param, &U ) <= 0 )
112*817466cbSJens Wiklander     {
113*817466cbSJens Wiklander         ret = 0;
114*817466cbSJens Wiklander     }
115*817466cbSJens Wiklander 
116*817466cbSJens Wiklander cleanup:
117*817466cbSJens Wiklander     mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
118*817466cbSJens Wiklander     return( ret );
119*817466cbSJens Wiklander }
120*817466cbSJens Wiklander 
121*817466cbSJens Wiklander void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
122*817466cbSJens Wiklander {
123*817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
124*817466cbSJens Wiklander }
125*817466cbSJens Wiklander 
126*817466cbSJens Wiklander /*
127*817466cbSJens Wiklander  * Parse the ServerKeyExchange parameters
128*817466cbSJens Wiklander  */
129*817466cbSJens Wiklander int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
130*817466cbSJens Wiklander                      unsigned char **p,
131*817466cbSJens Wiklander                      const unsigned char *end )
132*817466cbSJens Wiklander {
133*817466cbSJens Wiklander     int ret;
134*817466cbSJens Wiklander 
135*817466cbSJens Wiklander     if( ( ret = dhm_read_bignum( &ctx->P,  p, end ) ) != 0 ||
136*817466cbSJens Wiklander         ( ret = dhm_read_bignum( &ctx->G,  p, end ) ) != 0 ||
137*817466cbSJens Wiklander         ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
138*817466cbSJens Wiklander         return( ret );
139*817466cbSJens Wiklander 
140*817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
141*817466cbSJens Wiklander         return( ret );
142*817466cbSJens Wiklander 
143*817466cbSJens Wiklander     ctx->len = mbedtls_mpi_size( &ctx->P );
144*817466cbSJens Wiklander 
145*817466cbSJens Wiklander     return( 0 );
146*817466cbSJens Wiklander }
147*817466cbSJens Wiklander 
148*817466cbSJens Wiklander /*
149*817466cbSJens Wiklander  * Setup and write the ServerKeyExchange parameters
150*817466cbSJens Wiklander  */
151*817466cbSJens Wiklander int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
152*817466cbSJens Wiklander                      unsigned char *output, size_t *olen,
153*817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
154*817466cbSJens Wiklander                      void *p_rng )
155*817466cbSJens Wiklander {
156*817466cbSJens Wiklander     int ret, count = 0;
157*817466cbSJens Wiklander     size_t n1, n2, n3;
158*817466cbSJens Wiklander     unsigned char *p;
159*817466cbSJens Wiklander 
160*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
161*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
162*817466cbSJens Wiklander 
163*817466cbSJens Wiklander     /*
164*817466cbSJens Wiklander      * Generate X as large as possible ( < P )
165*817466cbSJens Wiklander      */
166*817466cbSJens Wiklander     do
167*817466cbSJens Wiklander     {
168*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
169*817466cbSJens Wiklander 
170*817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
171*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
172*817466cbSJens Wiklander 
173*817466cbSJens Wiklander         if( count++ > 10 )
174*817466cbSJens Wiklander             return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
175*817466cbSJens Wiklander     }
176*817466cbSJens Wiklander     while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
177*817466cbSJens Wiklander 
178*817466cbSJens Wiklander     /*
179*817466cbSJens Wiklander      * Calculate GX = G^X mod P
180*817466cbSJens Wiklander      */
181*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
182*817466cbSJens Wiklander                           &ctx->P , &ctx->RP ) );
183*817466cbSJens Wiklander 
184*817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
185*817466cbSJens Wiklander         return( ret );
186*817466cbSJens Wiklander 
187*817466cbSJens Wiklander     /*
188*817466cbSJens Wiklander      * export P, G, GX
189*817466cbSJens Wiklander      */
190*817466cbSJens Wiklander #define DHM_MPI_EXPORT(X,n)                     \
191*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \
192*817466cbSJens Wiklander     *p++ = (unsigned char)( n >> 8 );           \
193*817466cbSJens Wiklander     *p++ = (unsigned char)( n      ); p += n;
194*817466cbSJens Wiklander 
195*817466cbSJens Wiklander     n1 = mbedtls_mpi_size( &ctx->P  );
196*817466cbSJens Wiklander     n2 = mbedtls_mpi_size( &ctx->G  );
197*817466cbSJens Wiklander     n3 = mbedtls_mpi_size( &ctx->GX );
198*817466cbSJens Wiklander 
199*817466cbSJens Wiklander     p = output;
200*817466cbSJens Wiklander     DHM_MPI_EXPORT( &ctx->P , n1 );
201*817466cbSJens Wiklander     DHM_MPI_EXPORT( &ctx->G , n2 );
202*817466cbSJens Wiklander     DHM_MPI_EXPORT( &ctx->GX, n3 );
203*817466cbSJens Wiklander 
204*817466cbSJens Wiklander     *olen  = p - output;
205*817466cbSJens Wiklander 
206*817466cbSJens Wiklander     ctx->len = n1;
207*817466cbSJens Wiklander 
208*817466cbSJens Wiklander cleanup:
209*817466cbSJens Wiklander 
210*817466cbSJens Wiklander     if( ret != 0 )
211*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
212*817466cbSJens Wiklander 
213*817466cbSJens Wiklander     return( 0 );
214*817466cbSJens Wiklander }
215*817466cbSJens Wiklander 
216*817466cbSJens Wiklander /*
217*817466cbSJens Wiklander  * Import the peer's public value G^Y
218*817466cbSJens Wiklander  */
219*817466cbSJens Wiklander int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
220*817466cbSJens Wiklander                      const unsigned char *input, size_t ilen )
221*817466cbSJens Wiklander {
222*817466cbSJens Wiklander     int ret;
223*817466cbSJens Wiklander 
224*817466cbSJens Wiklander     if( ctx == NULL || ilen < 1 || ilen > ctx->len )
225*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
226*817466cbSJens Wiklander 
227*817466cbSJens Wiklander     if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
228*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
229*817466cbSJens Wiklander 
230*817466cbSJens Wiklander     return( 0 );
231*817466cbSJens Wiklander }
232*817466cbSJens Wiklander 
233*817466cbSJens Wiklander /*
234*817466cbSJens Wiklander  * Create own private value X and export G^X
235*817466cbSJens Wiklander  */
236*817466cbSJens Wiklander int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
237*817466cbSJens Wiklander                      unsigned char *output, size_t olen,
238*817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
239*817466cbSJens Wiklander                      void *p_rng )
240*817466cbSJens Wiklander {
241*817466cbSJens Wiklander     int ret, count = 0;
242*817466cbSJens Wiklander 
243*817466cbSJens Wiklander     if( ctx == NULL || olen < 1 || olen > ctx->len )
244*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
245*817466cbSJens Wiklander 
246*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
247*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
248*817466cbSJens Wiklander 
249*817466cbSJens Wiklander     /*
250*817466cbSJens Wiklander      * generate X and calculate GX = G^X mod P
251*817466cbSJens Wiklander      */
252*817466cbSJens Wiklander     do
253*817466cbSJens Wiklander     {
254*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
255*817466cbSJens Wiklander 
256*817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
257*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
258*817466cbSJens Wiklander 
259*817466cbSJens Wiklander         if( count++ > 10 )
260*817466cbSJens Wiklander             return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
261*817466cbSJens Wiklander     }
262*817466cbSJens Wiklander     while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
263*817466cbSJens Wiklander 
264*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
265*817466cbSJens Wiklander                           &ctx->P , &ctx->RP ) );
266*817466cbSJens Wiklander 
267*817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
268*817466cbSJens Wiklander         return( ret );
269*817466cbSJens Wiklander 
270*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
271*817466cbSJens Wiklander 
272*817466cbSJens Wiklander cleanup:
273*817466cbSJens Wiklander 
274*817466cbSJens Wiklander     if( ret != 0 )
275*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
276*817466cbSJens Wiklander 
277*817466cbSJens Wiklander     return( 0 );
278*817466cbSJens Wiklander }
279*817466cbSJens Wiklander 
280*817466cbSJens Wiklander /*
281*817466cbSJens Wiklander  * Use the blinding method and optimisation suggested in section 10 of:
282*817466cbSJens Wiklander  *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
283*817466cbSJens Wiklander  *  DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
284*817466cbSJens Wiklander  *  Berlin Heidelberg, 1996. p. 104-113.
285*817466cbSJens Wiklander  */
286*817466cbSJens Wiklander static int dhm_update_blinding( mbedtls_dhm_context *ctx,
287*817466cbSJens Wiklander                     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
288*817466cbSJens Wiklander {
289*817466cbSJens Wiklander     int ret, count;
290*817466cbSJens Wiklander 
291*817466cbSJens Wiklander     /*
292*817466cbSJens Wiklander      * Don't use any blinding the first time a particular X is used,
293*817466cbSJens Wiklander      * but remember it to use blinding next time.
294*817466cbSJens Wiklander      */
295*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
296*817466cbSJens Wiklander     {
297*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
298*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
299*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
300*817466cbSJens Wiklander 
301*817466cbSJens Wiklander         return( 0 );
302*817466cbSJens Wiklander     }
303*817466cbSJens Wiklander 
304*817466cbSJens Wiklander     /*
305*817466cbSJens Wiklander      * Ok, we need blinding. Can we re-use existing values?
306*817466cbSJens Wiklander      * If yes, just update them by squaring them.
307*817466cbSJens Wiklander      */
308*817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
309*817466cbSJens Wiklander     {
310*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
311*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
312*817466cbSJens Wiklander 
313*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
314*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
315*817466cbSJens Wiklander 
316*817466cbSJens Wiklander         return( 0 );
317*817466cbSJens Wiklander     }
318*817466cbSJens Wiklander 
319*817466cbSJens Wiklander     /*
320*817466cbSJens Wiklander      * We need to generate blinding values from scratch
321*817466cbSJens Wiklander      */
322*817466cbSJens Wiklander 
323*817466cbSJens Wiklander     /* Vi = random( 2, P-1 ) */
324*817466cbSJens Wiklander     count = 0;
325*817466cbSJens Wiklander     do
326*817466cbSJens Wiklander     {
327*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) );
328*817466cbSJens Wiklander 
329*817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
330*817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
331*817466cbSJens Wiklander 
332*817466cbSJens Wiklander         if( count++ > 10 )
333*817466cbSJens Wiklander             return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
334*817466cbSJens Wiklander     }
335*817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
336*817466cbSJens Wiklander 
337*817466cbSJens Wiklander     /* Vf = Vi^-X mod P */
338*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
339*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
340*817466cbSJens Wiklander 
341*817466cbSJens Wiklander cleanup:
342*817466cbSJens Wiklander     return( ret );
343*817466cbSJens Wiklander }
344*817466cbSJens Wiklander 
345*817466cbSJens Wiklander /*
346*817466cbSJens Wiklander  * Derive and export the shared secret (G^Y)^X mod P
347*817466cbSJens Wiklander  */
348*817466cbSJens Wiklander int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
349*817466cbSJens Wiklander                      unsigned char *output, size_t output_size, size_t *olen,
350*817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
351*817466cbSJens Wiklander                      void *p_rng )
352*817466cbSJens Wiklander {
353*817466cbSJens Wiklander     int ret;
354*817466cbSJens Wiklander     mbedtls_mpi GYb;
355*817466cbSJens Wiklander 
356*817466cbSJens Wiklander     if( ctx == NULL || output_size < ctx->len )
357*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
358*817466cbSJens Wiklander 
359*817466cbSJens Wiklander     if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
360*817466cbSJens Wiklander         return( ret );
361*817466cbSJens Wiklander 
362*817466cbSJens Wiklander     mbedtls_mpi_init( &GYb );
363*817466cbSJens Wiklander 
364*817466cbSJens Wiklander     /* Blind peer's value */
365*817466cbSJens Wiklander     if( f_rng != NULL )
366*817466cbSJens Wiklander     {
367*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
368*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
369*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
370*817466cbSJens Wiklander     }
371*817466cbSJens Wiklander     else
372*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
373*817466cbSJens Wiklander 
374*817466cbSJens Wiklander     /* Do modular exponentiation */
375*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
376*817466cbSJens Wiklander                           &ctx->P, &ctx->RP ) );
377*817466cbSJens Wiklander 
378*817466cbSJens Wiklander     /* Unblind secret value */
379*817466cbSJens Wiklander     if( f_rng != NULL )
380*817466cbSJens Wiklander     {
381*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
382*817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
383*817466cbSJens Wiklander     }
384*817466cbSJens Wiklander 
385*817466cbSJens Wiklander     *olen = mbedtls_mpi_size( &ctx->K );
386*817466cbSJens Wiklander 
387*817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
388*817466cbSJens Wiklander 
389*817466cbSJens Wiklander cleanup:
390*817466cbSJens Wiklander     mbedtls_mpi_free( &GYb );
391*817466cbSJens Wiklander 
392*817466cbSJens Wiklander     if( ret != 0 )
393*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
394*817466cbSJens Wiklander 
395*817466cbSJens Wiklander     return( 0 );
396*817466cbSJens Wiklander }
397*817466cbSJens Wiklander 
398*817466cbSJens Wiklander /*
399*817466cbSJens Wiklander  * Free the components of a DHM key
400*817466cbSJens Wiklander  */
401*817466cbSJens Wiklander void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
402*817466cbSJens Wiklander {
403*817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->pX); mbedtls_mpi_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->Vi );
404*817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY );
405*817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->G );
406*817466cbSJens Wiklander     mbedtls_mpi_free( &ctx->P );
407*817466cbSJens Wiklander 
408*817466cbSJens Wiklander     mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
409*817466cbSJens Wiklander }
410*817466cbSJens Wiklander 
411*817466cbSJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C)
412*817466cbSJens Wiklander /*
413*817466cbSJens Wiklander  * Parse DHM parameters
414*817466cbSJens Wiklander  */
415*817466cbSJens Wiklander int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
416*817466cbSJens Wiklander                    size_t dhminlen )
417*817466cbSJens Wiklander {
418*817466cbSJens Wiklander     int ret;
419*817466cbSJens Wiklander     size_t len;
420*817466cbSJens Wiklander     unsigned char *p, *end;
421*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
422*817466cbSJens Wiklander     mbedtls_pem_context pem;
423*817466cbSJens Wiklander 
424*817466cbSJens Wiklander     mbedtls_pem_init( &pem );
425*817466cbSJens Wiklander 
426*817466cbSJens Wiklander     /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
427*817466cbSJens Wiklander     if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
428*817466cbSJens Wiklander         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
429*817466cbSJens Wiklander     else
430*817466cbSJens Wiklander         ret = mbedtls_pem_read_buffer( &pem,
431*817466cbSJens Wiklander                                "-----BEGIN DH PARAMETERS-----",
432*817466cbSJens Wiklander                                "-----END DH PARAMETERS-----",
433*817466cbSJens Wiklander                                dhmin, NULL, 0, &dhminlen );
434*817466cbSJens Wiklander 
435*817466cbSJens Wiklander     if( ret == 0 )
436*817466cbSJens Wiklander     {
437*817466cbSJens Wiklander         /*
438*817466cbSJens Wiklander          * Was PEM encoded
439*817466cbSJens Wiklander          */
440*817466cbSJens Wiklander         dhminlen = pem.buflen;
441*817466cbSJens Wiklander     }
442*817466cbSJens Wiklander     else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
443*817466cbSJens Wiklander         goto exit;
444*817466cbSJens Wiklander 
445*817466cbSJens Wiklander     p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
446*817466cbSJens Wiklander #else
447*817466cbSJens Wiklander     p = (unsigned char *) dhmin;
448*817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */
449*817466cbSJens Wiklander     end = p + dhminlen;
450*817466cbSJens Wiklander 
451*817466cbSJens Wiklander     /*
452*817466cbSJens Wiklander      *  DHParams ::= SEQUENCE {
453*817466cbSJens Wiklander      *      prime              INTEGER,  -- P
454*817466cbSJens Wiklander      *      generator          INTEGER,  -- g
455*817466cbSJens Wiklander      *      privateValueLength INTEGER OPTIONAL
456*817466cbSJens Wiklander      *  }
457*817466cbSJens Wiklander      */
458*817466cbSJens Wiklander     if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
459*817466cbSJens Wiklander             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
460*817466cbSJens Wiklander     {
461*817466cbSJens Wiklander         ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
462*817466cbSJens Wiklander         goto exit;
463*817466cbSJens Wiklander     }
464*817466cbSJens Wiklander 
465*817466cbSJens Wiklander     end = p + len;
466*817466cbSJens Wiklander 
467*817466cbSJens Wiklander     if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P  ) ) != 0 ||
468*817466cbSJens Wiklander         ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
469*817466cbSJens Wiklander     {
470*817466cbSJens Wiklander         ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
471*817466cbSJens Wiklander         goto exit;
472*817466cbSJens Wiklander     }
473*817466cbSJens Wiklander 
474*817466cbSJens Wiklander     if( p != end )
475*817466cbSJens Wiklander     {
476*817466cbSJens Wiklander         /* This might be the optional privateValueLength.
477*817466cbSJens Wiklander          * If so, we can cleanly discard it */
478*817466cbSJens Wiklander         mbedtls_mpi rec;
479*817466cbSJens Wiklander         mbedtls_mpi_init( &rec );
480*817466cbSJens Wiklander         ret = mbedtls_asn1_get_mpi( &p, end, &rec );
481*817466cbSJens Wiklander         mbedtls_mpi_free( &rec );
482*817466cbSJens Wiklander         if ( ret != 0 )
483*817466cbSJens Wiklander         {
484*817466cbSJens Wiklander             ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
485*817466cbSJens Wiklander             goto exit;
486*817466cbSJens Wiklander         }
487*817466cbSJens Wiklander         if ( p != end )
488*817466cbSJens Wiklander         {
489*817466cbSJens Wiklander             ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
490*817466cbSJens Wiklander                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
491*817466cbSJens Wiklander             goto exit;
492*817466cbSJens Wiklander         }
493*817466cbSJens Wiklander     }
494*817466cbSJens Wiklander 
495*817466cbSJens Wiklander     ret = 0;
496*817466cbSJens Wiklander 
497*817466cbSJens Wiklander     dhm->len = mbedtls_mpi_size( &dhm->P );
498*817466cbSJens Wiklander 
499*817466cbSJens Wiklander exit:
500*817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C)
501*817466cbSJens Wiklander     mbedtls_pem_free( &pem );
502*817466cbSJens Wiklander #endif
503*817466cbSJens Wiklander     if( ret != 0 )
504*817466cbSJens Wiklander         mbedtls_dhm_free( dhm );
505*817466cbSJens Wiklander 
506*817466cbSJens Wiklander     return( ret );
507*817466cbSJens Wiklander }
508*817466cbSJens Wiklander 
509*817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
510*817466cbSJens Wiklander /*
511*817466cbSJens Wiklander  * Load all data from a file into a given buffer.
512*817466cbSJens Wiklander  *
513*817466cbSJens Wiklander  * The file is expected to contain either PEM or DER encoded data.
514*817466cbSJens Wiklander  * A terminating null byte is always appended. It is included in the announced
515*817466cbSJens Wiklander  * length only if the data looks like it is PEM encoded.
516*817466cbSJens Wiklander  */
517*817466cbSJens Wiklander static int load_file( const char *path, unsigned char **buf, size_t *n )
518*817466cbSJens Wiklander {
519*817466cbSJens Wiklander     FILE *f;
520*817466cbSJens Wiklander     long size;
521*817466cbSJens Wiklander 
522*817466cbSJens Wiklander     if( ( f = fopen( path, "rb" ) ) == NULL )
523*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
524*817466cbSJens Wiklander 
525*817466cbSJens Wiklander     fseek( f, 0, SEEK_END );
526*817466cbSJens Wiklander     if( ( size = ftell( f ) ) == -1 )
527*817466cbSJens Wiklander     {
528*817466cbSJens Wiklander         fclose( f );
529*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
530*817466cbSJens Wiklander     }
531*817466cbSJens Wiklander     fseek( f, 0, SEEK_SET );
532*817466cbSJens Wiklander 
533*817466cbSJens Wiklander     *n = (size_t) size;
534*817466cbSJens Wiklander 
535*817466cbSJens Wiklander     if( *n + 1 == 0 ||
536*817466cbSJens Wiklander         ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
537*817466cbSJens Wiklander     {
538*817466cbSJens Wiklander         fclose( f );
539*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
540*817466cbSJens Wiklander     }
541*817466cbSJens Wiklander 
542*817466cbSJens Wiklander     if( fread( *buf, 1, *n, f ) != *n )
543*817466cbSJens Wiklander     {
544*817466cbSJens Wiklander         fclose( f );
545*817466cbSJens Wiklander         mbedtls_free( *buf );
546*817466cbSJens Wiklander         return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
547*817466cbSJens Wiklander     }
548*817466cbSJens Wiklander 
549*817466cbSJens Wiklander     fclose( f );
550*817466cbSJens Wiklander 
551*817466cbSJens Wiklander     (*buf)[*n] = '\0';
552*817466cbSJens Wiklander 
553*817466cbSJens Wiklander     if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
554*817466cbSJens Wiklander         ++*n;
555*817466cbSJens Wiklander 
556*817466cbSJens Wiklander     return( 0 );
557*817466cbSJens Wiklander }
558*817466cbSJens Wiklander 
559*817466cbSJens Wiklander /*
560*817466cbSJens Wiklander  * Load and parse DHM parameters
561*817466cbSJens Wiklander  */
562*817466cbSJens Wiklander int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
563*817466cbSJens Wiklander {
564*817466cbSJens Wiklander     int ret;
565*817466cbSJens Wiklander     size_t n;
566*817466cbSJens Wiklander     unsigned char *buf;
567*817466cbSJens Wiklander 
568*817466cbSJens Wiklander     if( ( ret = load_file( path, &buf, &n ) ) != 0 )
569*817466cbSJens Wiklander         return( ret );
570*817466cbSJens Wiklander 
571*817466cbSJens Wiklander     ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
572*817466cbSJens Wiklander 
573*817466cbSJens Wiklander     mbedtls_zeroize( buf, n );
574*817466cbSJens Wiklander     mbedtls_free( buf );
575*817466cbSJens Wiklander 
576*817466cbSJens Wiklander     return( ret );
577*817466cbSJens Wiklander }
578*817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
579*817466cbSJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */
580*817466cbSJens Wiklander 
581*817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
582*817466cbSJens Wiklander 
583*817466cbSJens Wiklander static const char mbedtls_test_dhm_params[] =
584*817466cbSJens Wiklander "-----BEGIN DH PARAMETERS-----\r\n"
585*817466cbSJens Wiklander "MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
586*817466cbSJens Wiklander "1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
587*817466cbSJens Wiklander "9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
588*817466cbSJens Wiklander "-----END DH PARAMETERS-----\r\n";
589*817466cbSJens Wiklander 
590*817466cbSJens Wiklander static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
591*817466cbSJens Wiklander 
592*817466cbSJens Wiklander /*
593*817466cbSJens Wiklander  * Checkup routine
594*817466cbSJens Wiklander  */
595*817466cbSJens Wiklander int mbedtls_dhm_self_test( int verbose )
596*817466cbSJens Wiklander {
597*817466cbSJens Wiklander     int ret;
598*817466cbSJens Wiklander     mbedtls_dhm_context dhm;
599*817466cbSJens Wiklander 
600*817466cbSJens Wiklander     mbedtls_dhm_init( &dhm );
601*817466cbSJens Wiklander 
602*817466cbSJens Wiklander     if( verbose != 0 )
603*817466cbSJens Wiklander         mbedtls_printf( "  DHM parameter load: " );
604*817466cbSJens Wiklander 
605*817466cbSJens Wiklander     if( ( ret = mbedtls_dhm_parse_dhm( &dhm,
606*817466cbSJens Wiklander                     (const unsigned char *) mbedtls_test_dhm_params,
607*817466cbSJens Wiklander                     mbedtls_test_dhm_params_len ) ) != 0 )
608*817466cbSJens Wiklander     {
609*817466cbSJens Wiklander         if( verbose != 0 )
610*817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
611*817466cbSJens Wiklander 
612*817466cbSJens Wiklander         ret = 1;
613*817466cbSJens Wiklander         goto exit;
614*817466cbSJens Wiklander     }
615*817466cbSJens Wiklander 
616*817466cbSJens Wiklander     if( verbose != 0 )
617*817466cbSJens Wiklander         mbedtls_printf( "passed\n\n" );
618*817466cbSJens Wiklander 
619*817466cbSJens Wiklander exit:
620*817466cbSJens Wiklander     mbedtls_dhm_free( &dhm );
621*817466cbSJens Wiklander 
622*817466cbSJens Wiklander     return( ret );
623*817466cbSJens Wiklander }
624*817466cbSJens Wiklander 
625*817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
626*817466cbSJens Wiklander 
627*817466cbSJens Wiklander #endif /* MBEDTLS_DHM_C */
628