Add min_version tests.

These tests use both APIs. This also modifies the inline version negotiation's
error codes (currently only used for DTLS) to align with SSLv23's error codes.
Note: the peer should send a protocol_version alert which is currently untested
because it's broken.

Upstream would send such an alert if TLS 1.0 was supported but not otherwise,
which is somewhat bizarre. We've actually regressed and never send the alert in
SSLv23. When version negotiation is unified, we'll get the alerts back.

Change-Id: I4c77bcef3a3cd54a039a642f189785cd34387410
Reviewed-on: https://boringssl-review.googlesource.com/2584
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 2b91f43..e3bf338 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -1703,6 +1703,94 @@
 	}
 }
 
+func addMinimumVersionTests() {
+	for i, shimVers := range tlsVersions {
+		// Assemble flags to disable all older versions on the shim.
+		var flags []string
+		for _, vers := range tlsVersions[:i] {
+			flags = append(flags, vers.flag)
+		}
+
+		for _, runnerVers := range tlsVersions {
+			protocols := []protocol{tls}
+			if runnerVers.hasDTLS && shimVers.hasDTLS {
+				protocols = append(protocols, dtls)
+			}
+			for _, protocol := range protocols {
+				suffix := shimVers.name + "-" + runnerVers.name
+				if protocol == dtls {
+					suffix += "-DTLS"
+				}
+				shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
+
+				// TODO(davidben): This should also assert on
+				// expectedLocalError to check we send an alert
+				// rather than close the connection, but the TLS
+				// code currently fails this.
+				var expectedVersion uint16
+				var shouldFail bool
+				var expectedError string
+				if runnerVers.version >= shimVers.version {
+					expectedVersion = runnerVers.version
+				} else {
+					shouldFail = true
+					expectedError = ":UNSUPPORTED_PROTOCOL:"
+				}
+
+				testCases = append(testCases, testCase{
+					protocol: protocol,
+					testType: clientTest,
+					name:     "MinimumVersion-Client-" + suffix,
+					config: Config{
+						MaxVersion: runnerVers.version,
+					},
+					flags:           flags,
+					expectedVersion: expectedVersion,
+					shouldFail:      shouldFail,
+					expectedError:   expectedError,
+				})
+				testCases = append(testCases, testCase{
+					protocol: protocol,
+					testType: clientTest,
+					name:     "MinimumVersion-Client2-" + suffix,
+					config: Config{
+						MaxVersion: runnerVers.version,
+					},
+					flags:           []string{"-min-version", shimVersFlag},
+					expectedVersion: expectedVersion,
+					shouldFail:      shouldFail,
+					expectedError:   expectedError,
+				})
+
+				testCases = append(testCases, testCase{
+					protocol: protocol,
+					testType: serverTest,
+					name:     "MinimumVersion-Server-" + suffix,
+					config: Config{
+						MaxVersion: runnerVers.version,
+					},
+					flags:           flags,
+					expectedVersion: expectedVersion,
+					shouldFail:      shouldFail,
+					expectedError:   expectedError,
+				})
+				testCases = append(testCases, testCase{
+					protocol: protocol,
+					testType: serverTest,
+					name:     "MinimumVersion-Server2-" + suffix,
+					config: Config{
+						MaxVersion: runnerVers.version,
+					},
+					flags:           []string{"-min-version", shimVersFlag},
+					expectedVersion: expectedVersion,
+					shouldFail:      shouldFail,
+					expectedError:   expectedError,
+				})
+			}
+		}
+	}
+}
+
 func addD5BugTests() {
 	testCases = append(testCases, testCase{
 		testType: serverTest,
@@ -2398,6 +2486,7 @@
 	addCBCSplittingTests()
 	addClientAuthTests()
 	addVersionNegotiationTests()
+	addMinimumVersionTests()
 	addD5BugTests()
 	addExtensionTests()
 	addResumptionVersionTests()