SSL_apply_handback: check that SSL version is valid.
Along the way, check the version against the cipher to make sure the
combination is possible.
(Found by fuzzing: a bad version trips an assert.)
Change-Id: Ib0a284fd5fd9b7ba5ceba63aa6224966282a2cb7
Reviewed-on: https://boringssl-review.googlesource.com/27265
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/handoff.cc b/ssl/handoff.cc
index 89fca2f..5ba1d11 100644
--- a/ssl/handoff.cc
+++ b/ssl/handoff.cc
@@ -252,10 +252,16 @@
}
ssl->version = session->ssl_version;
+ s3->have_version = true;
+ if (!ssl_method_supports_version(ssl->method, ssl->version) ||
+ session->cipher != s3->hs->new_cipher ||
+ ssl_protocol_version(ssl) < SSL_CIPHER_get_min_version(session->cipher) ||
+ SSL_CIPHER_get_max_version(session->cipher) < ssl_protocol_version(ssl)) {
+ return false;
+ }
ssl->do_handshake = ssl_server_handshake;
ssl->server = true;
- s3->have_version = true;
s3->hs->state = CBS_len(&transcript) == 0 ? state12_finish_server_handshake
: state12_read_client_certificate;
s3->session_reused = session_reused;
diff --git a/ssl/internal.h b/ssl/internal.h
index 9840aa4..be1b9dd 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -378,6 +378,10 @@
// ssl_supports_version returns whether |hs| supports |version|.
bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version);
+// ssl_method_supports_version returns whether |method| supports |version|.
+bool ssl_method_supports_version(const SSL_PROTOCOL_METHOD *method,
+ uint16_t version);
+
// ssl_add_supported_versions writes the supported versions of |hs| to |cbb|, in
// decreasing preference order.
bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb);
diff --git a/ssl/ssl_versions.cc b/ssl/ssl_versions.cc
index 0e28620..a09efa1 100644
--- a/ssl/ssl_versions.cc
+++ b/ssl/ssl_versions.cc
@@ -81,8 +81,8 @@
}
}
-static bool method_supports_version(const SSL_PROTOCOL_METHOD *method,
- uint16_t version) {
+bool ssl_method_supports_version(const SSL_PROTOCOL_METHOD *method,
+ uint16_t version) {
const uint16_t *versions;
size_t num_versions;
get_method_versions(method, &versions, &num_versions);
@@ -164,7 +164,7 @@
static bool set_version_bound(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
uint16_t version) {
if (!api_version_to_wire(&version, version) ||
- !method_supports_version(method, version) ||
+ !ssl_method_supports_version(method, version) ||
!ssl_protocol_version_from_wire(out, version)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
return false;
@@ -292,7 +292,7 @@
bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
SSL *const ssl = hs->ssl;
uint16_t protocol_version;
- if (!method_supports_version(ssl->method, version) ||
+ if (!ssl_method_supports_version(ssl->method, version) ||
!ssl_protocol_version_from_wire(&protocol_version, version) ||
hs->min_version > protocol_version ||
protocol_version > hs->max_version) {