Commit 29b01d55 authored by Filippo Valsorda's avatar Filippo Valsorda

crypto/tls: implement TLS 1.3 KeyLogWriter support

Also, add support for the SSLKEYLOGFILE environment variable to the
tests, to simplify debugging of unexpected failures.

Updates #9671

Change-Id: I20a34a5824f083da93097b793d51e796d6eb302b
Reviewed-on: https://go-review.googlesource.com/c/147417
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarAdam Langley <agl@golang.org>
parent 14560da7
......@@ -853,14 +853,20 @@ func (c *Config) BuildNameToCertificate() {
}
}
// writeKeyLog logs client random and master secret if logging was enabled by
// setting c.KeyLogWriter.
func (c *Config) writeKeyLog(clientRandom, masterSecret []byte) error {
const (
keyLogLabelTLS12 = "CLIENT_RANDOM"
keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0"
keyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0"
)
func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
if c.KeyLogWriter == nil {
return nil
}
logLine := []byte(fmt.Sprintf("CLIENT_RANDOM %x %x\n", clientRandom, masterSecret))
logLine := []byte(fmt.Sprintf("%s %x %x\n", label, clientRandom, secret))
writerMutex.Lock()
_, err := c.KeyLogWriter.Write(logLine)
......
......@@ -524,7 +524,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
if err := c.config.writeKeyLog(hs.hello.random, hs.masterSecret); err != nil {
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return errors.New("tls: failed to write to key log: " + err.Error())
}
......
......@@ -968,6 +968,49 @@ func TestKeyLog(t *testing.T) {
checkKeylogLine("server", serverBuf.String())
}
func TestKeyLogTLS13(t *testing.T) {
var serverBuf, clientBuf bytes.Buffer
clientConfig := testConfig.Clone()
clientConfig.KeyLogWriter = &clientBuf
clientConfig.MaxVersion = VersionTLS13
serverConfig := testConfig.Clone()
serverConfig.KeyLogWriter = &serverBuf
serverConfig.MaxVersion = VersionTLS13
c, s := localPipe(t)
done := make(chan bool)
go func() {
defer close(done)
if err := Server(s, serverConfig).Handshake(); err != nil {
t.Errorf("server: %s", err)
return
}
s.Close()
}()
if err := Client(c, clientConfig).Handshake(); err != nil {
t.Fatalf("client: %s", err)
}
c.Close()
<-done
checkKeylogLines := func(side, loggedLines string) {
loggedLines = strings.TrimSpace(loggedLines)
lines := strings.Split(loggedLines, "\n")
if len(lines) != 4 {
t.Errorf("Expected the %s to log 4 lines, got %d", side, len(lines))
}
}
checkKeylogLines("client", clientBuf.String())
checkKeylogLines("server", serverBuf.String())
}
func TestHandshakeClientALPNMatch(t *testing.T) {
config := testConfig.Clone()
config.NextProtos = []string{"proto2", "proto1"}
......
......@@ -269,6 +269,17 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
serverHandshakeTrafficLabel, hs.transcript)
c.in.setTrafficSecret(hs.suite, serverSecret)
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
hs.masterSecret = hs.suite.extract(nil,
hs.suite.deriveSecret(handshakeSecret, "derived", nil))
......@@ -409,6 +420,17 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error {
serverApplicationTrafficLabel, hs.transcript)
c.in.setTrafficSecret(hs.suite, serverSecret)
err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
return nil
......
......@@ -528,7 +528,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
return err
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
if err := c.config.writeKeyLog(hs.clientHello.random, hs.masterSecret); err != nil {
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return err
}
......
......@@ -63,6 +63,13 @@ func init() {
testConfig.Certificates[1].Certificate = [][]byte{testSNICertificate}
testConfig.Certificates[1].PrivateKey = testRSAPrivateKey
testConfig.BuildNameToCertificate()
if keyFile := os.Getenv("SSLKEYLOGFILE"); keyFile != "" {
f, err := os.OpenFile(keyFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic("failed to open SSLKEYLOGFILE: " + err.Error())
}
testConfig.KeyLogWriter = f
}
}
func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
......
......@@ -336,6 +336,17 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
serverHandshakeTrafficLabel, hs.transcript)
c.out.setTrafficSecret(hs.suite, serverSecret)
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
encryptedExtensions := new(encryptedExtensionsMsg)
if len(hs.clientHello.alpnProtocols) > 0 {
......@@ -426,6 +437,17 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
serverApplicationTrafficLabel, hs.transcript)
c.out.setTrafficSecret(hs.suite, serverSecret)
err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
c.ekm = hs.suite.exportKeyingMaterial(masterSecret, hs.transcript)
return nil
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment