~bibledit/bibledit/client

« back to all changes in this revision

Viewing changes to mbedtls2/dhm.c

  • Committer: Teus Benschop
  • Date: 2024-08-17 17:08:44 UTC
  • Revision ID: teusjannette@gmail.com-20240817170844-0qf789ywtms3hyz7
new upstream version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#pragma clang diagnostic ignored "-Wunknown-warning-option"
 
2
#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
 
3
#pragma clang diagnostic ignored "-Wsign-conversion"
 
4
 
 
5
#pragma GCC diagnostic ignored "-Wconversion"
 
6
 
 
7
#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
 
8
#pragma clang diagnostic ignored "-Wsign-conversion"
 
9
 
 
10
#pragma GCC diagnostic ignored "-Wconversion"
 
11
 
 
12
#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
 
13
#pragma clang diagnostic ignored "-Wsign-conversion"
 
14
/*
 
15
 *  Diffie-Hellman-Merkle key exchange
 
16
 *
 
17
 *  Copyright The Mbed TLS Contributors
 
18
 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
19
 *
 
20
 *  This file is provided under the Apache License 2.0, or the
 
21
 *  GNU General Public License v2.0 or later.
 
22
 *
 
23
 *  **********
 
24
 *  Apache License 2.0:
 
25
 *
 
26
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 
27
 *  not use this file except in compliance with the License.
 
28
 *  You may obtain a copy of the License at
 
29
 *
 
30
 *  http://www.apache.org/licenses/LICENSE-2.0
 
31
 *
 
32
 *  Unless required by applicable law or agreed to in writing, software
 
33
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
34
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
35
 *  See the License for the specific language governing permissions and
 
36
 *  limitations under the License.
 
37
 *
 
38
 *  **********
 
39
 *
 
40
 *  **********
 
41
 *  GNU General Public License v2.0 or later:
 
42
 *
 
43
 *  This program is free software; you can redistribute it and/or modify
 
44
 *  it under the terms of the GNU General Public License as published by
 
45
 *  the Free Software Foundation; either version 2 of the License, or
 
46
 *  (at your option) any later version.
 
47
 *
 
48
 *  This program is distributed in the hope that it will be useful,
 
49
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
50
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
51
 *  GNU General Public License for more details.
 
52
 *
 
53
 *  You should have received a copy of the GNU General Public License along
 
54
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 
55
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
56
 *
 
57
 *  **********
 
58
 */
 
59
/*
 
60
 *  The following sources were referenced in the design of this implementation
 
61
 *  of the Diffie-Hellman-Merkle algorithm:
 
62
 *
 
63
 *  [1] Handbook of Applied Cryptography - 1997, Chapter 12
 
64
 *      Menezes, van Oorschot and Vanstone
 
65
 *
 
66
 */
 
67
 
 
68
#if !defined(MBEDTLS_CONFIG_FILE)
 
69
#include "mbedtls/config.h"
 
70
#else
 
71
#include MBEDTLS_CONFIG_FILE
 
72
#endif
 
73
 
 
74
#if defined(MBEDTLS_DHM_C)
 
75
 
 
76
#include "mbedtls/dhm.h"
 
77
#include "mbedtls/platform_util.h"
 
78
 
 
79
#include <string.h>
 
80
 
 
81
#if defined(MBEDTLS_PEM_PARSE_C)
 
82
#include "mbedtls/pem.h"
 
83
#endif
 
84
 
 
85
#if defined(MBEDTLS_ASN1_PARSE_C)
 
86
#include "mbedtls/asn1.h"
 
87
#endif
 
88
 
 
89
#if defined(MBEDTLS_PLATFORM_C)
 
90
#include "mbedtls/platform.h"
 
91
#else
 
92
#include <stdlib.h>
 
93
#include <stdio.h>
 
94
#define mbedtls_printf     printf
 
95
#define mbedtls_calloc    calloc
 
96
#define mbedtls_free       free
 
97
#endif
 
98
 
 
99
#if !defined(MBEDTLS_DHM_ALT)
 
100
 
 
101
#define DHM_VALIDATE_RET( cond )    \
 
102
    MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA )
 
103
#define DHM_VALIDATE( cond )        \
 
