Implement KeyUpdate in Go.

Implemented in preparation for testing the C implementation. Tested
against itself.

BUG=74

Change-Id: Iec1b9ad22e09711fa4e67c97cc3eb257585c3ae5
Reviewed-on: https://boringssl-review.googlesource.com/8873
Reviewed-by: Nick Harper <nharper@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
David Benjamin 2016-07-18 21:56:23 +02:00 committed by CQ bot account: commit-bot@chromium.org
parent 92d60c2059
commit 21c0028d40
6 changed files with 72 additions and 13 deletions

View File

@ -68,6 +68,7 @@ const (
typeClientKeyExchange uint8 = 16
typeFinished uint8 = 20
typeCertificateStatus uint8 = 22
typeKeyUpdate uint8 = 24 // draft-ietf-tls-tls13-13
typeNextProtocol uint8 = 67 // Not IANA assigned
typeChannelID uint8 = 203 // Not IANA assigned
)

View File

@ -159,6 +159,9 @@ type halfConn struct {
// used to save allocating a new buffer for each MAC.
inDigestBuf, outDigestBuf []byte
trafficSecret []byte
keyUpdateGeneration int
config *Config
}
@ -203,13 +206,23 @@ func (hc *halfConn) changeCipherSpec(config *Config) error {
return nil
}
// updateKeys sets the current cipher state.
func (hc *halfConn) updateKeys(cipher interface{}, version uint16) {
// useTrafficSecret sets the current cipher state for TLS 1.3.
func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret, phase []byte, side trafficDirection) {
hc.version = version
hc.cipher = cipher
hc.cipher = deriveTrafficAEAD(version, suite, secret, phase, side)
hc.trafficSecret = secret
hc.incEpoch()
}
func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) {
side := serverWrite
if c.isClient == isOutgoing {
side = clientWrite
}
hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), applicationPhase, side)
hc.keyUpdateGeneration++
}
// incSeq increments the sequence number.
func (hc *halfConn) incSeq(isOutgoing bool) {
limit := 0
@ -1175,6 +1188,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(helloVerifyRequestMsg)
case typeChannelID:
m = new(channelIDMsg)
case typeKeyUpdate:
m = new(keyUpdateMsg)
default:
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
@ -1280,6 +1295,13 @@ func (c *Conn) Write(b []byte) (int, error) {
return 0, alertInternalError
}
// Catch up with KeyUpdates from the peer.
for c.out.keyUpdateGeneration < c.in.keyUpdateGeneration {
if err := c.sendKeyUpdateLocked(); err != nil {
return 0, err
}
}
if c.config.Bugs.SendSpuriousAlert != 0 {
c.sendAlertLocked(alertLevelError, c.config.Bugs.SendSpuriousAlert)
}
@ -1357,6 +1379,11 @@ func (c *Conn) handlePostHandshakeMessage() error {
}
}
if _, ok := msg.(*keyUpdateMsg); ok {
c.in.doKeyUpdate(c, true)
return nil
}
// TODO(davidben): Add support for KeyUpdate.
c.sendAlert(alertUnexpectedMessage)
return alertUnexpectedMessage
@ -1648,3 +1675,21 @@ func (c *Conn) SendNewSessionTicket() error {
_, err := c.writeRecord(recordTypeHandshake, m.marshal())
return err
}
func (c *Conn) SendKeyUpdate() error {
c.out.Lock()
defer c.out.Unlock()
return c.sendKeyUpdateLocked()
}
func (c *Conn) sendKeyUpdateLocked() error {
m := new(keyUpdateMsg)
if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
return err
}
if err := c.flushHandshake(); err != nil {
return err
}
c.out.doKeyUpdate(c, false)
return nil
}

View File

@ -594,8 +594,8 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
// Switch to handshake traffic keys.
handshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, handshakeTrafficLabel)
c.out.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, clientWrite), c.vers)
c.in.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, serverWrite), c.vers)
c.out.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, clientWrite)
c.in.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, serverWrite)
msg, err := c.readHandshake()
if err != nil {
@ -767,10 +767,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.flushHandshake()
// Switch to application data keys.
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)
c.out.useTrafficSecret(c.vers, hs.suite, trafficSecret, applicationPhase, clientWrite)
c.in.useTrafficSecret(c.vers, hs.suite, trafficSecret, applicationPhase, serverWrite)
// TODO(davidben): Save the traffic secret for KeyUpdate.
c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)
return nil

View File

@ -1924,6 +1924,17 @@ func (*helloRequestMsg) unmarshal(data []byte) bool {
return len(data) == 4
}
type keyUpdateMsg struct {
}
func (*keyUpdateMsg) marshal() []byte {
return []byte{typeKeyUpdate, 0, 0, 0}
}
func (*keyUpdateMsg) unmarshal(data []byte) bool {
return len(data) == 4
}
func eqUint16s(x, y []uint16) bool {
if len(x) != len(y) {
return false

View File

@ -490,8 +490,8 @@ Curves:
// Switch to handshake traffic keys.
handshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, handshakeTrafficLabel)
c.out.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, serverWrite), c.vers)
c.in.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, clientWrite), c.vers)
c.out.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, serverWrite)
c.in.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, clientWrite)
if hs.suite.flags&suitePSK != 0 {
return errors.New("tls: PSK ciphers not implemented for TLS 1.3")
@ -591,7 +591,7 @@ Curves:
// Switch to application data keys on write. In particular, any alerts
// from the client certificate are sent over these keys.
c.out.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, serverWrite), c.vers)
c.out.useTrafficSecret(c.vers, hs.suite, trafficSecret, applicationPhase, serverWrite)
// If we requested a client certificate, then the client must send a
// certificate message, even if it's empty.
@ -664,9 +664,8 @@ Curves:
hs.writeClientHash(clientFinished.marshal())
// Switch to application data keys on read.
c.in.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, clientWrite), c.vers)
c.in.useTrafficSecret(c.vers, hs.suite, trafficSecret, applicationPhase, clientWrite)
// TODO(davidben): Save the traffic secret for KeyUpdate.
c.cipherSuite = hs.suite
c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)

View File

@ -493,3 +493,7 @@ func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret, phase []byte,
return suite.aead(version, key, iv)
}
func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte {
return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size())
}