Add machinery for testing TLS 1.3 cipher change synchronization.

This will be used for writing the equivalent test in TLS 1.3 to the
recent DTLS change and similar.

Change-Id: I280c3ca8f1d8e0981b6e7a499acb7eceebe43a0c
Reviewed-on: https://boringssl-review.googlesource.com/8792
Reviewed-by: Steven Valdez <svaldez@google.com>
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/ssl/test/runner/common.go b/ssl/test/runner/common.go
index e7bc9bd..8290444 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -516,6 +516,16 @@
 	// send unencrypted before ChangeCipherSpec rather than after it.
 	SendUnencryptedFinished bool
 
+	// PartialEncryptedExtensionsWithServerHello, if true, causes the TLS
+	// 1.3 server to send part of EncryptedExtensions unencrypted
+	// in the same record as ServerHello.
+	PartialEncryptedExtensionsWithServerHello bool
+
+	// PartialClientFinishedWithClientHello, if true, causes the TLS 1.3
+	// client to send part of Finished unencrypted in the same record as
+	// ClientHello.
+	PartialClientFinishedWithClientHello bool
+
 	// SendV2ClientHello causes the client to send a V2ClientHello
 	// instead of a normal ClientHello.
 	SendV2ClientHello bool
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index a357c1f..7b93313 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -257,7 +257,18 @@
 		c.writeV2Record(helloBytes)
 	} else {
 		helloBytes = hello.marshal()
-		c.writeRecord(recordTypeHandshake, helloBytes)
+		if c.config.Bugs.PartialClientFinishedWithClientHello {
+			// Include one byte of Finished. We can compute it
+			// without completing the handshake. This assumes we
+			// negotiate TLS 1.3 with no HelloRetryRequest or
+			// CertificateRequest.
+			toWrite := make([]byte, 0, len(helloBytes)+1)
+			toWrite = append(toWrite, helloBytes...)
+			toWrite = append(toWrite, typeFinished)
+			c.writeRecord(recordTypeHandshake, toWrite)
+		} else {
+			c.writeRecord(recordTypeHandshake, helloBytes)
+		}
 	}
 	c.flushHandshake()
 
@@ -657,7 +668,12 @@
 		finished.verifyData[0]++
 	}
 	hs.writeClientHash(finished.marshal())
-	c.writeRecord(recordTypeHandshake, finished.marshal())
+	if c.config.Bugs.PartialClientFinishedWithClientHello {
+		// The first byte has already been sent.
+		c.writeRecord(recordTypeHandshake, finished.marshal()[1:])
+	} else {
+		c.writeRecord(recordTypeHandshake, finished.marshal())
+	}
 	c.flushHandshake()
 
 	// Switch to application data keys.
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 50f9b7c..554eae2 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -390,7 +390,15 @@
 
 	// Send unencrypted ServerHello.
 	hs.writeServerHash(hs.hello.marshal())
-	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+	if config.Bugs.PartialEncryptedExtensionsWithServerHello {
+		helloBytes := hs.hello.marshal()
+		toWrite := make([]byte, 0, len(helloBytes)+1)
+		toWrite = append(toWrite, helloBytes...)
+		toWrite = append(toWrite, typeEncryptedExtensions)
+		c.writeRecord(recordTypeHandshake, toWrite)
+	} else {
+		c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+	}
 	c.flushHandshake()
 
 	// Compute the handshake secret.
@@ -414,7 +422,12 @@
 
 	// Send EncryptedExtensions.
 	hs.writeServerHash(encryptedExtensions.marshal())
-	c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal())
+	if config.Bugs.PartialEncryptedExtensionsWithServerHello {
+		// The first byte has already been sent.
+		c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()[1:])
+	} else {
+		c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal())
+	}
 
 	if hs.suite.flags&suitePSK == 0 {
 		if config.ClientAuth >= RequestClientCert {