EVP: Add EVP_PKEY_get_default_digest_name() and use it
authorRichard Levitte <levitte@openssl.org>
Mon, 13 Jan 2020 07:49:44 +0000 (08:49 +0100)
committerRichard Levitte <levitte@openssl.org>
Thu, 23 Jan 2020 16:59:12 +0000 (17:59 +0100)
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)

crypto/evp/m_sigver.c
crypto/evp/p_lib.c
doc/man3/EVP_PKEY_get_default_digest_nid.pod
include/openssl/core_names.h
include/openssl/evp.h
util/libcrypto.num

index 79099b1e356818d57cbabb6cbe0fb9c2fa518f94..05dc46e3b19d06836ca0aefb28c24f2d0d642ec8 100644 (file)
@@ -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) {
index 016bcf93c2eb186f6a7c07e05304c437bf3c0550..2aa2aa87afd4909c2f57dd5e831eeeb16eaac40b 100644 (file)
@@ -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;
index b2098a42c28902972ab4eb7c59c5029e99d29c2b..4a4ca4cad41c7f883fcd26c2fb4dd727666d2dbd 100644 (file)
@@ -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
 
index a347d967123a0d795596aaaf241f57c2fcb4de04..195fe6ed38ad698dcbd52a699e8b199eb700ca64 100644 (file)
@@ -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"
index 57a73382e88e3f95ef9e21f5dc75f436dbb5680a..6c042d376511a789104f173d8bd08589f25e8fa0 100644 (file)
@@ -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,
index 457f968889d590b91459b26297d87da299e5c51f..d0443c2f7789a29258e227d4b942088d8d1edfcc 100644 (file)
@@ -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: