Send half-RTT tickets when negotiating 0-RTT.

Once 0-RTT data is added to the current 0-RTT logic, the server will
trigger a write when processing incoming data via SSL_read. This means
SSL_read will block on transport write, which is something we've not
tried to avoid far (assuming no renegotiation).

The specification allows for tickets to be sent at half-RTT by
predicting the client Finished. By doing this we both get the tickets on
the wire sooner and avoid confusing I/O patterns. Moreover, we
anticipate we will need this mode for one of the QUIC stateless reject
patterns.

This is tested by always processing NewSessionTickets in the
ExpectHalfRTTData path on 0-RTT connections. As not other
implementations using BoGo may not do this, this is configurable via the
shim config.

BUG=76

Change-Id: Ia0f56ae63f15078ff1cacceba972d2b99001947f
Reviewed-on: https://boringssl-review.googlesource.com/14371
Reviewed-by: Steven Valdez <svaldez@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@chromium.org>
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/conn.go b/ssl/test/runner/conn.go
index ffe4f34..830977d 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -1425,6 +1425,43 @@
 	return n + m, c.out.setErrorLocked(err)
 }
 
+func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMsg, cipherSuite *cipherSuite) error {
+	if c.config.Bugs.ExpectGREASE && !newSessionTicket.hasGREASEExtension {
+		return errors.New("tls: no GREASE ticket extension found")
+	}
+
+	if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
+		return errors.New("tls: no ticket_early_data_info extension found")
+	}
+
+	if c.config.Bugs.ExpectNoNewSessionTicket {
+		return errors.New("tls: received unexpected NewSessionTicket")
+	}
+
+	if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
+		return nil
+	}
+
+	session := &ClientSessionState{
+		sessionTicket:      newSessionTicket.ticket,
+		vers:               c.vers,
+		cipherSuite:        cipherSuite.id,
+		masterSecret:       c.resumptionSecret,
+		serverCertificates: c.peerCertificates,
+		sctList:            c.sctList,
+		ocspResponse:       c.ocspResponse,
+		ticketCreationTime: c.config.time(),
+		ticketExpiration:   c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
+		ticketAgeAdd:       newSessionTicket.ticketAgeAdd,
+		maxEarlyDataSize:   newSessionTicket.maxEarlyDataSize,
+		earlyALPN:          c.clientProtocol,
+	}
+
+	cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+	c.config.ClientSessionCache.Put(cacheKey, session)
+	return nil
+}
+
 func (c *Conn) handlePostHandshakeMessage() error {
 	msg, err := c.readHandshake()
 	if err != nil {
@@ -1449,40 +1486,7 @@
 
 	if c.isClient {
 		if newSessionTicket, ok := msg.(*newSessionTicketMsg); ok {
-			if c.config.Bugs.ExpectGREASE && !newSessionTicket.hasGREASEExtension {
-				return errors.New("tls: no GREASE ticket extension found")
-			}
-
-			if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
-				return errors.New("tls: no ticket_early_data_info extension found")
-			}
-
-			if c.config.Bugs.ExpectNoNewSessionTicket {
-				return errors.New("tls: received unexpected NewSessionTicket")
-			}
-
-			if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
-				return nil
-			}
-
-			session := &ClientSessionState{
-				sessionTicket:      newSessionTicket.ticket,
-				vers:               c.vers,
-				cipherSuite:        c.cipherSuite.id,
-				masterSecret:       c.resumptionSecret,
-				serverCertificates: c.peerCertificates,
-				sctList:            c.sctList,
-				ocspResponse:       c.ocspResponse,
-				ticketCreationTime: c.config.time(),
-				ticketExpiration:   c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
-				ticketAgeAdd:       newSessionTicket.ticketAgeAdd,
-				maxEarlyDataSize:   newSessionTicket.maxEarlyDataSize,
-				earlyALPN:          c.clientProtocol,
-			}
-
-			cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
-			c.config.ClientSessionCache.Put(cacheKey, session)
-			return nil
+			return c.processTLS13NewSessionTicket(newSessionTicket, c.cipherSuite)
 		}
 	}