dhm.c 16 KB
Newer Older
1 2 3
/*
 *  Diffie-Hellman-Merkle key exchange
 *
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
4
 *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
Paul Bakker's avatar
Paul Bakker committed
5
 *
6
 *  This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker's avatar
Paul Bakker committed
7
 *
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
/*
 *  Reference:
 *
 *  http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12)
 */

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
28
#if !defined(MBEDTLS_CONFIG_FILE)
29
#include "mbedtls/config.h"
30
#else
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
31
#include MBEDTLS_CONFIG_FILE
32
#endif
33

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
34
#if defined(MBEDTLS_DHM_C)
35

36
#include "mbedtls/dhm.h"
37

38 39
#include <string.h>

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
40
#if defined(MBEDTLS_PEM_PARSE_C)
41
#include "mbedtls/pem.h"
42 43
#endif

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
44
#if defined(MBEDTLS_ASN1_PARSE_C)
45
#include "mbedtls/asn1.h"
46 47
#endif

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
48
#if defined(MBEDTLS_PLATFORM_C)
49
#include "mbedtls/platform.h"
50 51
#else
#include <stdlib.h>
52
#include <stdio.h>
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
53 54 55
#define mbedtls_printf     printf
#define mbedtls_malloc     malloc
#define mbedtls_free       free
56 57
#endif

58
/* Implementation that should never be optimized out by the compiler */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
59
static void mbedtls_zeroize( void *v, size_t n ) {
60 61 62
    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}

63
/*
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
64
 * helper to validate the mbedtls_mpi size and import it
65
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
66
static int dhm_read_bignum( mbedtls_mpi *X,
67
                            unsigned char **p,
68
                            const unsigned char *end )
69 70 71 72
{
    int ret, n;

    if( end - *p < 2 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
73
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
74 75 76 77 78

    n = ( (*p)[0] << 8 ) | (*p)[1];
    (*p) += 2;

    if( (int)( end - *p ) < n )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
79
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
80

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
81 82
    if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
        return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
83 84 85 86 87 88

    (*p) += n;

    return( 0 );
}

Paul Bakker's avatar
Paul Bakker committed
89
/*
90
 * Verify sanity of parameter with regards to P
91
 *
92
 * Parameter should be: 2 <= public_param <= P - 2
93 94 95 96
 *
 * For more information on the attack, see:
 *  http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
 *  http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
Paul Bakker's avatar
Paul Bakker committed
97
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
98
static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
Paul Bakker's avatar
Paul Bakker committed
99
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
100 101
    mbedtls_mpi L, U;
    int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
Paul Bakker's avatar
Paul Bakker committed
102

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
103
    mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U );
104

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
105 106
    MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) );
    MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
Paul Bakker's avatar
Paul Bakker committed
107

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
108 109
    if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 &&
        mbedtls_mpi_cmp_mpi( param, &U ) <= 0 )
Paul Bakker's avatar
Paul Bakker committed
110
    {
111
        ret = 0;
Paul Bakker's avatar
Paul Bakker committed
112 113
    }

114
cleanup:
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
115
    mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U );
116
    return( ret );
Paul Bakker's avatar
Paul Bakker committed
117 118
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
119
void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
Paul Bakker's avatar
Paul Bakker committed
120
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
121
    memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
Paul Bakker's avatar
Paul Bakker committed
122 123
}

124 125 126
/*
 * Parse the ServerKeyExchange parameters
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
127
int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
128
                     unsigned char **p,
129
                     const unsigned char *end )
130
{
Paul Bakker's avatar
Paul Bakker committed
131
    int ret;
132 133 134 135 136 137

    if( ( ret = dhm_read_bignum( &ctx->P,  p, end ) ) != 0 ||
        ( ret = dhm_read_bignum( &ctx->G,  p, end ) ) != 0 ||
        ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
        return( ret );

138 139 140
    if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
        return( ret );

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
141
    ctx->len = mbedtls_mpi_size( &ctx->P );
142 143 144 145 146 147 148

    return( 0 );
}

/*
 * Setup and write the ServerKeyExchange parameters
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
149
int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
150
                     unsigned char *output, size_t *olen,
151 152
                     int (*f_rng)(void *, unsigned char *, size_t),
                     void *p_rng )
153
{
154
    int ret, count = 0;
155
    size_t n1, n2, n3;
156 157
    unsigned char *p;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
158 159
    if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
160

161
    /*
162
     * Generate X as large as possible ( < P )
163
     */
