Send 0-RTT data in bogo.
Change-Id: I38cd04fa40edde4e4dd31fdc16bbf92985430198
Reviewed-on: https://boringssl-review.googlesource.com/12702
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>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 92f3e15..acb4114 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -254,6 +254,7 @@
ticketCreationTime time.Time
ticketExpiration time.Time
ticketAgeAdd uint32
+ maxEarlyDataSize uint32
}
// ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -1116,9 +1117,9 @@
// SendEarlyAlert, if true, sends a fatal alert after the ClientHello.
SendEarlyAlert bool
- // SendEarlyDataLength, if non-zero, is the amount of early data to send after
- // the ClientHello.
- SendEarlyDataLength int
+ // SendFakeEarlyDataLength, if non-zero, is the amount of early data to
+ // send after the ClientHello.
+ SendFakeEarlyDataLength int
// OmitEarlyDataExtension, if true, causes the early data extension to
// be omitted in the ClientHello.
@@ -1132,6 +1133,12 @@
// data interleaved with the second ClientHello and the client Finished.
InterleaveEarlyData bool
+ // SendEarlyData causes a TLS 1.3 client to send the provided data
+ // in application data records immediately after the ClientHello,
+ // provided that the client has a PSK that is appropriate for sending
+ // early data and includes that PSK in its ClientHello.
+ SendEarlyData [][]byte
+
// SendHalfRTTData causes a TLS 1.3 server to send the provided
// data in application data records before reading the client's
// Finished message.
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 0cc0b38..0235e42 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -223,6 +223,14 @@
hc.incEpoch()
}
+// resetCipher changes the cipher state back to no encryption to be able
+// to send an unencrypted ClientHello in response to HelloRetryRequest
+// after 0-RTT data was rejected.
+func (hc *halfConn) resetCipher() {
+ hc.cipher = nil
+ hc.incEpoch()
+}
+
func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) {
side := serverWrite
if c.isClient == isOutgoing {
@@ -990,7 +998,7 @@
// L < c.out.Mutex.
func (c *Conn) sendAlert(err alert) error {
level := byte(alertLevelError)
- if err == alertNoRenegotiation || err == alertCloseNotify || err == alertNoCertificate {
+ if err == alertNoRenegotiation || err == alertCloseNotify || err == alertNoCertificate || err == alertEndOfEarlyData {
level = alertLevelWarning
}
return c.SendAlert(level, err)
@@ -1471,7 +1479,7 @@
return errors.New("tls: no GREASE ticket extension found")
}
- if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.earlyDataInfo == 0 {
+ if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
return errors.New("tls: no ticket_early_data_info extension found")
}
@@ -1494,6 +1502,7 @@
ticketCreationTime: c.config.time(),
ticketExpiration: c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
ticketAgeAdd: newSessionTicket.ticketAgeAdd,
+ maxEarlyDataSize: newSessionTicket.maxEarlyDataSize,
}
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
@@ -1789,7 +1798,7 @@
m := &newSessionTicketMsg{
version: c.vers,
ticketLifetime: uint32(24 * time.Hour / time.Second),
- earlyDataInfo: c.config.Bugs.SendTicketEarlyDataInfo,
+ maxEarlyDataSize: c.config.Bugs.SendTicketEarlyDataInfo,
duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo,
customExtension: c.config.Bugs.CustomTicketExtension,
ticketAgeAdd: ticketAgeAdd,
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 02daa78..afc1958 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -324,8 +324,16 @@
hello.cipherSuites = c.config.Bugs.SendCipherSuites
}
- if c.config.Bugs.SendEarlyDataLength > 0 && !c.config.Bugs.OmitEarlyDataExtension {
+ var sendEarlyData bool
+ if len(hello.pskIdentities) > 0 && session.maxEarlyDataSize > 0 && c.config.Bugs.SendEarlyData != nil {
hello.hasEarlyData = true
+ sendEarlyData = true
+ }
+ if c.config.Bugs.SendFakeEarlyDataLength > 0 {
+ hello.hasEarlyData = true
+ }
+ if c.config.Bugs.OmitEarlyDataExtension {
+ hello.hasEarlyData = false
}
var helloBytes []byte
@@ -368,9 +376,25 @@
if c.config.Bugs.SendEarlyAlert {
c.sendAlert(alertHandshakeFailure)
}
- if c.config.Bugs.SendEarlyDataLength > 0 {
- c.sendFakeEarlyData(c.config.Bugs.SendEarlyDataLength)
+ if c.config.Bugs.SendFakeEarlyDataLength > 0 {
+ c.sendFakeEarlyData(c.config.Bugs.SendFakeEarlyDataLength)
}
+
+ // Derive early write keys and set Conn state to allow early writes.
+ if sendEarlyData {
+ finishedHash := newFinishedHash(session.vers, pskCipherSuite)
+ finishedHash.addEntropy(session.masterSecret)
+ finishedHash.Write(helloBytes)
+ earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel)
+ c.out.useTrafficSecret(session.vers, pskCipherSuite, earlyTrafficSecret, clientWrite)
+
+ for _, earlyData := range c.config.Bugs.SendEarlyData {
+ if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil {
+ return err
+ }
+ }
+ }
+
msg, err := c.readHandshake()
if err != nil {
return err
@@ -427,6 +451,7 @@
helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg)
var secondHelloBytes []byte
if haveHelloRetryRequest {
+ c.out.resetCipher()
if len(helloRetryRequest.cookie) > 0 {
hello.tls13Cookie = helloRetryRequest.cookie
}
@@ -701,9 +726,9 @@
c.setShortHeader()
}
- // Switch to handshake traffic keys.
+ // Derive handshake traffic keys and switch read key to handshake
+ // traffic key.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
- c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
@@ -850,6 +875,13 @@
c.input = nil
}
+ // Send EndOfEarlyData and then switch write key to handshake
+ // traffic key.
+ if c.out.cipher != nil {
+ c.sendAlert(alertEndOfEarlyData)
+ }
+ c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
+
if certReq != nil && !c.config.Bugs.SkipClientCertificate {
certMsg := &certificateMsg{
hasRequestContext: true,
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 62309b8..1141797 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -824,23 +824,22 @@
}
type serverHelloMsg struct {
- raw []byte
- isDTLS bool
- vers uint16
- versOverride uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- hasKeyShare bool
- keyShare keyShareEntry
- hasPSKIdentity bool
- pskIdentity uint16
- earlyDataIndication bool
- compressionMethod uint8
- customExtension string
- unencryptedALPN string
- shortHeader bool
- extensions serverExtensions
+ raw []byte
+ isDTLS bool
+ vers uint16
+ versOverride uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ hasKeyShare bool
+ keyShare keyShareEntry
+ hasPSKIdentity bool
+ pskIdentity uint16
+ compressionMethod uint8
+ customExtension string
+ unencryptedALPN string
+ shortHeader bool
+ extensions serverExtensions
}
func (m *serverHelloMsg) marshal() []byte {
@@ -895,10 +894,6 @@
extensions.addU16(2) // Length
extensions.addU16(m.pskIdentity)
}
- if m.earlyDataIndication {
- extensions.addU16(extensionEarlyData)
- extensions.addU16(0) // Length
- }
if len(m.customExtension) > 0 {
extensions.addU16(extensionCustom)
customExt := extensions.addU16LengthPrefixed()
@@ -1005,11 +1000,6 @@
}
m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
m.hasPSKIdentity = true
- case extensionEarlyData:
- if len(d) != 0 {
- return false
- }
- m.earlyDataIndication = true
case extensionShortHeader:
if len(d) != 0 {
return false
@@ -1089,6 +1079,7 @@
customExtension string
npnAfterAlpn bool
hasKeyShare bool
+ hasEarlyData bool
keyShare keyShareEntry
supportedPoints []uint8
}
@@ -1192,6 +1183,10 @@
supportedPoints := supportedPointsList.addU8LengthPrefixed()
supportedPoints.addBytes(m.supportedPoints)
}
+ if m.hasEarlyData {
+ extensions.addU16(extensionEarlyData)
+ extensions.addBytes([]byte{0, 0})
+ }
}
func (m *serverExtensions) unmarshal(data []byte, version uint16) bool {
@@ -1306,6 +1301,11 @@
if version < VersionTLS13 {
return false
}
+ case extensionEarlyData:
+ if version < VersionTLS13 || length != 0 {
+ return false
+ }
+ m.hasEarlyData = true
default:
// Unknown extensions are illegal from the server.
return false
@@ -2008,7 +2008,7 @@
ticketLifetime uint32
ticketAgeAdd uint32
ticket []byte
- earlyDataInfo uint32
+ maxEarlyDataSize uint32
customExtension string
duplicateEarlyDataInfo bool
hasGREASEExtension bool
@@ -2033,12 +2033,12 @@
if m.version >= VersionTLS13 {
extensions := body.addU16LengthPrefixed()
- if m.earlyDataInfo > 0 {
+ if m.maxEarlyDataSize > 0 {
extensions.addU16(extensionTicketEarlyDataInfo)
- extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
+ extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
if m.duplicateEarlyDataInfo {
extensions.addU16(extensionTicketEarlyDataInfo)
- extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
+ extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
}
}
if len(m.customExtension) > 0 {
@@ -2111,7 +2111,7 @@
if length != 4 {
return false
}
- m.earlyDataInfo = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ m.maxEarlyDataSize = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
default:
if isGREASEValue(extension) {
m.hasGREASEExtension = true
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 4e08200..5885221 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -9228,7 +9228,7 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 4,
+ SendFakeEarlyDataLength: 4,
},
},
})
@@ -9239,8 +9239,8 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 4,
- OmitEarlyDataExtension: true,
+ SendFakeEarlyDataLength: 4,
+ OmitEarlyDataExtension: true,
},
},
shouldFail: true,
@@ -9253,7 +9253,7 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 16384 + 1,
+ SendFakeEarlyDataLength: 16384 + 1,
},
},
shouldFail: true,
@@ -9266,8 +9266,8 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 4,
- InterleaveEarlyData: true,
+ SendFakeEarlyDataLength: 4,
+ InterleaveEarlyData: true,
},
},
shouldFail: true,
@@ -9280,7 +9280,7 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 4,
+ SendFakeEarlyDataLength: 4,
},
},
shouldFail: true,
@@ -9294,7 +9294,7 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 4,
+ SendFakeEarlyDataLength: 4,
},
DefaultCurves: []CurveID{},
},
@@ -9306,8 +9306,8 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 4,
- InterleaveEarlyData: true,
+ SendFakeEarlyDataLength: 4,
+ InterleaveEarlyData: true,
},
DefaultCurves: []CurveID{},
},
@@ -9321,7 +9321,7 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyDataLength: 16384 + 1,
+ SendFakeEarlyDataLength: 16384 + 1,
},
DefaultCurves: []CurveID{},
},
@@ -9337,8 +9337,8 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendEarlyAlert: true,
- SendEarlyDataLength: 4,
+ SendEarlyAlert: true,
+ SendFakeEarlyDataLength: 4,
},
DefaultCurves: []CurveID{},
},
@@ -10153,8 +10153,8 @@
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- EnableShortHeader: true,
- SendEarlyDataLength: 1,
+ EnableShortHeader: true,
+ SendFakeEarlyDataLength: 1,
},
},
flags: []string{"-enable-short-header"},