Change CCS_OK to EXPECT_CCS.

Now that the flag is set accurately, use it to enforce that the handshake and
CCS synchronization. If EXPECT_CCS is set, enforce that:

(a) No handshake records may be received before ChangeCipherSpec.

(b) There is no pending handshake data at the point EXPECT_CCS is set.

Change-Id: I04b228fe6a7a771cf6600b7d38aa762b2d553f08
Reviewed-on: https://boringssl-review.googlesource.com/1299
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 7319463..7b8d964 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -375,6 +375,11 @@
 	// and 1.0.1 modes, respectively.
 	EarlyChangeCipherSpec int
 
+	// FragmentAcrossChangeCipherSpec causes the implementation to fragment
+	// the Finished (or NextProto) message around the ChangeCipherSpec
+	// messages.
+	FragmentAcrossChangeCipherSpec bool
+
 	// SkipNewSessionTicket causes the server to skip sending the
 	// NewSessionTicket message despite promising to in ServerHello.
 	SkipNewSessionTicket bool
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 32b90e2..80208dd 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -584,10 +584,7 @@
 func (hs *clientHandshakeState) sendFinished() error {
 	c := hs.c
 
-	if !c.config.Bugs.SkipChangeCipherSpec &&
-		c.config.Bugs.EarlyChangeCipherSpec == 0 {
-		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
-	}
+	var postCCSBytes []byte
 	if hs.serverHello.nextProtoNeg {
 		nextProto := new(nextProtoMsg)
 		proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
@@ -595,8 +592,9 @@
 		c.clientProtocol = proto
 		c.clientProtocolFallback = fallback
 
-		hs.finishedHash.Write(nextProto.marshal())
-		c.writeRecord(recordTypeHandshake, nextProto.marshal())
+		nextProtoBytes := nextProto.marshal()
+		hs.finishedHash.Write(nextProtoBytes)
+		postCCSBytes = append(postCCSBytes, nextProtoBytes...)
 	}
 
 	finished := new(finishedMsg)
@@ -605,8 +603,21 @@
 	} else {
 		finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
 	}
-	hs.finishedHash.Write(finished.marshal())
-	c.writeRecord(recordTypeHandshake, finished.marshal())
+	finishedBytes := finished.marshal()
+	hs.finishedHash.Write(finishedBytes)
+	postCCSBytes = append(postCCSBytes, finishedBytes...)
+
+	if c.config.Bugs.FragmentAcrossChangeCipherSpec {
+		c.writeRecord(recordTypeHandshake, postCCSBytes[:5])
+		postCCSBytes = postCCSBytes[5:]
+	}
+
+	if !c.config.Bugs.SkipChangeCipherSpec &&
+		c.config.Bugs.EarlyChangeCipherSpec == 0 {
+		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	}
+
+	c.writeRecord(recordTypeHandshake, postCCSBytes)
 	return nil
 }
 
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 8cdecd7..68ba734 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -598,14 +598,21 @@
 func (hs *serverHandshakeState) sendFinished() error {
 	c := hs.c
 
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+	postCCSBytes := finished.marshal()
+	hs.finishedHash.Write(postCCSBytes)
+
+	if c.config.Bugs.FragmentAcrossChangeCipherSpec {
+		c.writeRecord(recordTypeHandshake, postCCSBytes[:5])
+		postCCSBytes = postCCSBytes[5:]
+	}
+
 	if !c.config.Bugs.SkipChangeCipherSpec {
 		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 	}
 
-	finished := new(finishedMsg)
-	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
-	hs.finishedHash.Write(finished.marshal())
-	c.writeRecord(recordTypeHandshake, finished.marshal())
+	c.writeRecord(recordTypeHandshake, postCCSBytes)
 
 	c.cipherSuite = hs.suite.id
 
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index f4a0891..1ed733c 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -234,7 +234,7 @@
 			},
 		},
 		shouldFail:    true,
-		expectedError: ":GOT_A_FIN_BEFORE_A_CCS:",
+		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
 	},
 	{
 		testType: serverTest,
@@ -245,7 +245,7 @@
 			},
 		},
 		shouldFail:    true,
-		expectedError: ":GOT_A_FIN_BEFORE_A_CCS:",
+		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
 	},
 	{
 		testType: serverTest,
@@ -260,7 +260,43 @@
 			"-advertise-npn", "\x03foo\x03bar\x03baz",
 		},
 		shouldFail:    true,
-		expectedError: ":GOT_NEXT_PROTO_BEFORE_A_CCS:",
+		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+	},
+	{
+		name: "FragmentAcrossChangeCipherSpec-Client",
+		config: Config{
+			Bugs: ProtocolBugs{
+				FragmentAcrossChangeCipherSpec: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+	},
+	{
+		testType: serverTest,
+		name:     "FragmentAcrossChangeCipherSpec-Server",
+		config: Config{
+			Bugs: ProtocolBugs{
+				FragmentAcrossChangeCipherSpec: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
+	},
+	{
+		testType: serverTest,
+		name:     "FragmentAcrossChangeCipherSpec-Server-NPN",
+		config: Config{
+			NextProtos: []string{"bar"},
+			Bugs: ProtocolBugs{
+				FragmentAcrossChangeCipherSpec: true,
+			},
+		},
+		flags: []string{
+			"-advertise-npn", "\x03foo\x03bar\x03baz",
+		},
+		shouldFail:    true,
+		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
 	},
 	{
 		testType: serverTest,