Skip to content

Commit

Permalink
crypto/tls: add ClientSessionState.ResumptionState and NewResumptionS…
Browse files Browse the repository at this point in the history
…tate

For #60105
Fixes #25351

Change-Id: Iffd658f2663cfc47b48157824226ed6c0260a59e
Reviewed-on: https://go-review.googlesource.com/c/go/+/496820
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Damien Neil <[email protected]>
Reviewed-by: Matthew Dempsky <[email protected]>
Run-TryBot: Filippo Valsorda <[email protected]>
Reviewed-by: Marten Seemann <[email protected]>
  • Loading branch information
FiloSottile committed May 24, 2023
1 parent 6d05bc7 commit 371ebe7
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 8 deletions.
2 changes: 2 additions & 0 deletions api/next/60105.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pkg crypto/tls, func ParseSessionState([]uint8) (*SessionState, error) #60105
pkg crypto/tls, method (*SessionState) Bytes() ([]uint8, error) #60105
pkg crypto/tls, type SessionState struct #60105
pkg crypto/tls, func NewResumptionState([]uint8, *SessionState) (*ClientSessionState, error) #60105
pkg crypto/tls, method (*ClientSessionState) ResumptionState() ([]uint8, *SessionState, error) #60105
41 changes: 41 additions & 0 deletions src/crypto/tls/handshake_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,47 @@ func testResumption(t *testing.T, version uint16) {

clientConfig.ClientSessionCache = nil
testResumeState("WithoutSessionCache", false)

clientConfig.ClientSessionCache = &serializingClientCache{t: t}
testResumeState("BeforeSerializingCache", false)
testResumeState("WithSerializingCache", true)
}

type serializingClientCache struct {
t *testing.T

ticket, state []byte
}

func (c *serializingClientCache) Get(sessionKey string) (session *ClientSessionState, ok bool) {
if c.ticket == nil {
return nil, false
}
state, err := ParseSessionState(c.state)
if err != nil {
c.t.Error(err)
return nil, false
}
cs, err := NewResumptionState(c.ticket, state)
if err != nil {
c.t.Error(err)
return nil, false
}
return cs, true
}

func (c *serializingClientCache) Put(sessionKey string, cs *ClientSessionState) {
ticket, state, err := cs.ResumptionState()
if err != nil {
c.t.Error(err)
return
}
stateBytes, err := state.Bytes()
if err != nil {
c.t.Error(err)
return
}
c.ticket, c.state = ticket, stateBytes
}

func TestLRUClientSessionCache(t *testing.T) {
Expand Down
37 changes: 29 additions & 8 deletions src/crypto/tls/ticket.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,9 @@ type SessionState struct {
ageAdd uint32
}

// ClientSessionState contains the state needed by clients to resume TLS
// sessions.
type ClientSessionState struct {
ticket []byte
session *SessionState
}

// Bytes encodes the session, including any private fields, so that it can be
// parsed by [ParseSessionState]. The encoding contains secret values.
// parsed by [ParseSessionState]. The encoding contains secret values critical
// to the security of future and possibly past sessions.
//
// The specific encoding should be considered opaque and may change incompatibly
// between Go versions.
Expand Down Expand Up @@ -293,3 +287,30 @@ func (c *Conn) decryptTicket(encrypted []byte) []byte {

return nil
}

// ClientSessionState contains the state needed by a client to
// resume a previous TLS session.
type ClientSessionState struct {
ticket []byte
session *SessionState
}

// ResumptionState returns the session ticket sent by the server (also known as
// the session's identity) and the state necessary to resume this session.
//
// It can be called by [ClientSessionCache.Put] to serialize (with
// [SessionState.Bytes]) and store the session.
func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionState, err error) {
return cs.ticket, cs.session, nil
}

// NewResumptionState returns a state value that can be returned by
// [ClientSessionCache.Get] to resume a previous session.
//
// state needs to be returned by [ParseSessionState], and the ticket and session
// state must have been returned by [ClientSessionState.ResumptionState].
func NewResumptionState(ticket []byte, state *SessionState) (*ClientSessionState, error) {
return &ClientSessionState{
ticket: ticket, session: state,
}, nil
}

0 comments on commit 371ebe7

Please sign in to comment.