104
    MBEDTLS_INTERNAL_VALIDATE( cond )
 
105
 
 
106
/*
 
107
 * helper to validate the mbedtls_mpi size and import it
 
108
 */
 
109
static int dhm_read_bignum( mbedtls_mpi *X,
 
110
                            unsigned char **p,
 
111
                            const unsigned char *end )
 
112
{
 
113
    int ret, n;
 
114
 
 
115
    if( end - *p < 2 )
 
116
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
117
 
 
118
    n = ( (*p)[0] << 8 ) | (*p)[1];
 
119
    (*p) += 2;
 
120
 
 
121
    if( (int)( end - *p ) < n )
 
122
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
123
 
 
124
    if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 )
 
125
        return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret );
 
126
 
 
127
    (*p) += n;
 
128
 
 
129
    return( 0 );
 
130
}
 
131
 
 
132
/*
 
133
 * Verify sanity of parameter with regards to P
 
134
 *
 
135
 * Parameter should be: 2 <= public_param <= P - 2
 
136
 *
 
137
 * This means that we need to return an error if
 
138
 *              public_param < 2 or public_param > P-2
 
139
 *
 
140
 * For more information on the attack, see:
 
141
 *  http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf
 
142
 *  http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643
 
143
 */
 
144
static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P )
 
145
{
 
146
    mbedtls_mpi U;
 
147
    int ret = 0;
 
148
 
 
149
    mbedtls_mpi_init( &U );
 
150
 
 
151
    MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) );
 
152
 
 
153
    if( mbedtls_mpi_cmp_int( param, 2 ) < 0 ||
 
154
        mbedtls_mpi_cmp_mpi( param, &U ) > 0 )
 
155
    {
 
156
        ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA;
 
157
    }
 
158
 
 
159
cleanup:
 
160
    mbedtls_mpi_free( &U );
 
161
    return( ret );
 
162
}
 
163
 
 
164
void mbedtls_dhm_init( mbedtls_dhm_context *ctx )
 
165
{
 
166
    DHM_VALIDATE( ctx != NULL );
 
167
    memset( ctx, 0, sizeof( mbedtls_dhm_context ) );
 
168
}
 
169
 
 
170
/*
 
171
 * Parse the ServerKeyExchange parameters
 
172
 */
 
173
int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx,
 
174
                     unsigned char **p,
 
175
                     const unsigned char *end )
 
176
{
 
177
    int ret;
 
178
    DHM_VALIDATE_RET( ctx != NULL );
 
179
    DHM_VALIDATE_RET( p != NULL && *p != NULL );
 
180
    DHM_VALIDATE_RET( end != NULL );
 
181
 
 
182
    if( ( ret = dhm_read_bignum( &ctx->P,  p, end ) ) != 0 ||
 
183
        ( ret = dhm_read_bignum( &ctx->G,  p, end ) ) != 0 ||
 
184
        ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 )
 
185
        return( ret );
 
186
 
 
187
    if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
 
188
        return( ret );
 
189
 
 
190
    ctx->len = mbedtls_mpi_size( &ctx->P );
 
191
 
 
192
    return( 0 );
 
193
}
 
194
 
 
195
/*
 
196
 * Pick a random R in the range [2, M-2] for blinding or key generation.
 
197
 */
 
198
static int dhm_random_below( mbedtls_mpi *R, const mbedtls_mpi *M,
 
199
                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
 
200
{
 
201
    int ret, count;
 
202
    size_t m_size = mbedtls_mpi_size( M );
 
203
    size_t m_bitlen = mbedtls_mpi_bitlen( M );
 
204
 
 
205
    count = 0;
 
206
    do
 
207
    {
 
208
        if( count++ > 30 )
 
209
            return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
 
210
 
 
211
        MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( R, m_size, f_rng, p_rng ) );
 
212
        MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( R, ( m_size * 8 ) - m_bitlen ) );
 
213
    }
 
214
    while( dhm_check_range( R, M ) != 0 );
 
215
 
 
216
cleanup:
 
217
    return( ret );
 
218
}
 
219
 
 
220
static int dhm_make_common( mbedtls_dhm_context *ctx, int x_size,
 
221
                            int (*f_rng)(void *, unsigned char *, size_t),
 
222
                            void *p_rng )
 
