diff options
Diffstat (limited to 'crypto/dh')
| -rw-r--r-- | crypto/dh/build.info | 16 | ||||
| -rw-r--r-- | crypto/dh/dh1024.pem | 5 | ||||
| -rw-r--r-- | crypto/dh/dh192.pem | 3 | ||||
| -rw-r--r-- | crypto/dh/dh2048.pem | 16 | ||||
| -rw-r--r-- | crypto/dh/dh4096.pem | 14 | ||||
| -rw-r--r-- | crypto/dh/dh512.pem | 4 | ||||
| -rw-r--r-- | crypto/dh/dh_ameth.c | 715 | ||||
| -rw-r--r-- | crypto/dh/dh_asn1.c | 95 | ||||
| -rw-r--r-- | crypto/dh/dh_backend.c | 250 | ||||
| -rw-r--r-- | crypto/dh/dh_check.c | 262 | ||||
| -rw-r--r-- | crypto/dh/dh_depr.c | 22 | ||||
| -rw-r--r-- | crypto/dh/dh_err.c | 59 | ||||
| -rw-r--r-- | crypto/dh/dh_gen.c | 136 | ||||
| -rw-r--r-- | crypto/dh/dh_group_params.c | 99 | ||||
| -rw-r--r-- | crypto/dh/dh_kdf.c | 181 | ||||
| -rw-r--r-- | crypto/dh/dh_key.c | 413 | ||||
| -rw-r--r-- | crypto/dh/dh_lib.c | 153 | ||||
| -rw-r--r-- | crypto/dh/dh_local.h | 27 | ||||
| -rw-r--r-- | crypto/dh/dh_meth.c | 16 | ||||
| -rw-r--r-- | crypto/dh/dh_pmeth.c | 227 | ||||
| -rw-r--r-- | crypto/dh/dh_prn.c | 12 | ||||
| -rw-r--r-- | crypto/dh/dh_rfc5114.c | 18 | ||||
| -rw-r--r-- | crypto/dh/dh_rfc7919.c | 74 |
23 files changed, 1615 insertions, 1202 deletions
diff --git a/crypto/dh/build.info b/crypto/dh/build.info index b19ff6dbac19..b41356727185 100644 --- a/crypto/dh/build.info +++ b/crypto/dh/build.info @@ -1,5 +1,13 @@ LIBS=../../libcrypto -SOURCE[../../libcrypto]=\ - dh_asn1.c dh_gen.c dh_key.c dh_lib.c dh_check.c dh_err.c dh_depr.c \ - dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c dh_meth.c \ - dh_rfc7919.c + +$COMMON=dh_lib.c dh_key.c dh_group_params.c dh_check.c dh_backend.c dh_gen.c \ + dh_kdf.c + +SOURCE[../../libcrypto]=$COMMON\ + dh_asn1.c dh_err.c \ + dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_meth.c +IF[{- !$disabled{'deprecated-0.9.8'} -}] + SOURCE[../../libcrypto]=dh_depr.c +ENDIF + +SOURCE[../../providers/libfips.a]=$COMMON diff --git a/crypto/dh/dh1024.pem b/crypto/dh/dh1024.pem deleted file mode 100644 index 81d43f6a3eae..000000000000 --- a/crypto/dh/dh1024.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq -/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx -/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC ------END DH PARAMETERS----- diff --git a/crypto/dh/dh192.pem b/crypto/dh/dh192.pem deleted file mode 100644 index 521c07271d0d..000000000000 --- a/crypto/dh/dh192.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN DH PARAMETERS----- -MB4CGQDUoLoCULb9LsYm5+/WN992xxbiLQlEuIsCAQM= ------END DH PARAMETERS----- diff --git a/crypto/dh/dh2048.pem b/crypto/dh/dh2048.pem deleted file mode 100644 index 295460f5081e..000000000000 --- a/crypto/dh/dh2048.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEA7ZKJNYJFVcs7+6J2WmkEYb8h86tT0s0h2v94GRFS8Q7B4lW9aG9o -AFO5Imov5Jo0H2XMWTKKvbHbSe3fpxJmw/0hBHAY8H/W91hRGXKCeyKpNBgdL8sh -z22SrkO2qCnHJ6PLAMXy5fsKpFmFor2tRfCzrfnggTXu2YOzzK7q62bmqVdmufEo -pT8igNcLpvZxk5uBDvhakObMym9mX3rAEBoe8PwttggMYiiw7NuJKO4MqD1llGkW -aVM8U2ATsCun1IKHrRxynkE1/MJ86VHeYYX8GZt2YA8z+GuzylIOKcMH6JAWzMwA -Gbatw6QwizOhr9iMjZ0B26TE3X8LvW84wwIBAg== ------END DH PARAMETERS----- ------BEGIN DH PARAMETERS----- -MIIBCAKCAQEArtA3w73zP6Lu3EOQtwogiXt3AXXpuS6yD4BhzNS1pZFyPHk0/an5 -8ydEkPhQZHKDW+BZJxxPLANaTudWo2YT8TgtvUdN6KSgMiEi6McwqDw+SADuvW+F -SKUYFxG6VFIxyEP6xBdf+vhJxEDbRG2EYsHDRRtJ76gp9cSKTHusf2R+4AAVGqnt -gRAbNqtcOar/7FSj+Pl8G3v0Bty0LcCSpbqgYlnv6z+rErQmmC6PPvSz97TDMCok -yKpCE9hFA1zkqK3TH4FmFvGeIaXJUIBZf4mArWuBTjWFW3nmhESRUn1VK3K3x42N -a5k6c2+EhrMFiLjxuH6JZoqL0/E93FF9SwIBAg== ------END DH PARAMETERS----- diff --git a/crypto/dh/dh4096.pem b/crypto/dh/dh4096.pem deleted file mode 100644 index 390943a21dc4..000000000000 --- a/crypto/dh/dh4096.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN DH PARAMETERS----- -MIICCAKCAgEA/urRnb6vkPYc/KEGXWnbCIOaKitq7ySIq9dTH7s+Ri59zs77zty7 -vfVlSe6VFTBWgYjD2XKUFmtqq6CqXMhVX5ElUDoYDpAyTH85xqNFLzFC7nKrff/H -TFKNttp22cZE9V0IPpzedPfnQkE7aUdmF9JnDyv21Z/818O93u1B4r0szdnmEvEF -bKuIxEHX+bp0ZR7RqE1AeifXGJX3d6tsd2PMAObxwwsv55RGkn50vHO4QxtTARr1 -rRUV5j3B3oPMgC7Offxx+98Xn45B1/G0Prp11anDsR1PGwtaCYipqsvMwQUSJtyE -EOQWk+yFkeMe4vWv367eEi0Sd/wnC+TSXBE3pYvpYerJ8n1MceI5GQTdarJ77OW9 -bGTHmxRsLSCM1jpLdPja5jjb4siAa6EHc4qN9c/iFKS3PQPJEnX7pXKBRs5f7AF3 -W3RIGt+G9IVNZfXaS7Z/iCpgzgvKCs0VeqN38QsJGtC1aIkwOeyjPNy2G6jJ4yqH -ovXYt/0mc00vCWeSNS1wren0pR2EiLxX0ypjjgsU1mk/Z3b/+zVf7fZSIB+nDLjb -NPtUlJCVGnAeBK1J1nG3TQicqowOXoM6ISkdaXj5GPJdXHab2+S7cqhKGv5qC7rR -jT6sx7RUr0CNTxzLI7muV2/a4tGmj0PSdXQdsZ7tw7gbXlaWT1+MM2MCAQI= ------END DH PARAMETERS----- - diff --git a/crypto/dh/dh512.pem b/crypto/dh/dh512.pem deleted file mode 100644 index 0a4d863ebe27..000000000000 --- a/crypto/dh/dh512.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN DH PARAMETERS----- -MEYCQQDaWDwW2YUiidDkr3VvTMqS3UvlM7gE+w/tlO+cikQD7VdGUNNpmdsp13Yn -a6LT1BLiGPTdHghM9tgAPnxHdOgzAgEC ------END DH PARAMETERS----- diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c index 576409ccb51b..8430872a9ab6 100644 --- a/crypto/dh/dh_ameth.c +++ b/crypto/dh/dh_ameth.c @@ -1,21 +1,30 @@ /* - * Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> -#include "internal/cryptlib.h" #include <openssl/x509.h> #include <openssl/asn1.h> -#include "dh_local.h" #include <openssl/bn.h> +#include <openssl/core_names.h> +#include <openssl/param_build.h> +#include "internal/ffc.h" +#include "internal/cryptlib.h" #include "crypto/asn1.h" +#include "crypto/dh.h" #include "crypto/evp.h" -#include <openssl/cms.h> +#include "dh_local.h" /* * i2d/d2i like DH parameter functions which use the appropriate routine for @@ -25,14 +34,20 @@ static DH *d2i_dhp(const EVP_PKEY *pkey, const unsigned char **pp, long length) { - if (pkey->ameth == &dhx_asn1_meth) - return d2i_DHxparams(NULL, pp, length); - return d2i_DHparams(NULL, pp, length); + DH *dh = NULL; + int is_dhx = (pkey->ameth == &ossl_dhx_asn1_meth); + + if (is_dhx) + dh = d2i_DHxparams(NULL, pp, length); + else + dh = d2i_DHparams(NULL, pp, length); + + return dh; } static int i2d_dhp(const EVP_PKEY *pkey, const DH *a, unsigned char **pp) { - if (pkey->ameth == &dhx_asn1_meth) + if (pkey->ameth == &ossl_dhx_asn1_meth) return i2d_DHxparams(a, pp); return i2d_DHparams(a, pp); } @@ -42,7 +57,7 @@ static void int_dh_free(EVP_PKEY *pkey) DH_free(pkey->pkey.dh); } -static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) +static int dh_pub_decode(EVP_PKEY *pkey, const X509_PUBKEY *pubkey) { const unsigned char *p, *pm; int pklen, pmlen; @@ -59,7 +74,7 @@ static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) X509_ALGOR_get0(NULL, &ptype, &pval, palg); if (ptype != V_ASN1_SEQUENCE) { - DHerr(DH_F_DH_PUB_DECODE, DH_R_PARAMETER_ENCODING_ERROR); + ERR_raise(ERR_LIB_DH, DH_R_PARAMETER_ENCODING_ERROR); goto err; } @@ -68,18 +83,18 @@ static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) pmlen = pstr->length; if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL) { - DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR); + ERR_raise(ERR_LIB_DH, DH_R_DECODE_ERROR); goto err; } if ((public_key = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) { - DHerr(DH_F_DH_PUB_DECODE, DH_R_DECODE_ERROR); + ERR_raise(ERR_LIB_DH, DH_R_DECODE_ERROR); goto err; } /* We have parameters now set public key */ if ((dh->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) { - DHerr(DH_F_DH_PUB_DECODE, DH_R_BN_DECODE_ERROR); + ERR_raise(ERR_LIB_DH, DH_R_BN_DECODE_ERROR); goto err; } @@ -91,7 +106,6 @@ static int dh_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) ASN1_INTEGER_free(public_key); DH_free(dh); return 0; - } static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) @@ -107,18 +121,18 @@ static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) str = ASN1_STRING_new(); if (str == NULL) { - DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); goto err; } str->length = i2d_dhp(pkey, dh, &str->data); if (str->length <= 0) { - DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); goto err; } ptype = V_ASN1_SEQUENCE; pub_key = BN_to_ASN1_INTEGER(dh->pub_key, NULL); - if (!pub_key) + if (pub_key == NULL) goto err; penclen = i2d_ASN1_INTEGER(pub_key, &penc); @@ -126,7 +140,7 @@ static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) ASN1_INTEGER_free(pub_key); if (penclen <= 0) { - DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); goto err; } @@ -149,54 +163,15 @@ static int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) static int dh_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8) { - const unsigned char *p, *pm; - int pklen, pmlen; - int ptype; - const void *pval; - const ASN1_STRING *pstr; - const X509_ALGOR *palg; - ASN1_INTEGER *privkey = NULL; - - DH *dh = NULL; - - if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) - return 0; - - X509_ALGOR_get0(NULL, &ptype, &pval, palg); - - if (ptype != V_ASN1_SEQUENCE) - goto decerr; - if ((privkey = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) - goto decerr; + int ret = 0; + DH *dh = ossl_dh_key_from_pkcs8(p8, NULL, NULL); - pstr = pval; - pm = pstr->data; - pmlen = pstr->length; - if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL) - goto decerr; - - /* We have parameters now set private key */ - if ((dh->priv_key = BN_secure_new()) == NULL - || !ASN1_INTEGER_to_BN(privkey, dh->priv_key)) { - DHerr(DH_F_DH_PRIV_DECODE, DH_R_BN_ERROR); - goto dherr; + if (dh != NULL) { + ret = 1; + EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh); } - /* Calculate public key */ - if (!DH_generate_key(dh)) - goto dherr; - - EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh); - - ASN1_STRING_clear_free(privkey); - - return 1; - decerr: - DHerr(DH_F_DH_PRIV_DECODE, EVP_R_DECODE_ERROR); - dherr: - DH_free(dh); - ASN1_STRING_clear_free(privkey); - return 0; + return ret; } static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) @@ -209,13 +184,13 @@ static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) params = ASN1_STRING_new(); if (params == NULL) { - DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); goto err; } params->length = i2d_dhp(pkey, pkey->pkey.dh, ¶ms->data); if (params->length <= 0) { - DHerr(DH_F_DH_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); goto err; } params->type = V_ASN1_SEQUENCE; @@ -223,26 +198,29 @@ static int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) /* Get private key into integer */ prkey = BN_to_ASN1_INTEGER(pkey->pkey.dh->priv_key, NULL); - if (!prkey) { - DHerr(DH_F_DH_PRIV_ENCODE, DH_R_BN_ERROR); + if (prkey == NULL) { + ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR); goto err; } dplen = i2d_ASN1_INTEGER(prkey, &dp); ASN1_STRING_clear_free(prkey); - prkey = NULL; - if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0, - V_ASN1_SEQUENCE, params, dp, dplen)) + if (dplen <= 0) { + ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR); goto err; + } + if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0, + V_ASN1_SEQUENCE, params, dp, dplen)) { + OPENSSL_clear_free(dp, dplen); + goto err; + } return 1; err: - OPENSSL_free(dp); ASN1_STRING_free(params); - ASN1_STRING_clear_free(prkey); return 0; } @@ -251,10 +229,9 @@ static int dh_param_decode(EVP_PKEY *pkey, { DH *dh; - if ((dh = d2i_dhp(pkey, pder, derlen)) == NULL) { - DHerr(DH_F_DH_PARAM_DECODE, ERR_R_DH_LIB); + if ((dh = d2i_dhp(pkey, pder, derlen)) == NULL) return 0; - } + dh->dirty_cnt++; EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh); return 1; } @@ -280,7 +257,7 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype) else pub_key = NULL; - if (x->p == NULL || (ptype == 2 && priv_key == NULL) + if (x->params.p == NULL || (ptype == 2 && priv_key == NULL) || (ptype > 0 && pub_key == NULL)) { reason = ERR_R_PASSED_NULL_PARAMETER; goto err; @@ -293,8 +270,8 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype) else ktype = "DH Parameters"; - BIO_indent(bp, indent, 128); - if (BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) + if (!BIO_indent(bp, indent, 128) + || BIO_printf(bp, "%s: (%d bit)\n", ktype, DH_bits(x)) <= 0) goto err; indent += 4; @@ -303,44 +280,20 @@ static int do_dh_print(BIO *bp, const DH *x, int indent, int ptype) if (!ASN1_bn_print(bp, "public-key:", pub_key, NULL, indent)) goto err; - if (!ASN1_bn_print(bp, "prime:", x->p, NULL, indent)) - goto err; - if (!ASN1_bn_print(bp, "generator:", x->g, NULL, indent)) - goto err; - if (x->q && !ASN1_bn_print(bp, "subgroup order:", x->q, NULL, indent)) - goto err; - if (x->j && !ASN1_bn_print(bp, "subgroup factor:", x->j, NULL, indent)) - goto err; - if (x->seed) { - int i; - BIO_indent(bp, indent, 128); - BIO_puts(bp, "seed:"); - for (i = 0; i < x->seedlen; i++) { - if ((i % 15) == 0) { - if (BIO_puts(bp, "\n") <= 0 - || !BIO_indent(bp, indent + 4, 128)) - goto err; - } - if (BIO_printf(bp, "%02x%s", x->seed[i], - ((i + 1) == x->seedlen) ? "" : ":") <= 0) - goto err; - } - if (BIO_write(bp, "\n", 1) <= 0) - return 0; - } - if (x->counter && !ASN1_bn_print(bp, "counter:", x->counter, NULL, indent)) + if (!ossl_ffc_params_print(bp, &x->params, indent)) goto err; + if (x->length != 0) { - BIO_indent(bp, indent, 128); - if (BIO_printf(bp, "recommended-private-length: %d bits\n", - (int)x->length) <= 0) + if (!BIO_indent(bp, indent, 128) + || BIO_printf(bp, "recommended-private-length: %d bits\n", + (int)x->length) <= 0) goto err; } return 1; err: - DHerr(DH_F_DO_DH_PRINT, reason); + ERR_raise(ERR_LIB_DH, reason); return 0; } @@ -351,7 +304,7 @@ static int int_dh_size(const EVP_PKEY *pkey) static int dh_bits(const EVP_PKEY *pkey) { - return BN_num_bits(pkey->pkey.dh->p); + return DH_bits(pkey->pkey.dh); } static int dh_security_bits(const EVP_PKEY *pkey) @@ -361,64 +314,23 @@ static int dh_security_bits(const EVP_PKEY *pkey) static int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { - if (BN_cmp(a->pkey.dh->p, b->pkey.dh->p) || - BN_cmp(a->pkey.dh->g, b->pkey.dh->g)) - return 0; - else if (a->ameth == &dhx_asn1_meth) { - if (BN_cmp(a->pkey.dh->q, b->pkey.dh->q)) - return 0; - } - return 1; -} - -static int int_dh_bn_cpy(BIGNUM **dst, const BIGNUM *src) -{ - BIGNUM *a; - - /* - * If source is read only just copy the pointer, so - * we don't have to reallocate it. - */ - if (src == NULL) - a = NULL; - else if (BN_get_flags(src, BN_FLG_STATIC_DATA) - && !BN_get_flags(src, BN_FLG_MALLOCED)) - a = (BIGNUM *)src; - else if ((a = BN_dup(src)) == NULL) - return 0; - BN_clear_free(*dst); - *dst = a; - return 1; + return ossl_ffc_params_cmp(&a->pkey.dh->params, &b->pkey.dh->params, + a->ameth != &ossl_dhx_asn1_meth); } static int int_dh_param_copy(DH *to, const DH *from, int is_x942) { if (is_x942 == -1) - is_x942 = ! !from->q; - if (!int_dh_bn_cpy(&to->p, from->p)) + is_x942 = (from->params.q != NULL); + if (!ossl_ffc_params_copy(&to->params, &from->params)) return 0; - if (!int_dh_bn_cpy(&to->g, from->g)) - return 0; - if (is_x942) { - if (!int_dh_bn_cpy(&to->q, from->q)) - return 0; - if (!int_dh_bn_cpy(&to->j, from->j)) - return 0; - OPENSSL_free(to->seed); - to->seed = NULL; - to->seedlen = 0; - if (from->seed) { - to->seed = OPENSSL_memdup(from->seed, from->seedlen); - if (!to->seed) - return 0; - to->seedlen = from->seedlen; - } - } else + if (!is_x942) to->length = from->length; + to->dirty_cnt++; return 1; } -DH *DHparams_dup(DH *dh) +DH *DHparams_dup(const DH *dh) { DH *ret; ret = DH_new(); @@ -439,14 +351,14 @@ static int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) return 0; } return int_dh_param_copy(to->pkey.dh, from->pkey.dh, - from->ameth == &dhx_asn1_meth); + from->ameth == &ossl_dhx_asn1_meth); } static int dh_missing_parameters(const EVP_PKEY *a) { - if (a->pkey.dh == NULL || a->pkey.dh->p == NULL || a->pkey.dh->g == NULL) - return 1; - return 0; + return a->pkey.dh == NULL + || a->pkey.dh->params.p == NULL + || a->pkey.dh->params.g == NULL; } static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) @@ -482,27 +394,31 @@ int DHparams_print(BIO *bp, const DH *x) return do_dh_print(bp, x, 4, 0); } -#ifndef OPENSSL_NO_CMS -static int dh_cms_decrypt(CMS_RecipientInfo *ri); -static int dh_cms_encrypt(CMS_RecipientInfo *ri); -#endif - static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) { + DH *dh; switch (op) { -#ifndef OPENSSL_NO_CMS - - case ASN1_PKEY_CTRL_CMS_ENVELOPE: - if (arg1 == 1) - return dh_cms_decrypt(arg2); - else if (arg1 == 0) - return dh_cms_encrypt(arg2); + case ASN1_PKEY_CTRL_SET1_TLS_ENCPT: + /* We should only be here if we have a legacy key */ + if (!ossl_assert(evp_pkey_is_legacy(pkey))) + return 0; + dh = (DH *) evp_pkey_get0_DH_int(pkey); + if (dh == NULL) + return 0; + return ossl_dh_buf2key(dh, arg2, arg1); + case ASN1_PKEY_CTRL_GET1_TLS_ENCPT: + dh = (DH *) EVP_PKEY_get0_DH(pkey); + if (dh == NULL) + return 0; + return ossl_dh_key2buf(dh, arg2, 0, 1); + default: return -2; + } +} - case ASN1_PKEY_CTRL_CMS_RI_TYPE: - *(int *)arg2 = CMS_RECIPINFO_AGREE; - return 1; -#endif +static int dhx_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) +{ + switch (op) { default: return -2; } @@ -514,7 +430,7 @@ static int dh_pkey_public_check(const EVP_PKEY *pkey) DH *dh = pkey->pkey.dh; if (dh->pub_key == NULL) { - DHerr(DH_F_DH_PKEY_PUBLIC_CHECK, DH_R_MISSING_PUBKEY); + ERR_raise(ERR_LIB_DH, DH_R_MISSING_PUBKEY); return 0; } @@ -528,7 +444,120 @@ static int dh_pkey_param_check(const EVP_PKEY *pkey) return DH_check_ex(dh); } -const EVP_PKEY_ASN1_METHOD dh_asn1_meth = { +static size_t dh_pkey_dirty_cnt(const EVP_PKEY *pkey) +{ + return pkey->pkey.dh->dirty_cnt; +} + +static int dh_pkey_export_to(const EVP_PKEY *from, void *to_keydata, + OSSL_FUNC_keymgmt_import_fn *importer, + OSSL_LIB_CTX *libctx, const char *propq) +{ + DH *dh = from->pkey.dh; + OSSL_PARAM_BLD *tmpl; + const BIGNUM *p = DH_get0_p(dh), *g = DH_get0_g(dh), *q = DH_get0_q(dh); + long l = DH_get_length(dh); + const BIGNUM *pub_key = DH_get0_pub_key(dh); + const BIGNUM *priv_key = DH_get0_priv_key(dh); + OSSL_PARAM *params = NULL; + int selection = 0; + int rv = 0; + + if (p == NULL || g == NULL) + return 0; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + return 0; + if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, p) + || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, g)) + goto err; + if (q != NULL) { + if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, q)) + goto err; + } + selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; + if (l > 0) { + if (!OSSL_PARAM_BLD_push_long(tmpl, OSSL_PKEY_PARAM_DH_PRIV_LEN, l)) + goto err; + selection |= OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS; + } + if (pub_key != NULL) { + if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key)) + goto err; + selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + } + if (priv_key != NULL) { + if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, + priv_key)) + goto err; + selection |= OSSL_KEYMGMT_SELECT_PRIVATE_KEY; + } + + if ((params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL) + goto err; + + /* We export, the provider imports */ + rv = importer(to_keydata, selection, params); + + OSSL_PARAM_free(params); +err: + OSSL_PARAM_BLD_free(tmpl); + return rv; +} + +static int dh_pkey_import_from_type(const OSSL_PARAM params[], void *vpctx, + int type) +{ + EVP_PKEY_CTX *pctx = vpctx; + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx); + DH *dh = ossl_dh_new_ex(pctx->libctx); + + if (dh == NULL) { + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); + return 0; + } + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, type == EVP_PKEY_DH ? DH_FLAG_TYPE_DH : DH_FLAG_TYPE_DHX); + + if (!ossl_dh_params_fromdata(dh, params) + || !ossl_dh_key_fromdata(dh, params, 1) + || !EVP_PKEY_assign(pkey, type, dh)) { + DH_free(dh); + return 0; + } + return 1; +} + +static int dh_pkey_import_from(const OSSL_PARAM params[], void *vpctx) +{ + return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DH); +} + +static int dhx_pkey_import_from(const OSSL_PARAM params[], void *vpctx) +{ + return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DHX); +} + +static int dh_pkey_copy(EVP_PKEY *to, EVP_PKEY *from) +{ + DH *dh = from->pkey.dh; + DH *dupkey = NULL; + int ret; + + if (dh != NULL) { + dupkey = ossl_dh_dup(dh, OSSL_KEYMGMT_SELECT_ALL); + if (dupkey == NULL) + return 0; + } + + ret = EVP_PKEY_assign(to, from->type, dupkey); + if (!ret) + DH_free(dupkey); + return ret; +} + +const EVP_PKEY_ASN1_METHOD ossl_dh_asn1_meth = { EVP_PKEY_DH, EVP_PKEY_DH, 0, @@ -558,16 +587,23 @@ const EVP_PKEY_ASN1_METHOD dh_asn1_meth = { 0, int_dh_free, - 0, + dh_pkey_ctrl, 0, 0, 0, 0, 0, 0, dh_pkey_public_check, - dh_pkey_param_check + dh_pkey_param_check, + + 0, 0, 0, 0, + + dh_pkey_dirty_cnt, + dh_pkey_export_to, + dh_pkey_import_from, + dh_pkey_copy }; -const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = { +const EVP_PKEY_ASN1_METHOD ossl_dhx_asn1_meth = { EVP_PKEY_DHX, EVP_PKEY_DHX, 0, @@ -597,315 +633,16 @@ const EVP_PKEY_ASN1_METHOD dhx_asn1_meth = { 0, int_dh_free, - dh_pkey_ctrl, + dhx_pkey_ctrl, 0, 0, 0, 0, 0, 0, dh_pkey_public_check, - dh_pkey_param_check + dh_pkey_param_check, + 0, 0, 0, 0, + dh_pkey_dirty_cnt, + dh_pkey_export_to, + dhx_pkey_import_from, + dh_pkey_copy }; - -#ifndef OPENSSL_NO_CMS - -static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx, - X509_ALGOR *alg, ASN1_BIT_STRING *pubkey) -{ - const ASN1_OBJECT *aoid; - int atype; - const void *aval; - ASN1_INTEGER *public_key = NULL; - int rv = 0; - EVP_PKEY *pkpeer = NULL, *pk = NULL; - DH *dhpeer = NULL; - const unsigned char *p; - int plen; - - X509_ALGOR_get0(&aoid, &atype, &aval, alg); - if (OBJ_obj2nid(aoid) != NID_dhpublicnumber) - goto err; - /* Only absent parameters allowed in RFC XXXX */ - if (atype != V_ASN1_UNDEF && atype == V_ASN1_NULL) - goto err; - - pk = EVP_PKEY_CTX_get0_pkey(pctx); - if (pk == NULL || pk->type != EVP_PKEY_DHX) - goto err; - - /* Get parameters from parent key */ - dhpeer = DHparams_dup(pk->pkey.dh); - if (dhpeer == NULL) - goto err; - - /* We have parameters now set public key */ - plen = ASN1_STRING_length(pubkey); - p = ASN1_STRING_get0_data(pubkey); - if (p == NULL || plen == 0) - goto err; - - if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL) { - DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_DECODE_ERROR); - goto err; - } - - /* We have parameters now set public key */ - if ((dhpeer->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) { - DHerr(DH_F_DH_CMS_SET_PEERKEY, DH_R_BN_DECODE_ERROR); - goto err; - } - - pkpeer = EVP_PKEY_new(); - if (pkpeer == NULL) - goto err; - - EVP_PKEY_assign(pkpeer, pk->ameth->pkey_id, dhpeer); - dhpeer = NULL; - if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0) - rv = 1; - err: - ASN1_INTEGER_free(public_key); - EVP_PKEY_free(pkpeer); - DH_free(dhpeer); - return rv; -} - -static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) -{ - int rv = 0; - - X509_ALGOR *alg, *kekalg = NULL; - ASN1_OCTET_STRING *ukm; - const unsigned char *p; - unsigned char *dukm = NULL; - size_t dukmlen = 0; - int keylen, plen; - const EVP_CIPHER *kekcipher; - EVP_CIPHER_CTX *kekctx; - - if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) - goto err; - - /* - * For DH we only have one OID permissible. If ever any more get defined - * we will need something cleverer. - */ - if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) { - DHerr(DH_F_DH_CMS_SET_SHARED_INFO, DH_R_KDF_PARAMETER_ERROR); - goto err; - } - - if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, EVP_PKEY_DH_KDF_X9_42) <= 0) - goto err; - - if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0) - goto err; - - if (alg->parameter->type != V_ASN1_SEQUENCE) - goto err; - - p = alg->parameter->value.sequence->data; - plen = alg->parameter->value.sequence->length; - kekalg = d2i_X509_ALGOR(NULL, &p, plen); - if (!kekalg) - goto err; - kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); - if (!kekctx) - goto err; - kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); - if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE) - goto err; - if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) - goto err; - if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) - goto err; - - keylen = EVP_CIPHER_CTX_key_length(kekctx); - if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) - goto err; - /* Use OBJ_nid2obj to ensure we use built in OID that isn't freed */ - if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, - OBJ_nid2obj(EVP_CIPHER_type(kekcipher))) - <= 0) - goto err; - - if (ukm) { - dukmlen = ASN1_STRING_length(ukm); - dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen); - if (!dukm) - goto err; - } - - if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) - goto err; - dukm = NULL; - - rv = 1; - err: - X509_ALGOR_free(kekalg); - OPENSSL_free(dukm); - return rv; -} - -static int dh_cms_decrypt(CMS_RecipientInfo *ri) -{ - EVP_PKEY_CTX *pctx; - pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); - if (!pctx) - return 0; - /* See if we need to set peer key */ - if (!EVP_PKEY_CTX_get0_peerkey(pctx)) { - X509_ALGOR *alg; - ASN1_BIT_STRING *pubkey; - if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey, - NULL, NULL, NULL)) - return 0; - if (!alg || !pubkey) - return 0; - if (!dh_cms_set_peerkey(pctx, alg, pubkey)) { - DHerr(DH_F_DH_CMS_DECRYPT, DH_R_PEER_KEY_ERROR); - return 0; - } - } - /* Set DH derivation parameters and initialise unwrap context */ - if (!dh_cms_set_shared_info(pctx, ri)) { - DHerr(DH_F_DH_CMS_DECRYPT, DH_R_SHARED_INFO_ERROR); - return 0; - } - return 1; -} - -static int dh_cms_encrypt(CMS_RecipientInfo *ri) -{ - EVP_PKEY_CTX *pctx; - EVP_PKEY *pkey; - EVP_CIPHER_CTX *ctx; - int keylen; - X509_ALGOR *talg, *wrap_alg = NULL; - const ASN1_OBJECT *aoid; - ASN1_BIT_STRING *pubkey; - ASN1_STRING *wrap_str; - ASN1_OCTET_STRING *ukm; - unsigned char *penc = NULL, *dukm = NULL; - int penclen; - size_t dukmlen = 0; - int rv = 0; - int kdf_type, wrap_nid; - const EVP_MD *kdf_md; - pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); - if (!pctx) - return 0; - /* Get ephemeral key */ - pkey = EVP_PKEY_CTX_get0_pkey(pctx); - if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey, - NULL, NULL, NULL)) - goto err; - X509_ALGOR_get0(&aoid, NULL, NULL, talg); - /* Is everything uninitialised? */ - if (aoid == OBJ_nid2obj(NID_undef)) { - ASN1_INTEGER *pubk = BN_to_ASN1_INTEGER(pkey->pkey.dh->pub_key, NULL); - if (!pubk) - goto err; - /* Set the key */ - - penclen = i2d_ASN1_INTEGER(pubk, &penc); - ASN1_INTEGER_free(pubk); - if (penclen <= 0) - goto err; - ASN1_STRING_set0(pubkey, penc, penclen); - pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); - pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT; - - penc = NULL; - X509_ALGOR_set0(talg, OBJ_nid2obj(NID_dhpublicnumber), - V_ASN1_UNDEF, NULL); - } - - /* See if custom parameters set */ - kdf_type = EVP_PKEY_CTX_get_dh_kdf_type(pctx); - if (kdf_type <= 0) - goto err; - if (!EVP_PKEY_CTX_get_dh_kdf_md(pctx, &kdf_md)) - goto err; - - if (kdf_type == EVP_PKEY_DH_KDF_NONE) { - kdf_type = EVP_PKEY_DH_KDF_X9_42; - if (EVP_PKEY_CTX_set_dh_kdf_type(pctx, kdf_type) <= 0) - goto err; - } else if (kdf_type != EVP_PKEY_DH_KDF_X9_42) - /* Unknown KDF */ - goto err; - if (kdf_md == NULL) { - /* Only SHA1 supported */ - kdf_md = EVP_sha1(); - if (EVP_PKEY_CTX_set_dh_kdf_md(pctx, kdf_md) <= 0) - goto err; - } else if (EVP_MD_type(kdf_md) != NID_sha1) - /* Unsupported digest */ - goto err; - - if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm)) - goto err; - - /* Get wrap NID */ - ctx = CMS_RecipientInfo_kari_get0_ctx(ri); - wrap_nid = EVP_CIPHER_CTX_type(ctx); - if (EVP_PKEY_CTX_set0_dh_kdf_oid(pctx, OBJ_nid2obj(wrap_nid)) <= 0) - goto err; - keylen = EVP_CIPHER_CTX_key_length(ctx); - - /* Package wrap algorithm in an AlgorithmIdentifier */ - - wrap_alg = X509_ALGOR_new(); - if (wrap_alg == NULL) - goto err; - wrap_alg->algorithm = OBJ_nid2obj(wrap_nid); - wrap_alg->parameter = ASN1_TYPE_new(); - if (wrap_alg->parameter == NULL) - goto err; - if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0) - goto err; - if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) { - ASN1_TYPE_free(wrap_alg->parameter); - wrap_alg->parameter = NULL; - } - - if (EVP_PKEY_CTX_set_dh_kdf_outlen(pctx, keylen) <= 0) - goto err; - - if (ukm) { - dukmlen = ASN1_STRING_length(ukm); - dukm = OPENSSL_memdup(ASN1_STRING_get0_data(ukm), dukmlen); - if (!dukm) - goto err; - } - - if (EVP_PKEY_CTX_set0_dh_kdf_ukm(pctx, dukm, dukmlen) <= 0) - goto err; - dukm = NULL; - - /* - * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter - * of another AlgorithmIdentifier. - */ - penc = NULL; - penclen = i2d_X509_ALGOR(wrap_alg, &penc); - if (!penc || !penclen) - goto err; - wrap_str = ASN1_STRING_new(); - if (wrap_str == NULL) - goto err; - ASN1_STRING_set0(wrap_str, penc, penclen); - penc = NULL; - X509_ALGOR_set0(talg, OBJ_nid2obj(NID_id_smime_alg_ESDH), - V_ASN1_SEQUENCE, wrap_str); - - rv = 1; - - err: - OPENSSL_free(penc); - X509_ALGOR_free(wrap_alg); - OPENSSL_free(dukm); - return rv; -} - -#endif diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c index e37f0904e560..5fa91a8ec7dc 100644 --- a/crypto/dh/dh_asn1.c +++ b/crypto/dh/dh_asn1.c @@ -1,18 +1,25 @@ /* - * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/bn.h> #include "dh_local.h" #include <openssl/objects.h> #include <openssl/asn1t.h> +#include "crypto/dh.h" /* Override the default free and new methods */ static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, @@ -27,17 +34,24 @@ static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, DH_free((DH *)*pval); *pval = NULL; return 2; + } else if (operation == ASN1_OP_D2I_POST) { + DH *dh = (DH *)*pval; + + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, DH_FLAG_TYPE_DH); + ossl_dh_cache_named_group(dh); + dh->dirty_cnt++; } return 1; } ASN1_SEQUENCE_cb(DHparams, dh_cb) = { - ASN1_SIMPLE(DH, p, BIGNUM), - ASN1_SIMPLE(DH, g, BIGNUM), + ASN1_SIMPLE(DH, params.p, BIGNUM), + ASN1_SIMPLE(DH, params.g, BIGNUM), ASN1_OPT_EMBED(DH, length, ZINT32), } ASN1_SEQUENCE_END_cb(DH, DHparams) -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(DH, DHparams, DHparams) /* * Internal only structures for handling X9.42 DH: this gets translated to or @@ -74,14 +88,14 @@ int_dhx942_dh *d2i_int_dhx(int_dhx942_dh **a, const unsigned char **pp, long length); int i2d_int_dhx(const int_dhx942_dh *a, unsigned char **pp); -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(int_dhx942_dh, DHxparams, int_dhx) - -/* Application public function: read in X9.42 DH parameters into DH structure */ +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(int_dhx942_dh, DHxparams, int_dhx) DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length) { + FFC_PARAMS *params; int_dhx942_dh *dhx = NULL; DH *dh = NULL; + dh = DH_new(); if (dh == NULL) return NULL; @@ -91,48 +105,63 @@ DH *d2i_DHxparams(DH **a, const unsigned char **pp, long length) return NULL; } - if (a) { + if (a != NULL) { DH_free(*a); *a = dh; } - dh->p = dhx->p; - dh->q = dhx->q; - dh->g = dhx->g; - dh->j = dhx->j; + params = &dh->params; + DH_set0_pqg(dh, dhx->p, dhx->q, dhx->g); + ossl_ffc_params_set0_j(params, dhx->j); - if (dhx->vparams) { - dh->seed = dhx->vparams->seed->data; - dh->seedlen = dhx->vparams->seed->length; - dh->counter = dhx->vparams->counter; - dhx->vparams->seed->data = NULL; + if (dhx->vparams != NULL) { + /* The counter has a maximum value of 4 * numbits(p) - 1 */ + size_t counter = (size_t)BN_get_word(dhx->vparams->counter); + ossl_ffc_params_set_validate_params(params, dhx->vparams->seed->data, + dhx->vparams->seed->length, + counter); ASN1_BIT_STRING_free(dhx->vparams->seed); + BN_free(dhx->vparams->counter); OPENSSL_free(dhx->vparams); dhx->vparams = NULL; } OPENSSL_free(dhx); + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, DH_FLAG_TYPE_DHX); return dh; } int i2d_DHxparams(const DH *dh, unsigned char **pp) { + int ret = 0; int_dhx942_dh dhx; - int_dhvparams dhv; - ASN1_BIT_STRING bs; - dhx.p = dh->p; - dhx.g = dh->g; - dhx.q = dh->q; - dhx.j = dh->j; - if (dh->counter && dh->seed && dh->seedlen > 0) { - bs.flags = ASN1_STRING_FLAG_BITS_LEFT; - bs.data = dh->seed; - bs.length = dh->seedlen; - dhv.seed = &bs; - dhv.counter = dh->counter; + int_dhvparams dhv = { NULL, NULL }; + ASN1_BIT_STRING seed; + size_t seedlen = 0; + const FFC_PARAMS *params = &dh->params; + int counter; + + ossl_ffc_params_get0_pqg(params, (const BIGNUM **)&dhx.p, + (const BIGNUM **)&dhx.q, (const BIGNUM **)&dhx.g); + dhx.j = params->j; + ossl_ffc_params_get_validate_params(params, &seed.data, &seedlen, &counter); + seed.length = (int)seedlen; + + if (counter != -1 && seed.data != NULL && seed.length > 0) { + seed.flags = ASN1_STRING_FLAG_BITS_LEFT; + dhv.seed = &seed; + dhv.counter = BN_new(); + if (dhv.counter == NULL) + return 0; + if (!BN_set_word(dhv.counter, (BN_ULONG)counter)) + goto err; dhx.vparams = &dhv; - } else + } else { dhx.vparams = NULL; - - return i2d_int_dhx(&dhx, pp); + } + ret = i2d_int_dhx(&dhx, pp); +err: + BN_free(dhv.counter); + return ret; } diff --git a/crypto/dh/dh_backend.c b/crypto/dh/dh_backend.c new file mode 100644 index 000000000000..726843fd30cd --- /dev/null +++ b/crypto/dh/dh_backend.c @@ -0,0 +1,250 @@ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <openssl/err.h> +#include <openssl/core_names.h> +#ifndef FIPS_MODULE +# include <openssl/x509.h> +#endif +#include "internal/param_build_set.h" +#include "crypto/dh.h" +#include "dh_local.h" + +/* + * The intention with the "backend" source file is to offer backend functions + * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider + * implementations alike. + */ + +static int dh_ffc_params_fromdata(DH *dh, const OSSL_PARAM params[]) +{ + int ret; + FFC_PARAMS *ffc; + + if (dh == NULL) + return 0; + ffc = ossl_dh_get0_params(dh); + if (ffc == NULL) + return 0; + + ret = ossl_ffc_params_fromdata(ffc, params); + if (ret) + ossl_dh_cache_named_group(dh); /* This increments dh->dirty_cnt */ + return ret; +} + +int ossl_dh_params_fromdata(DH *dh, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *param_priv_len; + long priv_len; + + if (!dh_ffc_params_fromdata(dh, params)) + return 0; + + param_priv_len = + OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_LEN); + if (param_priv_len != NULL + && (!OSSL_PARAM_get_long(param_priv_len, &priv_len) + || !DH_set_length(dh, priv_len))) + return 0; + + return 1; +} + +int ossl_dh_key_fromdata(DH *dh, const OSSL_PARAM params[], int include_private) +{ + const OSSL_PARAM *param_priv_key, *param_pub_key; + BIGNUM *priv_key = NULL, *pub_key = NULL; + + if (dh == NULL) + return 0; + + param_priv_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); + param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); + + if (include_private + && param_priv_key != NULL + && !OSSL_PARAM_get_BN(param_priv_key, &priv_key)) + goto err; + + if (param_pub_key != NULL + && !OSSL_PARAM_get_BN(param_pub_key, &pub_key)) + goto err; + + if (!DH_set0_key(dh, pub_key, priv_key)) + goto err; + + return 1; + + err: + BN_clear_free(priv_key); + BN_free(pub_key); + return 0; +} + +int ossl_dh_params_todata(DH *dh, OSSL_PARAM_BLD *bld, OSSL_PARAM params[]) +{ + long l = DH_get_length(dh); + + if (!ossl_ffc_params_todata(ossl_dh_get0_params(dh), bld, params)) + return 0; + if (l > 0 + && !ossl_param_build_set_long(bld, params, OSSL_PKEY_PARAM_DH_PRIV_LEN, l)) + return 0; + return 1; +} + +int ossl_dh_key_todata(DH *dh, OSSL_PARAM_BLD *bld, OSSL_PARAM params[], + int include_private) +{ + const BIGNUM *priv = NULL, *pub = NULL; + + if (dh == NULL) + return 0; + + DH_get0_key(dh, &pub, &priv); + if (priv != NULL + && include_private + && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PRIV_KEY, priv)) + return 0; + if (pub != NULL + && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PUB_KEY, pub)) + return 0; + + return 1; +} + +int ossl_dh_is_foreign(const DH *dh) +{ +#ifndef FIPS_MODULE + if (dh->engine != NULL || ossl_dh_get_method(dh) != DH_OpenSSL()) + return 1; +#endif + return 0; +} + +static ossl_inline int dh_bn_dup_check(BIGNUM **out, const BIGNUM *f) +{ + if (f != NULL && (*out = BN_dup(f)) == NULL) + return 0; + return 1; +} + +DH *ossl_dh_dup(const DH *dh, int selection) +{ + DH *dupkey = NULL; + + /* Do not try to duplicate foreign DH keys */ + if (ossl_dh_is_foreign(dh)) + return NULL; + + if ((dupkey = ossl_dh_new_ex(dh->libctx)) == NULL) + return NULL; + + dupkey->length = DH_get_length(dh); + if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0 + && !ossl_ffc_params_copy(&dupkey->params, &dh->params)) + goto err; + + dupkey->flags = dh->flags; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0 + && ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0 + || !dh_bn_dup_check(&dupkey->pub_key, dh->pub_key))) + goto err; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 + && ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) == 0 + || !dh_bn_dup_check(&dupkey->priv_key, dh->priv_key))) + goto err; + +#ifndef FIPS_MODULE + if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_DH, + &dupkey->ex_data, &dh->ex_data)) + goto err; +#endif + + return dupkey; + + err: + DH_free(dupkey); + return NULL; +} + +#ifndef FIPS_MODULE +DH *ossl_dh_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, + OSSL_LIB_CTX *libctx, const char *propq) +{ + const unsigned char *p, *pm; + int pklen, pmlen; + int ptype; + const void *pval; + const ASN1_STRING *pstr; + const X509_ALGOR *palg; + BIGNUM *privkey_bn = NULL; + ASN1_INTEGER *privkey = NULL; + DH *dh = NULL; + + if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8inf)) + return 0; + + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + if (ptype != V_ASN1_SEQUENCE) + goto decerr; + if ((privkey = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) + goto decerr; + + pstr = pval; + pm = pstr->data; + pmlen = pstr->length; + switch (OBJ_obj2nid(palg->algorithm)) { + case NID_dhKeyAgreement: + dh = d2i_DHparams(NULL, &pm, pmlen); + break; + case NID_dhpublicnumber: + dh = d2i_DHxparams(NULL, &pm, pmlen); + break; + default: + goto decerr; + } + if (dh == NULL) + goto decerr; + + /* We have parameters now set private key */ + if ((privkey_bn = BN_secure_new()) == NULL + || !ASN1_INTEGER_to_BN(privkey, privkey_bn)) { + ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR); + BN_clear_free(privkey_bn); + goto dherr; + } + if (!DH_set0_key(dh, NULL, privkey_bn)) + goto dherr; + /* Calculate public key, increments dirty_cnt */ + if (!DH_generate_key(dh)) + goto dherr; + + goto done; + + decerr: + ERR_raise(ERR_LIB_DH, EVP_R_DECODE_ERROR); + dherr: + DH_free(dh); + dh = NULL; + done: + ASN1_STRING_clear_free(privkey); + return dh; +} +#endif diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c index 4ac169e75c23..e20eb62081c5 100644 --- a/crypto/dh/dh_check.c +++ b/crypto/dh/dh_check.c @@ -1,18 +1,23 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/bn.h> #include "dh_local.h" - -# define DH_NUMBER_ITERATIONS_FOR_PRIME 64 +#include "crypto/dh.h" /*- * Check that p and g are suitable enough @@ -28,13 +33,39 @@ int DH_check_params_ex(const DH *dh) return 0; if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) - DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_CHECK_P_NOT_PRIME); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME); if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) - DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_NOT_SUITABLE_GENERATOR); + ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR); + if ((errflags & DH_MODULUS_TOO_SMALL) != 0) + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); + if ((errflags & DH_MODULUS_TOO_LARGE) != 0) + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); return errflags == 0; } +#ifdef FIPS_MODULE +int DH_check_params(const DH *dh, int *ret) +{ + int nid; + + *ret = 0; + /* + * SP800-56A R3 Section 5.5.2 Assurances of Domain Parameter Validity + * (1a) The domain parameters correspond to any approved safe prime group. + */ + nid = DH_get_nid((DH *)dh); + if (nid != NID_undef) + return 1; + /* + * OR + * (2b) FFC domain params conform to FIPS-186-4 explicit domain param + * validity tests. + */ + return ossl_ffc_params_FIPS186_4_validate(dh->libctx, &dh->params, + FFC_PARAM_TYPE_DH, ret, NULL); +} +#else int DH_check_params(const DH *dh, int *ret) { int ok = 0; @@ -42,7 +73,7 @@ int DH_check_params(const DH *dh, int *ret) BN_CTX *ctx = NULL; *ret = 0; - ctx = BN_CTX_new(); + ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; BN_CTX_start(ctx); @@ -50,14 +81,20 @@ int DH_check_params(const DH *dh, int *ret) if (tmp == NULL) goto err; - if (!BN_is_odd(dh->p)) + if (!BN_is_odd(dh->params.p)) *ret |= DH_CHECK_P_NOT_PRIME; - if (BN_is_negative(dh->g) || BN_is_zero(dh->g) || BN_is_one(dh->g)) + if (BN_is_negative(dh->params.g) + || BN_is_zero(dh->params.g) + || BN_is_one(dh->params.g)) *ret |= DH_NOT_SUITABLE_GENERATOR; - if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1)) + if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1)) goto err; - if (BN_cmp(dh->g, tmp) >= 0) + if (BN_cmp(dh->params.g, tmp) >= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; + if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) + *ret |= DH_MODULUS_TOO_SMALL; + if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) + *ret |= DH_MODULUS_TOO_LARGE; ok = 1; err: @@ -65,6 +102,7 @@ int DH_check_params(const DH *dh, int *ret) BN_CTX_free(ctx); return ok; } +#endif /* FIPS_MODULE */ /*- * Check that p is a safe prime and @@ -78,33 +116,53 @@ int DH_check_ex(const DH *dh) return 0; if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_NOT_SUITABLE_GENERATOR); + ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR); if ((errflags & DH_CHECK_Q_NOT_PRIME) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_Q_NOT_PRIME); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME); if ((errflags & DH_CHECK_INVALID_Q_VALUE) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_INVALID_Q_VALUE); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE); if ((errflags & DH_CHECK_INVALID_J_VALUE) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_INVALID_J_VALUE); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE); if ((errflags & DH_UNABLE_TO_CHECK_GENERATOR) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_UNABLE_TO_CHECK_GENERATOR); + ERR_raise(ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR); if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_PRIME); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME); if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0) - DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_SAFE_PRIME); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME); + if ((errflags & DH_MODULUS_TOO_SMALL) != 0) + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); + if ((errflags & DH_MODULUS_TOO_LARGE) != 0) + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); return errflags == 0; } +/* Note: according to documentation - this only checks the params */ int DH_check(const DH *dh, int *ret) { - int ok = 0, r; +#ifdef FIPS_MODULE + return DH_check_params(dh, ret); +#else + int ok = 0, r, q_good = 0; BN_CTX *ctx = NULL; BIGNUM *t1 = NULL, *t2 = NULL; + int nid = DH_get_nid((DH *)dh); + + *ret = 0; + if (nid != NID_undef) + return 1; + + /* Don't do any checks at all with an excessively large modulus */ + if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); + *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_P_NOT_PRIME; + return 0; + } if (!DH_check_params(dh, ret)) return 0; - ctx = BN_CTX_new(); + ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; BN_CTX_start(ctx); @@ -113,41 +171,49 @@ int DH_check(const DH *dh, int *ret) if (t2 == NULL) goto err; - if (dh->q) { - if (BN_cmp(dh->g, BN_value_one()) <= 0) + if (dh->params.q != NULL) { + if (BN_ucmp(dh->params.p, dh->params.q) > 0) + q_good = 1; + else + *ret |= DH_CHECK_INVALID_Q_VALUE; + } + + if (q_good) { + if (BN_cmp(dh->params.g, BN_value_one()) <= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; - else if (BN_cmp(dh->g, dh->p) >= 0) + else if (BN_cmp(dh->params.g, dh->params.p) >= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; else { /* Check g^q == 1 mod p */ - if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) + if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) goto err; if (!BN_is_one(t1)) *ret |= DH_NOT_SUITABLE_GENERATOR; } - r = BN_is_prime_ex(dh->q, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + r = BN_check_prime(dh->params.q, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_Q_NOT_PRIME; /* Check p == 1 mod q i.e. q divides p - 1 */ - if (!BN_div(t1, t2, dh->p, dh->q, ctx)) + if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) goto err; if (!BN_is_one(t2)) *ret |= DH_CHECK_INVALID_Q_VALUE; - if (dh->j && BN_cmp(dh->j, t1)) + if (dh->params.j != NULL + && BN_cmp(dh->params.j, t1)) *ret |= DH_CHECK_INVALID_J_VALUE; } - r = BN_is_prime_ex(dh->p, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + r = BN_check_prime(dh->params.p, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_P_NOT_PRIME; - else if (!dh->q) { - if (!BN_rshift1(t1, dh->p)) + else if (dh->params.q == NULL) { + if (!BN_rshift1(t1, dh->params.p)) goto err; - r = BN_is_prime_ex(t1, DH_NUMBER_ITERATIONS_FOR_PRIME, ctx, NULL); + r = BN_check_prime(t1, ctx, NULL); if (r < 0) goto err; if (!r) @@ -158,6 +224,7 @@ int DH_check(const DH *dh, int *ret) BN_CTX_end(ctx); BN_CTX_free(ctx); return ok; +#endif /* FIPS_MODULE */ } int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) @@ -168,47 +235,126 @@ int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) return 0; if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0) - DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_SMALL); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL); if ((errflags & DH_CHECK_PUBKEY_TOO_LARGE) != 0) - DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_LARGE); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE); if ((errflags & DH_CHECK_PUBKEY_INVALID) != 0) - DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_INVALID); + ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID); return errflags == 0; } +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation. + */ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { + /* Don't do any checks at all with an excessively large modulus */ + if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); + *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_PUBKEY_INVALID; + return 0; + } + + if (dh->params.q != NULL && BN_ucmp(dh->params.p, dh->params.q) < 0) { + *ret |= DH_CHECK_INVALID_Q_VALUE | DH_CHECK_PUBKEY_INVALID; + return 1; + } + + return ossl_ffc_validate_public_key(&dh->params, pub_key, ret); +} + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation. + * To only be used with ephemeral FFC public keys generated using the approved + * safe-prime groups. + */ +int ossl_dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret) +{ + return ossl_ffc_validate_public_key_partial(&dh->params, pub_key, ret) + && *ret == 0; +} + +int ossl_dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret) +{ int ok = 0; - BIGNUM *tmp = NULL; - BN_CTX *ctx = NULL; + BIGNUM *two_powN = NULL, *upper; *ret = 0; - ctx = BN_CTX_new(); - if (ctx == NULL) - goto err; - BN_CTX_start(ctx); - tmp = BN_CTX_get(ctx); - if (tmp == NULL || !BN_set_word(tmp, 1)) - goto err; - if (BN_cmp(pub_key, tmp) <= 0) - *ret |= DH_CHECK_PUBKEY_TOO_SMALL; - if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1)) - goto err; - if (BN_cmp(pub_key, tmp) >= 0) - *ret |= DH_CHECK_PUBKEY_TOO_LARGE; + two_powN = BN_new(); + if (two_powN == NULL) + return 0; - if (dh->q != NULL) { - /* Check pub_key^q == 1 mod p */ - if (!BN_mod_exp(tmp, pub_key, dh->q, dh->p, ctx)) - goto err; - if (!BN_is_one(tmp)) - *ret |= DH_CHECK_PUBKEY_INVALID; + if (dh->params.q != NULL) { + upper = dh->params.q; +#ifndef FIPS_MODULE + } else if (dh->params.p != NULL) { + /* + * We do not have q so we just check the key is within some + * reasonable range, or the number of bits is equal to dh->length. + */ + int length = dh->length; + + if (length == 0) { + length = BN_num_bits(dh->params.p) - 1; + if (BN_num_bits(priv_key) <= length + && BN_num_bits(priv_key) > 1) + ok = 1; + } else if (BN_num_bits(priv_key) == length) { + ok = 1; + } + goto end; +#endif + } else { + goto end; } + /* Is it from an approved Safe prime group ?*/ + if (DH_get_nid((DH *)dh) != NID_undef && dh->length != 0) { + if (!BN_lshift(two_powN, BN_value_one(), dh->length)) + goto end; + if (BN_cmp(two_powN, dh->params.q) < 0) + upper = two_powN; + } + if (!ossl_ffc_validate_private_key(upper, priv_key, ret)) + goto end; + ok = 1; - err: - BN_CTX_end(ctx); - BN_CTX_free(ctx); +end: + BN_free(two_powN); return ok; } + +/* + * FFC pairwise check from SP800-56A R3. + * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency + */ +int ossl_dh_check_pairwise(const DH *dh) +{ + int ret = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL; + + if (dh->params.p == NULL + || dh->params.g == NULL + || dh->priv_key == NULL + || dh->pub_key == NULL) + return 0; + + ctx = BN_CTX_new_ex(dh->libctx); + if (ctx == NULL) + goto err; + pub_key = BN_new(); + if (pub_key == NULL) + goto err; + + /* recalculate the public key = (g ^ priv) mod p */ + if (!ossl_dh_generate_public_key(ctx, dh, dh->priv_key, pub_key)) + goto err; + /* check it matches the existing pubic_key */ + ret = BN_cmp(pub_key, dh->pub_key) == 0; +err: + BN_free(pub_key); + BN_CTX_free(ctx); + return ret; +} diff --git a/crypto/dh/dh_depr.c b/crypto/dh/dh_depr.c index f8ed1b7461ee..5822d511d958 100644 --- a/crypto/dh/dh_depr.c +++ b/crypto/dh/dh_depr.c @@ -1,7 +1,7 @@ /* - * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -9,15 +9,18 @@ /* This file contains deprecated functions as wrappers to the new ones */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <openssl/opensslconf.h> -#if OPENSSL_API_COMPAT >= 0x00908000L -NON_EMPTY_TRANSLATION_UNIT -#else -# include <stdio.h> -# include "internal/cryptlib.h" -# include <openssl/bn.h> -# include <openssl/dh.h> +#include <stdio.h> +#include "internal/cryptlib.h" +#include <openssl/bn.h> +#include <openssl/dh.h> DH *DH_generate_parameters(int prime_len, int generator, void (*callback) (int, int, void *), void *cb_arg) @@ -43,4 +46,3 @@ DH *DH_generate_parameters(int prime_len, int generator, DH_free(ret); return NULL; } -#endif diff --git a/crypto/dh/dh_err.c b/crypto/dh/dh_err.c index 7285587b4ade..f76ac0dd1463 100644 --- a/crypto/dh/dh_err.c +++ b/crypto/dh/dh_err.c @@ -1,8 +1,8 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -10,43 +10,14 @@ #include <openssl/err.h> #include <openssl/dherr.h> +#include "crypto/dherr.h" -#ifndef OPENSSL_NO_ERR +#ifndef OPENSSL_NO_DH -static const ERR_STRING_DATA DH_str_functs[] = { - {ERR_PACK(ERR_LIB_DH, DH_F_COMPUTE_KEY, 0), "compute_key"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DHPARAMS_PRINT_FP, 0), "DHparams_print_fp"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS, 0), - "dh_builtin_genparams"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_CHECK_EX, 0), "DH_check_ex"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_CHECK_PARAMS_EX, 0), "DH_check_params_ex"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_CHECK_PUB_KEY_EX, 0), "DH_check_pub_key_ex"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_DECRYPT, 0), "dh_cms_decrypt"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_SET_PEERKEY, 0), "dh_cms_set_peerkey"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_SET_SHARED_INFO, 0), - "dh_cms_set_shared_info"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_METH_DUP, 0), "DH_meth_dup"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_METH_NEW, 0), "DH_meth_new"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_METH_SET1_NAME, 0), "DH_meth_set1_name"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_NEW_BY_NID, 0), "DH_new_by_nid"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_NEW_METHOD, 0), "DH_new_method"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_PARAM_DECODE, 0), "dh_param_decode"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_PKEY_PUBLIC_CHECK, 0), - "dh_pkey_public_check"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_PRIV_DECODE, 0), "dh_priv_decode"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_PRIV_ENCODE, 0), "dh_priv_encode"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_PUB_DECODE, 0), "dh_pub_decode"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DH_PUB_ENCODE, 0), "dh_pub_encode"}, - {ERR_PACK(ERR_LIB_DH, DH_F_DO_DH_PRINT, 0), "do_dh_print"}, - {ERR_PACK(ERR_LIB_DH, DH_F_GENERATE_KEY, 0), "generate_key"}, - {ERR_PACK(ERR_LIB_DH, DH_F_PKEY_DH_CTRL_STR, 0), "pkey_dh_ctrl_str"}, - {ERR_PACK(ERR_LIB_DH, DH_F_PKEY_DH_DERIVE, 0), "pkey_dh_derive"}, - {ERR_PACK(ERR_LIB_DH, DH_F_PKEY_DH_INIT, 0), "pkey_dh_init"}, - {ERR_PACK(ERR_LIB_DH, DH_F_PKEY_DH_KEYGEN, 0), "pkey_dh_keygen"}, - {0, NULL} -}; +# ifndef OPENSSL_NO_ERR static const ERR_STRING_DATA DH_str_reasons[] = { + {ERR_PACK(ERR_LIB_DH, 0, DH_R_BAD_FFC_PARAMETERS), "bad ffc parameters"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR), "bad generator"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_BN_DECODE_ERROR), "bn decode error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_BN_ERROR), "bn error"}, @@ -70,10 +41,12 @@ static const ERR_STRING_DATA DH_str_reasons[] = { {ERR_PACK(ERR_LIB_DH, 0, DH_R_INVALID_PARAMETER_NID), "invalid parameter nid"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_INVALID_PUBKEY), "invalid public key"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_INVALID_SECRET), "invalid secret"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_KDF_PARAMETER_ERROR), "kdf parameter error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_KEYS_NOT_SET), "keys not set"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_MISSING_PUBKEY), "missing pubkey"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_LARGE), "modulus too large"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_SMALL), "modulus too small"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_NOT_SUITABLE_GENERATOR), "not suitable generator"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PARAMETERS_SET), "no parameters set"}, @@ -81,21 +54,23 @@ static const ERR_STRING_DATA DH_str_reasons[] = { {ERR_PACK(ERR_LIB_DH, 0, DH_R_PARAMETER_ENCODING_ERROR), "parameter encoding error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_PEER_KEY_ERROR), "peer key error"}, + {ERR_PACK(ERR_LIB_DH, 0, DH_R_Q_TOO_LARGE), "q too large"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_SHARED_INFO_ERROR), "shared info error"}, {ERR_PACK(ERR_LIB_DH, 0, DH_R_UNABLE_TO_CHECK_GENERATOR), "unable to check generator"}, {0, NULL} }; -#endif +# endif -int ERR_load_DH_strings(void) +int ossl_err_load_DH_strings(void) { -#ifndef OPENSSL_NO_ERR - if (ERR_func_error_string(DH_str_functs[0].error) == NULL) { - ERR_load_strings_const(DH_str_functs); +# ifndef OPENSSL_NO_ERR + if (ERR_reason_error_string(DH_str_reasons[0].error) == NULL) ERR_load_strings_const(DH_str_reasons); - } -#endif +# endif return 1; } +#else +NON_EMPTY_TRANSLATION_UNIT +#endif diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c index ab82ab58bd2a..aec6b853169a 100644 --- a/crypto/dh/dh_gen.c +++ b/crypto/dh/dh_gen.c @@ -1,7 +1,7 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -12,22 +12,120 @@ * dh_depr.c as wrappers to these ones. - Geoff */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + * + * NOTE: When generating keys for key-agreement schemes - FIPS 140-2 IG 9.9 + * states that no additional pairwise tests are required (apart from the tests + * specified in SP800-56A) when generating keys. Hence DH pairwise tests are + * omitted here. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/bn.h> +#include <openssl/sha.h> +#include "crypto/dh.h" #include "dh_local.h" +#ifndef FIPS_MODULE static int dh_builtin_genparams(DH *ret, int prime_len, int generator, BN_GENCB *cb); +#endif /* FIPS_MODULE */ + +int ossl_dh_generate_ffc_parameters(DH *dh, int type, int pbits, int qbits, + BN_GENCB *cb) +{ + int ret, res; + +#ifndef FIPS_MODULE + if (type == DH_PARAMGEN_TYPE_FIPS_186_2) + ret = ossl_ffc_params_FIPS186_2_generate(dh->libctx, &dh->params, + FFC_PARAM_TYPE_DH, + pbits, qbits, &res, cb); + else +#endif + ret = ossl_ffc_params_FIPS186_4_generate(dh->libctx, &dh->params, + FFC_PARAM_TYPE_DH, + pbits, qbits, &res, cb); + if (ret > 0) + dh->dirty_cnt++; + return ret; +} + +int ossl_dh_get_named_group_uid_from_size(int pbits) +{ + /* + * Just choose an approved safe prime group. + * The alternative to this is to generate FIPS186-4 domain parameters i.e. + * return dh_generate_ffc_parameters(ret, prime_len, 0, NULL, cb); + * As the FIPS186-4 generated params are for backwards compatibility, + * the safe prime group should be used as the default. + */ + int nid; + + switch (pbits) { + case 2048: + nid = NID_ffdhe2048; + break; + case 3072: + nid = NID_ffdhe3072; + break; + case 4096: + nid = NID_ffdhe4096; + break; + case 6144: + nid = NID_ffdhe6144; + break; + case 8192: + nid = NID_ffdhe8192; + break; + /* unsupported prime_len */ + default: + return NID_undef; + } + return nid; +} + +#ifdef FIPS_MODULE + +static int dh_gen_named_group(OSSL_LIB_CTX *libctx, DH *ret, int prime_len) +{ + DH *dh; + int ok = 0; + int nid = ossl_dh_get_named_group_uid_from_size(prime_len); + + if (nid == NID_undef) + return 0; + + dh = ossl_dh_new_by_nid_ex(libctx, nid); + if (dh != NULL + && ossl_ffc_params_copy(&ret->params, &dh->params)) { + ok = 1; + ret->dirty_cnt++; + } + DH_free(dh); + return ok; +} +#endif /* FIPS_MODULE */ int DH_generate_parameters_ex(DH *ret, int prime_len, int generator, BN_GENCB *cb) { +#ifdef FIPS_MODULE + if (generator != 2) + return 0; + return dh_gen_named_group(ret->libctx, ret, prime_len); +#else if (ret->meth->generate_params) return ret->meth->generate_params(ret, prime_len, generator, cb); return dh_builtin_genparams(ret, prime_len, generator, cb); +#endif /* FIPS_MODULE */ } +#ifndef FIPS_MODULE /*- * We generate DH parameters as follows * find a prime p which is prime_len bits long, @@ -53,10 +151,6 @@ int DH_generate_parameters_ex(DH *ret, int prime_len, int generator, * for 2, p mod 24 == 23 * for 3, p mod 12 == 11 * for 5, p mod 60 == 59 - * - * However for compatibility with previous versions we use: - * for 2, p mod 24 == 11 - * for 5, p mod 60 == 23 */ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, BN_GENCB *cb) @@ -65,7 +159,17 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, int g, ok = -1; BN_CTX *ctx = NULL; - ctx = BN_CTX_new(); + if (prime_len > OPENSSL_DH_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); + return 0; + } + + if (prime_len < DH_MIN_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); + return 0; + } + + ctx = BN_CTX_new_ex(ret->libctx); if (ctx == NULL) goto err; BN_CTX_start(ctx); @@ -75,25 +179,25 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, goto err; /* Make sure 'ret' has the necessary elements */ - if (!ret->p && ((ret->p = BN_new()) == NULL)) + if (ret->params.p == NULL && ((ret->params.p = BN_new()) == NULL)) goto err; - if (!ret->g && ((ret->g = BN_new()) == NULL)) + if (ret->params.g == NULL && ((ret->params.g = BN_new()) == NULL)) goto err; if (generator <= 1) { - DHerr(DH_F_DH_BUILTIN_GENPARAMS, DH_R_BAD_GENERATOR); + ERR_raise(ERR_LIB_DH, DH_R_BAD_GENERATOR); goto err; } if (generator == DH_GENERATOR_2) { if (!BN_set_word(t1, 24)) goto err; - if (!BN_set_word(t2, 11)) + if (!BN_set_word(t2, 23)) goto err; g = 2; } else if (generator == DH_GENERATOR_5) { if (!BN_set_word(t1, 60)) goto err; - if (!BN_set_word(t2, 23)) + if (!BN_set_word(t2, 59)) goto err; g = 5; } else { @@ -109,16 +213,17 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, g = generator; } - if (!BN_generate_prime_ex(ret->p, prime_len, 1, t1, t2, cb)) + if (!BN_generate_prime_ex2(ret->params.p, prime_len, 1, t1, t2, cb, ctx)) goto err; if (!BN_GENCB_call(cb, 3, 0)) goto err; - if (!BN_set_word(ret->g, g)) + if (!BN_set_word(ret->params.g, g)) goto err; + ret->dirty_cnt++; ok = 1; err: if (ok == -1) { - DHerr(DH_F_DH_BUILTIN_GENPARAMS, ERR_R_BN_LIB); + ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB); ok = 0; } @@ -126,3 +231,4 @@ static int dh_builtin_genparams(DH *ret, int prime_len, int generator, BN_CTX_free(ctx); return ok; } +#endif /* FIPS_MODULE */ diff --git a/crypto/dh/dh_group_params.c b/crypto/dh/dh_group_params.c new file mode 100644 index 000000000000..460bd8f00989 --- /dev/null +++ b/crypto/dh/dh_group_params.c @@ -0,0 +1,99 @@ +/* + * Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* DH parameters from RFC7919 and RFC3526 */ + +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + +#include <stdio.h> +#include "internal/cryptlib.h" +#include "internal/ffc.h" +#include "dh_local.h" +#include <openssl/bn.h> +#include <openssl/objects.h> +#include "internal/nelem.h" +#include "crypto/dh.h" + +static DH *dh_param_init(OSSL_LIB_CTX *libctx, const DH_NAMED_GROUP *group) +{ + DH *dh = ossl_dh_new_ex(libctx); + + if (dh == NULL) + return NULL; + + ossl_ffc_named_group_set(&dh->params, group); + dh->params.nid = ossl_ffc_named_group_get_uid(group); + dh->dirty_cnt++; + return dh; +} + +DH *ossl_dh_new_by_nid_ex(OSSL_LIB_CTX *libctx, int nid) +{ + const DH_NAMED_GROUP *group; + + if ((group = ossl_ffc_uid_to_dh_named_group(nid)) != NULL) + return dh_param_init(libctx, group); + + ERR_raise(ERR_LIB_DH, DH_R_INVALID_PARAMETER_NID); + return NULL; +} + +DH *DH_new_by_nid(int nid) +{ + return ossl_dh_new_by_nid_ex(NULL, nid); +} + +void ossl_dh_cache_named_group(DH *dh) +{ + const DH_NAMED_GROUP *group; + + if (dh == NULL) + return; + + dh->params.nid = NID_undef; /* flush cached value */ + + /* Exit if p or g is not set */ + if (dh->params.p == NULL + || dh->params.g == NULL) + return; + + if ((group = ossl_ffc_numbers_to_dh_named_group(dh->params.p, + dh->params.q, + dh->params.g)) != NULL) { + if (dh->params.q == NULL) + dh->params.q = (BIGNUM *)ossl_ffc_named_group_get_q(group); + /* cache the nid and default key length */ + dh->params.nid = ossl_ffc_named_group_get_uid(group); + dh->params.keylength = ossl_ffc_named_group_get_keylength(group); + dh->dirty_cnt++; + } +} + +int ossl_dh_is_named_safe_prime_group(const DH *dh) +{ + int id = DH_get_nid(dh); + + /* + * Exclude RFC5114 groups (id = 1..3) since they do not have + * q = (p - 1) / 2 + */ + return (id > 3); +} + +int DH_get_nid(const DH *dh) +{ + if (dh == NULL) + return NID_undef; + + return dh->params.nid; +} diff --git a/crypto/dh/dh_kdf.c b/crypto/dh/dh_kdf.c index e17122bc82e3..6e99466e60b3 100644 --- a/crypto/dh/dh_kdf.c +++ b/crypto/dh/dh_kdf.c @@ -1,150 +1,81 @@ /* - * Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2013-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ -#include "e_os.h" +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" -#ifndef OPENSSL_NO_CMS +#include "e_os.h" +#include "e_os.h" #include <string.h> +#include <openssl/core_names.h> #include <openssl/dh.h> #include <openssl/evp.h> #include <openssl/asn1.h> -#include <openssl/cms.h> - - -/* Key derivation from X9.42/RFC2631 */ -/* Uses CMS functions, hence the #ifdef wrapper. */ +#include <openssl/kdf.h> +#include "internal/provider.h" +#include "crypto/dh.h" -#define DH_KDF_MAX (1L << 30) - -/* Skip past an ASN1 structure: for OBJECT skip content octets too */ - -static int skip_asn1(unsigned char **pp, long *plen, int exptag) +/* Key derivation function from X9.63/SECG */ +int ossl_dh_kdf_X9_42_asn1(unsigned char *out, size_t outlen, + const unsigned char *Z, size_t Zlen, + const char *cek_alg, + const unsigned char *ukm, size_t ukmlen, + const EVP_MD *md, + OSSL_LIB_CTX *libctx, const char *propq) { - const unsigned char *q = *pp; - int i, tag, xclass; - long tmplen; - i = ASN1_get_object(&q, &tmplen, &tag, &xclass, *plen); - if (i & 0x80) - return 0; - if (tag != exptag || xclass != V_ASN1_UNIVERSAL) - return 0; - if (tag == V_ASN1_OBJECT) - q += tmplen; - *plen -= q - *pp; - *pp = (unsigned char *)q; - return 1; -} - -/* - * Encode the DH shared info structure, return an offset to the counter value - * so we can update the structure without reencoding it. - */ + int ret = 0; + EVP_KDF_CTX *kctx = NULL; + EVP_KDF *kdf = NULL; + OSSL_PARAM params[5], *p = params; + const char *mdname = EVP_MD_get0_name(md); -static int dh_sharedinfo_encode(unsigned char **pder, unsigned char **pctr, - ASN1_OBJECT *key_oid, size_t outlen, - const unsigned char *ukm, size_t ukmlen) -{ - unsigned char *p; - int derlen; - long tlen; - /* "magic" value to check offset is sane */ - static unsigned char ctr[4] = { 0xF3, 0x17, 0x22, 0x53 }; - X509_ALGOR atmp; - ASN1_OCTET_STRING ctr_oct, ukm_oct, *pukm_oct; - ASN1_TYPE ctr_atype; - if (ukmlen > DH_KDF_MAX || outlen > DH_KDF_MAX) - return 0; - ctr_oct.data = ctr; - ctr_oct.length = 4; - ctr_oct.flags = 0; - ctr_oct.type = V_ASN1_OCTET_STRING; - ctr_atype.type = V_ASN1_OCTET_STRING; - ctr_atype.value.octet_string = &ctr_oct; - atmp.algorithm = key_oid; - atmp.parameter = &ctr_atype; - if (ukm) { - ukm_oct.type = V_ASN1_OCTET_STRING; - ukm_oct.flags = 0; - ukm_oct.data = (unsigned char *)ukm; - ukm_oct.length = ukmlen; - pukm_oct = &ukm_oct; - } else - pukm_oct = NULL; - derlen = CMS_SharedInfo_encode(pder, &atmp, pukm_oct, outlen); - if (derlen <= 0) - return 0; - p = *pder; - tlen = derlen; - if (!skip_asn1(&p, &tlen, V_ASN1_SEQUENCE)) - return 0; - if (!skip_asn1(&p, &tlen, V_ASN1_SEQUENCE)) - return 0; - if (!skip_asn1(&p, &tlen, V_ASN1_OBJECT)) - return 0; - if (!skip_asn1(&p, &tlen, V_ASN1_OCTET_STRING)) + kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_X942KDF_ASN1, propq); + if (kdf == NULL) return 0; - if (CRYPTO_memcmp(p, ctr, 4)) - return 0; - *pctr = p; - return derlen; + kctx = EVP_KDF_CTX_new(kdf); + if (kctx == NULL) + goto err; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + (char *)mdname, 0); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, + (unsigned char *)Z, Zlen); + if (ukm != NULL) + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_UKM, + (unsigned char *)ukm, ukmlen); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CEK_ALG, + (char *)cek_alg, 0); + *p = OSSL_PARAM_construct_end(); + ret = EVP_KDF_derive(kctx, out, outlen, params) > 0; +err: + EVP_KDF_CTX_free(kctx); + EVP_KDF_free(kdf); + return ret; } +#if !defined(FIPS_MODULE) int DH_KDF_X9_42(unsigned char *out, size_t outlen, const unsigned char *Z, size_t Zlen, ASN1_OBJECT *key_oid, const unsigned char *ukm, size_t ukmlen, const EVP_MD *md) { - EVP_MD_CTX *mctx = NULL; - int rv = 0; - unsigned int i; - size_t mdlen; - unsigned char *der = NULL, *ctr; - int derlen; - if (Zlen > DH_KDF_MAX) - return 0; - mctx = EVP_MD_CTX_new(); - if (mctx == NULL) + char key_alg[OSSL_MAX_NAME_SIZE]; + const OSSL_PROVIDER *prov = EVP_MD_get0_provider(md); + OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov); + + if (OBJ_obj2txt(key_alg, sizeof(key_alg), key_oid, 0) <= 0) return 0; - mdlen = EVP_MD_size(md); - derlen = dh_sharedinfo_encode(&der, &ctr, key_oid, outlen, ukm, ukmlen); - if (derlen == 0) - goto err; - for (i = 1;; i++) { - unsigned char mtmp[EVP_MAX_MD_SIZE]; - if (!EVP_DigestInit_ex(mctx, md, NULL) - || !EVP_DigestUpdate(mctx, Z, Zlen)) - goto err; - ctr[3] = i & 0xFF; - ctr[2] = (i >> 8) & 0xFF; - ctr[1] = (i >> 16) & 0xFF; - ctr[0] = (i >> 24) & 0xFF; - if (!EVP_DigestUpdate(mctx, der, derlen)) - goto err; - if (outlen >= mdlen) { - if (!EVP_DigestFinal(mctx, out, NULL)) - goto err; - outlen -= mdlen; - if (outlen == 0) - break; - out += mdlen; - } else { - if (!EVP_DigestFinal(mctx, mtmp, NULL)) - goto err; - memcpy(out, mtmp, outlen); - OPENSSL_cleanse(mtmp, mdlen); - break; - } - } - rv = 1; - err: - OPENSSL_free(der); - EVP_MD_CTX_free(mctx); - return rv; + + return ossl_dh_kdf_X9_42_asn1(out, outlen, Z, Zlen, key_alg, + ukm, ukmlen, md, libctx, NULL); } -#endif +#endif /* !defined(FIPS_MODULE) */ diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c index 117f2fa883ff..19208a860212 100644 --- a/crypto/dh/dh_key.c +++ b/crypto/dh/dh_key.c @@ -1,28 +1,110 @@ /* - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include "dh_local.h" #include "crypto/bn.h" +#include "crypto/dh.h" +#include "crypto/security_bits.h" + +#ifdef FIPS_MODULE +# define MIN_STRENGTH 112 +#else +# define MIN_STRENGTH 80 +#endif static int generate_key(DH *dh); -static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh); static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); static int dh_init(DH *dh); static int dh_finish(DH *dh); -int DH_generate_key(DH *dh) +/* + * See SP800-56Ar3 Section 5.7.1.1 + * Finite Field Cryptography Diffie-Hellman (FFC DH) Primitive + */ +int ossl_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) { - return dh->meth->generate_key(dh); + BN_CTX *ctx = NULL; + BN_MONT_CTX *mont = NULL; + BIGNUM *z = NULL, *pminus1; + int ret = -1; + + if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); + goto err; + } + + if (dh->params.q != NULL + && BN_num_bits(dh->params.q) > OPENSSL_DH_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_Q_TOO_LARGE); + goto err; + } + + if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); + return 0; + } + + ctx = BN_CTX_new_ex(dh->libctx); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + pminus1 = BN_CTX_get(ctx); + z = BN_CTX_get(ctx); + if (z == NULL) + goto err; + + if (dh->priv_key == NULL) { + ERR_raise(ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE); + goto err; + } + + if (dh->flags & DH_FLAG_CACHE_MONT_P) { + mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, + dh->lock, dh->params.p, ctx); + BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME); + if (!mont) + goto err; + } + + /* (Step 1) Z = pub_key^priv_key mod p */ + if (!dh->meth->bn_mod_exp(dh, z, pub_key, dh->priv_key, dh->params.p, ctx, + mont)) { + ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB); + goto err; + } + + /* (Step 2) Error if z <= 1 or z = p - 1 */ + if (BN_copy(pminus1, dh->params.p) == NULL + || !BN_sub_word(pminus1, 1) + || BN_cmp(z, BN_value_one()) <= 0 + || BN_cmp(z, pminus1) == 0) { + ERR_raise(ERR_LIB_DH, DH_R_INVALID_SECRET); + goto err; + } + + /* return the padded key, i.e. same number of bytes as the modulus */ + ret = BN_bn2binpad(z, key, BN_num_bytes(dh->params.p)); + err: + BN_clear(z); /* (Step 2) destroy intermediate values */ + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ret; } /*- @@ -35,7 +117,12 @@ int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) volatile size_t npad = 0, mask = 1; /* compute the key; ret is constant unless compute_key is external */ - if ((ret = dh->meth->compute_key(key, pub_key, dh)) <= 0) +#ifdef FIPS_MODULE + ret = ossl_dh_compute_key(key, pub_key, dh); +#else + ret = dh->meth->compute_key(key, pub_key, dh); +#endif + if (ret <= 0) return ret; /* count leading zero bytes, yet still touch all bytes */ @@ -59,10 +146,14 @@ int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) int rv, pad; /* rv is constant unless compute_key is external */ +#ifdef FIPS_MODULE + rv = ossl_dh_compute_key(key, pub_key, dh); +#else rv = dh->meth->compute_key(key, pub_key, dh); +#endif if (rv <= 0) return rv; - pad = BN_num_bytes(dh->p) - rv; + pad = BN_num_bytes(dh->params.p) - rv; /* pad is constant (zero) unless compute_key is external */ if (pad > 0) { memmove(key + pad, key, rv); @@ -74,7 +165,7 @@ int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) static DH_METHOD dh_ossl = { "OpenSSL DH Method", generate_key, - compute_key, + ossl_dh_compute_key, dh_bn_mod_exp, dh_init, dh_finish, @@ -90,31 +181,110 @@ const DH_METHOD *DH_OpenSSL(void) return &dh_ossl; } +const DH_METHOD *DH_get_default_method(void) +{ + return default_DH_method; +} + +static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, + const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) +{ + return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx); +} + +static int dh_init(DH *dh) +{ + dh->flags |= DH_FLAG_CACHE_MONT_P; + dh->dirty_cnt++; + return 1; +} + +static int dh_finish(DH *dh) +{ + BN_MONT_CTX_free(dh->method_mont_p); + return 1; +} + +#ifndef FIPS_MODULE void DH_set_default_method(const DH_METHOD *meth) { default_DH_method = meth; } +#endif /* FIPS_MODULE */ -const DH_METHOD *DH_get_default_method(void) +int DH_generate_key(DH *dh) { - return default_DH_method; +#ifdef FIPS_MODULE + return generate_key(dh); +#else + return dh->meth->generate_key(dh); +#endif +} + +int ossl_dh_generate_public_key(BN_CTX *ctx, const DH *dh, + const BIGNUM *priv_key, BIGNUM *pub_key) +{ + int ret = 0; + BIGNUM *prk = BN_new(); + BN_MONT_CTX *mont = NULL; + + if (prk == NULL) + return 0; + + if (dh->flags & DH_FLAG_CACHE_MONT_P) { + /* + * We take the input DH as const, but we lie, because in some cases we + * want to get a hold of its Montgomery context. + * + * We cast to remove the const qualifier in this case, it should be + * fine... + */ + BN_MONT_CTX **pmont = (BN_MONT_CTX **)&dh->method_mont_p; + + mont = BN_MONT_CTX_set_locked(pmont, dh->lock, dh->params.p, ctx); + if (mont == NULL) + goto err; + } + BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); + + /* pub_key = g^priv_key mod p */ + if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p, + ctx, mont)) + goto err; + ret = 1; +err: + BN_clear_free(prk); + return ret; } static int generate_key(DH *dh) { int ok = 0; int generate_new_key = 0; - unsigned l; +#ifndef FIPS_MODULE + int l; +#endif BN_CTX *ctx = NULL; - BN_MONT_CTX *mont = NULL; BIGNUM *pub_key = NULL, *priv_key = NULL; - if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { - DHerr(DH_F_GENERATE_KEY, DH_R_MODULUS_TOO_LARGE); + if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); return 0; } - ctx = BN_CTX_new(); + if (dh->params.q != NULL + && BN_num_bits(dh->params.q) > OPENSSL_DH_MAX_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_Q_TOO_LARGE); + return 0; + } + + if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) { + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); + return 0; + } + + ctx = BN_CTX_new_ex(dh->libctx); if (ctx == NULL) goto err; @@ -123,68 +293,87 @@ static int generate_key(DH *dh) if (priv_key == NULL) goto err; generate_new_key = 1; - } else + } else { priv_key = dh->priv_key; + } if (dh->pub_key == NULL) { pub_key = BN_new(); if (pub_key == NULL) goto err; - } else + } else { pub_key = dh->pub_key; - - if (dh->flags & DH_FLAG_CACHE_MONT_P) { - mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, - dh->lock, dh->p, ctx); - if (!mont) - goto err; } - if (generate_new_key) { - if (dh->q) { - do { - if (!BN_priv_rand_range(priv_key, dh->q)) - goto err; - } - while (BN_is_zero(priv_key) || BN_is_one(priv_key)); + /* Is it an approved safe prime ?*/ + if (DH_get_nid(dh) != NID_undef) { + int max_strength = + ossl_ifc_ffc_compute_security_bits(BN_num_bits(dh->params.p)); + + if (dh->params.q == NULL + || dh->length > BN_num_bits(dh->params.q)) + goto err; + /* dh->length = maximum bit length of generated private key */ + if (!ossl_ffc_generate_private_key(ctx, &dh->params, dh->length, + max_strength, priv_key)) + goto err; } else { - /* secret exponent length */ - l = dh->length ? dh->length : BN_num_bits(dh->p) - 1; - if (!BN_priv_rand(priv_key, l, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) +#ifdef FIPS_MODULE + if (dh->params.q == NULL) goto err; - /* - * We handle just one known case where g is a quadratic non-residue: - * for g = 2: p % 8 == 3 - */ - if (BN_is_word(dh->g, DH_GENERATOR_2) && !BN_is_bit_set(dh->p, 2)) { - /* clear bit 0, since it won't be a secret anyway */ - if (!BN_clear_bit(priv_key, 0)) +#else + if (dh->params.q == NULL) { + /* secret exponent length, must satisfy 2^l < (p-1)/2 */ + l = BN_num_bits(dh->params.p); + if (dh->length >= l) + goto err; + l -= 2; + if (dh->length != 0 && dh->length < l) + l = dh->length; + if (!BN_priv_rand_ex(priv_key, l, BN_RAND_TOP_ONE, + BN_RAND_BOTTOM_ANY, 0, ctx)) + goto err; + /* + * We handle just one known case where g is a quadratic non-residue: + * for g = 2: p % 8 == 3 + */ + if (BN_is_word(dh->params.g, DH_GENERATOR_2) + && !BN_is_bit_set(dh->params.p, 2)) { + /* clear bit 0, since it won't be a secret anyway */ + if (!BN_clear_bit(priv_key, 0)) + goto err; + } + } else +#endif + { + /* Do a partial check for invalid p, q, g */ + if (!ossl_ffc_params_simple_validate(dh->libctx, &dh->params, + FFC_PARAM_TYPE_DH, NULL)) + goto err; + /* + * For FFC FIPS 186-4 keygen + * security strength s = 112, + * Max Private key size N = len(q) + */ + if (!ossl_ffc_generate_private_key(ctx, &dh->params, + BN_num_bits(dh->params.q), + MIN_STRENGTH, + priv_key)) goto err; } } } - { - BIGNUM *prk = BN_new(); - - if (prk == NULL) - goto err; - BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); - - if (!dh->meth->bn_mod_exp(dh, pub_key, dh->g, prk, dh->p, ctx, mont)) { - BN_clear_free(prk); - goto err; - } - /* We MUST free prk before any further use of priv_key */ - BN_clear_free(prk); - } + if (!ossl_dh_generate_public_key(ctx, dh, priv_key, pub_key)) + goto err; dh->pub_key = pub_key; dh->priv_key = priv_key; + dh->dirty_cnt++; ok = 1; err: if (ok != 1) - DHerr(DH_F_GENERATE_KEY, ERR_R_BN_LIB); + ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB); if (pub_key != dh->pub_key) BN_free(pub_key); @@ -194,73 +383,73 @@ static int generate_key(DH *dh) return ok; } -static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) +int ossl_dh_buf2key(DH *dh, const unsigned char *buf, size_t len) { - BN_CTX *ctx = NULL; - BN_MONT_CTX *mont = NULL; - BIGNUM *tmp; - int ret = -1; - int check_result; + int err_reason = DH_R_BN_ERROR; + BIGNUM *pubkey = NULL; + const BIGNUM *p; + int ret; - if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { - DHerr(DH_F_COMPUTE_KEY, DH_R_MODULUS_TOO_LARGE); + if ((pubkey = BN_bin2bn(buf, len, NULL)) == NULL) goto err; - } - - ctx = BN_CTX_new(); - if (ctx == NULL) - goto err; - BN_CTX_start(ctx); - tmp = BN_CTX_get(ctx); - if (tmp == NULL) - goto err; - - if (dh->priv_key == NULL) { - DHerr(DH_F_COMPUTE_KEY, DH_R_NO_PRIVATE_VALUE); + DH_get0_pqg(dh, &p, NULL, NULL); + if (p == NULL || BN_num_bytes(p) == 0) { + err_reason = DH_R_NO_PARAMETERS_SET; goto err; } - - if (dh->flags & DH_FLAG_CACHE_MONT_P) { - mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, - dh->lock, dh->p, ctx); - BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME); - if (!mont) - goto err; - } - - if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) { - DHerr(DH_F_COMPUTE_KEY, DH_R_INVALID_PUBKEY); + /* Prevent small subgroup attacks per RFC 8446 Section 4.2.8.1 */ + if (!ossl_dh_check_pub_key_partial(dh, pubkey, &ret)) { + err_reason = DH_R_INVALID_PUBKEY; goto err; } - - if (!dh-> - meth->bn_mod_exp(dh, tmp, pub_key, dh->priv_key, dh->p, ctx, mont)) { - DHerr(DH_F_COMPUTE_KEY, ERR_R_BN_LIB); + if (DH_set0_key(dh, pubkey, NULL) != 1) goto err; - } - - ret = BN_bn2binpad(tmp, key, BN_num_bytes(dh->p)); - err: - BN_CTX_end(ctx); - BN_CTX_free(ctx); - return ret; -} - -static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, - const BIGNUM *a, const BIGNUM *p, - const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) -{ - return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx); -} - -static int dh_init(DH *dh) -{ - dh->flags |= DH_FLAG_CACHE_MONT_P; return 1; +err: + ERR_raise(ERR_LIB_DH, err_reason); + BN_free(pubkey); + return 0; } -static int dh_finish(DH *dh) +size_t ossl_dh_key2buf(const DH *dh, unsigned char **pbuf_out, size_t size, + int alloc) { - BN_MONT_CTX_free(dh->method_mont_p); - return 1; + const BIGNUM *pubkey; + unsigned char *pbuf = NULL; + const BIGNUM *p; + int p_size; + + DH_get0_pqg(dh, &p, NULL, NULL); + DH_get0_key(dh, &pubkey, NULL); + if (p == NULL || pubkey == NULL + || (p_size = BN_num_bytes(p)) == 0 + || BN_num_bytes(pubkey) == 0) { + ERR_raise(ERR_LIB_DH, DH_R_INVALID_PUBKEY); + return 0; + } + if (pbuf_out != NULL && (alloc || *pbuf_out != NULL)) { + if (!alloc) { + if (size >= (size_t)p_size) + pbuf = *pbuf_out; + } else { + pbuf = OPENSSL_malloc(p_size); + } + + if (pbuf == NULL) { + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); + return 0; + } + /* + * As per Section 4.2.8.1 of RFC 8446 left pad public + * key with zeros to the size of p + */ + if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) { + if (alloc) + OPENSSL_free(pbuf); + ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR); + return 0; + } + *pbuf_out = pbuf; + } + return p_size; } diff --git a/crypto/dh/dh_lib.c b/crypto/dh/dh_lib.c index 04b79d355ca4..5577413e1e0c 100644 --- a/crypto/dh/dh_lib.c +++ b/crypto/dh/dh_lib.c @@ -1,19 +1,34 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> +#include <openssl/bn.h> +#ifndef FIPS_MODULE +# include <openssl/engine.h> +#endif +#include <openssl/obj_mac.h> +#include <openssl/core_names.h> #include "internal/cryptlib.h" #include "internal/refcount.h" -#include <openssl/bn.h> +#include "crypto/evp.h" +#include "crypto/dh.h" #include "dh_local.h" -#include <openssl/engine.h> +static DH *dh_new_intern(ENGINE *engine, OSSL_LIB_CTX *libctx); + +#ifndef FIPS_MODULE int DH_set_method(DH *dh, const DH_METHOD *meth) { /* @@ -34,34 +49,52 @@ int DH_set_method(DH *dh, const DH_METHOD *meth) return 1; } +const DH_METHOD *ossl_dh_get_method(const DH *dh) +{ + return dh->meth; +} +# ifndef OPENSSL_NO_DEPRECATED_3_0 DH *DH_new(void) { - return DH_new_method(NULL); + return dh_new_intern(NULL, NULL); } +# endif DH *DH_new_method(ENGINE *engine) { + return dh_new_intern(engine, NULL); +} +#endif /* !FIPS_MODULE */ + +DH *ossl_dh_new_ex(OSSL_LIB_CTX *libctx) +{ + return dh_new_intern(NULL, libctx); +} + +static DH *dh_new_intern(ENGINE *engine, OSSL_LIB_CTX *libctx) +{ DH *ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); return NULL; } ret->references = 1; ret->lock = CRYPTO_THREAD_lock_new(); if (ret->lock == NULL) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } + ret->libctx = libctx; ret->meth = DH_get_default_method(); -#ifndef OPENSSL_NO_ENGINE +#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_ENGINE) ret->flags = ret->meth->flags; /* early default init */ if (engine) { if (!ENGINE_init(engine)) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB); + ERR_raise(ERR_LIB_DH, ERR_R_ENGINE_LIB); goto err; } ret->engine = engine; @@ -70,7 +103,7 @@ DH *DH_new_method(ENGINE *engine) if (ret->engine) { ret->meth = ENGINE_get_DH(ret->engine); if (ret->meth == NULL) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB); + ERR_raise(ERR_LIB_DH, ERR_R_ENGINE_LIB); goto err; } } @@ -78,11 +111,15 @@ DH *DH_new_method(ENGINE *engine) ret->flags = ret->meth->flags; +#ifndef FIPS_MODULE if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DH, ret, &ret->ex_data)) goto err; +#endif /* FIPS_MODULE */ + + ossl_ffc_params_init(&ret->params); if ((ret->meth->init != NULL) && !ret->meth->init(ret)) { - DHerr(DH_F_DH_NEW_METHOD, ERR_R_INIT_FAIL); + ERR_raise(ERR_LIB_DH, ERR_R_INIT_FAIL); goto err; } @@ -108,20 +145,16 @@ void DH_free(DH *r) if (r->meth != NULL && r->meth->finish != NULL) r->meth->finish(r); -#ifndef OPENSSL_NO_ENGINE +#if !defined(FIPS_MODULE) +# if !defined(OPENSSL_NO_ENGINE) ENGINE_finish(r->engine); -#endif - +# endif CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, r, &r->ex_data); +#endif CRYPTO_THREAD_lock_free(r->lock); - BN_clear_free(r->p); - BN_clear_free(r->g); - BN_clear_free(r->q); - BN_clear_free(r->j); - OPENSSL_free(r->seed); - BN_clear_free(r->counter); + ossl_ffc_params_cleanup(&r->params); BN_clear_free(r->pub_key); BN_clear_free(r->priv_key); OPENSSL_free(r); @@ -139,76 +172,71 @@ int DH_up_ref(DH *r) return ((i > 1) ? 1 : 0); } +void ossl_dh_set0_libctx(DH *d, OSSL_LIB_CTX *libctx) +{ + d->libctx = libctx; +} + +#ifndef FIPS_MODULE int DH_set_ex_data(DH *d, int idx, void *arg) { return CRYPTO_set_ex_data(&d->ex_data, idx, arg); } -void *DH_get_ex_data(DH *d, int idx) +void *DH_get_ex_data(const DH *d, int idx) { return CRYPTO_get_ex_data(&d->ex_data, idx); } +#endif int DH_bits(const DH *dh) { - return BN_num_bits(dh->p); + if (dh->params.p != NULL) + return BN_num_bits(dh->params.p); + return -1; } int DH_size(const DH *dh) { - return BN_num_bytes(dh->p); + if (dh->params.p != NULL) + return BN_num_bytes(dh->params.p); + return -1; } int DH_security_bits(const DH *dh) { int N; - if (dh->q) - N = BN_num_bits(dh->q); + + if (dh->params.q != NULL) + N = BN_num_bits(dh->params.q); else if (dh->length) N = dh->length; else N = -1; - return BN_security_bits(BN_num_bits(dh->p), N); + if (dh->params.p != NULL) + return BN_security_bits(BN_num_bits(dh->params.p), N); + return -1; } - void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { - if (p != NULL) - *p = dh->p; - if (q != NULL) - *q = dh->q; - if (g != NULL) - *g = dh->g; + ossl_ffc_params_get0_pqg(&dh->params, p, q, g); } int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { - /* If the fields p and g in d are NULL, the corresponding input + /* + * If the fields p and g in dh are NULL, the corresponding input * parameters MUST be non-NULL. q may remain NULL. */ - if ((dh->p == NULL && p == NULL) - || (dh->g == NULL && g == NULL)) + if ((dh->params.p == NULL && p == NULL) + || (dh->params.g == NULL && g == NULL)) return 0; - if (p != NULL) { - BN_free(dh->p); - dh->p = p; - } - if (q != NULL) { - BN_free(dh->q); - dh->q = q; - } - if (g != NULL) { - BN_free(dh->g); - dh->g = g; - } - - if (q != NULL) { - dh->length = BN_num_bits(q); - } - + ossl_ffc_params_set0_pqg(&dh->params, p, q, g); + ossl_dh_cache_named_group(dh); + dh->dirty_cnt++; return 1; } @@ -220,6 +248,7 @@ long DH_get_length(const DH *dh) int DH_set_length(DH *dh, long length) { dh->length = length; + dh->dirty_cnt++; return 1; } @@ -242,22 +271,23 @@ int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) dh->priv_key = priv_key; } + dh->dirty_cnt++; return 1; } const BIGNUM *DH_get0_p(const DH *dh) { - return dh->p; + return dh->params.p; } const BIGNUM *DH_get0_q(const DH *dh) { - return dh->q; + return dh->params.q; } const BIGNUM *DH_get0_g(const DH *dh) { - return dh->g; + return dh->params.g; } const BIGNUM *DH_get0_priv_key(const DH *dh) @@ -285,7 +315,18 @@ void DH_set_flags(DH *dh, int flags) dh->flags |= flags; } +#ifndef FIPS_MODULE ENGINE *DH_get0_engine(DH *dh) { return dh->engine; } +#endif /*FIPS_MODULE */ + +FFC_PARAMS *ossl_dh_get0_params(DH *dh) +{ + return &dh->params; +} +int ossl_dh_get0_nid(const DH *dh) +{ + return dh->params.nid; +} diff --git a/crypto/dh/dh_local.h b/crypto/dh/dh_local.h index 0a8391a6c004..1ff075e3dc1d 100644 --- a/crypto/dh/dh_local.h +++ b/crypto/dh/dh_local.h @@ -1,7 +1,7 @@ /* - * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -9,6 +9,9 @@ #include <openssl/dh.h> #include "internal/refcount.h" +#include "internal/ffc.h" + +#define DH_MIN_MODULUS_BITS 512 struct dh_st { /* @@ -17,24 +20,24 @@ struct dh_st { */ int pad; int version; - BIGNUM *p; - BIGNUM *g; - int32_t length; /* optional */ + FFC_PARAMS params; + /* max generated private key length (can be less than len(q)) */ + int32_t length; BIGNUM *pub_key; /* g^x % p */ BIGNUM *priv_key; /* x */ int flags; BN_MONT_CTX *method_mont_p; - /* Place holders if we want to do X9.42 DH */ - BIGNUM *q; - BIGNUM *j; - unsigned char *seed; - int seedlen; - BIGNUM *counter; CRYPTO_REF_COUNT references; +#ifndef FIPS_MODULE CRYPTO_EX_DATA ex_data; - const DH_METHOD *meth; ENGINE *engine; +#endif + OSSL_LIB_CTX *libctx; + const DH_METHOD *meth; CRYPTO_RWLOCK *lock; + + /* Provider data */ + size_t dirty_cnt; /* If any key material changes, increment this */ }; struct dh_method { diff --git a/crypto/dh/dh_meth.c b/crypto/dh/dh_meth.c index 8a54a8108fc3..5c15cd2b8cc2 100644 --- a/crypto/dh/dh_meth.c +++ b/crypto/dh/dh_meth.c @@ -1,12 +1,18 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include "dh_local.h" #include <string.h> #include <openssl/err.h> @@ -25,7 +31,7 @@ DH_METHOD *DH_meth_new(const char *name, int flags) OPENSSL_free(dhm); } - DHerr(DH_F_DH_METH_NEW, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); return NULL; } @@ -51,7 +57,7 @@ DH_METHOD *DH_meth_dup(const DH_METHOD *dhm) OPENSSL_free(ret); } - DHerr(DH_F_DH_METH_DUP, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); return NULL; } @@ -65,7 +71,7 @@ int DH_meth_set1_name(DH_METHOD *dhm, const char *name) char *tmpname = OPENSSL_strdup(name); if (tmpname == NULL) { - DHerr(DH_F_DH_METH_SET1_NAME, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); return 0; } diff --git a/crypto/dh/dh_pmeth.c b/crypto/dh/dh_pmeth.c index 1fd94deb4731..931e1b88ec6f 100644 --- a/crypto/dh/dh_pmeth.c +++ b/crypto/dh/dh_pmeth.c @@ -1,12 +1,18 @@ /* - * Copyright 2006-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2006-2025 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH & DSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/asn1t.h> @@ -24,12 +30,11 @@ typedef struct { /* Parameter gen parameters */ int prime_len; int generator; - int use_dsa; + int paramgen_type; int subprime_len; int pad; /* message digest used for parameter generation */ const EVP_MD *md; - int rfc5114_param; int param_nid; /* Keygen callback info */ int gentmp[2]; @@ -51,7 +56,7 @@ static int pkey_dh_init(EVP_PKEY_CTX *ctx) DH_PKEY_CTX *dctx; if ((dctx = OPENSSL_zalloc(sizeof(*dctx))) == NULL) { - DHerr(DH_F_PKEY_DH_INIT, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); return 0; } dctx->prime_len = 2048; @@ -69,6 +74,7 @@ static int pkey_dh_init(EVP_PKEY_CTX *ctx) static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) { DH_PKEY_CTX *dctx = ctx->data; + if (dctx != NULL) { OPENSSL_free(dctx->kdf_ukm); ASN1_OBJECT_free(dctx->kdf_oid); @@ -77,9 +83,10 @@ static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) } -static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) +static int pkey_dh_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src) { DH_PKEY_CTX *dctx, *sctx; + if (!pkey_dh_init(dst)) return 0; sctx = src->data; @@ -87,10 +94,9 @@ static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) dctx->prime_len = sctx->prime_len; dctx->subprime_len = sctx->subprime_len; dctx->generator = sctx->generator; - dctx->use_dsa = sctx->use_dsa; + dctx->paramgen_type = sctx->paramgen_type; dctx->pad = sctx->pad; dctx->md = sctx->md; - dctx->rfc5114_param = sctx->rfc5114_param; dctx->param_nid = sctx->param_nid; dctx->kdf_type = sctx->kdf_type; @@ -119,7 +125,7 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return 1; case EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN: - if (dctx->use_dsa == 0) + if (dctx->paramgen_type == DH_PARAMGEN_TYPE_GENERATOR) return -2; dctx->subprime_len = p1; return 1; @@ -129,30 +135,30 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return 1; case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR: - if (dctx->use_dsa) + if (dctx->paramgen_type != DH_PARAMGEN_TYPE_GENERATOR) return -2; dctx->generator = p1; return 1; case EVP_PKEY_CTRL_DH_PARAMGEN_TYPE: #ifdef OPENSSL_NO_DSA - if (p1 != 0) + if (p1 != DH_PARAMGEN_TYPE_GENERATOR) return -2; #else if (p1 < 0 || p1 > 2) return -2; #endif - dctx->use_dsa = p1; + dctx->paramgen_type = p1; return 1; case EVP_PKEY_CTRL_DH_RFC5114: if (p1 < 1 || p1 > 3 || dctx->param_nid != NID_undef) return -2; - dctx->rfc5114_param = p1; + dctx->param_nid = p1; return 1; case EVP_PKEY_CTRL_DH_NID: - if (p1 <= 0 || dctx->rfc5114_param != 0) + if (p1 <= 0 || dctx->param_nid != NID_undef) return -2; dctx->param_nid = p1; return 1; @@ -164,11 +170,7 @@ static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) case EVP_PKEY_CTRL_DH_KDF_TYPE: if (p1 == -2) return dctx->kdf_type; -#ifdef OPENSSL_NO_CMS - if (p1 != EVP_PKEY_DH_KDF_NONE) -#else if (p1 != EVP_PKEY_DH_KDF_NONE && p1 != EVP_PKEY_DH_KDF_X9_42) -#endif return -2; dctx->kdf_type = p1; return 1; @@ -229,11 +231,12 @@ static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, } if (strcmp(type, "dh_rfc5114") == 0) { DH_PKEY_CTX *dctx = ctx->data; - int len; - len = atoi(value); - if (len < 0 || len > 3) + int id; + + id = atoi(value); + if (id < 0 || id > 3) return -2; - dctx->rfc5114_param = len; + dctx->param_nid = id; return 1; } if (strcmp(type, "dh_param") == 0) { @@ -241,7 +244,7 @@ static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, int nid = OBJ_sn2nid(value); if (nid == NID_undef) { - DHerr(DH_F_PKEY_DH_CTRL_STR, DH_R_INVALID_PARAMETER_NAME); + ERR_raise(ERR_LIB_DH, DH_R_INVALID_PARAMETER_NAME); return -2; } dctx->param_nid = nid; @@ -270,116 +273,91 @@ static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, return -2; } -#ifndef OPENSSL_NO_DSA - -extern int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, - const EVP_MD *evpmd, - const unsigned char *seed_in, size_t seed_len, - unsigned char *seed_out, int *counter_ret, - unsigned long *h_ret, BN_GENCB *cb); - -extern int dsa_builtin_paramgen2(DSA *ret, size_t L, size_t N, - const EVP_MD *evpmd, - const unsigned char *seed_in, - size_t seed_len, int idx, - unsigned char *seed_out, int *counter_ret, - unsigned long *h_ret, BN_GENCB *cb); - -static DSA *dsa_dh_generate(DH_PKEY_CTX *dctx, BN_GENCB *pcb) +static DH *ffc_params_generate(OSSL_LIB_CTX *libctx, DH_PKEY_CTX *dctx, + BN_GENCB *pcb) { - DSA *ret; + DH *ret; int rv = 0; + int res; int prime_len = dctx->prime_len; int subprime_len = dctx->subprime_len; - const EVP_MD *md = dctx->md; - if (dctx->use_dsa > 2) + + if (dctx->paramgen_type > DH_PARAMGEN_TYPE_FIPS_186_4) return NULL; - ret = DSA_new(); + ret = DH_new(); if (ret == NULL) return NULL; + if (subprime_len == -1) { if (prime_len >= 2048) subprime_len = 256; else subprime_len = 160; } - if (md == NULL) { - if (prime_len >= 2048) - md = EVP_sha256(); - else - md = EVP_sha1(); - } - if (dctx->use_dsa == 1) - rv = dsa_builtin_paramgen(ret, prime_len, subprime_len, md, - NULL, 0, NULL, NULL, NULL, pcb); - else if (dctx->use_dsa == 2) - rv = dsa_builtin_paramgen2(ret, prime_len, subprime_len, md, - NULL, 0, -1, NULL, NULL, NULL, pcb); + + if (dctx->md != NULL) + ossl_ffc_set_digest(&ret->params, EVP_MD_get0_name(dctx->md), NULL); + +# ifndef FIPS_MODULE + if (dctx->paramgen_type == DH_PARAMGEN_TYPE_FIPS_186_2) + rv = ossl_ffc_params_FIPS186_2_generate(libctx, &ret->params, + FFC_PARAM_TYPE_DH, + prime_len, subprime_len, &res, + pcb); + else +# endif + /* For FIPS we always use the DH_PARAMGEN_TYPE_FIPS_186_4 generator */ + if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2) + rv = ossl_ffc_params_FIPS186_4_generate(libctx, &ret->params, + FFC_PARAM_TYPE_DH, + prime_len, subprime_len, &res, + pcb); if (rv <= 0) { - DSA_free(ret); + DH_free(ret); return NULL; } return ret; } -#endif - -static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) +static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, + EVP_PKEY *pkey) { DH *dh = NULL; DH_PKEY_CTX *dctx = ctx->data; - BN_GENCB *pcb; + BN_GENCB *pcb = NULL; int ret; - if (dctx->rfc5114_param) { - switch (dctx->rfc5114_param) { - case 1: - dh = DH_get_1024_160(); - break; - case 2: - dh = DH_get_2048_224(); - break; + /* + * Look for a safe prime group for key establishment. Which uses + * either RFC_3526 (modp_XXXX) or RFC_7919 (ffdheXXXX). + * RFC_5114 is also handled here for param_nid = (1..3) + */ + if (dctx->param_nid != NID_undef) { + int type = dctx->param_nid <= 3 ? EVP_PKEY_DHX : EVP_PKEY_DH; - case 3: - dh = DH_get_2048_256(); - break; - - default: - return -2; - } - EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh); - return 1; - } - - if (dctx->param_nid != 0) { if ((dh = DH_new_by_nid(dctx->param_nid)) == NULL) return 0; - EVP_PKEY_assign(pkey, EVP_PKEY_DH, dh); + EVP_PKEY_assign(pkey, type, dh); return 1; } - if (ctx->pkey_gencb) { + if (ctx->pkey_gencb != NULL) { pcb = BN_GENCB_new(); if (pcb == NULL) return 0; evp_pkey_set_cb_translate(pcb, ctx); - } else - pcb = NULL; -#ifndef OPENSSL_NO_DSA - if (dctx->use_dsa) { - DSA *dsa_dh; - dsa_dh = dsa_dh_generate(dctx, pcb); + } +# ifdef FIPS_MODULE + dctx->paramgen_type = DH_PARAMGEN_TYPE_FIPS_186_4; +# endif /* FIPS_MODULE */ + if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2) { + dh = ffc_params_generate(NULL, dctx, pcb); BN_GENCB_free(pcb); - if (dsa_dh == NULL) - return 0; - dh = DSA_dup_DH(dsa_dh); - DSA_free(dsa_dh); - if (!dh) + if (dh == NULL) return 0; EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh); return 1; } -#endif dh = DH_new(); if (dh == NULL) { BN_GENCB_free(pcb); @@ -400,11 +378,11 @@ static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) DH_PKEY_CTX *dctx = ctx->data; DH *dh = NULL; - if (ctx->pkey == NULL && dctx->param_nid == 0) { - DHerr(DH_F_PKEY_DH_KEYGEN, DH_R_NO_PARAMETERS_SET); + if (ctx->pkey == NULL && dctx->param_nid == NID_undef) { + ERR_raise(ERR_LIB_DH, DH_R_NO_PARAMETERS_SET); return 0; } - if (dctx->param_nid != 0) + if (dctx->param_nid != NID_undef) dh = DH_new_by_nid(dctx->param_nid); else dh = DH_new(); @@ -414,7 +392,7 @@ static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) /* Note: if error return, pkey is freed by parent routine */ if (ctx->pkey != NULL && !EVP_PKEY_copy_parameters(pkey, ctx->pkey)) return 0; - return DH_generate_key(pkey->pkey.dh); + return DH_generate_key((DH *)EVP_PKEY_get0_DH(pkey)); } static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, @@ -422,33 +400,40 @@ static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, { int ret; DH *dh; + const DH *dhpub; DH_PKEY_CTX *dctx = ctx->data; - BIGNUM *dhpub; - if (!ctx->pkey || !ctx->peerkey) { - DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET); + BIGNUM *dhpubbn; + + if (ctx->pkey == NULL || ctx->peerkey == NULL) { + ERR_raise(ERR_LIB_DH, DH_R_KEYS_NOT_SET); + return 0; + } + dh = (DH *)EVP_PKEY_get0_DH(ctx->pkey); + dhpub = EVP_PKEY_get0_DH(ctx->peerkey); + if (dhpub == NULL || dh == NULL) { + ERR_raise(ERR_LIB_DH, DH_R_KEYS_NOT_SET); return 0; } - dh = ctx->pkey->pkey.dh; - dhpub = ctx->peerkey->pkey.dh->pub_key; + dhpubbn = dhpub->pub_key; if (dctx->kdf_type == EVP_PKEY_DH_KDF_NONE) { if (key == NULL) { *keylen = DH_size(dh); return 1; } if (dctx->pad) - ret = DH_compute_key_padded(key, dhpub, dh); + ret = DH_compute_key_padded(key, dhpubbn, dh); else - ret = DH_compute_key(key, dhpub, dh); - if (ret < 0) + ret = DH_compute_key(key, dhpubbn, dh); + if (ret <= 0) return ret; *keylen = ret; return 1; } -#ifndef OPENSSL_NO_CMS else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) { unsigned char *Z = NULL; - size_t Zlen = 0; + int Zlen = 0; + if (!dctx->kdf_outlen || !dctx->kdf_oid) return 0; if (key == NULL) { @@ -458,12 +443,13 @@ static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, if (*keylen != dctx->kdf_outlen) return 0; ret = 0; - Zlen = DH_size(dh); - Z = OPENSSL_malloc(Zlen); - if (Z == NULL) { - goto err; + if ((Zlen = DH_size(dh)) <= 0) + return 0; + if ((Z = OPENSSL_malloc(Zlen)) == NULL) { + ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); + return 0; } - if (DH_compute_key_padded(Z, dhpub, dh) <= 0) + if (DH_compute_key_padded(Z, dhpubbn, dh) <= 0) goto err; if (!DH_KDF_X9_42(key, *keylen, Z, Zlen, dctx->kdf_oid, dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md)) @@ -474,11 +460,10 @@ static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, OPENSSL_clear_free(Z, Zlen); return ret; } -#endif return 0; } -const EVP_PKEY_METHOD dh_pkey_meth = { +static const EVP_PKEY_METHOD dh_pkey_meth = { EVP_PKEY_DH, 0, pkey_dh_init, @@ -512,7 +497,12 @@ const EVP_PKEY_METHOD dh_pkey_meth = { pkey_dh_ctrl_str }; -const EVP_PKEY_METHOD dhx_pkey_meth = { +const EVP_PKEY_METHOD *ossl_dh_pkey_method(void) +{ + return &dh_pkey_meth; +} + +static const EVP_PKEY_METHOD dhx_pkey_meth = { EVP_PKEY_DHX, 0, pkey_dh_init, @@ -545,3 +535,8 @@ const EVP_PKEY_METHOD dhx_pkey_meth = { pkey_dh_ctrl, pkey_dh_ctrl_str }; + +const EVP_PKEY_METHOD *ossl_dhx_pkey_method(void) +{ + return &dhx_pkey_meth; +} diff --git a/crypto/dh/dh_prn.c b/crypto/dh/dh_prn.c index aab1733db3b3..5d31254dcbc6 100644 --- a/crypto/dh/dh_prn.c +++ b/crypto/dh/dh_prn.c @@ -1,12 +1,18 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/evp.h> @@ -19,7 +25,7 @@ int DHparams_print_fp(FILE *fp, const DH *x) int ret; if ((b = BIO_new(BIO_s_file())) == NULL) { - DHerr(DH_F_DHPARAMS_PRINT_FP, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_DH, ERR_R_BUF_LIB); return 0; } BIO_set_fp(b, fp, BIO_NOCLOSE); diff --git a/crypto/dh/dh_rfc5114.c b/crypto/dh/dh_rfc5114.c index e3603a05a322..7b1e0610bd71 100644 --- a/crypto/dh/dh_rfc5114.c +++ b/crypto/dh/dh_rfc5114.c @@ -1,12 +1,18 @@ /* - * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include "internal/cryptlib.h" #include "dh_local.h" @@ -26,10 +32,10 @@ DH *DH_get_##x(void) \ \ if (dh == NULL) \ return NULL; \ - dh->p = BN_dup(&_bignum_dh##x##_p); \ - dh->g = BN_dup(&_bignum_dh##x##_g); \ - dh->q = BN_dup(&_bignum_dh##x##_q); \ - if (dh->p == NULL || dh->q == NULL || dh->g == NULL) {\ + dh->params.p = BN_dup(&ossl_bignum_dh##x##_p); \ + dh->params.g = BN_dup(&ossl_bignum_dh##x##_g); \ + dh->params.q = BN_dup(&ossl_bignum_dh##x##_q); \ + if (dh->params.p == NULL || dh->params.q == NULL || dh->params.g == NULL) {\ DH_free(dh); \ return NULL; \ } \ diff --git a/crypto/dh/dh_rfc7919.c b/crypto/dh/dh_rfc7919.c deleted file mode 100644 index 03d30a1f5d59..000000000000 --- a/crypto/dh/dh_rfc7919.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the OpenSSL license (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include "internal/cryptlib.h" -#include "dh_local.h" -#include <openssl/bn.h> -#include <openssl/objects.h> -#include "crypto/bn_dh.h" - -static DH *dh_param_init(const BIGNUM *p, int32_t nbits) -{ - DH *dh = DH_new(); - if (dh == NULL) - return NULL; - dh->p = (BIGNUM *)p; - dh->g = (BIGNUM *)&_bignum_const_2; - dh->length = nbits; - return dh; -} - -DH *DH_new_by_nid(int nid) -{ - switch (nid) { - case NID_ffdhe2048: - return dh_param_init(&_bignum_ffdhe2048_p, 225); - case NID_ffdhe3072: - return dh_param_init(&_bignum_ffdhe3072_p, 275); - case NID_ffdhe4096: - return dh_param_init(&_bignum_ffdhe4096_p, 325); - case NID_ffdhe6144: - return dh_param_init(&_bignum_ffdhe6144_p, 375); - case NID_ffdhe8192: - return dh_param_init(&_bignum_ffdhe8192_p, 400); - default: - DHerr(DH_F_DH_NEW_BY_NID, DH_R_INVALID_PARAMETER_NID); - return NULL; - } -} - -int DH_get_nid(const DH *dh) -{ - int nid; - - if (BN_get_word(dh->g) != 2) - return NID_undef; - if (!BN_cmp(dh->p, &_bignum_ffdhe2048_p)) - nid = NID_ffdhe2048; - else if (!BN_cmp(dh->p, &_bignum_ffdhe3072_p)) - nid = NID_ffdhe3072; - else if (!BN_cmp(dh->p, &_bignum_ffdhe4096_p)) - nid = NID_ffdhe4096; - else if (!BN_cmp(dh->p, &_bignum_ffdhe6144_p)) - nid = NID_ffdhe6144; - else if (!BN_cmp(dh->p, &_bignum_ffdhe8192_p)) - nid = NID_ffdhe8192; - else - return NID_undef; - if (dh->q != NULL) { - BIGNUM *q = BN_dup(dh->p); - - /* Check q = p * 2 + 1 we already know q is odd, so just shift right */ - if (q == NULL || !BN_rshift1(q, q) || !BN_cmp(dh->q, q)) - nid = NID_undef; - BN_free(q); - } - return nid; -} |
