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