Coverage Report

Created: 2026-02-14 07:04

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