Add SSL_get_server_key_exchange_hash.
This exposes the ServerKeyExchange signature hash type used in the most recent
handshake, for histogramming on the client.
BUG=549662
Change-Id: I8a4e00ac735b1ecd2c2df824112c3a0bc62332a7
Reviewed-on: https://boringssl-review.googlesource.com/6413
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/internal.h b/ssl/internal.h
index aa8c4ef..520131e 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1294,8 +1294,13 @@
const EVP_MD *tls1_choose_signing_digest(SSL *ssl);
size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs);
-int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
- CBS *cbs, EVP_PKEY *pkey);
+
+/* tls12_check_peer_sigalg checks that |hash| and |signature| are consistent
+ * with |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,
+ uint8_t hash, uint8_t signature, EVP_PKEY *pkey);
void ssl_set_client_disabled(SSL *s);
#endif /* OPENSSL_HEADER_SSL_INTERNAL_H */
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 04c06dd..843403b 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1244,9 +1244,17 @@
}
if (SSL_USE_SIGALGS(s)) {
- if (!tls12_check_peer_sigalg(&md, &al, s, &server_key_exchange, pkey)) {
+ uint8_t hash, signature;
+ if (!CBS_get_u8(&server_key_exchange, &hash) ||
+ !CBS_get_u8(&server_key_exchange, &signature)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
+ if (!tls12_check_peer_sigalg(s, &md, &al, hash, signature, pkey)) {
+ goto f_err;
+ }
+ s->s3->tmp.server_key_exchange_hash = hash;
} else if (pkey->type == EVP_PKEY_RSA) {
md = EVP_md5_sha1();
} else {
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index fad2d0a..8cfa0e6 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -2056,9 +2056,17 @@
CBS_init(&certificate_verify, s->init_msg, n);
/* Determine the digest type if needbe. */
- if (SSL_USE_SIGALGS(s) &&
- !tls12_check_peer_sigalg(&md, &al, s, &certificate_verify, pkey)) {
- goto f_err;
+ if (SSL_USE_SIGALGS(s)) {
+ uint8_t hash, signature_type;
+ if (!CBS_get_u8(&certificate_verify, &hash) ||
+ !CBS_get_u8(&certificate_verify, &signature_type)) {
+ al = SSL_AD_DECODE_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto f_err;
+ }
+ if (!tls12_check_peer_sigalg(s, &md, &al, hash, signature_type, pkey)) {
+ goto f_err;
+ }
}
/* Compute the digest. */
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 68eb4ac..16c24df 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2651,6 +2651,9 @@
}
return 1;
+
+uint8_t SSL_get_server_key_exchange_hash(const SSL *ssl) {
+ return ssl->s3->tmp.server_key_exchange_hash;
}
int SSL_clear(SSL *ssl) {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 301d49a..9a29028 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -640,16 +640,11 @@
return sizeof(tls12_sigalgs);
}
-/* tls12_check_peer_sigalg parses a SignatureAndHashAlgorithm out of |cbs|. It
- * checks it is consistent with |s|'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(const EVP_MD **out_md, int *out_alert, SSL *s,
- CBS *cbs, EVP_PKEY *pkey) {
+int tls12_check_peer_sigalg(SSL *ssl, const EVP_MD **out_md, int *out_alert,
+ uint8_t hash, uint8_t signature, EVP_PKEY *pkey) {
const uint8_t *sent_sigs;
size_t sent_sigslen, i;
int sigalg = tls12_get_sigid(pkey->type);
- uint8_t hash, signature;
/* Should never happen */
if (sigalg == -1) {
@@ -658,13 +653,6 @@
return 0;
}
- if (!CBS_get_u8(cbs, &hash) ||
- !CBS_get_u8(cbs, &signature)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
/* Check key type is consistent with signature */
if (sigalg != signature) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
@@ -681,8 +669,8 @@
return 0;
}
- if (s->server && (!tls1_check_curve_id(s, curve_id) ||
- comp_id != TLSEXT_ECPOINTFORMAT_uncompressed)) {
+ if (ssl->server && (!tls1_check_curve_id(ssl, curve_id) ||
+ comp_id != TLSEXT_ECPOINTFORMAT_uncompressed)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
@@ -690,7 +678,7 @@
}
/* Check signature matches a type we sent */
- sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
+ sent_sigslen = tls12_get_psigalgs(ssl, &sent_sigs);
for (i = 0; i < sent_sigslen; i += 2, sent_sigs += 2) {
if (hash == sent_sigs[0] && signature == sent_sigs[1]) {
break;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index fe3dd6f..07ba9f5 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1061,6 +1061,15 @@
}
}
+ if (config->expect_server_key_exchange_hash != 0 &&
+ config->expect_server_key_exchange_hash !=
+ SSL_get_server_key_exchange_hash(ssl)) {
+ fprintf(stderr, "ServerKeyExchange hash was %d, wanted %d.\n",
+ SSL_get_server_key_exchange_hash(ssl),
+ config->expect_server_key_exchange_hash);
+ return false;
+ }
+
if (!config->is_server) {
/* Clients should expect a peer certificate chain iff this was not a PSK
* cipher suite. */
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 158f082..6ab71cf 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -4026,6 +4026,19 @@
},
},
})
+
+ testCases = append(testCases, testCase{
+ name: "SigningHash-ServerKeyExchange-Verify-" + hash.name,
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ SignatureAndHashes: []signatureAndHash{
+ {signatureRSA, 42},
+ {signatureRSA, hash.id},
+ {signatureRSA, 255},
+ },
+ },
+ flags: []string{"-expect-server-key-exchange-hash", strconv.Itoa(int(hash.id))},
+ })
}
// Test that hash resolution takes the signature type into account.
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 8b540c3..50e6b23 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -141,6 +141,8 @@
{ "-mtu", &TestConfig::mtu },
{ "-export-keying-material", &TestConfig::export_keying_material },
{ "-expect-total-renegotiations", &TestConfig::expect_total_renegotiations },
+ { "-expect-server-key-exchange-hash",
+ &TestConfig::expect_server_key_exchange_hash },
};
} // namespace
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index a72d66b..9f295ae 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -100,6 +100,7 @@
bool renegotiate_freely = false;
bool renegotiate_ignore = false;
bool disable_npn = false;
+ int expect_server_key_exchange_hash = 0;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);