Support accepting TLS 1.3 tickets on the Go client.

We still don't do anything useful with them, but we know not to put them
in the session ticket field.

In doing so, fix a bug in the CorruptTicket option where it would crash
if tickets are exactly 40 byets in length.

BUG=75

Change-Id: Id1039a58ed314a67d0af4f2c7e0617987c2bd6b5
Reviewed-on: https://boringssl-review.googlesource.com/8872
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 01:17:13 +02:00 committed by CQ bot account: commit-bot@chromium.org
parent 58104889ad
commit d5a4ecb61a
2 changed files with 63 additions and 34 deletions

View File

@ -877,15 +877,12 @@ Again:
b = nil b = nil
case recordTypeHandshake: case recordTypeHandshake:
// Allow handshake data while reading application data to
// trigger post-handshake messages.
// TODO(rsc): Should at least pick off connection close. // TODO(rsc): Should at least pick off connection close.
if typ != want { if typ != want && want != recordTypeApplicationData {
// A client might need to process a HelloRequest from
// the server, thus receiving a handshake message when
// application data is expected is ok.
if !c.isClient || want != recordTypeApplicationData {
return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
} }
}
c.hand.Write(data) c.hand.Write(data)
} }
@ -1316,23 +1313,53 @@ func (c *Conn) Write(b []byte) (int, error) {
return n + m, c.out.setErrorLocked(err) return n + m, c.out.setErrorLocked(err)
} }
func (c *Conn) handleRenegotiation() error { func (c *Conn) handlePostHandshakeMessage() error {
c.handshakeComplete = false
if !c.isClient {
panic("renegotiation should only happen for a client")
}
msg, err := c.readHandshake() msg, err := c.readHandshake()
if err != nil { if err != nil {
return err return err
} }
if c.vers < VersionTLS13 {
if !c.isClient {
c.sendAlert(alertUnexpectedMessage)
return errors.New("tls: unexpected post-handshake message")
}
_, ok := msg.(*helloRequestMsg) _, ok := msg.(*helloRequestMsg)
if !ok { if !ok {
c.sendAlert(alertUnexpectedMessage) c.sendAlert(alertUnexpectedMessage)
return alertUnexpectedMessage return alertUnexpectedMessage
} }
c.handshakeComplete = false
return c.Handshake() return c.Handshake()
}
if c.isClient {
if newSessionTicket, ok := msg.(*newSessionTicketMsg); ok {
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,
}
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
c.config.ClientSessionCache.Put(cacheKey, session)
return nil
}
}
// TODO(davidben): Add support for KeyUpdate.
c.sendAlert(alertUnexpectedMessage)
return alertUnexpectedMessage
} }
func (c *Conn) Renegotiate() error { func (c *Conn) Renegotiate() error {
@ -1369,9 +1396,9 @@ func (c *Conn) Read(b []byte) (n int, err error) {
return 0, err return 0, err
} }
if c.hand.Len() > 0 { if c.hand.Len() > 0 {
// We received handshake bytes, indicating the // We received handshake bytes, indicating a
// start of a renegotiation. // post-handshake message.
if err := c.handleRenegotiation(); err != nil { if err := c.handlePostHandshakeMessage(); err != nil {
return 0, err return 0, err
} }
continue continue

View File

@ -220,19 +220,21 @@ NextCipherSuite:
} }
if session != nil { if session != nil {
if session.sessionTicket != nil { ticket := session.sessionTicket
hello.sessionTicket = session.sessionTicket if c.config.Bugs.CorruptTicket && len(ticket) > 0 {
if c.config.Bugs.CorruptTicket { ticket = make([]byte, len(session.sessionTicket))
hello.sessionTicket = make([]byte, len(session.sessionTicket)) copy(ticket, session.sessionTicket)
copy(hello.sessionTicket, session.sessionTicket)
if len(hello.sessionTicket) > 0 {
offset := 40 offset := 40
if offset > len(hello.sessionTicket) { if offset >= len(ticket) {
offset = len(hello.sessionTicket) - 1 offset = len(ticket) - 1
}
hello.sessionTicket[offset] ^= 0x40
} }
ticket[offset] ^= 0x40
} }
if session.vers >= VersionTLS13 {
// TODO(davidben): Offer TLS 1.3 tickets.
} else if ticket != nil {
hello.sessionTicket = ticket
// A random session ID is used to detect when the // A random session ID is used to detect when the
// server accepted the ticket and is resuming a session // server accepted the ticket and is resuming a session
// (see RFC 5077). // (see RFC 5077).
@ -768,9 +770,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.out.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, clientWrite), c.vers) 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.in.updateKeys(deriveTrafficAEAD(c.vers, hs.suite, trafficSecret, applicationPhase, serverWrite), c.vers)
// TODO(davidben): Derive and save the resumption master secret for receiving tickets.
// TODO(davidben): Save the traffic secret for KeyUpdate. // TODO(davidben): Save the traffic secret for KeyUpdate.
c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel) c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)
return nil return nil
} }