223
{
 
224
    int ret = 0;
 
225
 
 
226
    if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 )
 
227
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
228
    if( x_size < 0 )
 
229
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
230
 
 
231
    if( (unsigned) x_size < mbedtls_mpi_size( &ctx->P ) )
 
232
    {
 
233
        MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) );
 
234
    }
 
235
    else
 
236
    {
 
237
        /* Generate X as large as possible ( <= P - 2 ) */
 
238
        ret = dhm_random_below( &ctx->X, &ctx->P, f_rng, p_rng );
 
239
        if( ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
 
240
            return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED );
 
241
        if( ret != 0 )
 
242
            return( ret );
 
243
    }
 
244
 
 
245
    /*
 
246
     * Calculate GX = G^X mod P
 
247
     */
 
248
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X,
 
249
                          &ctx->P , &ctx->RP ) );
 
250
 
 
251
    if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 )
 
252
        return( ret );
 
253
 
 
254
cleanup:
 
255
    return( ret );
 
256
}
 
257
 
 
258
/*
 
259
 * Setup and write the ServerKeyExchange parameters
 
260
 */
 
261
int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size,
 
262
                     unsigned char *output, size_t *olen,
 
263
                     int (*f_rng)(void *, unsigned char *, size_t),
 
264
                     void *p_rng )
 
265
{
 
266
    int ret;
 
267
    size_t n1, n2, n3;
 
268
    unsigned char *p;
 
269
    DHM_VALIDATE_RET( ctx != NULL );
 
270
    DHM_VALIDATE_RET( output != NULL );
 
271
    DHM_VALIDATE_RET( olen != NULL );
 
272
    DHM_VALIDATE_RET( f_rng != NULL );
 
273
 
 
274
    ret = dhm_make_common( ctx, x_size, f_rng, p_rng );
 
275
    if( ret != 0 )
 
276
        goto cleanup;
 
277
 
 
278
    /*
 
279
     * Export P, G, GX. RFC 5246 §4.4 states that "leading zero octets are
 
280
     * not required". We omit leading zeros for compactness.
 
281
     */
 
282
#define DHM_MPI_EXPORT( X, n )                                          \
 
283
    do {                                                                \
 
284
        MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ),               \
 
285
                                                   p + 2,               \
 
286
                                                   ( n ) ) );           \
 
287
        *p++ = (unsigned char)( ( n ) >> 8 );                           \
 
288
        *p++ = (unsigned char)( ( n )      );                           \
 
289
        p += ( n );                                                     \
 
290
    } while( 0 )
 
291
 
 
292
    n1 = mbedtls_mpi_size( &ctx->P  );
 
293
    n2 = mbedtls_mpi_size( &ctx->G  );
 
294
    n3 = mbedtls_mpi_size( &ctx->GX );
 
295
 
 
296
    p = output;
 
297
    DHM_MPI_EXPORT( &ctx->P , n1 );
 
298
    DHM_MPI_EXPORT( &ctx->G , n2 );
 
299
    DHM_MPI_EXPORT( &ctx->GX, n3 );
 
300
 
 
301
    *olen = p - output;
 
302
 
 
303
    ctx->len = n1;
 
304
 
 
305
cleanup:
 
306
    if( ret != 0 && ret > -128 )
 
307
        return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret );
 
308
    return( ret );
 
309
}
 
310
 
 
311
/*
 
312
 * Set prime modulus and generator
 
313
 */
 
314
int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx,
 
315
                           const mbedtls_mpi *P,
 
316
                           const mbedtls_mpi *G )
 
317
{
 
318
    int ret;
 
319
    DHM_VALIDATE_RET( ctx != NULL );
 
320
    DHM_VALIDATE_RET( P != NULL );
 
321
    DHM_VALIDATE_RET( G != NULL );
 
322
 
 
323
    if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ||
 
324
        ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 )
 
325
    {
 
326
        return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret );
 
327
    }
 
328
 
 
329
    ctx->len = mbedtls_mpi_size( &ctx->P );
 
330
    return( 0 );
 
331
}
 
332
 
 
333
/*
 
334
 * Import the peer's public value G^Y
 
335
 */
 
336
int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx,
 
