Clean up s23_srvr.c.

ssl23_get_client_hello has lots of remnants of SSLv2 support and remnants of an
even older SSL_OP_NON_EXPORT_FIRST option (see upstream's
d92f0bb6e9ed94ac0c3aa0c939f2565f2ed95935) which complicates the logic.

Split it into three states and move V2ClientHello parsing into its own
function. Port it to CBS and CBB to give bounds checks on the V2ClientHello
parse.

This fixes a minor bug where, if the SSL_accept call in ssl23_get_client_hello
failed, cb would not be NULL'd and SSL_CB_ACCEPT_LOOP would get reported an
extra time.

It also unbreaks the invariant between s->packet, s->packet_length,
s->s3->rbuf.buf, and s->s3->rbuf.offset at the point the switch, although this
was of no consequence because the first ssl3_read_n call passes extend = 0
which resets s->packet and s->packet_length.

It also makes us tolerant to major version bumps in the ClientHello. Add tests
for TLS tolerance of both minor and major version bumps as well as the HTTP
request error codes.

Change-Id: I948337f4dc483f4ebe1742d3eba53b045b260257
Reviewed-on: https://boringssl-review.googlesource.com/1455
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 8859db8..ed60a3b 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -410,6 +410,10 @@
 	// RenewTicketOnResume causes the server to renew the session ticket and
 	// send a NewSessionTicket message during an abbreviated handshake.
 	RenewTicketOnResume bool
+
+	// SendClientVersion, if non-zero, causes the client to send a different
+	// TLS version in the ClientHello than the maximum supported version.
+	SendClientVersion uint16
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 9d2c1fa..fa84074 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -52,6 +52,10 @@
 		duplicateExtension:  c.config.Bugs.DuplicateExtension,
 	}
 
+	if c.config.Bugs.SendClientVersion != 0 {
+		hello.vers = c.config.Bugs.SendClientVersion
+	}
+
 	possibleCipherSuites := c.config.cipherSuites()
 	hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
 
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 2addab1..57bcf87 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -85,6 +85,9 @@
 	// resumeSession controls whether a second connection should be tested
 	// which resumes the first session.
 	resumeSession bool
+	// sendPrefix sends a prefix on the socket before actually performing a
+	// handshake.
+	sendPrefix string
 	// flags, if not empty, contains a list of command-line flags that will
 	// be passed to the shim program.
 	flags []string
@@ -382,9 +385,79 @@
 		shouldFail:    true,
 		expectedError: ":RECORD_TOO_SMALL:",
 	},
+	{
+		testType: serverTest,
+		name:     "MinorVersionTolerance",
+		config: Config{
+			Bugs: ProtocolBugs{
+				SendClientVersion: 0x03ff,
+			},
+		},
+		expectedVersion: VersionTLS12,
+	},
+	{
+		testType: serverTest,
+		name:     "MajorVersionTolerance",
+		config: Config{
+			Bugs: ProtocolBugs{
+				SendClientVersion: 0x0400,
+			},
+		},
+		expectedVersion: VersionTLS12,
+	},
+	{
+		testType: serverTest,
+		name:     "VersionTooLow",
+		config: Config{
+			Bugs: ProtocolBugs{
+				SendClientVersion: 0x0200,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNSUPPORTED_PROTOCOL:",
+	},
+	{
+		testType:      serverTest,
+		name:          "HttpGET",
+		sendPrefix:    "GET / HTTP/1.0\n",
+		shouldFail:    true,
+		expectedError: ":HTTP_REQUEST:",
+	},
+	{
+		testType:      serverTest,
+		name:          "HttpPOST",
+		sendPrefix:    "POST / HTTP/1.0\n",
+		shouldFail:    true,
+		expectedError: ":HTTP_REQUEST:",
+	},
+	{
+		testType:      serverTest,
+		name:          "HttpHEAD",
+		sendPrefix:    "HEAD / HTTP/1.0\n",
+		shouldFail:    true,
+		expectedError: ":HTTP_REQUEST:",
+	},
+	{
+		testType:      serverTest,
+		name:          "HttpPUT",
+		sendPrefix:    "PUT / HTTP/1.0\n",
+		shouldFail:    true,
+		expectedError: ":HTTP_REQUEST:",
+	},
+	{
+		testType:      serverTest,
+		name:          "HttpCONNECT",
+		sendPrefix:    "CONNECT www.google.com:443 HTTP/1.0\n",
+		shouldFail:    true,
+		expectedError: ":HTTPS_PROXY_REQUEST:",
+	},
 }
 
 func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
+	if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
+		return err
+	}
+
 	var tlsConn *Conn
 	if test.testType == clientTest {
 		tlsConn = Server(conn, config)
@@ -991,7 +1064,7 @@
 	// Client sends a V2ClientHello.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
-		name:     "SendV2ClientHello",
+		name:     "SendV2ClientHello" + suffix,
 		config: Config{
 			// Choose a cipher suite that does not involve
 			// elliptic curves, so no extensions are