Add tests for CVE-2014-3511.

Also change MaxHandshakeRecordLength to 1 in the handshake coverage tests to
better stress the state machine.

Change-Id: I27fce2c000b3d4818fd2e9a47fb09d3f646dd1bd
Reviewed-on: https://boringssl-review.googlesource.com/1452
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index d69f09f..6c1dfcd 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -393,10 +393,15 @@
 	SendFallbackSCSV bool
 
 	// MaxHandshakeRecordLength, if non-zero, is the maximum size of a
-	// handshake record. Handshake messages will be split at the record
-	// layer.
+	// handshake record. Handshake messages will be split into multiple
+	// records at the specified size, except that the client_version will
+	// never be fragmented.
 	MaxHandshakeRecordLength int
 
+	// FragmentClientVersion will allow MaxHandshakeRecordLength to apply to
+	// the first 6 bytes of the ClientHello.
+	FragmentClientVersion bool
+
 	// RsaClientKeyExchangeVersion, if non-zero, causes the client to send a
 	// ClientKeyExchange with the specified version rather than the
 	// client_version when performing the RSA key exchange.
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 52582ad..f3e2495 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -714,6 +714,8 @@
 // c.out.Mutex <= L.
 func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
 	b := c.out.newBlock()
+	first := true
+	isClientHello := typ == recordTypeHandshake && len(data) > 0 && data[0] == typeClientHello
 	for len(data) > 0 {
 		m := len(data)
 		if m > maxPlaintext {
@@ -721,9 +723,16 @@
 		}
 		if typ == recordTypeHandshake && c.config.Bugs.MaxHandshakeRecordLength > 0 && m > c.config.Bugs.MaxHandshakeRecordLength {
 			m = c.config.Bugs.MaxHandshakeRecordLength
+			// By default, do not fragment the client_version or
+			// server_version, which are located in the first 6
+			// bytes.
+			if first && isClientHello && !c.config.Bugs.FragmentClientVersion && m < 6 {
+				m = 6
+			}
 		}
 		explicitIVLen := 0
 		explicitIVIsSeq := false
+		first = false
 
 		var cbc cbcMode
 		if c.out.version >= VersionTLS11 {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 701de81..36276be 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -383,6 +383,18 @@
 			},
 		},
 	},
+	{
+		testType: serverTest,
+		name:     "FragmentedClientVersion",
+		config: Config{
+			Bugs: ProtocolBugs{
+				MaxHandshakeRecordLength: 1,
+				FragmentClientVersion:    true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":RECORD_TOO_SMALL:",
+	},
 }
 
 func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
@@ -863,7 +875,7 @@
 	}
 	if splitHandshake {
 		suffix += "-SplitHandshakeRecords"
-		maxHandshakeRecordLength = 10
+		maxHandshakeRecordLength = 1
 	}
 
 	// Basic handshake, with resumption. Client and server.