Coverage Report

Created: 2024-08-17 06:45

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