Add EVP_PKEY_supports_digest.

This is intended for TLS client auth with Windows CAPI- and CNG-backed keys
which implement sign over sign_raw and do not support all hash functions. Only
plumbed through RSA for now.

Change-Id: Ica42e7fb026840f817a169da9372dda226f7d6fd
Reviewed-on: https://boringssl-review.googlesource.com/2250
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
index c7c4ffb..ab84b48 100644
--- a/crypto/evp/evp.c
+++ b/crypto/evp/evp.c
@@ -124,6 +124,13 @@
   return 0;
 }
 
+int EVP_PKEY_supports_digest(const EVP_PKEY *pkey, const EVP_MD *md) {
+  if (pkey->ameth && pkey->ameth->pkey_supports_digest) {
+    return pkey->ameth->pkey_supports_digest(pkey, md);
+  }
+  return 1;
+}
+
 int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
   if (a->type != b->type) {
     return -1;
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index ff310e9..2b0f608 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -106,6 +106,12 @@
    * custom implementations which do not expose key material and parameters.*/
   int (*pkey_opaque)(const EVP_PKEY *pk);
 
+  /* pkey_supports_digest returns one if |pkey| supports digests of
+   * type |md|. This is intended for use with EVP_PKEYs backing custom
+   * implementations which can't sign all digests. If null, it is
+   * assumed that all digests are supported. */
+  int (*pkey_supports_digest)(const EVP_PKEY *pkey, const EVP_MD *md);
+
   int (*pkey_size)(const EVP_PKEY *pk);
   int (*pkey_bits)(const EVP_PKEY *pk);
 
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index a423fb8..48a175b 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -555,6 +555,7 @@
   eckey_priv_print,
 
   eckey_opaque,
+  0 /* pkey_supports_digest */,
 
   int_ec_size,
   ec_bits,
diff --git a/crypto/evp/p_hmac_asn1.c b/crypto/evp/p_hmac_asn1.c
index 06ba0e5..8aa6676 100644
--- a/crypto/evp/p_hmac_asn1.c
+++ b/crypto/evp/p_hmac_asn1.c
@@ -80,7 +80,7 @@
     "HMAC",              "OpenSSL HMAC method", 0 /* pub_decode */,
     0 /* pub_encode */,  0 /* pub_cmp */,       0 /* pub_print */,
     0 /*priv_decode */,  0 /* priv_encode */,   0 /* priv_print */,
-    0 /* pkey_opaque */,
+    0 /* pkey_opaque */, 0 /* pkey_supports_digest */,
     hmac_size,           0 /* pkey_bits */,     0 /* param_decode */,
     0 /* param_encode*/, 0 /* param_missing*/,  0 /* param_copy*/,
     0 /* param_cmp*/,    0 /* param_print*/,    0 /* sig_print*/,
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 9c88512..f478d50 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -153,6 +153,10 @@
   return RSA_is_opaque(pkey->pkey.rsa);
 }
 
+static int rsa_supports_digest(const EVP_PKEY *pkey, const EVP_MD *md) {
+  return RSA_supports_digest(pkey->pkey.rsa, md);
+}
+
 static int int_rsa_size(const EVP_PKEY *pkey) {
   return RSA_size(pkey->pkey.rsa);
 }
@@ -683,6 +687,7 @@
   rsa_priv_print,
 
   rsa_opaque,
+  rsa_supports_digest,
 
   int_rsa_size,
   rsa_bits,
diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c
index 147de19..1ea5fef 100644
--- a/crypto/rsa/rsa.c
+++ b/crypto/rsa/rsa.c
@@ -260,6 +260,13 @@
   return rsa->meth && (rsa->meth->flags & RSA_FLAG_OPAQUE);
 }
 
+int RSA_supports_digest(const RSA *rsa, const EVP_MD *md) {
+  if (rsa->meth && rsa->meth->supports_digest) {
+    return rsa->meth->supports_digest(rsa, md);
+  }
+  return 1;
+}
+
 int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
                          CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) {
   return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_RSA, argl, argp, new_func,
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 9e4920a..a760386 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -94,6 +94,12 @@
  * an error to attempt to duplicate, export, or compare an opaque key. */
 OPENSSL_EXPORT int EVP_PKEY_is_opaque(const EVP_PKEY *pkey);
 
+/* EVP_PKEY_supports_digest returns one if |pkey| supports digests of
+ * type |md|. This is intended for use with EVP_PKEYs backing custom
+ * implementations which can't sign all digests. */
+OPENSSL_EXPORT int EVP_PKEY_supports_digest(const EVP_PKEY *pkey,
+                                            const EVP_MD *md);
+
 /* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if
  * not and a negative number on error.
  *
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
index 16683ce..a545734 100644
--- a/include/openssl/rsa.h
+++ b/include/openssl/rsa.h
@@ -259,9 +259,13 @@
 OPENSSL_EXPORT unsigned RSA_size(const RSA *rsa);
 
 /* RSA_is_opaque returns one if |rsa| is opaque and doesn't expose its key
- * material. Otherwise it return zero. */
+ * material. Otherwise it returns zero. */
 OPENSSL_EXPORT int RSA_is_opaque(const RSA *rsa);
 
+/* RSA_supports_digest returns one if |rsa| supports signing digests
+ * of type |md|. Otherwise it returns zero. */
+OPENSSL_EXPORT int RSA_supports_digest(const RSA *rsa, const EVP_MD *md);
+
 /* RSAPublicKey_dup allocates a fresh |RSA| and copies the private key from
  * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */
 OPENSSL_EXPORT RSA *RSAPublicKey_dup(const RSA *rsa);
@@ -410,6 +414,10 @@
   int flags;
 
   int (*keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+
+  /* supports_digest returns one if |rsa| supports digests of type
+   * |md|. If null, it is assumed that all digests are supported. */
+  int (*supports_digest)(const RSA *rsa, const EVP_MD *md);
 };