164 165
    do
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
166
        mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng );
167

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
168 169
        while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
            MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
170 171

        if( count++ > 10 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
172
            return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
173 174
    }
    while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
175

176 177 178
    /*
     * Calculate GX = G^X mod P
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
179
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
180 181
                          &ctx->P , &ctx->RP ) );

182
    if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
Paul Bakker's avatar
Paul Bakker committed
183 184
        return( ret );

185 186 187 188
    /*
     * export P, G, GX
     */
#define DHM_MPI_EXPORT(X,n)                     \
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
189
    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \
190 191 192
    *p++ = (unsigned char)( n >> 8 );           \
    *p++ = (unsigned char)( n      ); p += n;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
193 194 195
    n1 = mbedtls_mpi_size( &ctx->P  );
    n2 = mbedtls_mpi_size( &ctx->G  );
    n3 = mbedtls_mpi_size( &ctx->GX );
196 197 198 199 200 201 202 203 204 205 206 207 208

    p = output;
    DHM_MPI_EXPORT( &ctx->P , n1 );
    DHM_MPI_EXPORT( &ctx->G , n2 );
    DHM_MPI_EXPORT( &ctx->GX, n3 );

    *olen  = p - output;

    ctx->len = n1;

cleanup:

    if( ret != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
209
        return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
210 211 212 213 214 215 216

    return( 0 );
}

/*
 * Import the peer's public value G^Y
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
217
int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
218
                     const unsigned char *input, size_t ilen )
219 220 221 222
{
    int ret;

    if( ctx == NULL || ilen < 1 || ilen > ctx->len )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
223
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
224

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
225 226
    if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
        return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
227 228 229 230 231 232 233

    return( 0 );
}

/*
 * Create own private value X and export G^X
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
234
int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
235
                     unsigned char *output, size_t olen,
236 237
                     int (*f_rng)(void *, unsigned char *, size_t),
                     void *p_rng )
238
{
239
    int ret, count = 0;
240 241

    if( ctx == NULL || olen < 1 || olen > ctx->len )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
242
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
243

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
244 245
    if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
246

247 248 249
    /*
     * generate X and calculate GX = G^X mod P
     */
250 251
    do
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
252
        mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng );
253

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
254 255
        while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 )
            MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) );
256 257

        if( count++ > 10 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
258
            return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
259 260
    }
    while( dhm_check_range( &ctx->X, &ctx->P ) != 0 );
261

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
262
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
263 264
                          &ctx->P , &ctx->RP ) );

265 266
    if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
        return( ret );
Paul Bakker's avatar
Paul Bakker committed
267

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
268
    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
269 270 271 272

cleanup:

    if( ret != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
273
        return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
274 275 276 277

    return( 0 );
}

278 279 280
/*
 * Use the blinding method and optimisation suggested in section 10 of:
 *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
281
 *  DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
282 283
 *  Berlin Heidelberg, 1996. p. 104-113.
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
284
static int dhm_update_blinding( mbedtls_dhm_context *ctx,
285 286 287 288 289
                    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
{
    int ret, count;

    /*
290 291
     * Don't use any blinding the first time a particular X is used,
     * but remember it to use blinding next time.
292
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
293
    if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
294
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
295 296 297
        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
298 299

        return( 0 );
300 301 302
    }

    /*
303 304
     * Ok, we need blinding. Can we re-use existing values?
     * If yes, just update them by squaring them.
305
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
306
    if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
307
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
308 309
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
310

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
311 312
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
313

314
        return( 0 );
315
    }
316 317

    /*
318
     * We need to generate blinding values from scratch
319
     */
320

321 322 323 324
    /* Vi = random( 2, P-1 ) */
    count = 0;
    do
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
325
        mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng );
