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);
};