From 97a0a0829331ca51d730adec5b74ec520c8b3ebd Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 13 Jul 2016 17:57:35 -0400 Subject: [PATCH] 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 Reviewed-by: David Benjamin --- ssl/test/runner/conn.go | 10 ++++++++-- ssl/test/runner/handshake_client.go | 5 +++-- ssl/test/runner/handshake_server.go | 6 ++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go index 7628c0fd..f10a4951 100644 --- a/ssl/test/runner/conn.go +++ b/ssl/test/runner/conn.go @@ -55,7 +55,7 @@ type Conn struct { peerSignatureAlgorithm signatureAlgorithm clientRandom, serverRandom [32]byte - masterSecret [48]byte + exporterSecret []byte clientProtocol string clientProtocolFallback bool @@ -1527,6 +1527,12 @@ func (c *Conn) ExportKeyingMaterial(length int, label, context []byte, useContex 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 @@ func (c *Conn) ExportKeyingMaterial(length int, label, context []byte, useContex 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 4ff70126..10c847e3 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go @@ -410,13 +410,13 @@ NextCipherSuite: } 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 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { if c.config.Bugs.BadFinished { finished.verifyData[0]++ } + hs.writeClientHash(finished.marshal()) c.writeRecord(recordTypeHandshake, finished.marshal()) c.flushHandshake() @@ -651,9 +652,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { 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 8690aeb0..46607262 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -120,11 +120,12 @@ func (c *Conn) serverHandshake() error { 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 @@ Curves: 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 }