quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

dhm.c (19807B)


      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  */
     41 static 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  */
     79 static 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 
     93 cleanup:
     94     mbedtls_mpi_free(&U);
     95     return ret;
     96 }
     97 
     98 void mbedtls_dhm_init(mbedtls_dhm_context *ctx)
     99 {
    100     memset(ctx, 0, sizeof(mbedtls_dhm_context));
    101 }
    102 
    103 size_t mbedtls_dhm_get_bitlen(const mbedtls_dhm_context *ctx)
    104 {
    105     return mbedtls_mpi_bitlen(&ctx->P);
    106 }
    107 
    108 size_t mbedtls_dhm_get_len(const mbedtls_dhm_context *ctx)
    109 {
    110     return mbedtls_mpi_size(&ctx->P);
    111 }
    112 
    113 int 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  */
    146 int 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  */
    168 static 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 
    176 cleanup:
    177     return ret;
    178 }
    179 
    180 static 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 
    216 cleanup:
    217     return ret;
    218 }
    219 
    220 /*
    221  * Setup and write the ServerKeyExchange parameters
    222  */
    223 int 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 
    262 cleanup:
    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  */
    272 int 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  */
    289 int 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  */
    308 int 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 
    329 cleanup:
    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  */
    343 static 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 
    396 cleanup:
    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  */
    405 int 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 
    445 cleanup:
    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  */
    458 void 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  */
    482 int 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 
    561 exit:
    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  */
    580 static 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  */
    627 int 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)
    650 static 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 */
    657 static 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 
    673 static const size_t mbedtls_test_dhm_params_len = sizeof(mbedtls_test_dhm_params);
    674 
    675 /*
    676  * Checkup routine
    677  */
    678 int 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 
    704 exit:
    705     mbedtls_dhm_free(&dhm);
    706 
    707     return ret;
    708 }
    709 
    710 #endif /* MBEDTLS_SELF_TEST */
    711 
    712 #endif /* MBEDTLS_DHM_C */