Support default versions with set_{min,max}_proto_version.

Upstream makes 0 mean "min/max supported version". Match that behavior,
although call it "default" instead. It shouldn't get you TLS 1.3 until
we're ready to turn it on everywhere.

BUG=90

Change-Id: I9f122fceb701b7d4de2ff70afbc1ffdf370cb97e
Reviewed-on: https://boringssl-review.googlesource.com/11181
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index d629b8f..8454c30 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -565,19 +565,25 @@
 #define TLS1_3_DRAFT_VERSION 14
 
 /* SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
- * |version|. It returns one on success and zero if |version| is invalid. */
-OPENSSL_EXPORT int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version);
+ * |version|. If |version| is zero, the default minimum version is used. It
+ * returns one on success and zero if |version| is invalid. */
+OPENSSL_EXPORT int SSL_CTX_set_min_proto_version(SSL_CTX *ctx,
+                                                 uint16_t version);
 
 /* SSL_CTX_set_max_proto_version sets the maximum protocol version for |ctx| to
- * |version|. It returns one on success and zero if |version| is invalid. */
-OPENSSL_EXPORT int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version);
+ * |version|. If |version| is zero, the default maximum version is used. It
+ * returns one on success and zero if |version| is invalid. */
+OPENSSL_EXPORT int SSL_CTX_set_max_proto_version(SSL_CTX *ctx,
+                                                 uint16_t version);
 
 /* SSL_set_min_proto_version sets the minimum protocol version for |ssl| to
- * |version|. It returns one on success and zero if |version| is invalid. */
+ * |version|. If |version| is zero, the default minimum version is used. It
+ * returns one on success and zero if |version| is invalid. */
 OPENSSL_EXPORT int SSL_set_min_proto_version(SSL *ssl, uint16_t version);
 
 /* SSL_set_max_proto_version sets the maximum protocol version for |ssl| to
- * |version|. It returns one on success and zero if |version| is invalid. */
+ * |version|. If |version| is zero, the default maximum version is used. It
+ * returns one on success and zero if |version| is invalid. */
 OPENSSL_EXPORT int SSL_set_max_proto_version(SSL *ssl, uint16_t version);
 
 /* SSL_version returns the TLS or DTLS protocol version used by |ssl|, which is
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 8232532..6ec7d25 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -305,17 +305,12 @@
     ret->options |= SSL_OP_NO_TICKET;
   }
 
-  ret->min_version = ret->method->min_version;
-  ret->max_version = ret->method->max_version;
-
   /* Lock the SSL_CTX to the specified version, for compatibility with legacy
    * uses of SSL_METHOD. */
-  if (method->version != 0) {
-    SSL_CTX_set_max_proto_version(ret, method->version);
-    SSL_CTX_set_min_proto_version(ret, method->version);
-  } else if (!method->method->is_dtls) {
-    /* TODO(svaldez): Enable TLS 1.3 by default once fully implemented. */
-    SSL_CTX_set_max_proto_version(ret, TLS1_2_VERSION);
+  if (!SSL_CTX_set_max_proto_version(ret, method->version) ||
+      !SSL_CTX_set_min_proto_version(ret, method->version)) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    goto err2;
   }
 
   return ret;
@@ -949,20 +944,44 @@
   return SSL_ERROR_SYSCALL;
 }
 
+static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+                           uint16_t version) {
+  if (version == 0) {
+    *out = method->min_version;
+    return 1;
+  }
+
+  return method->version_from_wire(out, version);
+}
+
+static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+                           uint16_t version) {
+  if (version == 0) {
+    *out = method->max_version;
+    /* TODO(svaldez): Enable TLS 1.3 by default once fully implemented. */
+    if (*out > TLS1_2_VERSION) {
+      *out = TLS1_2_VERSION;
+    }
+    return 1;
+  }
+
+  return method->version_from_wire(out, version);
+}
+
 int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) {
-  return ctx->method->version_from_wire(&ctx->min_version, version);
+  return set_min_version(ctx->method, &ctx->min_version, version);
 }
 
 int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) {
-  return ctx->method->version_from_wire(&ctx->max_version, version);
+  return set_max_version(ctx->method, &ctx->max_version, version);
 }
 
 int SSL_set_min_proto_version(SSL *ssl, uint16_t version) {
-  return ssl->method->version_from_wire(&ssl->min_version, version);
+  return set_min_version(ssl->method, &ssl->min_version, version);
 }
 
 int SSL_set_max_proto_version(SSL *ssl, uint16_t version) {
-  return ssl->method->version_from_wire(&ssl->max_version, version);
+  return set_max_version(ssl->method, &ssl->max_version, version);
 }
 
 uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index a90e993..48dbbac 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -2106,6 +2106,19 @@
     return false;
   }
 
+  if (!SSL_CTX_set_max_proto_version(ctx.get(), 0) ||
+      !SSL_CTX_set_min_proto_version(ctx.get(), 0)) {
+    fprintf(stderr, "Could not set default TLS version.\n");
+    return false;
+  }
+
+  if (ctx->min_version != SSL3_VERSION ||
+      ctx->max_version != TLS1_2_VERSION) {
+    fprintf(stderr, "Default TLS versions were incorrect (%04x and %04x).\n",
+            ctx->min_version, ctx->max_version);
+    return false;
+  }
+
   ctx.reset(SSL_CTX_new(DTLS_method()));
   if (!ctx) {
     return false;
@@ -2131,6 +2144,19 @@
     return false;
   }
 
+  if (!SSL_CTX_set_max_proto_version(ctx.get(), 0) ||
+      !SSL_CTX_set_min_proto_version(ctx.get(), 0)) {
+    fprintf(stderr, "Could not set default DTLS version.\n");
+    return false;
+  }
+
+  if (ctx->min_version != TLS1_1_VERSION ||
+      ctx->max_version != TLS1_2_VERSION) {
+    fprintf(stderr, "Default DTLS versions were incorrect (%04x and %04x).\n",
+            ctx->min_version, ctx->max_version);
+    return false;
+  }
+
   return true;
 }