Widen SSL_PRIVATE_KEY_METHOD types to include the curve name.
This makes custom private keys and EVP_PKEYs symmetric again. There is
no longer a requirement that the caller pre-filter the configured
signing prefs.
Also switch EVP_PKEY_RSA to NID_rsaEncryption. These are identical, but
if some key types are to be NIDs, we should make them all NIDs.
Change-Id: I82ea41c27a3c57f4c4401ffe1ccad406783e4c64
Reviewed-on: https://boringssl-review.googlesource.com/8785
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 7b4b349..75ea320 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -980,8 +980,12 @@
/* SSL_PRIVATE_KEY_METHOD describes private key hooks. This is used to off-load
* signing operations to a custom, potentially asynchronous, backend. */
typedef struct ssl_private_key_method_st {
- /* type returns either |EVP_PKEY_RSA| or |EVP_PKEY_EC| to denote the type of
- * key used by |ssl|. */
+ /* type returns the type of the key used by |ssl|. For RSA keys, return
+ * |NID_rsaEncryption|. For ECDSA keys, return |NID_X9_62_prime256v1|,
+ * |NID_secp384r1|, or |NID_secp521r1|, depending on the curve.
+ *
+ * Returning |EVP_PKEY_EC| for ECDSA keys is deprecated and may result in
+ * connection failures in TLS 1.3. */
int (*type)(SSL *ssl);
/* max_signature_len returns the maximum length of a signature signed by the
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index fbf935d..7cd8265 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -1424,7 +1424,7 @@
size_t decrypt_len;
if (ssl->state == SSL3_ST_SR_KEY_EXCH_A) {
if (!ssl_has_private_key(ssl) ||
- ssl_private_key_type(ssl) != EVP_PKEY_RSA) {
+ ssl_private_key_type(ssl) != NID_rsaEncryption) {
al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE);
goto f_err;
diff --git a/ssl/internal.h b/ssl/internal.h
index be7bde2..06148f1 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -468,6 +468,10 @@
* configured and zero otherwise. */
int ssl_has_private_key(const SSL *ssl);
+/* ssl_is_ecdsa_key_type returns one if |type| is an ECDSA key type and zero
+ * otherwise. */
+int ssl_is_ecdsa_key_type(int type);
+
/* ssl_private_key_* call the corresponding function on the
* |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement
* the operation with |EVP_PKEY|. */
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index ca52233..9842d96 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1905,10 +1905,11 @@
uint32_t mask_a = 0;
if (ssl->cert->x509 != NULL && ssl_has_private_key(ssl)) {
- if (ssl_private_key_type(ssl) == EVP_PKEY_RSA) {
+ int type = ssl_private_key_type(ssl);
+ if (type == NID_rsaEncryption) {
mask_k |= SSL_kRSA;
mask_a |= SSL_aRSA;
- } else if (ssl_private_key_type(ssl) == EVP_PKEY_EC) {
+ } else if (ssl_is_ecdsa_key_type(type)) {
/* An ECC certificate may be usable for ECDSA cipher suites depending on
* the key usage extension and on the client's group preferences. */
X509 *x = ssl->cert->x509;
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index fec5d46..9678493 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -400,11 +400,32 @@
return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL;
}
+int ssl_is_ecdsa_key_type(int type) {
+ switch (type) {
+ /* TODO(davidben): Remove support for |EVP_PKEY_EC| key types. */
+ case EVP_PKEY_EC:
+ case NID_X9_62_prime256v1:
+ case NID_secp384r1:
+ case NID_secp521r1:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
int ssl_private_key_type(SSL *ssl) {
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->type(ssl);
}
- return EVP_PKEY_id(ssl->cert->privatekey);
+ switch (EVP_PKEY_id(ssl->cert->privatekey)) {
+ case EVP_PKEY_RSA:
+ return NID_rsaEncryption;
+ case EVP_PKEY_EC:
+ return EC_GROUP_get_curve_name(
+ EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(ssl->cert->privatekey)));
+ default:
+ return NID_undef;
+ }
}
size_t ssl_private_key_max_signature_len(SSL *ssl) {
@@ -716,31 +737,28 @@
uint16_t signature_algorithm) {
const EVP_MD *md;
if (is_rsa_pkcs1(&md, signature_algorithm)) {
- return ssl_private_key_type(ssl) == EVP_PKEY_RSA;
+ return ssl_private_key_type(ssl) == NID_rsaEncryption;
}
int curve;
if (is_ecdsa(&curve, &md, signature_algorithm)) {
- if (ssl_private_key_type(ssl) != EVP_PKEY_EC) {
+ int type = ssl_private_key_type(ssl);
+ if (!ssl_is_ecdsa_key_type(type)) {
return 0;
}
- /* For non-custom keys, also check the curve matches. Custom private keys
- * must instead configure the signature algorithms accordingly. */
- if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
- ssl->cert->key_method == NULL) {
- EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->cert->privatekey);
- if (curve == NID_undef ||
- EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)) != curve) {
- return 0;
- }
+ /* Prior to TLS 1.3, ECDSA curves did not match the signature algorithm. */
+ if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return 1;
}
- return 1;
+
+ /* TODO(davidben): Remove support for EVP_PKEY_EC keys. */
+ return curve != NID_undef && (type == EVP_PKEY_EC || type == curve);
}
if (is_rsa_pss(&md, signature_algorithm)) {
if (ssl3_protocol_version(ssl) < TLS1_3_VERSION ||
- ssl_private_key_type(ssl) != EVP_PKEY_RSA) {
+ ssl_private_key_type(ssl) != NID_rsaEncryption) {
return 0;
}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 4594649..9761dc9 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2596,12 +2596,17 @@
/* Before TLS 1.2, the signature algorithm isn't negotiated as part of the
* handshake. It is fixed at MD5-SHA1 for RSA and SHA1 for ECDSA. */
if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) {
- if (ssl_private_key_type(ssl) == EVP_PKEY_RSA) {
+ int type = ssl_private_key_type(ssl);
+ if (type == NID_rsaEncryption) {
*out = SSL_SIGN_RSA_PKCS1_MD5_SHA1;
- } else {
- *out = SSL_SIGN_ECDSA_SHA1;
+ return 1;
}
- return 1;
+ if (ssl_is_ecdsa_key_type(type)) {
+ *out = SSL_SIGN_ECDSA_SHA1;
+ return 1;
+ }
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS);
+ return 0;
}
const uint16_t *sigalgs;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 3cfbeb3..c505f21 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -147,7 +147,16 @@
}
static int AsyncPrivateKeyType(SSL *ssl) {
- return EVP_PKEY_id(GetTestState(ssl)->private_key.get());
+ EVP_PKEY *key = GetTestState(ssl)->private_key.get();
+ switch (EVP_PKEY_id(key)) {
+ case EVP_PKEY_RSA:
+ return NID_rsaEncryption;
+ case EVP_PKEY_EC:
+ return EC_GROUP_get_curve_name(
+ EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key)));
+ default:
+ return NID_undef;
+ }
}
static size_t AsyncPrivateKeyMaxSignatureLen(SSL *ssl) {