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