326

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
327 328
        while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 )
            MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) );
329 330

        if( count++ > 10 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
331
            return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
332
    }
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
333
    while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 );
334

335
    /* Vf = Vi^-X mod P */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
336 337
    MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) );
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
338 339 340 341 342

cleanup:
    return( ret );
}

343 344 345
/*
 * Derive and export the shared secret (G^Y)^X mod P
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
346
int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
347 348 349
                     unsigned char *output, size_t *olen,
                     int (*f_rng)(void *, unsigned char *, size_t),
                     void *p_rng )
350 351
{
    int ret;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
352
    mbedtls_mpi GYb;
353

354
    if( ctx == NULL || *olen < ctx->len )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
355
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
356

357
    if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
Paul Bakker's avatar
Paul Bakker committed
358 359
        return( ret );

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
360
    mbedtls_mpi_init( &GYb );
361 362

    /* Blind peer's value */
363
    if( f_rng != NULL )
364
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
365 366 367
        MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
368 369
    }
    else
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
370
        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
371 372

    /* Do modular exponentiation */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
373
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
374 375 376
                          &ctx->P, &ctx->RP ) );

    /* Unblind secret value */
377
    if( f_rng != NULL )
378
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
379 380
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
381 382
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
383
    *olen = mbedtls_mpi_size( &ctx->K );
384

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
385
    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
386 387

cleanup:
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
388
    mbedtls_mpi_free( &GYb );
389 390

    if( ret != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
391
        return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
392 393 394 395 396 397 398

    return( 0 );
}

/*
 * Free the components of a DHM key
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
399
void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
400
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
401 402 403 404
    mbedtls_mpi_free( &ctx->pX); mbedtls_mpi_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->Vi );
    mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY );
    mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->G );
    mbedtls_mpi_free( &ctx->P );
405

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
406
    mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
407 408
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
409
#if defined(MBEDTLS_ASN1_PARSE_C)
410 411 412
/*
 * Parse DHM parameters
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
413
int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
414
                   size_t dhminlen )
415 416 417 418
{
    int ret;
    size_t len;
    unsigned char *p, *end;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
419 420
#if defined(MBEDTLS_PEM_PARSE_C)
    mbedtls_pem_context pem;
421

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
422
    mbedtls_pem_init( &pem );
423

424 425 426 427 428 429 430 431
    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
    if( dhmin[dhminlen - 1] != '\0' )
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
    else
        ret = mbedtls_pem_read_buffer( &pem,
                               "-----BEGIN DH PARAMETERS-----",
                               "-----END DH PARAMETERS-----",
                               dhmin, NULL, 0, &dhminlen );
432 433 434 435 436 437 438 439

    if( ret == 0 )
    {
        /*
         * Was PEM encoded
         */
        dhminlen = pem.buflen;
    }
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
440
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
441 442 443 444 445
        goto exit;

    p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
#else
    p = (unsigned char *) dhmin;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
446
#endif /* MBEDTLS_PEM_PARSE_C */
447 448 449 450
    end = p + dhminlen;

    /*
     *  DHParams ::= SEQUENCE {
451 452 453
     *      prime              INTEGER,  -- P
     *      generator          INTEGER,  -- g
     *      privateValueLength INTEGER OPTIONAL
454 455
     *  }
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
456 457
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
458
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
459
        ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
460 461 462 463 464
        goto exit;
    }

    end = p + len;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
465 466
    if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P  ) ) != 0 ||
        ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
467
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
468
        ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
469 470 471 472 473
        goto exit;
    }

    if( p != end )
    {
474 475 476 477 478 479
        /* This might be the optional privateValueLength.
         * If so, we can cleanly discard it */
        mbedtls_mpi rec;
        mbedtls_mpi_init( &rec );
        ret = mbedtls_asn1_get_mpi( &p, end, &rec );
        mbedtls_mpi_free( &rec );
480 481
        if ( ret != 0 )
        {
482
            ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
483 484 485 486
            goto exit;
        }
        if ( p != end )
        {
487 488
            ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
489 490
            goto exit;
        }
