crypto/tls: add WrapSession and UnwrapSession

There was a bug in TestResumption: the first ExpiredSessionTicket was
inserting a ticket far in the future, so the second ExpiredSessionTicket
wasn't actually supposed to fail. However, there was a bug in
checkForResumption->sendSessionTicket, too: if a session was not resumed
because it was too old, its createdAt was still persisted in the next
ticket. The two bugs used to cancel each other out.

For #60105
Fixes #19199

Change-Id: Ic9b2aab943dcbf0de62b8758a6195319dc286e2f
Reviewed-on: https://go-review.googlesource.com/c/go/+/496821
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Filippo Valsorda 2023-05-22 10:49:07 +02:00
parent 170472af9d
commit 7147979294
6 changed files with 178 additions and 55 deletions

View file

@ -275,12 +275,29 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
break
}
plaintext := c.decryptTicket(identity.label)
if plaintext == nil {
continue
var sessionState *SessionState
if c.config.UnwrapSession != nil {
var err error
sessionState, err = c.config.UnwrapSession(identity.label, c.connectionStateLocked())
if err != nil {
return err
}
if sessionState == nil {
continue
}
} else {
plaintext := c.config.decryptTicket(identity.label, c.ticketKeys)
if plaintext == nil {
continue
}
var err error
sessionState, err = ParseSessionState(plaintext)
if err != nil {
continue
}
}
sessionState, err := ParseSessionState(plaintext)
if err != nil || sessionState.version != VersionTLS13 {
if sessionState.version != VersionTLS13 {
continue
}
@ -781,14 +798,21 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
return err
}
state.secret = psk
stateBytes, err := state.Bytes()
if err != nil {
c.sendAlert(alertInternalError)
return err
}
m.label, err = c.encryptTicket(stateBytes)
if err != nil {
return err
if c.config.WrapSession != nil {
m.label, err = c.config.WrapSession(c.connectionStateLocked(), state)
if err != nil {
return err
}
} else {
stateBytes, err := state.Bytes()
if err != nil {
c.sendAlert(alertInternalError)
return err
}
m.label, err = c.config.encryptTicket(stateBytes, c.ticketKeys)
if err != nil {
return err
}
}
m.lifetime = uint32(maxSessionTicketLifetime / time.Second)