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"},