Teach bssl server about -max-version and -min-version.

Change-Id: Ifbfae883638b35bb274f2002bc53fbba77c7aa85
Reviewed-on: https://boringssl-review.googlesource.com/8821
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/tool/client.cc b/tool/client.cc
index 8851c44..c26a917 100644
--- a/tool/client.cc
+++ b/tool/client.cc
@@ -105,27 +105,6 @@
   return pkey;
 }
 
-static bool VersionFromString(uint16_t *out_version,
-                              const std::string& version) {
-  if (version == "ssl3") {
-    *out_version = SSL3_VERSION;
-    return true;
-  } else if (version == "tls1" || version == "tls1.0") {
-    *out_version = TLS1_VERSION;
-    return true;
-  } else if (version == "tls1.1") {
-    *out_version = TLS1_1_VERSION;
-    return true;
-  } else if (version == "tls1.2") {
-    *out_version = TLS1_2_VERSION;
-    return true;
-  } else if (version == "tls1.3") {
-    *out_version = TLS1_3_VERSION;
-    return true;
-  }
-  return false;
-}
-
 static int NextProtoSelectCallback(SSL* ssl, uint8_t** out, uint8_t* outlen,
                                    const uint8_t* in, unsigned inlen, void* arg) {
   *out = reinterpret_cast<uint8_t *>(arg);
diff --git a/tool/server.cc b/tool/server.cc
index 14f37a4..e0aeb13 100644
--- a/tool/server.cc
+++ b/tool/server.cc
@@ -31,6 +31,14 @@
      "An OpenSSL-style cipher suite string that configures the offered ciphers",
     },
     {
+     "-max-version", kOptionalArgument,
+     "The maximum acceptable protocol version",
+    },
+    {
+     "-min-version", kOptionalArgument,
+     "The minimum acceptable protocol version",
+    },
+    {
       "-key", kOptionalArgument,
       "Private-key file to use (default is server.pem)",
     },
@@ -118,6 +126,26 @@
     return false;
   }
 
+  if (args_map.count("-max-version") != 0) {
+    uint16_t version;
+    if (!VersionFromString(&version, args_map["-max-version"])) {
+      fprintf(stderr, "Unknown protocol version: '%s'\n",
+              args_map["-max-version"].c_str());
+      return false;
+    }
+    SSL_CTX_set_max_version(ctx, version);
+  }
+
+  if (args_map.count("-min-version") != 0) {
+    uint16_t version;
+    if (!VersionFromString(&version, args_map["-min-version"])) {
+      fprintf(stderr, "Unknown protocol version: '%s'\n",
+              args_map["-min-version"].c_str());
+      return false;
+    }
+    SSL_CTX_set_min_version(ctx, version);
+  }
+
   if (args_map.count("-ocsp-response") != 0 &&
       !LoadOCSPResponse(ctx, args_map["-ocsp-response"].c_str())) {
     fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
diff --git a/tool/transport_common.cc b/tool/transport_common.cc
index eff8e75..ed1bc0f 100644
--- a/tool/transport_common.cc
+++ b/tool/transport_common.cc
@@ -181,6 +181,26 @@
   return ok;
 }
 
+bool VersionFromString(uint16_t *out_version, const std::string &version) {
+  if (version == "ssl3") {
+    *out_version = SSL3_VERSION;
+    return true;
+  } else if (version == "tls1" || version == "tls1.0") {
+    *out_version = TLS1_VERSION;
+    return true;
+  } else if (version == "tls1.1") {
+    *out_version = TLS1_1_VERSION;
+    return true;
+  } else if (version == "tls1.2") {
+    *out_version = TLS1_2_VERSION;
+    return true;
+  } else if (version == "tls1.3") {
+    *out_version = TLS1_3_VERSION;
+    return true;
+  }
+  return false;
+}
+
 void PrintConnectionInfo(const SSL *ssl) {
   const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
 
diff --git a/tool/transport_common.h b/tool/transport_common.h
index a57a916..7595f45 100644
--- a/tool/transport_common.h
+++ b/tool/transport_common.h
@@ -31,6 +31,8 @@
 // It returns true on success and false otherwise.
 bool Accept(int *out_sock, const std::string &port);
 
+bool VersionFromString(uint16_t *out_version, const std::string &version);
+
 void PrintConnectionInfo(const SSL *ssl);
 
 bool SocketSetNonBlocking(int sock, bool is_non_blocking);