491 492 493 494
    }

    ret = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
495
    dhm->len = mbedtls_mpi_size( &dhm->P );
496

497
exit:
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
498 499
#if defined(MBEDTLS_PEM_PARSE_C)
    mbedtls_pem_free( &pem );
500 501
#endif
    if( ret != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
502
        mbedtls_dhm_free( dhm );
503 504 505 506

    return( ret );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
507
#if defined(MBEDTLS_FS_IO)
508 509
/*
 * Load all data from a file into a given buffer.
510 511 512 513
 *
 * The file is expected to contain either PEM or DER encoded data.
 * A terminating null byte is always appended. It is included in the announced
 * length only if the data looks like it is PEM encoded.
514 515 516 517 518 519 520
 */
static int load_file( const char *path, unsigned char **buf, size_t *n )
{
    FILE *f;
    long size;

    if( ( f = fopen( path, "rb" ) ) == NULL )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
521
        return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
522 523 524 525 526

    fseek( f, 0, SEEK_END );
    if( ( size = ftell( f ) ) == -1 )
    {
        fclose( f );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
527
        return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
528 529 530 531 532 533
    }
    fseek( f, 0, SEEK_SET );

    *n = (size_t) size;

    if( *n + 1 == 0 ||
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
534
        ( *buf = mbedtls_malloc( *n + 1 ) ) == NULL )
535 536
    {
        fclose( f );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
537
        return( MBEDTLS_ERR_DHM_MALLOC_FAILED );
538 539 540 541 542
    }

    if( fread( *buf, 1, *n, f ) != *n )
    {
        fclose( f );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
543 544
        mbedtls_free( *buf );
        return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
545 546 547 548 549 550
    }

    fclose( f );

    (*buf)[*n] = '\0';

551 552 553
    if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
        ++*n;

554 555 556 557 558 559
    return( 0 );
}

/*
 * Load and parse DHM parameters
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
560
int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
561 562 563 564 565
{
    int ret;
    size_t n;
    unsigned char *buf;

566
    if( ( ret = load_file( path, &buf, &n ) ) != 0 )
567 568
        return( ret );

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
569
    ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
570

571
    mbedtls_zeroize( buf, n );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
572
    mbedtls_free( buf );
573 574 575

    return( ret );
}
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
576 577
#endif /* MBEDTLS_FS_IO */
#endif /* MBEDTLS_ASN1_PARSE_C */
578

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
579
#if defined(MBEDTLS_SELF_TEST)
580

581
#include "mbedtls/certs.h"
582

583 584 585
/*
 * Checkup routine
 */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
586
int mbedtls_dhm_self_test( int verbose )
587
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
588
#if defined(MBEDTLS_CERTS_C)
589
    int ret;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
590
    mbedtls_dhm_context dhm;
591

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
592
    mbedtls_dhm_init( &dhm );
Paul Bakker's avatar
Paul Bakker committed
593

594
    if( verbose != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
595
        mbedtls_printf( "  DHM parameter load: " );
596

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
597
    if( ( ret = mbedtls_dhm_parse_dhm( &dhm, (const unsigned char *) mbedtls_test_dhm_params,
598
                               mbedtls_test_dhm_params_len ) ) != 0 )
599 600
    {
        if( verbose != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
601
            mbedtls_printf( "failed\n" );
602

603
        ret = 1;
Paul Bakker's avatar
Paul Bakker committed
604
        goto exit;
605 606 607
    }

    if( verbose != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
608
        mbedtls_printf( "passed\n\n" );
609

Paul Bakker's avatar
Paul Bakker committed
610
exit:
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
611
    mbedtls_dhm_free( &dhm );
612

Paul Bakker's avatar
Paul Bakker committed
613
    return( ret );
614
#else
615
    if( verbose != 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
616
        mbedtls_printf( "  DHM parameter load: skipped\n" );
617 618

    return( 0 );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
619
#endif /* MBEDTLS_CERTS_C */
620 621
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
622
#endif /* MBEDTLS_SELF_TEST */
623

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
624
#endif /* MBEDTLS_DHM_C */