337
                     const unsigned char *input, size_t ilen )
 
338
{
 
339
    int ret;
 
340
    DHM_VALIDATE_RET( ctx != NULL );
 
341
    DHM_VALIDATE_RET( input != NULL );
 
342
 
 
343
    if( ilen < 1 || ilen > ctx->len )
 
344
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
345
 
 
346
    if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 )
 
347
        return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret );
 
348
 
 
349
    return( 0 );
 
350
}
 
351
 
 
352
/*
 
353
 * Create own private value X and export G^X
 
354
 */
 
355
int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size,
 
356
                     unsigned char *output, size_t olen,
 
357
                     int (*f_rng)(void *, unsigned char *, size_t),
 
358
                     void *p_rng )
 
359
{
 
360
    int ret;
 
361
    DHM_VALIDATE_RET( ctx != NULL );
 
362
    DHM_VALIDATE_RET( output != NULL );
 
363
    DHM_VALIDATE_RET( f_rng != NULL );
 
364
 
 
365
    if( olen < 1 || olen > ctx->len )
 
366
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
367
 
 
368
    ret = dhm_make_common( ctx, x_size, f_rng, p_rng );
 
369
    if( ret == MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED )
 
370
        return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED );
 
371
    if( ret != 0 )
 
372
        goto cleanup;
 
373
 
 
374
    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) );
 
375
 
 
376
cleanup:
 
377
    if( ret != 0 && ret > -128 )
 
378
        return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret );
 
379
 
 
380
    return( ret );
 
381
}
 
382
 
 
383
 
 
384
/*
 
385
 * Use the blinding method and optimisation suggested in section 10 of:
 
386
 *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
 
387
 *  DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
 
388
 *  Berlin Heidelberg, 1996. p. 104-113.
 
389
 */
 
390
static int dhm_update_blinding( mbedtls_dhm_context *ctx,
 
391
                    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
 
392
{
 
393
    int ret;
 
394
    mbedtls_mpi R;
 
395
 
 
396
    mbedtls_mpi_init( &R );
 
397
 
 
398
    /*
 
399
     * Don't use any blinding the first time a particular X is used,
 
400
     * but remember it to use blinding next time.
 
401
     */
 
402
    if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 )
 
403
    {
 
404
        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) );
 
405
        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) );
 
406
        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) );
 
407
 
 
408
        return( 0 );
 
409
    }
 
410
 
 
411
    /*
 
412
     * Ok, we need blinding. Can we re-use existing values?
 
413
     * If yes, just update them by squaring them.
 
414
     */
 
415
    if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 )
 
416
    {
 
417
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
 
418
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) );
 
419
 
 
420
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
 
421
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
 
422
 
 
423
        return( 0 );
 
424
    }
 
425
 
 
426
    /*
 
427
     * We need to generate blinding values from scratch
 
428
     */
 
429
 
 
430
    /* Vi = random( 2, P-2 ) */
 
431
    MBEDTLS_MPI_CHK( dhm_random_below( &ctx->Vi, &ctx->P, f_rng, p_rng ) );
 
432
 
 
433
    /* Vf = Vi^-X mod P
 
434
     * First compute Vi^-1 = R * (R Vi)^-1, (avoiding leaks from inv_mod),
 
435
     * then elevate to the Xth power. */
 
436
    MBEDTLS_MPI_CHK( dhm_random_below( &R, &ctx->P, f_rng, p_rng ) );
 
437
    MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vi, &R ) );
 
438
    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
 
439
    MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vf, &ctx->P ) );
 
440
    MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &R ) );
 
441
    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) );
 
442
 
 
443
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) );
 
444
 
 
445
cleanup:
 
446
    mbedtls_mpi_free( &R );
 
447
 
 
448
    return( ret );
 
449
}
 
450
 
 
451
/*
 
452
 * Derive and export the shared secret (G^Y)^X mod P
 
453
 */
 
454
int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx,
 
455
                     unsigned char *output, size_t output_size, size_t *olen,
 
456
                     int (*f_rng)(void *, unsigned char *, size_t),
 
457
                     void *p_rng )
 
