@@ -27,13 +27,15 @@ type SessionState struct {
27
27
//
28
28
// Certificate CertificateChain<0..2^24-1>;
29
29
//
30
+ // opaque Extra<0..2^24-1>;
31
+ //
30
32
// struct {
31
33
// uint16 version;
32
34
// SessionStateType type;
33
35
// uint16 cipher_suite;
34
36
// uint64 created_at;
35
37
// opaque secret<1..2^8-1>;
36
- // opaque extra<0..2^24-1>;
38
+ // Extra extra<0..2^24-1>;
37
39
// uint8 ext_master_secret = { 0, 1 };
38
40
// uint8 early_data = { 0, 1 };
39
41
// CertificateEntry certificate_list<0..2^24-1>;
@@ -62,12 +64,13 @@ type SessionState struct {
62
64
//
63
65
// This allows [Config.UnwrapSession]/[Config.WrapSession] and
64
66
// [ClientSessionCache] implementations to store and retrieve additional
65
- // data.
67
+ // data alongside this session .
66
68
//
67
- // If Extra is already set, the implementation must preserve the previous
68
- // value across a round-trip, for example by appending and stripping a
69
- // fixed-length suffix.
70
- Extra []byte
69
+ // To allow different layers in a protocol stack to share this field,
70
+ // applications must only append to it, not replace it, and must use entries
71
+ // that can be recognized even if out of order (for example, by starting
72
+ // with a id and version prefix).
73
+ Extra [][]byte
71
74
72
75
// EarlyData indicates whether the ticket can be used for 0-RTT in a QUIC
73
76
// connection. The application may set this to false if it is true to
@@ -115,7 +118,11 @@ func (s *SessionState) Bytes() ([]byte, error) {
115
118
b .AddBytes (s .secret )
116
119
})
117
120
b .AddUint24LengthPrefixed (func (b * cryptobyte.Builder ) {
118
- b .AddBytes (s .Extra )
121
+ for _ , extra := range s .Extra {
122
+ b .AddUint24LengthPrefixed (func (b * cryptobyte.Builder ) {
123
+ b .AddBytes (extra )
124
+ })
125
+ }
119
126
})
120
127
if s .extMasterSecret {
121
128
b .AddUint8 (1 )
@@ -176,19 +183,27 @@ func ParseSessionState(data []byte) (*SessionState, error) {
176
183
s := cryptobyte .String (data )
177
184
var typ , extMasterSecret , earlyData uint8
178
185
var cert Certificate
186
+ var extra cryptobyte.String
179
187
if ! s .ReadUint16 (& ss .version ) ||
180
188
! s .ReadUint8 (& typ ) ||
181
189
(typ != 1 && typ != 2 ) ||
182
190
! s .ReadUint16 (& ss .cipherSuite ) ||
183
191
! readUint64 (& s , & ss .createdAt ) ||
184
192
! readUint8LengthPrefixed (& s , & ss .secret ) ||
185
- ! readUint24LengthPrefixed ( & s , & ss . Extra ) ||
193
+ ! s . ReadUint24LengthPrefixed ( & extra ) ||
186
194
! s .ReadUint8 (& extMasterSecret ) ||
187
195
! s .ReadUint8 (& earlyData ) ||
188
196
len (ss .secret ) == 0 ||
189
197
! unmarshalCertificate (& s , & cert ) {
190
198
return nil , errors .New ("tls: invalid session encoding" )
191
199
}
200
+ for ! extra .Empty () {
201
+ var e []byte
202
+ if ! readUint24LengthPrefixed (& extra , & e ) {
203
+ return nil , errors .New ("tls: invalid session encoding" )
204
+ }
205
+ ss .Extra = append (ss .Extra , e )
206
+ }
192
207
switch extMasterSecret {
193
208
case 0 :
194
209
ss .extMasterSecret = false
0 commit comments