1
2
3
4
5 package tls
6
7 import (
8 "crypto/aes"
9 "crypto/cipher"
10 "crypto/hmac"
11 "crypto/sha256"
12 "crypto/subtle"
13 "crypto/x509"
14 "errors"
15 "io"
16
17 "golang.org/x/crypto/cryptobyte"
18 )
19
20
21 type SessionState struct {
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 Extra [][]byte
74
75
76
77
78 EarlyData bool
79
80 version uint16
81 isClient bool
82 cipherSuite uint16
83
84
85
86 createdAt uint64
87 secret []byte
88 extMasterSecret bool
89 peerCertificates []*x509.Certificate
90 activeCertHandles []*activeCert
91 ocspResponse []byte
92 scts [][]byte
93 verifiedChains [][]*x509.Certificate
94 alpnProtocol string
95
96
97 useBy uint64
98 ageAdd uint32
99 ticket []byte
100 }
101
102
103
104
105
106
107
108 func (s *SessionState) Bytes() ([]byte, error) {
109 var b cryptobyte.Builder
110 b.AddUint16(s.version)
111 if s.isClient {
112 b.AddUint8(2)
113 } else {
114 b.AddUint8(1)
115 }
116 b.AddUint16(s.cipherSuite)
117 addUint64(&b, s.createdAt)
118 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
119 b.AddBytes(s.secret)
120 })
121 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
122 for _, extra := range s.Extra {
123 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
124 b.AddBytes(extra)
125 })
126 }
127 })
128 if s.extMasterSecret {
129 b.AddUint8(1)
130 } else {
131 b.AddUint8(0)
132 }
133 if s.EarlyData {
134 b.AddUint8(1)
135 } else {
136 b.AddUint8(0)
137 }
138 marshalCertificate(&b, Certificate{
139 Certificate: certificatesToBytesSlice(s.peerCertificates),
140 OCSPStaple: s.ocspResponse,
141 SignedCertificateTimestamps: s.scts,
142 })
143 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
144 for _, chain := range s.verifiedChains {
145 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
146
147 if len(chain) == 0 {
148 b.SetError(errors.New("tls: internal error: empty verified chain"))
149 return
150 }
151 for _, cert := range chain[1:] {
152 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
153 b.AddBytes(cert.Raw)
154 })
155 }
156 })
157 }
158 })
159 if s.EarlyData {
160 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
161 b.AddBytes([]byte(s.alpnProtocol))
162 })
163 }
164 if s.isClient {
165 if s.version >= VersionTLS13 {
166 addUint64(&b, s.useBy)
167 b.AddUint32(s.ageAdd)
168 }
169 }
170 return b.Bytes()
171 }
172
173 func certificatesToBytesSlice(certs []*x509.Certificate) [][]byte {
174 s := make([][]byte, 0, len(certs))
175 for _, c := range certs {
176 s = append(s, c.Raw)
177 }
178 return s
179 }
180
181
182 func ParseSessionState(data []byte) (*SessionState, error) {
183 ss := &SessionState{}
184 s := cryptobyte.String(data)
185 var typ, extMasterSecret, earlyData uint8
186 var cert Certificate
187 var extra cryptobyte.String
188 if !s.ReadUint16(&ss.version) ||
189 !s.ReadUint8(&typ) ||
190 (typ != 1 && typ != 2) ||
191 !s.ReadUint16(&ss.cipherSuite) ||
192 !readUint64(&s, &ss.createdAt) ||
193 !readUint8LengthPrefixed(&s, &ss.secret) ||
194 !s.ReadUint24LengthPrefixed(&extra) ||
195 !s.ReadUint8(&extMasterSecret) ||
196 !s.ReadUint8(&earlyData) ||
197 len(ss.secret) == 0 ||
198 !unmarshalCertificate(&s, &cert) {
199 return nil, errors.New("tls: invalid session encoding")
200 }
201 for !extra.Empty() {
202 var e []byte
203 if !readUint24LengthPrefixed(&extra, &e) {
204 return nil, errors.New("tls: invalid session encoding")
205 }
206 ss.Extra = append(ss.Extra, e)
207 }
208 switch extMasterSecret {
209 case 0:
210 ss.extMasterSecret = false
211 case 1:
212 ss.extMasterSecret = true
213 default:
214 return nil, errors.New("tls: invalid session encoding")
215 }
216 switch earlyData {
217 case 0:
218 ss.EarlyData = false
219 case 1:
220 ss.EarlyData = true
221 default:
222 return nil, errors.New("tls: invalid session encoding")
223 }
224 for _, cert := range cert.Certificate {
225 c, err := globalCertCache.newCert(cert)
226 if err != nil {
227 return nil, err
228 }
229 ss.activeCertHandles = append(ss.activeCertHandles, c)
230 ss.peerCertificates = append(ss.peerCertificates, c.cert)
231 }
232 ss.ocspResponse = cert.OCSPStaple
233 ss.scts = cert.SignedCertificateTimestamps
234 var chainList cryptobyte.String
235 if !s.ReadUint24LengthPrefixed(&chainList) {
236 return nil, errors.New("tls: invalid session encoding")
237 }
238 for !chainList.Empty() {
239 var certList cryptobyte.String
240 if !chainList.ReadUint24LengthPrefixed(&certList) {
241 return nil, errors.New("tls: invalid session encoding")
242 }
243 var chain []*x509.Certificate
244 if len(ss.peerCertificates) == 0 {
245 return nil, errors.New("tls: invalid session encoding")
246 }
247 chain = append(chain, ss.peerCertificates[0])
248 for !certList.Empty() {
249 var cert []byte
250 if !readUint24LengthPrefixed(&certList, &cert) {
251 return nil, errors.New("tls: invalid session encoding")
252 }
253 c, err := globalCertCache.newCert(cert)
254 if err != nil {
255 return nil, err
256 }
257 ss.activeCertHandles = append(ss.activeCertHandles, c)
258 chain = append(chain, c.cert)
259 }
260 ss.verifiedChains = append(ss.verifiedChains, chain)
261 }
262 if ss.EarlyData {
263 var alpn []byte
264 if !readUint8LengthPrefixed(&s, &alpn) {
265 return nil, errors.New("tls: invalid session encoding")
266 }
267 ss.alpnProtocol = string(alpn)
268 }
269 if isClient := typ == 2; !isClient {
270 if !s.Empty() {
271 return nil, errors.New("tls: invalid session encoding")
272 }
273 return ss, nil
274 }
275 ss.isClient = true
276 if len(ss.peerCertificates) == 0 {
277 return nil, errors.New("tls: no server certificates in client session")
278 }
279 if ss.version < VersionTLS13 {
280 if !s.Empty() {
281 return nil, errors.New("tls: invalid session encoding")
282 }
283 return ss, nil
284 }
285 if !s.ReadUint64(&ss.useBy) || !s.ReadUint32(&ss.ageAdd) || !s.Empty() {
286 return nil, errors.New("tls: invalid session encoding")
287 }
288 return ss, nil
289 }
290
291
292
293 func (c *Conn) sessionState() *SessionState {
294 return &SessionState{
295 version: c.vers,
296 cipherSuite: c.cipherSuite,
297 createdAt: uint64(c.config.time().Unix()),
298 alpnProtocol: c.clientProtocol,
299 peerCertificates: c.peerCertificates,
300 activeCertHandles: c.activeCertHandles,
301 ocspResponse: c.ocspResponse,
302 scts: c.scts,
303 isClient: c.isClient,
304 extMasterSecret: c.extMasterSecret,
305 verifiedChains: c.verifiedChains,
306 }
307 }
308
309
310
311 func (c *Config) EncryptTicket(cs ConnectionState, ss *SessionState) ([]byte, error) {
312 ticketKeys := c.ticketKeys(nil)
313 stateBytes, err := ss.Bytes()
314 if err != nil {
315 return nil, err
316 }
317 return c.encryptTicket(stateBytes, ticketKeys)
318 }
319
320 func (c *Config) encryptTicket(state []byte, ticketKeys []ticketKey) ([]byte, error) {
321 if len(ticketKeys) == 0 {
322 return nil, errors.New("tls: internal error: session ticket keys unavailable")
323 }
324
325 encrypted := make([]byte, aes.BlockSize+len(state)+sha256.Size)
326 iv := encrypted[:aes.BlockSize]
327 ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
328 authenticated := encrypted[:len(encrypted)-sha256.Size]
329 macBytes := encrypted[len(encrypted)-sha256.Size:]
330
331 if _, err := io.ReadFull(c.rand(), iv); err != nil {
332 return nil, err
333 }
334 key := ticketKeys[0]
335 block, err := aes.NewCipher(key.aesKey[:])
336 if err != nil {
337 return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
338 }
339 cipher.NewCTR(block, iv).XORKeyStream(ciphertext, state)
340
341 mac := hmac.New(sha256.New, key.hmacKey[:])
342 mac.Write(authenticated)
343 mac.Sum(macBytes[:0])
344
345 return encrypted, nil
346 }
347
348
349
350
351
352 func (c *Config) DecryptTicket(identity []byte, cs ConnectionState) (*SessionState, error) {
353 ticketKeys := c.ticketKeys(nil)
354 stateBytes := c.decryptTicket(identity, ticketKeys)
355 if stateBytes == nil {
356 return nil, nil
357 }
358 s, err := ParseSessionState(stateBytes)
359 if err != nil {
360 return nil, nil
361 }
362 return s, nil
363 }
364
365 func (c *Config) decryptTicket(encrypted []byte, ticketKeys []ticketKey) []byte {
366 if len(encrypted) < aes.BlockSize+sha256.Size {
367 return nil
368 }
369
370 iv := encrypted[:aes.BlockSize]
371 ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
372 authenticated := encrypted[:len(encrypted)-sha256.Size]
373 macBytes := encrypted[len(encrypted)-sha256.Size:]
374
375 for _, key := range ticketKeys {
376 mac := hmac.New(sha256.New, key.hmacKey[:])
377 mac.Write(authenticated)
378 expected := mac.Sum(nil)
379
380 if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
381 continue
382 }
383
384 block, err := aes.NewCipher(key.aesKey[:])
385 if err != nil {
386 return nil
387 }
388 plaintext := make([]byte, len(ciphertext))
389 cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
390
391 return plaintext
392 }
393
394 return nil
395 }
396
397
398
399 type ClientSessionState struct {
400 session *SessionState
401 }
402
403
404
405
406
407
408 func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionState, err error) {
409 if cs == nil || cs.session == nil {
410 return nil, nil, nil
411 }
412 return cs.session.ticket, cs.session, nil
413 }
414
415
416
417
418
419
420 func NewResumptionState(ticket []byte, state *SessionState) (*ClientSessionState, error) {
421 state.ticket = ticket
422 return &ClientSessionState{
423 session: state,
424 }, nil
425 }
426
View as plain text