11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci/*
111cb0ef41Sopenharmony_ci * DH low level APIs are deprecated for public use, but still ok for
121cb0ef41Sopenharmony_ci * internal use.
131cb0ef41Sopenharmony_ci */
141cb0ef41Sopenharmony_ci#include "internal/deprecated.h"
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci#include <stdio.h>
171cb0ef41Sopenharmony_ci#include "internal/cryptlib.h"
181cb0ef41Sopenharmony_ci#include "dh_local.h"
191cb0ef41Sopenharmony_ci#include "crypto/bn.h"
201cb0ef41Sopenharmony_ci#include "crypto/dh.h"
211cb0ef41Sopenharmony_ci#include "crypto/security_bits.h"
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci#ifdef FIPS_MODULE
241cb0ef41Sopenharmony_ci# define MIN_STRENGTH 112
251cb0ef41Sopenharmony_ci#else
261cb0ef41Sopenharmony_ci# define MIN_STRENGTH 80
271cb0ef41Sopenharmony_ci#endif
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cistatic int generate_key(DH *dh);
301cb0ef41Sopenharmony_cistatic int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
311cb0ef41Sopenharmony_ci                         const BIGNUM *a, const BIGNUM *p,
321cb0ef41Sopenharmony_ci                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
331cb0ef41Sopenharmony_cistatic int dh_init(DH *dh);
341cb0ef41Sopenharmony_cistatic int dh_finish(DH *dh);
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci/*
371cb0ef41Sopenharmony_ci * See SP800-56Ar3 Section 5.7.1.1
381cb0ef41Sopenharmony_ci * Finite Field Cryptography Diffie-Hellman (FFC DH) Primitive
391cb0ef41Sopenharmony_ci */
401cb0ef41Sopenharmony_ciint ossl_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
411cb0ef41Sopenharmony_ci{
421cb0ef41Sopenharmony_ci    BN_CTX *ctx = NULL;
431cb0ef41Sopenharmony_ci    BN_MONT_CTX *mont = NULL;
441cb0ef41Sopenharmony_ci    BIGNUM *z = NULL, *pminus1;
451cb0ef41Sopenharmony_ci    int ret = -1;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci    if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
481cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
491cb0ef41Sopenharmony_ci        goto err;
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    if (dh->params.q != NULL
531cb0ef41Sopenharmony_ci        && BN_num_bits(dh->params.q) > OPENSSL_DH_MAX_MODULUS_BITS) {
541cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_Q_TOO_LARGE);
551cb0ef41Sopenharmony_ci        goto err;
561cb0ef41Sopenharmony_ci    }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci    if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) {
591cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
601cb0ef41Sopenharmony_ci        return 0;
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci    ctx = BN_CTX_new_ex(dh->libctx);
641cb0ef41Sopenharmony_ci    if (ctx == NULL)
651cb0ef41Sopenharmony_ci        goto err;
661cb0ef41Sopenharmony_ci    BN_CTX_start(ctx);
671cb0ef41Sopenharmony_ci    pminus1 = BN_CTX_get(ctx);
681cb0ef41Sopenharmony_ci    z = BN_CTX_get(ctx);
691cb0ef41Sopenharmony_ci    if (z == NULL)
701cb0ef41Sopenharmony_ci        goto err;
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci    if (dh->priv_key == NULL) {
731cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE);
741cb0ef41Sopenharmony_ci        goto err;
751cb0ef41Sopenharmony_ci    }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci    if (dh->flags & DH_FLAG_CACHE_MONT_P) {
781cb0ef41Sopenharmony_ci        mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
791cb0ef41Sopenharmony_ci                                      dh->lock, dh->params.p, ctx);
801cb0ef41Sopenharmony_ci        BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME);
811cb0ef41Sopenharmony_ci        if (!mont)
821cb0ef41Sopenharmony_ci            goto err;
831cb0ef41Sopenharmony_ci    }
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    /* (Step 1) Z = pub_key^priv_key mod p */
861cb0ef41Sopenharmony_ci    if (!dh->meth->bn_mod_exp(dh, z, pub_key, dh->priv_key, dh->params.p, ctx,
871cb0ef41Sopenharmony_ci                              mont)) {
881cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB);
891cb0ef41Sopenharmony_ci        goto err;
901cb0ef41Sopenharmony_ci    }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci    /* (Step 2) Error if z <= 1 or z = p - 1 */
931cb0ef41Sopenharmony_ci    if (BN_copy(pminus1, dh->params.p) == NULL
941cb0ef41Sopenharmony_ci        || !BN_sub_word(pminus1, 1)
951cb0ef41Sopenharmony_ci        || BN_cmp(z, BN_value_one()) <= 0
961cb0ef41Sopenharmony_ci        || BN_cmp(z, pminus1) == 0) {
971cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_INVALID_SECRET);
981cb0ef41Sopenharmony_ci        goto err;
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci    /* return the padded key, i.e. same number of bytes as the modulus */
1021cb0ef41Sopenharmony_ci    ret = BN_bn2binpad(z, key, BN_num_bytes(dh->params.p));
1031cb0ef41Sopenharmony_ci err:
1041cb0ef41Sopenharmony_ci    BN_clear(z); /* (Step 2) destroy intermediate values */
1051cb0ef41Sopenharmony_ci    BN_CTX_end(ctx);
1061cb0ef41Sopenharmony_ci    BN_CTX_free(ctx);
1071cb0ef41Sopenharmony_ci    return ret;
1081cb0ef41Sopenharmony_ci}
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci/*-
1111cb0ef41Sopenharmony_ci * NB: This function is inherently not constant time due to the
1121cb0ef41Sopenharmony_ci * RFC 5246 (8.1.2) padding style that strips leading zero bytes.
1131cb0ef41Sopenharmony_ci */
1141cb0ef41Sopenharmony_ciint DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
1151cb0ef41Sopenharmony_ci{
1161cb0ef41Sopenharmony_ci    int ret = 0, i;
1171cb0ef41Sopenharmony_ci    volatile size_t npad = 0, mask = 1;
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    /* compute the key; ret is constant unless compute_key is external */
1201cb0ef41Sopenharmony_ci#ifdef FIPS_MODULE
1211cb0ef41Sopenharmony_ci    ret = ossl_dh_compute_key(key, pub_key, dh);
1221cb0ef41Sopenharmony_ci#else
1231cb0ef41Sopenharmony_ci    ret = dh->meth->compute_key(key, pub_key, dh);
1241cb0ef41Sopenharmony_ci#endif
1251cb0ef41Sopenharmony_ci    if (ret <= 0)
1261cb0ef41Sopenharmony_ci        return ret;
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci    /* count leading zero bytes, yet still touch all bytes */
1291cb0ef41Sopenharmony_ci    for (i = 0; i < ret; i++) {
1301cb0ef41Sopenharmony_ci        mask &= !key[i];
1311cb0ef41Sopenharmony_ci        npad += mask;
1321cb0ef41Sopenharmony_ci    }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    /* unpad key */
1351cb0ef41Sopenharmony_ci    ret -= npad;
1361cb0ef41Sopenharmony_ci    /* key-dependent memory access, potentially leaking npad / ret */
1371cb0ef41Sopenharmony_ci    memmove(key, key + npad, ret);
1381cb0ef41Sopenharmony_ci    /* key-dependent memory access, potentially leaking npad / ret */
1391cb0ef41Sopenharmony_ci    memset(key + ret, 0, npad);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    return ret;
1421cb0ef41Sopenharmony_ci}
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ciint DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh)
1451cb0ef41Sopenharmony_ci{
1461cb0ef41Sopenharmony_ci    int rv, pad;
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci    /* rv is constant unless compute_key is external */
1491cb0ef41Sopenharmony_ci#ifdef FIPS_MODULE
1501cb0ef41Sopenharmony_ci    rv = ossl_dh_compute_key(key, pub_key, dh);
1511cb0ef41Sopenharmony_ci#else
1521cb0ef41Sopenharmony_ci    rv = dh->meth->compute_key(key, pub_key, dh);
1531cb0ef41Sopenharmony_ci#endif
1541cb0ef41Sopenharmony_ci    if (rv <= 0)
1551cb0ef41Sopenharmony_ci        return rv;
1561cb0ef41Sopenharmony_ci    pad = BN_num_bytes(dh->params.p) - rv;
1571cb0ef41Sopenharmony_ci    /* pad is constant (zero) unless compute_key is external */
1581cb0ef41Sopenharmony_ci    if (pad > 0) {
1591cb0ef41Sopenharmony_ci        memmove(key + pad, key, rv);
1601cb0ef41Sopenharmony_ci        memset(key, 0, pad);
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci    return rv + pad;
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_cistatic DH_METHOD dh_ossl = {
1661cb0ef41Sopenharmony_ci    "OpenSSL DH Method",
1671cb0ef41Sopenharmony_ci    generate_key,
1681cb0ef41Sopenharmony_ci    ossl_dh_compute_key,
1691cb0ef41Sopenharmony_ci    dh_bn_mod_exp,
1701cb0ef41Sopenharmony_ci    dh_init,
1711cb0ef41Sopenharmony_ci    dh_finish,
1721cb0ef41Sopenharmony_ci    DH_FLAG_FIPS_METHOD,
1731cb0ef41Sopenharmony_ci    NULL,
1741cb0ef41Sopenharmony_ci    NULL
1751cb0ef41Sopenharmony_ci};
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_cistatic const DH_METHOD *default_DH_method = &dh_ossl;
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ciconst DH_METHOD *DH_OpenSSL(void)
1801cb0ef41Sopenharmony_ci{
1811cb0ef41Sopenharmony_ci    return &dh_ossl;
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ciconst DH_METHOD *DH_get_default_method(void)
1851cb0ef41Sopenharmony_ci{
1861cb0ef41Sopenharmony_ci    return default_DH_method;
1871cb0ef41Sopenharmony_ci}
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_cistatic int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
1901cb0ef41Sopenharmony_ci                         const BIGNUM *a, const BIGNUM *p,
1911cb0ef41Sopenharmony_ci                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
1921cb0ef41Sopenharmony_ci{
1931cb0ef41Sopenharmony_ci    return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
1941cb0ef41Sopenharmony_ci}
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_cistatic int dh_init(DH *dh)
1971cb0ef41Sopenharmony_ci{
1981cb0ef41Sopenharmony_ci    dh->flags |= DH_FLAG_CACHE_MONT_P;
1991cb0ef41Sopenharmony_ci    dh->dirty_cnt++;
2001cb0ef41Sopenharmony_ci    return 1;
2011cb0ef41Sopenharmony_ci}
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_cistatic int dh_finish(DH *dh)
2041cb0ef41Sopenharmony_ci{
2051cb0ef41Sopenharmony_ci    BN_MONT_CTX_free(dh->method_mont_p);
2061cb0ef41Sopenharmony_ci    return 1;
2071cb0ef41Sopenharmony_ci}
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci#ifndef FIPS_MODULE
2101cb0ef41Sopenharmony_civoid DH_set_default_method(const DH_METHOD *meth)
2111cb0ef41Sopenharmony_ci{
2121cb0ef41Sopenharmony_ci    default_DH_method = meth;
2131cb0ef41Sopenharmony_ci}
2141cb0ef41Sopenharmony_ci#endif /* FIPS_MODULE */
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ciint DH_generate_key(DH *dh)
2171cb0ef41Sopenharmony_ci{
2181cb0ef41Sopenharmony_ci#ifdef FIPS_MODULE
2191cb0ef41Sopenharmony_ci    return generate_key(dh);
2201cb0ef41Sopenharmony_ci#else
2211cb0ef41Sopenharmony_ci    return dh->meth->generate_key(dh);
2221cb0ef41Sopenharmony_ci#endif
2231cb0ef41Sopenharmony_ci}
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ciint ossl_dh_generate_public_key(BN_CTX *ctx, const DH *dh,
2261cb0ef41Sopenharmony_ci                                const BIGNUM *priv_key, BIGNUM *pub_key)
2271cb0ef41Sopenharmony_ci{
2281cb0ef41Sopenharmony_ci    int ret = 0;
2291cb0ef41Sopenharmony_ci    BIGNUM *prk = BN_new();
2301cb0ef41Sopenharmony_ci    BN_MONT_CTX *mont = NULL;
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci    if (prk == NULL)
2331cb0ef41Sopenharmony_ci        return 0;
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci    if (dh->flags & DH_FLAG_CACHE_MONT_P) {
2361cb0ef41Sopenharmony_ci        /*
2371cb0ef41Sopenharmony_ci         * We take the input DH as const, but we lie, because in some cases we
2381cb0ef41Sopenharmony_ci         * want to get a hold of its Montgomery context.
2391cb0ef41Sopenharmony_ci         *
2401cb0ef41Sopenharmony_ci         * We cast to remove the const qualifier in this case, it should be
2411cb0ef41Sopenharmony_ci         * fine...
2421cb0ef41Sopenharmony_ci         */
2431cb0ef41Sopenharmony_ci        BN_MONT_CTX **pmont = (BN_MONT_CTX **)&dh->method_mont_p;
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci        mont = BN_MONT_CTX_set_locked(pmont, dh->lock, dh->params.p, ctx);
2461cb0ef41Sopenharmony_ci        if (mont == NULL)
2471cb0ef41Sopenharmony_ci            goto err;
2481cb0ef41Sopenharmony_ci    }
2491cb0ef41Sopenharmony_ci    BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci    /* pub_key = g^priv_key mod p */
2521cb0ef41Sopenharmony_ci    if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p,
2531cb0ef41Sopenharmony_ci                              ctx, mont))
2541cb0ef41Sopenharmony_ci        goto err;
2551cb0ef41Sopenharmony_ci    ret = 1;
2561cb0ef41Sopenharmony_cierr:
2571cb0ef41Sopenharmony_ci    BN_clear_free(prk);
2581cb0ef41Sopenharmony_ci    return ret;
2591cb0ef41Sopenharmony_ci}
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_cistatic int generate_key(DH *dh)
2621cb0ef41Sopenharmony_ci{
2631cb0ef41Sopenharmony_ci    int ok = 0;
2641cb0ef41Sopenharmony_ci    int generate_new_key = 0;
2651cb0ef41Sopenharmony_ci#ifndef FIPS_MODULE
2661cb0ef41Sopenharmony_ci    unsigned l;
2671cb0ef41Sopenharmony_ci#endif
2681cb0ef41Sopenharmony_ci    BN_CTX *ctx = NULL;
2691cb0ef41Sopenharmony_ci    BIGNUM *pub_key = NULL, *priv_key = NULL;
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ci    if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
2721cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
2731cb0ef41Sopenharmony_ci        return 0;
2741cb0ef41Sopenharmony_ci    }
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci    if (dh->params.q != NULL
2771cb0ef41Sopenharmony_ci        && BN_num_bits(dh->params.q) > OPENSSL_DH_MAX_MODULUS_BITS) {
2781cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_Q_TOO_LARGE);
2791cb0ef41Sopenharmony_ci        return 0;
2801cb0ef41Sopenharmony_ci    }
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_ci    if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) {
2831cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
2841cb0ef41Sopenharmony_ci        return 0;
2851cb0ef41Sopenharmony_ci    }
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci    ctx = BN_CTX_new_ex(dh->libctx);
2881cb0ef41Sopenharmony_ci    if (ctx == NULL)
2891cb0ef41Sopenharmony_ci        goto err;
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci    if (dh->priv_key == NULL) {
2921cb0ef41Sopenharmony_ci        priv_key = BN_secure_new();
2931cb0ef41Sopenharmony_ci        if (priv_key == NULL)
2941cb0ef41Sopenharmony_ci            goto err;
2951cb0ef41Sopenharmony_ci        generate_new_key = 1;
2961cb0ef41Sopenharmony_ci    } else {
2971cb0ef41Sopenharmony_ci        priv_key = dh->priv_key;
2981cb0ef41Sopenharmony_ci    }
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci    if (dh->pub_key == NULL) {
3011cb0ef41Sopenharmony_ci        pub_key = BN_new();
3021cb0ef41Sopenharmony_ci        if (pub_key == NULL)
3031cb0ef41Sopenharmony_ci            goto err;
3041cb0ef41Sopenharmony_ci    } else {
3051cb0ef41Sopenharmony_ci        pub_key = dh->pub_key;
3061cb0ef41Sopenharmony_ci    }
3071cb0ef41Sopenharmony_ci    if (generate_new_key) {
3081cb0ef41Sopenharmony_ci        /* Is it an approved safe prime ?*/
3091cb0ef41Sopenharmony_ci        if (DH_get_nid(dh) != NID_undef) {
3101cb0ef41Sopenharmony_ci            int max_strength =
3111cb0ef41Sopenharmony_ci                    ossl_ifc_ffc_compute_security_bits(BN_num_bits(dh->params.p));
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci            if (dh->params.q == NULL
3141cb0ef41Sopenharmony_ci                || dh->length > BN_num_bits(dh->params.q))
3151cb0ef41Sopenharmony_ci                goto err;
3161cb0ef41Sopenharmony_ci            /* dh->length = maximum bit length of generated private key */
3171cb0ef41Sopenharmony_ci            if (!ossl_ffc_generate_private_key(ctx, &dh->params, dh->length,
3181cb0ef41Sopenharmony_ci                                               max_strength, priv_key))
3191cb0ef41Sopenharmony_ci                goto err;
3201cb0ef41Sopenharmony_ci        } else {
3211cb0ef41Sopenharmony_ci#ifdef FIPS_MODULE
3221cb0ef41Sopenharmony_ci            if (dh->params.q == NULL)
3231cb0ef41Sopenharmony_ci                goto err;
3241cb0ef41Sopenharmony_ci#else
3251cb0ef41Sopenharmony_ci            if (dh->params.q == NULL) {
3261cb0ef41Sopenharmony_ci                /* secret exponent length, must satisfy 2^(l-1) <= p */
3271cb0ef41Sopenharmony_ci                if (dh->length != 0
3281cb0ef41Sopenharmony_ci                    && dh->length >= BN_num_bits(dh->params.p))
3291cb0ef41Sopenharmony_ci                    goto err;
3301cb0ef41Sopenharmony_ci                l = dh->length ? dh->length : BN_num_bits(dh->params.p) - 1;
3311cb0ef41Sopenharmony_ci                if (!BN_priv_rand_ex(priv_key, l, BN_RAND_TOP_ONE,
3321cb0ef41Sopenharmony_ci                                     BN_RAND_BOTTOM_ANY, 0, ctx))
3331cb0ef41Sopenharmony_ci                    goto err;
3341cb0ef41Sopenharmony_ci                /*
3351cb0ef41Sopenharmony_ci                 * We handle just one known case where g is a quadratic non-residue:
3361cb0ef41Sopenharmony_ci                 * for g = 2: p % 8 == 3
3371cb0ef41Sopenharmony_ci                 */
3381cb0ef41Sopenharmony_ci                if (BN_is_word(dh->params.g, DH_GENERATOR_2)
3391cb0ef41Sopenharmony_ci                    && !BN_is_bit_set(dh->params.p, 2)) {
3401cb0ef41Sopenharmony_ci                    /* clear bit 0, since it won't be a secret anyway */
3411cb0ef41Sopenharmony_ci                    if (!BN_clear_bit(priv_key, 0))
3421cb0ef41Sopenharmony_ci                        goto err;
3431cb0ef41Sopenharmony_ci                }
3441cb0ef41Sopenharmony_ci            } else
3451cb0ef41Sopenharmony_ci#endif
3461cb0ef41Sopenharmony_ci            {
3471cb0ef41Sopenharmony_ci                /* Do a partial check for invalid p, q, g */
3481cb0ef41Sopenharmony_ci                if (!ossl_ffc_params_simple_validate(dh->libctx, &dh->params,
3491cb0ef41Sopenharmony_ci                                                     FFC_PARAM_TYPE_DH, NULL))
3501cb0ef41Sopenharmony_ci                    goto err;
3511cb0ef41Sopenharmony_ci                /*
3521cb0ef41Sopenharmony_ci                 * For FFC FIPS 186-4 keygen
3531cb0ef41Sopenharmony_ci                 * security strength s = 112,
3541cb0ef41Sopenharmony_ci                 * Max Private key size N = len(q)
3551cb0ef41Sopenharmony_ci                 */
3561cb0ef41Sopenharmony_ci                if (!ossl_ffc_generate_private_key(ctx, &dh->params,
3571cb0ef41Sopenharmony_ci                                                   BN_num_bits(dh->params.q),
3581cb0ef41Sopenharmony_ci                                                   MIN_STRENGTH,
3591cb0ef41Sopenharmony_ci                                                   priv_key))
3601cb0ef41Sopenharmony_ci                    goto err;
3611cb0ef41Sopenharmony_ci            }
3621cb0ef41Sopenharmony_ci        }
3631cb0ef41Sopenharmony_ci    }
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci    if (!ossl_dh_generate_public_key(ctx, dh, priv_key, pub_key))
3661cb0ef41Sopenharmony_ci        goto err;
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci    dh->pub_key = pub_key;
3691cb0ef41Sopenharmony_ci    dh->priv_key = priv_key;
3701cb0ef41Sopenharmony_ci    dh->dirty_cnt++;
3711cb0ef41Sopenharmony_ci    ok = 1;
3721cb0ef41Sopenharmony_ci err:
3731cb0ef41Sopenharmony_ci    if (ok != 1)
3741cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB);
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci    if (pub_key != dh->pub_key)
3771cb0ef41Sopenharmony_ci        BN_free(pub_key);
3781cb0ef41Sopenharmony_ci    if (priv_key != dh->priv_key)
3791cb0ef41Sopenharmony_ci        BN_free(priv_key);
3801cb0ef41Sopenharmony_ci    BN_CTX_free(ctx);
3811cb0ef41Sopenharmony_ci    return ok;
3821cb0ef41Sopenharmony_ci}
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ciint ossl_dh_buf2key(DH *dh, const unsigned char *buf, size_t len)
3851cb0ef41Sopenharmony_ci{
3861cb0ef41Sopenharmony_ci    int err_reason = DH_R_BN_ERROR;
3871cb0ef41Sopenharmony_ci    BIGNUM *pubkey = NULL;
3881cb0ef41Sopenharmony_ci    const BIGNUM *p;
3891cb0ef41Sopenharmony_ci    int ret;
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci    if ((pubkey = BN_bin2bn(buf, len, NULL)) == NULL)
3921cb0ef41Sopenharmony_ci        goto err;
3931cb0ef41Sopenharmony_ci    DH_get0_pqg(dh, &p, NULL, NULL);
3941cb0ef41Sopenharmony_ci    if (p == NULL || BN_num_bytes(p) == 0) {
3951cb0ef41Sopenharmony_ci        err_reason = DH_R_NO_PARAMETERS_SET;
3961cb0ef41Sopenharmony_ci        goto err;
3971cb0ef41Sopenharmony_ci    }
3981cb0ef41Sopenharmony_ci    /* Prevent small subgroup attacks per RFC 8446 Section 4.2.8.1 */
3991cb0ef41Sopenharmony_ci    if (!ossl_dh_check_pub_key_partial(dh, pubkey, &ret)) {
4001cb0ef41Sopenharmony_ci        err_reason = DH_R_INVALID_PUBKEY;
4011cb0ef41Sopenharmony_ci        goto err;
4021cb0ef41Sopenharmony_ci    }
4031cb0ef41Sopenharmony_ci    if (DH_set0_key(dh, pubkey, NULL) != 1)
4041cb0ef41Sopenharmony_ci        goto err;
4051cb0ef41Sopenharmony_ci    return 1;
4061cb0ef41Sopenharmony_cierr:
4071cb0ef41Sopenharmony_ci    ERR_raise(ERR_LIB_DH, err_reason);
4081cb0ef41Sopenharmony_ci    BN_free(pubkey);
4091cb0ef41Sopenharmony_ci    return 0;
4101cb0ef41Sopenharmony_ci}
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_cisize_t ossl_dh_key2buf(const DH *dh, unsigned char **pbuf_out, size_t size,
4131cb0ef41Sopenharmony_ci                       int alloc)
4141cb0ef41Sopenharmony_ci{
4151cb0ef41Sopenharmony_ci    const BIGNUM *pubkey;
4161cb0ef41Sopenharmony_ci    unsigned char *pbuf = NULL;
4171cb0ef41Sopenharmony_ci    const BIGNUM *p;
4181cb0ef41Sopenharmony_ci    int p_size;
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci    DH_get0_pqg(dh, &p, NULL, NULL);
4211cb0ef41Sopenharmony_ci    DH_get0_key(dh, &pubkey, NULL);
4221cb0ef41Sopenharmony_ci    if (p == NULL || pubkey == NULL
4231cb0ef41Sopenharmony_ci            || (p_size = BN_num_bytes(p)) == 0
4241cb0ef41Sopenharmony_ci            || BN_num_bytes(pubkey) == 0) {
4251cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_INVALID_PUBKEY);
4261cb0ef41Sopenharmony_ci        return 0;
4271cb0ef41Sopenharmony_ci    }
4281cb0ef41Sopenharmony_ci    if (pbuf_out != NULL && (alloc || *pbuf_out != NULL)) {
4291cb0ef41Sopenharmony_ci        if (!alloc) {
4301cb0ef41Sopenharmony_ci            if (size >= (size_t)p_size)
4311cb0ef41Sopenharmony_ci                pbuf = *pbuf_out;
4321cb0ef41Sopenharmony_ci        } else {
4331cb0ef41Sopenharmony_ci            pbuf = OPENSSL_malloc(p_size);
4341cb0ef41Sopenharmony_ci        }
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci        if (pbuf == NULL) {
4371cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
4381cb0ef41Sopenharmony_ci            return 0;
4391cb0ef41Sopenharmony_ci        }
4401cb0ef41Sopenharmony_ci        /*
4411cb0ef41Sopenharmony_ci         * As per Section 4.2.8.1 of RFC 8446 left pad public
4421cb0ef41Sopenharmony_ci         * key with zeros to the size of p
4431cb0ef41Sopenharmony_ci         */
4441cb0ef41Sopenharmony_ci        if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) {
4451cb0ef41Sopenharmony_ci            if (alloc)
4461cb0ef41Sopenharmony_ci                OPENSSL_free(pbuf);
4471cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR);
4481cb0ef41Sopenharmony_ci            return 0;
4491cb0ef41Sopenharmony_ci        }
4501cb0ef41Sopenharmony_ci        *pbuf_out = pbuf;
4511cb0ef41Sopenharmony_ci    }
4521cb0ef41Sopenharmony_ci    return p_size;
4531cb0ef41Sopenharmony_ci}
454