Cleaning up internal use of Signature Algorithms.
The signing logic itself still depends on pre-hashed messages and will be fixed
in later commits.
Change-Id: I901b0d99917c311653d44efa34a044bbb9f11e57
Reviewed-on: https://boringssl-review.googlesource.com/8545
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 40d9368..00eaacf 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -248,6 +248,11 @@
#define SSL_SIGN_ECDSA_SECP384R1_SHA384 0x0503
#define SSL_SIGN_ECDSA_SECP521R1_SHA512 0x0603
+/* Reserved SignatureScheme value to indicate RSA with MD5-SHA1. This will never
+ * be negotiated in TLS 1.2 and up, but is used to unify signing interfaces in
+ * older TLS versions. */
+#define SSL_SIGN_RSA_PKCS1_MD5_SHA1 0xff01
+
#define TLSEXT_MAXLEN_host_name 255
/* PSK ciphersuites from 4279 */
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 229cf1a..a55327b 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -1307,22 +1307,21 @@
goto err;
}
- const EVP_MD *md = NULL;
+ uint16_t signature_algorithm = 0;
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
- uint16_t signature_algorithm;
if (!CBS_get_u16(&server_key_exchange, &signature_algorithm)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
- if (!tls12_check_peer_sigalg(ssl, &md, &al, signature_algorithm, pkey)) {
+ if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm, pkey)) {
goto f_err;
}
ssl->s3->tmp.peer_signature_algorithm = signature_algorithm;
} else if (pkey->type == EVP_PKEY_RSA) {
- md = EVP_md5_sha1();
- } else {
- md = EVP_sha1();
+ signature_algorithm = SSL_SIGN_RSA_PKCS1_MD5_SHA1;
+ } else if (pkey->type == EVP_PKEY_EC) {
+ signature_algorithm = SSL_SIGN_ECDSA_SHA1;
}
/* The last field in |server_key_exchange| is the signature. */
@@ -1334,6 +1333,12 @@
goto f_err;
}
+ const EVP_MD *md = tls12_get_hash(signature_algorithm);
+ if (md == NULL) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ goto f_err;
+ }
int sig_ok = EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) &&
EVP_DigestVerifyUpdate(&md_ctx, ssl->s3->client_random,
SSL3_RANDOM_SIZE) &&
@@ -1816,11 +1821,10 @@
goto err;
}
- /* Select and write out the digest type in TLS 1.2. */
- const EVP_MD *md = NULL;
+ uint16_t signature_algorithm = tls1_choose_signature_algorithm(ssl);
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
- md = tls1_choose_signing_digest(ssl);
- if (!tls12_add_sigalg(ssl, &body, md)) {
+ /* Write out the digest type in TLS 1.2. */
+ if (!CBB_add_u16(&body, signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -1841,8 +1845,7 @@
* selected here. */
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_len;
- if (!ssl3_cert_verify_hash(ssl, digest, &digest_len, &md,
- ssl_private_key_type(ssl))) {
+ if (!ssl3_cert_verify_hash(ssl, digest, &digest_len, signature_algorithm)) {
goto err;
}
@@ -1850,8 +1853,8 @@
ssl3_free_handshake_buffer(ssl);
/* Sign the digest. */
- sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len, md,
- digest, digest_len);
+ sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len,
+ signature_algorithm, digest, digest_len);
} else {
assert(ssl->state == SSL3_ST_CW_CERT_VRFY_B);
sign_result =
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index da13135..e2838bf 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -1249,18 +1249,13 @@
}
/* Determine the signature algorithm. */
- const EVP_MD *md;
+ uint16_t signature_algorithm = tls1_choose_signature_algorithm(ssl);
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
- md = tls1_choose_signing_digest(ssl);
- if (!tls12_add_sigalg(ssl, &body, md)) {
+ if (!CBB_add_u16(&body, signature_algorithm)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
}
- } else if (ssl_private_key_type(ssl) == EVP_PKEY_RSA) {
- md = EVP_md5_sha1();
- } else {
- md = EVP_sha1();
}
/* Add space for the signature. */
@@ -1279,6 +1274,14 @@
unsigned digest_len = 0;
EVP_MD_CTX md_ctx;
EVP_MD_CTX_init(&md_ctx);
+
+ const EVP_MD *md = tls12_get_hash(signature_algorithm);
+ if (md == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ goto err;
+ }
+
int digest_ret =
EVP_DigestInit_ex(&md_ctx, md, NULL) &&
EVP_DigestUpdate(&md_ctx, ssl->s3->client_random, SSL3_RANDOM_SIZE) &&
@@ -1290,8 +1293,9 @@
if (!digest_ret) {
goto err;
}
- sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len, md,
- digest, digest_len);
+ sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len,
+ signature_algorithm, digest,
+ digest_len);
} else {
assert(ssl->state == SSL3_ST_SW_KEY_EXCH_B);
sign_result =
@@ -1862,7 +1866,6 @@
CBS certificate_verify, signature;
X509 *peer = ssl->session->peer;
EVP_PKEY *pkey = NULL;
- const EVP_MD *md = NULL;
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_length;
EVP_PKEY_CTX *pctx = NULL;
@@ -1897,21 +1900,26 @@
CBS_init(&certificate_verify, ssl->init_msg, n);
/* Determine the digest type if needbe. */
+ uint16_t signature_algorithm = 0;
if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
- uint16_t signature_algorithm;
if (!CBS_get_u16(&certificate_verify, &signature_algorithm)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
- if (!tls12_check_peer_sigalg(ssl, &md, &al, signature_algorithm, pkey)) {
+ if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm, pkey)) {
goto f_err;
}
ssl->s3->tmp.peer_signature_algorithm = signature_algorithm;
+ } else if (pkey->type == EVP_PKEY_RSA) {
+ signature_algorithm = SSL_SIGN_RSA_PKCS1_MD5_SHA1;
+ } else if (pkey->type == EVP_PKEY_EC) {
+ signature_algorithm = SSL_SIGN_ECDSA_SHA1;
}
/* Compute the digest. */
- if (!ssl3_cert_verify_hash(ssl, digest, &digest_length, &md, pkey->type)) {
+ if (!ssl3_cert_verify_hash(ssl, digest, &digest_length,
+ signature_algorithm)) {
goto err;
}
@@ -1934,6 +1942,14 @@
if (pctx == NULL) {
goto err;
}
+
+ const EVP_MD *md = tls12_get_hash(signature_algorithm);
+ if (md == NULL) {
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
+ goto f_err;
+ }
+
int sig_ok = EVP_PKEY_verify_init(pctx) &&
EVP_PKEY_CTX_set_signature_md(pctx, md) &&
EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
diff --git a/ssl/internal.h b/ssl/internal.h
index 1c87136..82ca459 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -477,8 +477,8 @@
size_t ssl_private_key_max_signature_len(SSL *ssl);
enum ssl_private_key_result_t ssl_private_key_sign(
- SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md,
- const uint8_t *in, size_t in_len);
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint16_t signature_algorithm, const uint8_t *in, size_t in_len);
enum ssl_private_key_result_t ssl_private_key_sign_complete(
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out);
@@ -997,12 +997,12 @@
/* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes
* pointed to by |out| and writes the number of bytes to |*out_len|. |out| must
- * have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up, |*out_md| is used
- * for the hash function, otherwise the hash function depends on |pkey_type|
- * and is written to |*out_md|. It returns one on success and zero on
- * failure. */
+ * have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up,
+ * |signature_algorithm| is used to determine the hash function, otherwise the
+ * hash function depends on the private key type. It returns one on success and
+ * zero on failure. */
int ssl3_cert_verify_hash(SSL *ssl, uint8_t *out, size_t *out_len,
- const EVP_MD **out_md, int pkey_type);
+ uint16_t signature_algorithm);
int ssl3_send_finished(SSL *ssl, int a, int b);
int ssl3_supports_cipher(const SSL_CIPHER *cipher);
@@ -1136,11 +1136,6 @@
size_t ticket_len, const uint8_t *session_id,
size_t session_id_len);
-/* tls12_add_sigalg picks the SignatureScheme corresponding to |ssl|'s private
- * key and |md| and writes it to |out|. It returns one on success and zero on
- * failure. */
-int tls12_add_sigalg(SSL *ssl, CBB *out, const EVP_MD *md);
-
/* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
* it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
* one on success and zero on failure. */
@@ -1207,17 +1202,20 @@
uint32_t ssl_get_algorithm_prf(const SSL *ssl);
int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *sigalgs);
-/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key
- * based on the peer's preferences the digests supported. */
-const EVP_MD *tls1_choose_signing_digest(SSL *ssl);
+/* tls1_choose_signature_algorithm returns a signature algorithm for use with
+ * |ssl|'s private key based on the peer's preferences the digests supported. */
+uint16_t tls1_choose_signature_algorithm(SSL *ssl);
size_t tls12_get_psigalgs(SSL *ssl, const uint16_t **psigs);
+/* tls12_get_hash returns the EVP_MD corresponding to the TLS signature
+ * algorithm |sigalg|. It returns NULL if the type is unknown. */
+const EVP_MD *tls12_get_hash(uint16_t sigalg);
+
/* tls12_check_peer_sigalg checks that |signature_algorithm| is consistent with
- * the |pkey| and |ssl|'s sent, supported signature algorithms and, if so,
- * writes the relevant digest into |*out_md| and returns 1. Otherwise it
- * returns 0 and writes an alert into |*out_alert|. */
-int tls12_check_peer_sigalg(SSL *ssl, const EVP_MD **out_md, int *out_alert,
+ * the |pkey| and |ssl|'s sent, supported signature algorithms and returns 1.
+ * Otherwise it returns 0 and writes an alert into |*out_alert|. */
+int tls12_check_peer_sigalg(SSL *ssl, int *out_alert,
uint16_t signature_algorithm, EVP_PKEY *pkey);
void ssl_set_client_disabled(SSL *ssl);
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 1f6f2d3..8dee4d8 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -469,7 +469,7 @@
combined_tls_hash_fits_in_max);
int ssl3_cert_verify_hash(SSL *ssl, uint8_t *out, size_t *out_len,
- const EVP_MD **out_md, int pkey_type) {
+ uint16_t signature_algorithm) {
/* For TLS v1.2 send signature algorithm and signature using
* agreed digest and cached handshake records. Otherwise, use
* SHA1 or MD5 + SHA1 depending on key type. */
@@ -477,8 +477,13 @@
EVP_MD_CTX mctx;
unsigned len;
+ const EVP_MD *md = tls12_get_hash(signature_algorithm);
+ if (md == NULL) {
+ return 0;
+ }
+
EVP_MD_CTX_init(&mctx);
- if (!EVP_DigestInit_ex(&mctx, *out_md, NULL) ||
+ if (!EVP_DigestInit_ex(&mctx, md, NULL) ||
!EVP_DigestUpdate(&mctx, ssl->s3->handshake_buffer->data,
ssl->s3->handshake_buffer->length) ||
!EVP_DigestFinal(&mctx, out, &len)) {
@@ -487,20 +492,18 @@
return 0;
}
*out_len = len;
- } else if (pkey_type == EVP_PKEY_RSA) {
+ } else if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
if (ssl->s3->enc_method->cert_verify_mac(ssl, NID_md5, out) == 0 ||
ssl->s3->enc_method->cert_verify_mac(ssl, NID_sha1,
out + MD5_DIGEST_LENGTH) == 0) {
return 0;
}
*out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
- *out_md = EVP_md5_sha1();
- } else if (pkey_type == EVP_PKEY_EC) {
+ } else if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) {
if (ssl->s3->enc_method->cert_verify_mac(ssl, NID_sha1, out) == 0) {
return 0;
}
*out_len = SHA_DIGEST_LENGTH;
- *out_md = EVP_sha1();
} else {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index c17d2da..66e73b4 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -365,8 +365,13 @@
}
enum ssl_private_key_result_t ssl_private_key_sign(
- SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const EVP_MD *md,
- const uint8_t *in, size_t in_len) {
+ SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
+ uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
+ const EVP_MD *md = tls12_get_hash(signature_algorithm);
+ if (md == NULL) {
+ return ssl_private_key_failure;
+ }
+
if (ssl->cert->key_method != NULL) {
return ssl->cert->key_method->sign(ssl, out, out_len, max_out, md, in,
in_len);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 4f80865..e17d465 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -518,16 +518,15 @@
sizeof(kDefaultSignatureAlgorithms[0]);
}
-static int tls12_get_pkey_type(uint16_t sig_alg);
-static const EVP_MD *tls12_get_hash(uint16_t sig_alg);
+static int tls12_get_pkey_type(uint16_t sigalg);
-int tls12_check_peer_sigalg(SSL *ssl, const EVP_MD **out_md, int *out_alert,
- uint16_t signature_algorithm, EVP_PKEY *pkey) {
+int tls12_check_peer_sigalg(SSL *ssl, int *out_alert,
+ uint16_t sigalg, EVP_PKEY *pkey) {
const uint16_t *sent_sigs;
size_t sent_sigslen, i;
/* Check key type is consistent with signature */
- if (pkey->type != tls12_get_pkey_type(signature_algorithm)) {
+ if (pkey->type != tls12_get_pkey_type(sigalg)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
@@ -536,7 +535,7 @@
/* Check signature matches a type we sent */
sent_sigslen = tls12_get_psigalgs(ssl, &sent_sigs);
for (i = 0; i < sent_sigslen; i++) {
- if (signature_algorithm == sent_sigs[i]) {
+ if (sigalg == sent_sigs[i]) {
break;
}
}
@@ -547,13 +546,6 @@
return 0;
}
- *out_md = tls12_get_hash(signature_algorithm);
- if (*out_md == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_DIGEST);
- *out_alert = SSL_AD_ILLEGAL_PARAMETER;
- return 0;
- }
-
return 1;
}
@@ -2528,44 +2520,12 @@
return ret;
}
-/* Tables to translate from NIDs to TLS v1.2 ids
- *
- * TODO(svaldez): Remove decomposition of SignatureAlgorithm IDs. */
-typedef struct {
- int pkey_type;
- int md_type;
- uint16_t id;
-} tls12_lookup;
-
-static const tls12_lookup kTLS12SignatureAlgorithmIDs[] = {
- {EVP_PKEY_RSA, NID_sha512, SSL_SIGN_RSA_PKCS1_SHA512},
- {EVP_PKEY_EC, NID_sha512, SSL_SIGN_ECDSA_SECP521R1_SHA512},
- {EVP_PKEY_RSA, NID_sha384, SSL_SIGN_RSA_PKCS1_SHA384},
- {EVP_PKEY_EC, NID_sha384, SSL_SIGN_ECDSA_SECP384R1_SHA384},
- {EVP_PKEY_RSA, NID_sha256, SSL_SIGN_RSA_PKCS1_SHA256},
- {EVP_PKEY_EC, NID_sha256, SSL_SIGN_ECDSA_SECP256R1_SHA256},
- {EVP_PKEY_RSA, NID_sha1, SSL_SIGN_RSA_PKCS1_SHA1},
- {EVP_PKEY_EC, NID_sha1, SSL_SIGN_ECDSA_SHA1},
-};
-
-int tls12_add_sigalg(SSL *ssl, CBB *out, const EVP_MD *md) {
- int pkey_type = ssl_private_key_type(ssl);
- int md_type = EVP_MD_type(md);
-
- size_t i;
- for (i = 0; i < sizeof(kTLS12SignatureAlgorithmIDs) / sizeof(tls12_lookup);
- i++) {
- if (kTLS12SignatureAlgorithmIDs[i].pkey_type == pkey_type &&
- kTLS12SignatureAlgorithmIDs[i].md_type == md_type) {
- return CBB_add_u16(out, kTLS12SignatureAlgorithmIDs[i].id);
- }
+const EVP_MD *tls12_get_hash(uint16_t sigalg) {
+ if (sigalg == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
+ return EVP_md5_sha1();
}
- return 0;
-}
-
-static const EVP_MD *tls12_get_hash(uint16_t sig_alg) {
- switch (sig_alg >> 8) {
+ switch (sigalg >> 8) {
case TLSEXT_hash_sha1:
return EVP_sha1();
@@ -2584,9 +2544,9 @@
}
/* tls12_get_pkey_type returns the EVP_PKEY type corresponding to TLS signature
- * algorithm |sig_alg|. It returns -1 if the type is unknown. */
-static int tls12_get_pkey_type(uint16_t sig_alg) {
- switch (sig_alg & 0xff) {
+ * algorithm |sigalg|. It returns -1 if the type is unknown. */
+static int tls12_get_pkey_type(uint16_t sigalg) {
+ switch (sigalg & 0xff) {
case TLSEXT_signature_rsa:
return EVP_PKEY_RSA;
@@ -2643,11 +2603,20 @@
return 1;
}
-const EVP_MD *tls1_choose_signing_digest(SSL *ssl) {
+uint16_t tls1_choose_signature_algorithm(SSL *ssl) {
CERT *cert = ssl->cert;
int type = ssl_private_key_type(ssl);
size_t i, j;
+ /* 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 (type == EVP_PKEY_RSA) {
+ return SSL_SIGN_RSA_PKCS1_MD5_SHA1;
+ }
+ return SSL_SIGN_ECDSA_SHA1;
+ }
+
static const int kDefaultDigestList[] = {NID_sha256, NID_sha384, NID_sha512,
NID_sha1};
@@ -2662,19 +2631,25 @@
for (i = 0; i < num_digest_nids; i++) {
const int digest_nid = digest_nids[i];
for (j = 0; j < cert->peer_sigalgslen; j++) {
- const EVP_MD *md = tls12_get_hash(cert->peer_sigalgs[j]);
- if (md == NULL ||
- digest_nid != EVP_MD_type(md) ||
- tls12_get_pkey_type(cert->peer_sigalgs[j]) != type) {
+ uint16_t signature_algorithm = cert->peer_sigalgs[j];
+ /* SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal value and should never be
+ * negotiated. */
+ if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
continue;
}
-
- return md;
+ const EVP_MD *md = tls12_get_hash(signature_algorithm);
+ if (md != NULL && EVP_MD_type(md) == digest_nid &&
+ tls12_get_pkey_type(signature_algorithm) == type) {
+ return signature_algorithm;
+ }
}
}
/* If no suitable digest may be found, default to SHA-1. */
- return EVP_sha1();
+ if (type == EVP_PKEY_RSA) {
+ return SSL_SIGN_RSA_PKCS1_SHA1;
+ }
+ return SSL_SIGN_ECDSA_SHA1;
}
int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {