From ead0d2347a348f0916d6d25818d16d702f1d1156 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 13 Jan 2020 08:49:44 +0100 Subject: [PATCH] EVP: Add EVP_PKEY_get_default_digest_name() and use it It is the provider version of EVP_PKEY_get_default_digest_nid(). We make sure to use it in the non-legacy section of do_sigver_init() (internal implementation for EVP_DigestSignInit() and EVP_DigestVerifyInit()) Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10824) --- crypto/evp/m_sigver.c | 46 ++++++------- crypto/evp/p_lib.c | 71 +++++++++++++++++++- doc/man3/EVP_PKEY_get_default_digest_nid.pod | 34 +++++++--- include/openssl/core_names.h | 2 + include/openssl/evp.h | 2 + util/libcrypto.num | 1 + 6 files changed, 121 insertions(+), 35 deletions(-) diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 79099b1e35..05dc46e3b1 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -33,6 +33,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, EVP_SIGNATURE *signature = NULL; EVP_KEYMGMT *tmp_keymgmt = NULL; const char *supported_sig = NULL; + char locmdname[80] = ""; /* 80 chars should be enough */ void *provkey = NULL; int ret; @@ -63,22 +64,6 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, if (locpctx->keytype == NULL) goto legacy; - if (mdname == NULL) { - if (type != NULL) { - mdname = EVP_MD_name(type); - } else if (pkey != NULL) { - /* - * TODO(v3.0) work out a better way for EVP_PKEYs with no legacy - * component. - */ - if (pkey->pkey.ptr != NULL) { - int def_nid; - if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0) - mdname = OBJ_nid2sn(def_nid); - } - } - } - /* Ensure that the key is provided. If not, go legacy */ tmp_keymgmt = locpctx->keymgmt; provkey = evp_pkey_make_provided(locpctx->pkey, locpctx->libctx, @@ -131,6 +116,9 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, /* No more legacy from here down to legacy: */ + if (pctx != NULL) + *pctx = locpctx; + locpctx->op.sig.signature = signature; locpctx->operation = ver ? EVP_PKEY_OP_VERIFYCTX : EVP_PKEY_OP_SIGNCTX; @@ -142,15 +130,25 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, } if (type != NULL) { ctx->reqdigest = type; + if (mdname == NULL) + mdname = EVP_MD_name(type); } else { - /* - * This might be requested by a later call to EVP_MD_CTX_md(). In that - * case the "explicit fetch" rules apply for that function (as per - * man pages), i.e. the ref count is not updated so the EVP_MD should - * not be used beyound the lifetime of the EVP_MD_CTX. - */ - ctx->reqdigest = ctx->fetched_digest = - EVP_MD_fetch(locpctx->libctx, mdname, props); + if (mdname == NULL + && EVP_PKEY_get_default_digest_name(locpctx->pkey, locmdname, + sizeof(locmdname))) + mdname = locmdname; + + if (mdname != NULL) { + /* + * This might be requested by a later call to EVP_MD_CTX_md(). + * In that case the "explicit fetch" rules apply for that + * function (as per man pages), i.e. the ref count is not updated + * so the EVP_MD should not be used beyound the lifetime of the + * EVP_MD_CTX. + */ + ctx->reqdigest = ctx->fetched_digest = + EVP_MD_fetch(locpctx->libctx, mdname, props); + } } if (ver) { diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 016bcf93c2..2aa2aa87af 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -691,9 +691,39 @@ int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, pctx); } +static int legacy_asn1_ctrl_to_param(EVP_PKEY *pkey, int op, + int arg1, void *arg2) +{ + if (pkey->pkeys[0].keymgmt == NULL) + return 0; + switch (op) { + case ASN1_PKEY_CTRL_DEFAULT_MD_NID: + { + char mdname[80] = ""; + int nid; + int rv = EVP_PKEY_get_default_digest_name(pkey, mdname, + sizeof(mdname)); + + if (rv <= 0) + return rv; + nid = OBJ_sn2nid(mdname); + if (nid == NID_undef) + nid = OBJ_ln2nid(mdname); + if (nid == NID_undef) + return 0; + *(int *)arg2 = nid; + return 1; + } + default: + return -2; + } +} + static int evp_pkey_asn1_ctrl(EVP_PKEY *pkey, int op, int arg1, void *arg2) { - if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL) + if (pkey->ameth == NULL) + return legacy_asn1_ctrl_to_param(pkey, op, arg1, arg2); + if (pkey->ameth->pkey_ctrl == NULL) return -2; return pkey->ameth->pkey_ctrl(pkey, op, arg1, arg2); } @@ -703,6 +733,45 @@ int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid) return evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_DEFAULT_MD_NID, 0, pnid); } +int EVP_PKEY_get_default_digest_name(EVP_PKEY *pkey, + char *mdname, size_t mdname_sz) +{ + if (pkey->ameth == NULL) { + OSSL_PARAM params[3]; + char mddefault[100] = ""; + char mdmandatory[100] = ""; + + params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, + mddefault, sizeof(mddefault)); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, + mdmandatory, + sizeof(mdmandatory)); + params[2] = OSSL_PARAM_construct_end(); + if (!evp_keymgmt_get_key_params(pkey->pkeys[0].keymgmt, + pkey->pkeys[0].provdata, + params)) + return 0; + if (mdmandatory[0] != '\0') { + OPENSSL_strlcpy(mdname, mdmandatory, mdname_sz); + return 2; + } + OPENSSL_strlcpy(mdname, mddefault, mdname_sz); + return 1; + } + + { + int nid = NID_undef; + int rv = EVP_PKEY_get_default_digest_nid(pkey, &nid); + const char *name = rv > 0 ? OBJ_nid2sn(nid) : NULL; + + if (rv > 0) + OPENSSL_strlcpy(mdname, name, mdname_sz); + return rv; + } +} + int EVP_PKEY_supports_digest_nid(EVP_PKEY *pkey, int nid) { int rv, default_nid; diff --git a/doc/man3/EVP_PKEY_get_default_digest_nid.pod b/doc/man3/EVP_PKEY_get_default_digest_nid.pod index b2098a42c2..4a4ca4cad4 100644 --- a/doc/man3/EVP_PKEY_get_default_digest_nid.pod +++ b/doc/man3/EVP_PKEY_get_default_digest_nid.pod @@ -2,19 +2,32 @@ =head1 NAME -EVP_PKEY_get_default_digest_nid - get default signature digest +EVP_PKEY_get_default_digest_nid, EVP_PKEY_get_default_digest_name +- get default signature digest =head1 SYNOPSIS #include + + int EVP_PKEY_get_default_digest_name(EVP_PKEY *pkey, + char *mdname, size_t mdname_sz) int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid); =head1 DESCRIPTION -The EVP_PKEY_get_default_digest_nid() function sets B to the default -message digest NID for the public key signature operations associated with key -B. Note that some signature algorithms (i.e. Ed25519 and Ed448) do not use -a digest during signing. In this case B will be set to NID_undef. +EVP_PKEY_get_default_digest_name() fills in the default message digest +name for the public key signature operations associated with key +I into I, up to at most I bytes including the +ending NUL byte. + +EVP_PKEY_get_default_digest_nid() sets I to the default message +digest NID for the public key signature operations associated with key +I. Note that some signature algorithms (i.e. Ed25519 and Ed448) +do not use a digest during signing. In this case I will be set +to NID_undef. This function is only reliable for legacy keys, which +are keys with a B; these keys have typically +been loaded from engines, or created with L or +similar. =head1 NOTES @@ -22,11 +35,12 @@ For all current standard OpenSSL public key algorithms SHA256 is returned. =head1 RETURN VALUES -The EVP_PKEY_get_default_digest_nid() function returns 1 if the message digest -is advisory (that is other digests can be used) and 2 if it is mandatory (other -digests can not be used). It returns 0 or a negative value for failure. In -particular a return value of -2 indicates the operation is not supported by the -public key algorithm. +EVP_PKEY_get_default_digest_name() and EVP_PKEY_get_default_digest_nid() +both return 1 if the message digest is advisory (that is other digests +can be used) and 2 if it is mandatory (other digests can not be used). +They return 0 or a negative value for failure. In particular a return +value of -2 indicates the operation is not supported by the public key +algorithm. =head1 SEE ALSO diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index a347d96712..195fe6ed38 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -158,6 +158,8 @@ extern "C" { #define OSSL_PKEY_PARAM_BITS "bits" /* integer */ #define OSSL_PKEY_PARAM_MAX_SIZE "max-size" /* integer */ #define OSSL_PKEY_PARAM_SECURITY_BITS "security-bits" /* integer */ +#define OSSL_PKEY_PARAM_DEFAULT_DIGEST "default-digest" /* utf8 string */ +#define OSSL_PKEY_PARAM_MANDATORY_DIGEST "mandatory-digest" /* utf8 string */ /* Diffie-Hellman/DSA Parameters */ #define OSSL_PKEY_PARAM_FFC_P "p" diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 57a73382e8..6c042d3765 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1178,6 +1178,8 @@ int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid); +int EVP_PKEY_get_default_digest_name(EVP_PKEY *pkey, + char *mdname, size_t mdname_sz); int EVP_PKEY_supports_digest_nid(EVP_PKEY *pkey, int nid); int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, diff --git a/util/libcrypto.num b/util/libcrypto.num index 457f968889..d0443c2f77 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4912,3 +4912,4 @@ ASN1_UTCTIME_dup ? 3_0_0 EXIST::FUNCTION: ASN1_GENERALIZEDTIME_dup ? 3_0_0 EXIST::FUNCTION: RAND_priv_bytes_ex ? 3_0_0 EXIST::FUNCTION: RAND_bytes_ex ? 3_0_0 EXIST::FUNCTION: +EVP_PKEY_get_default_digest_name ? 3_0_0 EXIST::FUNCTION: -- 2.39.2