458
{
 
459
    int ret;
 
460
    mbedtls_mpi GYb;
 
461
    DHM_VALIDATE_RET( ctx != NULL );
 
462
    DHM_VALIDATE_RET( output != NULL );
 
463
    DHM_VALIDATE_RET( olen != NULL );
 
464
 
 
465
    if( output_size < ctx->len )
 
466
        return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA );
 
467
 
 
468
    if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 )
 
469
        return( ret );
 
470
 
 
471
    mbedtls_mpi_init( &GYb );
 
472
 
 
473
    /* Blind peer's value */
 
474
    if( f_rng != NULL )
 
475
    {
 
476
        MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) );
 
477
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) );
 
478
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) );
 
479
    }
 
480
    else
 
481
        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) );
 
482
 
 
483
    /* Do modular exponentiation */
 
484
    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X,
 
485
                          &ctx->P, &ctx->RP ) );
 
486
 
 
487
    /* Unblind secret value */
 
488
    if( f_rng != NULL )
 
489
    {
 
490
        MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) );
 
491
        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) );
 
492
    }
 
493
 
 
494
    /* Output the secret without any leading zero byte. This is mandatory
 
495
     * for TLS per RFC 5246 §8.1.2. */
 
496
    *olen = mbedtls_mpi_size( &ctx->K );
 
497
    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) );
 
498
 
 
499
cleanup:
 
500
    mbedtls_mpi_free( &GYb );
 
501
 
 
502
    if( ret != 0 )
 
503
        return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret );
 
504
 
 
505
    return( 0 );
 
506
}
 
507
 
 
508
/*
 
509
 * Free the components of a DHM key
 
510
 */
 
511
void mbedtls_dhm_free( mbedtls_dhm_context *ctx )
 
512
{
 
513
    if( ctx == NULL )
 
514
        return;
 
515
 
 
516
    mbedtls_mpi_free( &ctx->pX );
 
517
    mbedtls_mpi_free( &ctx->Vf );
 
518
    mbedtls_mpi_free( &ctx->Vi );
 
519
    mbedtls_mpi_free( &ctx->RP );
 
520
    mbedtls_mpi_free( &ctx->K  );
 
521
    mbedtls_mpi_free( &ctx->GY );
 
522
    mbedtls_mpi_free( &ctx->GX );
 
523
    mbedtls_mpi_free( &ctx->X  );
 
524
    mbedtls_mpi_free( &ctx->G  );
 
525
    mbedtls_mpi_free( &ctx->P  );
 
526
 
 
527
    mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) );
 
528
}
 
529
 
 
530
#if defined(MBEDTLS_ASN1_PARSE_C)
 
531
/*
 
532
 * Parse DHM parameters
 
533
 */
 
534
int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin,
 
535
                   size_t dhminlen )
 
536
{
 
537
    int ret;
 
538
    size_t len;
 
539
    unsigned char *p, *end;
 
540
#if defined(MBEDTLS_PEM_PARSE_C)
 
541
    mbedtls_pem_context pem;
 
542
#endif /* MBEDTLS_PEM_PARSE_C */
 
543
 
 
544
    DHM_VALIDATE_RET( dhm != NULL );
 
545
    DHM_VALIDATE_RET( dhmin != NULL );
 
546
 
 
547
#if defined(MBEDTLS_PEM_PARSE_C)
 
548
    mbedtls_pem_init( &pem );
 
549
 
 
550
    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
 
551
    if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' )
 
552
        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
 
553
    else
 
554
        ret = mbedtls_pem_read_buffer( &pem,
 
555
                               "-----BEGIN DH PARAMETERS-----",
 
556
                               "-----END DH PARAMETERS-----",
 
557
                               dhmin, NULL, 0, &dhminlen );
 
558
 
 
559
    if( ret == 0 )
 
560
    {
 
561
        /*
 
562
         * Was PEM encoded
 
563
         */
 
564
        dhminlen = pem.buflen;
 
565
    }
 
566
    else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
 
567
        goto exit;
 
568
 
 
569
    p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin;
 
570
#else
 
571
    p = (unsigned char *) dhmin;
 
572
#endif /* MBEDTLS_PEM_PARSE_C */
 
573
    end = p + dhminlen;
 
574
 
 
575
    /*
 
576
     *  DHParams ::= SEQUENCE {
 
577
     *      prime              INTEGER,  -- P
 
578
     *      generator          INTEGER,  -- g
 
579
     *      privateValueLength INTEGER OPTIONAL
 
580
     *  }
 
581
     */
 
582
    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
 
583
            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
 
584
    {
 
585
        ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
 
586
        goto exit;
 
587
    }
 
588
 
 
589
    end = p + len;
 
590
 
 
591
    if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P  ) ) != 0 ||
 
