aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2020-01-13 08:49:44 +0100
committerRichard Levitte <levitte@openssl.org>2020-01-23 17:59:12 +0100
commitead0d2347a348f0916d6d25818d16d702f1d1156 (patch)
tree46ec463c875a8f05e9f5af28d56bea142cab0895
parentc24937d5e71a990763f227be229ad41aab44728f (diff)
downloadopenssl-ead0d2347a348f0916d6d25818d16d702f1d1156.zip
openssl-ead0d2347a348f0916d6d25818d16d702f1d1156.tar.gz
openssl-ead0d2347a348f0916d6d25818d16d702f1d1156.tar.bz2
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 <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10824)
-rw-r--r--crypto/evp/m_sigver.c46
-rw-r--r--crypto/evp/p_lib.c71
-rw-r--r--doc/man3/EVP_PKEY_get_default_digest_nid.pod34
-rw-r--r--include/openssl/core_names.h2
-rw-r--r--include/openssl/evp.h2
-rw-r--r--util/libcrypto.num1
6 files changed, 121 insertions, 35 deletions
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index 79099b1..05dc46e 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 016bcf9..2aa2aa8 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 b2098a4..4a4ca4c 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 <openssl/evp.h>
+
+ 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<pnid> to the default
-message digest NID for the public key signature operations associated with key
-B<pkey>. Note that some signature algorithms (i.e. Ed25519 and Ed448) do not use
-a digest during signing. In this case B<pnid> 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<pkey> into I<mdname>, up to at most I<mdname_sz> bytes including the
+ending NUL byte.
+
+EVP_PKEY_get_default_digest_nid() sets I<pnid> to the default message
+digest NID for the public key signature operations associated with key
+I<pkey>. Note that some signature algorithms (i.e. Ed25519 and Ed448)
+do not use a digest during signing. In this case I<pnid> will be set
+to NID_undef. This function is only reliable for legacy keys, which
+are keys with a B<EVP_PKEY_ASN1_METHOD>; these keys have typically
+been loaded from engines, or created with L<EVP_PKEY_assign_RSA(3)> 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 a347d96..195fe6e 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 57a7338..6c042d3 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 457f968..d0443c2 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: