From 6801c27837b44b40aef0878a8a611413ef46e3eb Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 7 Jun 2023 21:36:19 +0200 Subject: [PATCH] crypto/tls: make SessionState.Extra a slice of byte slices Fixes #60539 Updates #60105 Change-Id: I7b567cc1d0901891ed97d29591db935cd487cc71 Reviewed-on: https://go-review.googlesource.com/c/go/+/501675 Auto-Submit: Filippo Valsorda Run-TryBot: Filippo Valsorda Reviewed-by: Roland Shoemaker TryBot-Result: Gopher Robot Reviewed-by: Damien Neil --- api/go1.21.txt | 2 +- src/crypto/tls/handshake_messages_test.go | 4 ++- src/crypto/tls/ticket.go | 31 +++++++++++++++++------ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/api/go1.21.txt b/api/go1.21.txt index ec11adf4b7..964392e0ec 100644 --- a/api/go1.21.txt +++ b/api/go1.21.txt @@ -80,7 +80,7 @@ pkg crypto/tls, type QUICEvent struct, Level QUICEncryptionLevel #44886 pkg crypto/tls, type QUICEvent struct, Suite uint16 #44886 pkg crypto/tls, type SessionState struct #60105 pkg crypto/tls, type SessionState struct, EarlyData bool #60107 -pkg crypto/tls, type SessionState struct, Extra []uint8 #60105 +pkg crypto/tls, type SessionState struct, Extra [][]uint8 #60539 pkg crypto/x509, type RevocationListEntry struct #53573 pkg crypto/x509, type RevocationListEntry struct, Extensions []pkix.Extension #53573 pkg crypto/x509, type RevocationListEntry struct, ExtraExtensions []pkix.Extension #53573 diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go index 224e17296f..72e8bd8c25 100644 --- a/src/crypto/tls/handshake_messages_test.go +++ b/src/crypto/tls/handshake_messages_test.go @@ -355,7 +355,9 @@ func (*SessionState) Generate(rand *rand.Rand, size int) reflect.Value { s.cipherSuite = uint16(rand.Intn(math.MaxUint16)) s.createdAt = uint64(rand.Int63()) s.secret = randomBytes(rand.Intn(100)+1, rand) - s.Extra = randomBytes(rand.Intn(100), rand) + for n, i := rand.Intn(3), 0; i < n; i++ { + s.Extra = append(s.Extra, randomBytes(rand.Intn(100), rand)) + } if rand.Intn(10) > 5 { s.EarlyData = true } diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go index 1a3d0c7cfd..b43101ff66 100644 --- a/src/crypto/tls/ticket.go +++ b/src/crypto/tls/ticket.go @@ -27,13 +27,15 @@ type SessionState struct { // // Certificate CertificateChain<0..2^24-1>; // + // opaque Extra<0..2^24-1>; + // // struct { // uint16 version; // SessionStateType type; // uint16 cipher_suite; // uint64 created_at; // opaque secret<1..2^8-1>; - // opaque extra<0..2^24-1>; + // Extra extra<0..2^24-1>; // uint8 ext_master_secret = { 0, 1 }; // uint8 early_data = { 0, 1 }; // CertificateEntry certificate_list<0..2^24-1>; @@ -62,12 +64,13 @@ type SessionState struct { // // This allows [Config.UnwrapSession]/[Config.WrapSession] and // [ClientSessionCache] implementations to store and retrieve additional - // data. + // data alongside this session. // - // 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 + // To allow different layers in a protocol stack to share this field, + // applications must only append to it, not replace it, and must use entries + // that can be recognized even if out of order (for example, by starting + // with a id and version prefix). + Extra [][]byte // EarlyData indicates whether the ticket can be used for 0-RTT in a QUIC // connection. The application may set this to false if it is true to @@ -115,7 +118,11 @@ func (s *SessionState) Bytes() ([]byte, error) { b.AddBytes(s.secret) }) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(s.Extra) + for _, extra := range s.Extra { + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(extra) + }) + } }) if s.extMasterSecret { b.AddUint8(1) @@ -176,19 +183,27 @@ func ParseSessionState(data []byte) (*SessionState, error) { s := cryptobyte.String(data) var typ, extMasterSecret, earlyData uint8 var cert Certificate + var extra cryptobyte.String if !s.ReadUint16(&ss.version) || !s.ReadUint8(&typ) || (typ != 1 && typ != 2) || !s.ReadUint16(&ss.cipherSuite) || !readUint64(&s, &ss.createdAt) || !readUint8LengthPrefixed(&s, &ss.secret) || - !readUint24LengthPrefixed(&s, &ss.Extra) || + !s.ReadUint24LengthPrefixed(&extra) || !s.ReadUint8(&extMasterSecret) || !s.ReadUint8(&earlyData) || len(ss.secret) == 0 || !unmarshalCertificate(&s, &cert) { return nil, errors.New("tls: invalid session encoding") } + for !extra.Empty() { + var e []byte + if !readUint24LengthPrefixed(&extra, &e) { + return nil, errors.New("tls: invalid session encoding") + } + ss.Extra = append(ss.Extra, e) + } switch extMasterSecret { case 0: ss.extMasterSecret = false -- 2.50.0