Implement exporters for TLS 1.3 in Go.

Tested against the C code.

Change-Id: I62639e1e46cd4f57625be5d4ff7f6902b318c278
Reviewed-on: https://boringssl-review.googlesource.com/8768
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 7628c0f..f10a495 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -55,7 +55,7 @@
 	peerSignatureAlgorithm signatureAlgorithm
 
 	clientRandom, serverRandom [32]byte
-	masterSecret               [48]byte
+	exporterSecret             []byte
 
 	clientProtocol         string
 	clientProtocolFallback bool
@@ -1527,6 +1527,12 @@
 		return nil, errors.New("tls: handshake has not yet been performed")
 	}
 
+	if enableTLS13Handshake && c.vers >= VersionTLS13 {
+		// TODO(davidben): What should we do with useContext? See
+		// https://github.com/tlswg/tls13-spec/issues/546
+		return hkdfExpandLabel(c.cipherSuite.hash(), c.exporterSecret, label, context, length), nil
+	}
+
 	seedLen := len(c.clientRandom) + len(c.serverRandom)
 	if useContext {
 		seedLen += 2 + len(context)
@@ -1539,7 +1545,7 @@
 		seed = append(seed, context...)
 	}
 	result := make([]byte, length)
-	prfForVersion(c.vers, c.cipherSuite)(result, c.masterSecret[:], label, seed)
+	prfForVersion(c.vers, c.cipherSuite)(result, c.exporterSecret, label, seed)
 	return result, nil
 }
 
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 4ff7012..10c847e 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -410,13 +410,13 @@
 		}
 
 		c.didResume = isResume
+		c.exporterSecret = hs.masterSecret
 	}
 
 	c.handshakeComplete = true
 	c.cipherSuite = suite
 	copy(c.clientRandom[:], hs.hello.random)
 	copy(c.serverRandom[:], hs.serverHello.random)
-	copy(c.masterSecret[:], hs.masterSecret)
 
 	return nil
 }
@@ -644,6 +644,7 @@
 	if c.config.Bugs.BadFinished {
 		finished.verifyData[0]++
 	}
+	hs.writeClientHash(finished.marshal())
 	c.writeRecord(recordTypeHandshake, finished.marshal())
 	c.flushHandshake()
 
@@ -651,9 +652,9 @@
 	c.out.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, clientWrite), c.vers)
 	c.in.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, serverWrite), c.vers)
 
-	// TODO(davidben): Derive and save the exporter master secret for key exporters. Swap out the masterSecret field.
 	// TODO(davidben): Derive and save the resumption master secret for receiving tickets.
 	// TODO(davidben): Save the traffic secret for KeyUpdate.
+	c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
 	return nil
 }
 
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 8690aeb..4660726 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -120,11 +120,12 @@
 				return err
 			}
 		}
+
+		c.exporterSecret = hs.masterSecret
 	}
 	c.handshakeComplete = true
 	copy(c.clientRandom[:], hs.clientHello.random)
 	copy(c.serverRandom[:], hs.hello.random)
-	copy(c.masterSecret[:], hs.masterSecret)
 
 	return nil
 }
@@ -544,15 +545,16 @@
 		c.sendAlert(alertHandshakeFailure)
 		return errors.New("tls: client's Finished message was incorrect")
 	}
+	hs.writeClientHash(clientFinished.marshal())
 
 	// Switch to application data keys.
 	c.out.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, serverWrite), c.vers)
 	c.in.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, clientWrite), c.vers)
 
-	// TODO(davidben): Derive and save the exporter master secret for key exporters. Swap out the masterSecret field.
 	// TODO(davidben): Derive and save the resumption master secret for receiving tickets.
 	// TODO(davidben): Save the traffic secret for KeyUpdate.
 	c.cipherSuite = hs.suite
+	c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
 	return nil
 }