592
        ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 )
 
593
    {
 
594
        ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
 
595
        goto exit;
 
596
    }
 
597
 
 
598
    if( p != end )
 
599
    {
 
600
        /* This might be the optional privateValueLength.
 
601
         * If so, we can cleanly discard it */
 
602
        mbedtls_mpi rec;
 
603
        mbedtls_mpi_init( &rec );
 
604
        ret = mbedtls_asn1_get_mpi( &p, end, &rec );
 
605
        mbedtls_mpi_free( &rec );
 
606
        if ( ret != 0 )
 
607
        {
 
608
            ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret;
 
609
            goto exit;
 
610
        }
 
611
        if ( p != end )
 
612
        {
 
613
            ret = MBEDTLS_ERR_DHM_INVALID_FORMAT +
 
614
                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
 
615
            goto exit;
 
616
        }
 
617
    }
 
618
 
 
619
    ret = 0;
 
620
 
 
621
    dhm->len = mbedtls_mpi_size( &dhm->P );
 
622
 
 
623
exit:
 
624
#if defined(MBEDTLS_PEM_PARSE_C)
 
625
    mbedtls_pem_free( &pem );
 
626
#endif
 
627
    if( ret != 0 )
 
628
        mbedtls_dhm_free( dhm );
 
629
 
 
630
    return( ret );
 
631
}
 
632
 
 
633
#if defined(MBEDTLS_FS_IO)
 
634
/*
 
635
 * Load all data from a file into a given buffer.
 
636
 *
 
637
 * The file is expected to contain either PEM or DER encoded data.
 
638
 * A terminating null byte is always appended. It is included in the announced
 
639
 * length only if the data looks like it is PEM encoded.
 
640
 */
 
641
static int load_file( const char *path, unsigned char **buf, size_t *n )
 
642
{
 
643
    FILE *f;
 
644
    long size;
 
645
 
 
646
    if( ( f = fopen( path, "rb" ) ) == NULL )
 
647
        return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
 
648
 
 
649
    fseek( f, 0, SEEK_END );
 
650
    if( ( size = ftell( f ) ) == -1 )
 
651
    {
 
652
        fclose( f );
 
653
        return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
 
654
    }
 
655
    fseek( f, 0, SEEK_SET );
 
656
 
 
657
    *n = (size_t) size;
 
658
 
 
659
    if( *n + 1 == 0 ||
 
660
        ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
 
661
    {
 
662
        fclose( f );
 
663
        return( MBEDTLS_ERR_DHM_ALLOC_FAILED );
 
664
    }
 
665
 
 
666
    if( fread( *buf, 1, *n, f ) != *n )
 
667
    {
 
668
        fclose( f );
 
669
 
 
670
        mbedtls_platform_zeroize( *buf, *n + 1 );
 
671
        mbedtls_free( *buf );
 
672
 
 
673
        return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
 
674
    }
 
675
 
 
676
    fclose( f );
 
677
 
 
678
    (*buf)[*n] = '\0';
 
679
 
 
680
    if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
 
681
        ++*n;
 
682
 
 
683
    return( 0 );
 
684
}
 
685
 
 
686
/*
 
687
 * Load and parse DHM parameters
 
688
 */
 
689
int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path )
 
690
{
 
691
    int ret;
 
692
    size_t n;
 
693
    unsigned char *buf;
 
694
    DHM_VALIDATE_RET( dhm != NULL );
 
695
    DHM_VALIDATE_RET( path != NULL );
 
696
 
 
697
    if( ( ret = load_file( path, &buf, &n ) ) != 0 )
 
698
        return( ret );
 
699
 
 
700
    ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
 
701
 
 
702
    mbedtls_platform_zeroize( buf, n );
 
703
    mbedtls_free( buf );
 
704
 
 
705
    return( ret );
 
706
}
 
