diff --git a/ticket.go b/ticket.go index bc63f51..ca8cc2d 100644 --- a/ticket.go +++ b/ticket.go @@ -33,6 +33,7 @@ type SessionState struct { // uint16 cipher_suite; // uint64 created_at; // opaque secret<1..2^8-1>; + // opaque extra<0..2^24-1>; // CertificateEntry certificate_list<0..2^24-1>; // select (SessionState.type) { // case server: /* empty */; @@ -50,6 +51,18 @@ type SessionState struct { // } SessionState; // + // Extra is ignored by crypto/tls, but is encoded by [SessionState.Bytes] + // and parsed by [ParseSessionState]. + // + // This allows [Config.UnwrapSession]/[Config.WrapSession] and + // [ClientSessionCache] implementations to store and retrieve additional + // data. + // + // If Extra is already set, the implementation must preserve the previous + // value across a round-trip, for example by appending and stripping a + // fixed-length suffix. + Extra []byte + version uint16 isClient bool cipherSuite uint16 @@ -90,6 +103,9 @@ func (s *SessionState) Bytes() ([]byte, error) { b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(s.secret) }) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(s.Extra) + }) marshalCertificate(&b, s.certificate()) if s.isClient { b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -144,6 +160,7 @@ func ParseSessionState(data []byte) (*SessionState, error) { !s.ReadUint16(&ss.cipherSuite) || !readUint64(&s, &ss.createdAt) || !readUint8LengthPrefixed(&s, &ss.secret) || + !readUint24LengthPrefixed(&s, &ss.Extra) || len(ss.secret) == 0 || !unmarshalCertificate(&s, &cert) { return nil, errors.New("tls: invalid session encoding")