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) {