707
#endif /* MBEDTLS_FS_IO */
 
708
#endif /* MBEDTLS_ASN1_PARSE_C */
 
709
#endif /* MBEDTLS_DHM_ALT */
 
710
 
 
711
#if defined(MBEDTLS_SELF_TEST)
 
712
 
 
713
#if defined(MBEDTLS_PEM_PARSE_C)
 
714
static const char mbedtls_test_dhm_params[] =
 
715
"-----BEGIN DH PARAMETERS-----\r\n"
 
716
"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n"
 
717
"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n"
 
718
"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n"
 
719
"-----END DH PARAMETERS-----\r\n";
 
720
#else /* MBEDTLS_PEM_PARSE_C */
 
721
static const char mbedtls_test_dhm_params[] = {
 
722
  0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0x9e, 0x35, 0xf4, 0x30, 0x44,
 
723
  0x3a, 0x09, 0x90, 0x4f, 0x3a, 0x39, 0xa9, 0x79, 0x79, 0x7d, 0x07, 0x0d,
 
724
  0xf5, 0x33, 0x78, 0xe7, 0x9c, 0x24, 0x38, 0xbe, 0xf4, 0xe7, 0x61, 0xf3,
 
725
  0xc7, 0x14, 0x55, 0x33, 0x28, 0x58, 0x9b, 0x04, 0x1c, 0x80, 0x9b, 0xe1,
 
726
  0xd6, 0xc6, 0xb5, 0xf1, 0xfc, 0x9f, 0x47, 0xd3, 0xa2, 0x54, 0x43, 0x18,
 
727
  0x82, 0x53, 0xa9, 0x92, 0xa5, 0x68, 0x18, 0xb3, 0x7b, 0xa9, 0xde, 0x5a,
 
728
  0x40, 0xd3, 0x62, 0xe5, 0x6e, 0xff, 0x0b, 0xe5, 0x41, 0x74, 0x74, 0xc1,
 
729
  0x25, 0xc1, 0x99, 0x27, 0x2c, 0x8f, 0xe4, 0x1d, 0xea, 0x73, 0x3d, 0xf6,
 
730
  0xf6, 0x62, 0xc9, 0x2a, 0xe7, 0x65, 0x56, 0xe7, 0x55, 0xd1, 0x0c, 0x64,
 
731
  0xe6, 0xa5, 0x09, 0x68, 0xf6, 0x7f, 0xc6, 0xea, 0x73, 0xd0, 0xdc, 0xa8,
 
732
  0x56, 0x9b, 0xe2, 0xba, 0x20, 0x4e, 0x23, 0x58, 0x0d, 0x8b, 0xca, 0x2f,
 
733
  0x49, 0x75, 0xb3, 0x02, 0x01, 0x02 };
 
734
#endif /* MBEDTLS_PEM_PARSE_C */
 
735
 
 
736
static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params );
 
737
 
 
738
/*
 
739
 * Checkup routine
 
740
 */
 
741
int mbedtls_dhm_self_test( int verbose )
 
742
{
 
743
    int ret;
 
744
    mbedtls_dhm_context dhm;
 
745
 
 
746
    mbedtls_dhm_init( &dhm );
 
747
 
 
748
    if( verbose != 0 )
 
749
        mbedtls_printf( "  DHM parameter load: " );
 
750
 
 
751
    if( ( ret = mbedtls_dhm_parse_dhm( &dhm,
 
752
                    (const unsigned char *) mbedtls_test_dhm_params,
 
753
                    mbedtls_test_dhm_params_len ) ) != 0 )
 
754
    {
 
755
        if( verbose != 0 )
 
756
            mbedtls_printf( "failed\n" );
 
757
 
 
758
        ret = 1;
 
759
        goto exit;
 
760
    }
 
761
 
 
762
    if( verbose != 0 )
 
763
        mbedtls_printf( "passed\n\n" );
 
764
 
 
765
exit:
 
766
    mbedtls_dhm_free( &dhm );
 
767
 
 
768
    return( ret );
 
769
}
 
770
 
 
771
#endif /* MBEDTLS_SELF_TEST */
 
772
 
 
773
#endif /* MBEDTLS_DHM_C */