Add EarlyChangeCipherSpec tests.

Adapted from patch in https://www.imperialviolet.org/2014/06/05/earlyccs.html.

Change-Id: I14bf314d105780e23e6bd09217870deff5744979
Reviewed-on: https://boringssl-review.googlesource.com/1292
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index d394b73..8ac76f6 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -368,6 +368,12 @@
 	// sending the ChangeCipherSpec message (and adjusting cipher
 	// state accordingly for the Finished message).
 	SkipChangeCipherSpec bool
+
+	// EarlyChangeCipherSpec causes the client to send an early
+	// ChangeCipherSpec message before the ClientKeyExchange. A value of
+	// zero disables this behavior. One and two configure variants for 0.9.8
+	// and 1.0.1 modes, respectively.
+	EarlyChangeCipherSpec int
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 9d07584..32b90e2 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -165,14 +165,21 @@
 	hs.finishedHash.Write(hs.hello.marshal())
 	hs.finishedHash.Write(hs.serverHello.marshal())
 
+	if c.config.Bugs.EarlyChangeCipherSpec > 0 {
+		hs.establishKeys()
+		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	}
+
 	isResume, err := hs.processServerHello()
 	if err != nil {
 		return err
 	}
 
 	if isResume {
-		if err := hs.establishKeys(); err != nil {
-			return err
+		if c.config.Bugs.EarlyChangeCipherSpec == 0 {
+			if err := hs.establishKeys(); err != nil {
+				return err
+			}
 		}
 		if err := hs.readSessionTicket(); err != nil {
 			return err
@@ -408,7 +415,9 @@
 		return err
 	}
 	if ckx != nil {
-		hs.finishedHash.Write(ckx.marshal())
+		if c.config.Bugs.EarlyChangeCipherSpec < 2 {
+			hs.finishedHash.Write(ckx.marshal())
+		}
 		c.writeRecord(recordTypeHandshake, ckx.marshal())
 	}
 
@@ -532,11 +541,13 @@
 		return unexpectedMessageError(serverFinished, msg)
 	}
 
-	verify := hs.finishedHash.serverSum(hs.masterSecret)
-	if len(verify) != len(serverFinished.verifyData) ||
-		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
-		c.sendAlert(alertHandshakeFailure)
-		return errors.New("tls: server's Finished message was incorrect")
+	if c.config.Bugs.EarlyChangeCipherSpec == 0 {
+		verify := hs.finishedHash.serverSum(hs.masterSecret)
+		if len(verify) != len(serverFinished.verifyData) ||
+			subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+			c.sendAlert(alertHandshakeFailure)
+			return errors.New("tls: server's Finished message was incorrect")
+		}
 	}
 	hs.finishedHash.Write(serverFinished.marshal())
 	return nil
@@ -573,7 +584,8 @@
 func (hs *clientHandshakeState) sendFinished() error {
 	c := hs.c
 
-	if !c.config.Bugs.SkipChangeCipherSpec {
+	if !c.config.Bugs.SkipChangeCipherSpec &&
+		c.config.Bugs.EarlyChangeCipherSpec == 0 {
 		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 	}
 	if hs.serverHello.nextProtoNeg {
@@ -588,7 +600,11 @@
 	}
 
 	finished := new(finishedMsg)
-	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	if c.config.Bugs.EarlyChangeCipherSpec == 2 {
+		finished.verifyData = hs.finishedHash.clientSum(nil)
+	} else {
+		finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	}
 	hs.finishedHash.Write(finished.marshal())
 	c.writeRecord(recordTypeHandshake, finished.marshal())
 	return nil
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 539a746..47af0e0 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -262,6 +262,28 @@
 		shouldFail:    true,
 		expectedError: ":GOT_NEXT_PROTO_BEFORE_A_CCS:",
 	},
+	{
+		testType: serverTest,
+		name:     "EarlyChangeCipherSpec-server-1",
+		config: Config{
+			Bugs: ProtocolBugs{
+				EarlyChangeCipherSpec: 1,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":CCS_RECEIVED_EARLY:",
+	},
+	{
+		testType: serverTest,
+		name:     "EarlyChangeCipherSpec-server-2",
+		config: Config{
+			Bugs: ProtocolBugs{
+				EarlyChangeCipherSpec: 2,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":CCS_RECEIVED_EARLY:",
+	},
 }
 
 func doExchange(testType testType, config *Config, conn net.Conn, messageLen int) error {