github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/tls/ticket.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 // A SessionState is a resumable session. 21 type SessionState struct { 22 // Encoded as a SessionState (in the language of RFC 8446, Section 3). 23 // 24 // enum { server(1), client(2) } SessionStateType; 25 // 26 // opaque Certificate<1..2^24-1>; 27 // 28 // Certificate CertificateChain<0..2^24-1>; 29 // 30 // opaque Extra<0..2^24-1>; 31 // 32 // struct { 33 // uint16 version; 34 // SessionStateType type; 35 // uint16 cipher_suite; 36 // uint64 created_at; 37 // opaque secret<1..2^8-1>; 38 // Extra extra<0..2^24-1>; 39 // uint8 ext_master_secret = { 0, 1 }; 40 // uint8 early_data = { 0, 1 }; 41 // CertificateEntry certificate_list<0..2^24-1>; 42 // CertificateChain verified_chains<0..2^24-1>; /* excluding leaf */ 43 // select (SessionState.early_data) { 44 // case 0: Empty; 45 // case 1: opaque alpn<1..2^8-1>; 46 // }; 47 // select (SessionState.type) { 48 // case server: Empty; 49 // case client: struct { 50 // select (SessionState.version) { 51 // case VersionTLS10..VersionTLS12: Empty; 52 // case VersionTLS13: struct { 53 // uint64 use_by; 54 // uint32 age_add; 55 // }; 56 // }; 57 // }; 58 // }; 59 // } SessionState; 60 // 61 62 // Extra is ignored by crypto/tls, but is encoded by [SessionState.Bytes] 63 // and parsed by [ParseSessionState]. 64 // 65 // This allows [Config.UnwrapSession]/[Config.WrapSession] and 66 // [ClientSessionCache] implementations to store and retrieve additional 67 // data alongside this session. 68 // 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 74 75 // EarlyData indicates whether the ticket can be used for 0-RTT in a QUIC 76 // connection. The application may set this to false if it is true to 77 // decline to offer 0-RTT even if supported. 78 EarlyData bool 79 80 version uint16 81 isClient bool 82 cipherSuite uint16 83 // createdAt is the generation time of the secret on the sever (which for 84 // TLS 1.0–1.2 might be earlier than the current session) and the time at 85 // which the ticket was received on the client. 86 createdAt uint64 // seconds since UNIX epoch 87 secret []byte // master secret for TLS 1.2, or the PSK for TLS 1.3 88 extMasterSecret bool 89 peerCertificates []*x509.Certificate 90 activeCertHandles []*activeCert 91 ocspResponse []byte 92 scts [][]byte 93 verifiedChains [][]*x509.Certificate 94 alpnProtocol string // only set if EarlyData is true 95 96 // Client-side TLS 1.3-only fields. 97 useBy uint64 // seconds since UNIX epoch 98 ageAdd uint32 99 } 100 101 // Bytes encodes the session, including any private fields, so that it can be 102 // parsed by [ParseSessionState]. The encoding contains secret values critical 103 // to the security of future and possibly past sessions. 104 // 105 // The specific encoding should be considered opaque and may change incompatibly 106 // between Go versions. 107 func (s *SessionState) Bytes() ([]byte, error) { 108 var b cryptobyte.Builder 109 b.AddUint16(s.version) 110 if s.isClient { 111 b.AddUint8(2) // client 112 } else { 113 b.AddUint8(1) // server 114 } 115 b.AddUint16(s.cipherSuite) 116 addUint64(&b, s.createdAt) 117 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 118 b.AddBytes(s.secret) 119 }) 120 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 121 for _, extra := range s.Extra { 122 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 123 b.AddBytes(extra) 124 }) 125 } 126 }) 127 if s.extMasterSecret { 128 b.AddUint8(1) 129 } else { 130 b.AddUint8(0) 131 } 132 if s.EarlyData { 133 b.AddUint8(1) 134 } else { 135 b.AddUint8(0) 136 } 137 marshalCertificate(&b, Certificate{ 138 Certificate: certificatesToBytesSlice(s.peerCertificates), 139 OCSPStaple: s.ocspResponse, 140 SignedCertificateTimestamps: s.scts, 141 }) 142 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 143 for _, chain := range s.verifiedChains { 144 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 145 // We elide the first certificate because it's always the leaf. 146 if len(chain) == 0 { 147 b.SetError(errors.New("tls: internal error: empty verified chain")) 148 return 149 } 150 for _, cert := range chain[1:] { 151 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 152 b.AddBytes(cert.Raw) 153 }) 154 } 155 }) 156 } 157 }) 158 if s.EarlyData { 159 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 160 b.AddBytes([]byte(s.alpnProtocol)) 161 }) 162 } 163 if s.isClient { 164 if s.version >= VersionTLS13 { 165 addUint64(&b, s.useBy) 166 b.AddUint32(s.ageAdd) 167 } 168 } 169 return b.Bytes() 170 } 171 172 func certificatesToBytesSlice(certs []*x509.Certificate) [][]byte { 173 s := make([][]byte, 0, len(certs)) 174 for _, c := range certs { 175 s = append(s, c.Raw) 176 } 177 return s 178 } 179 180 // ParseSessionState parses a [SessionState] encoded by [SessionState.Bytes]. 181 func ParseSessionState(data []byte) (*SessionState, error) { 182 ss := &SessionState{} 183 s := cryptobyte.String(data) 184 var typ, extMasterSecret, earlyData uint8 185 var cert Certificate 186 var extra cryptobyte.String 187 if !s.ReadUint16(&ss.version) || 188 !s.ReadUint8(&typ) || 189 (typ != 1 && typ != 2) || 190 !s.ReadUint16(&ss.cipherSuite) || 191 !readUint64(&s, &ss.createdAt) || 192 !readUint8LengthPrefixed(&s, &ss.secret) || 193 !s.ReadUint24LengthPrefixed(&extra) || 194 !s.ReadUint8(&extMasterSecret) || 195 !s.ReadUint8(&earlyData) || 196 len(ss.secret) == 0 || 197 !unmarshalCertificate(&s, &cert) { 198 return nil, errors.New("tls: invalid session encoding") 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 } 207 switch extMasterSecret { 208 case 0: 209 ss.extMasterSecret = false 210 case 1: 211 ss.extMasterSecret = true 212 default: 213 return nil, errors.New("tls: invalid session encoding") 214 } 215 switch earlyData { 216 case 0: 217 ss.EarlyData = false 218 case 1: 219 ss.EarlyData = true 220 default: 221 return nil, errors.New("tls: invalid session encoding") 222 } 223 for _, cert := range cert.Certificate { 224 c, err := globalCertCache.newCert(cert) 225 if err != nil { 226 return nil, err 227 } 228 ss.activeCertHandles = append(ss.activeCertHandles, c) 229 ss.peerCertificates = append(ss.peerCertificates, c.cert) 230 } 231 ss.ocspResponse = cert.OCSPStaple 232 ss.scts = cert.SignedCertificateTimestamps 233 var chainList cryptobyte.String 234 if !s.ReadUint24LengthPrefixed(&chainList) { 235 return nil, errors.New("tls: invalid session encoding") 236 } 237 for !chainList.Empty() { 238 var certList cryptobyte.String 239 if !chainList.ReadUint24LengthPrefixed(&certList) { 240 return nil, errors.New("tls: invalid session encoding") 241 } 242 var chain []*x509.Certificate 243 if len(ss.peerCertificates) == 0 { 244 return nil, errors.New("tls: invalid session encoding") 245 } 246 chain = append(chain, ss.peerCertificates[0]) 247 for !certList.Empty() { 248 var cert []byte 249 if !readUint24LengthPrefixed(&certList, &cert) { 250 return nil, errors.New("tls: invalid session encoding") 251 } 252 c, err := globalCertCache.newCert(cert) 253 if err != nil { 254 return nil, err 255 } 256 ss.activeCertHandles = append(ss.activeCertHandles, c) 257 chain = append(chain, c.cert) 258 } 259 ss.verifiedChains = append(ss.verifiedChains, chain) 260 } 261 if ss.EarlyData { 262 var alpn []byte 263 if !readUint8LengthPrefixed(&s, &alpn) { 264 return nil, errors.New("tls: invalid session encoding") 265 } 266 ss.alpnProtocol = string(alpn) 267 } 268 if isClient := typ == 2; !isClient { 269 if !s.Empty() { 270 return nil, errors.New("tls: invalid session encoding") 271 } 272 return ss, nil 273 } 274 ss.isClient = true 275 if len(ss.peerCertificates) == 0 { 276 return nil, errors.New("tls: no server certificates in client session") 277 } 278 if ss.version < VersionTLS13 { 279 if !s.Empty() { 280 return nil, errors.New("tls: invalid session encoding") 281 } 282 return ss, nil 283 } 284 if !s.ReadUint64(&ss.useBy) || !s.ReadUint32(&ss.ageAdd) || !s.Empty() { 285 return nil, errors.New("tls: invalid session encoding") 286 } 287 return ss, nil 288 } 289 290 // sessionState returns a partially filled-out [SessionState] with information 291 // from the current connection. 292 func (c *Conn) sessionState() (*SessionState, error) { 293 return &SessionState{ 294 version: c.vers, 295 cipherSuite: c.cipherSuite, 296 createdAt: uint64(c.config.time().Unix()), 297 alpnProtocol: c.clientProtocol, 298 peerCertificates: c.peerCertificates, 299 activeCertHandles: c.activeCertHandles, 300 ocspResponse: c.ocspResponse, 301 scts: c.scts, 302 isClient: c.isClient, 303 extMasterSecret: c.extMasterSecret, 304 verifiedChains: c.verifiedChains, 305 }, nil 306 } 307 308 // EncryptTicket encrypts a ticket with the Config's configured (or default) 309 // session ticket keys. It can be used as a [Config.WrapSession] implementation. 310 func (c *Config) EncryptTicket(cs ConnectionState, ss *SessionState) ([]byte, error) { 311 ticketKeys := c.ticketKeys(nil) 312 stateBytes, err := ss.Bytes() 313 if err != nil { 314 return nil, err 315 } 316 return c.encryptTicket(stateBytes, ticketKeys) 317 } 318 319 func (c *Config) encryptTicket(state []byte, ticketKeys []ticketKey) ([]byte, error) { 320 if len(ticketKeys) == 0 { 321 return nil, errors.New("tls: internal error: session ticket keys unavailable") 322 } 323 324 encrypted := make([]byte, aes.BlockSize+len(state)+sha256.Size) 325 iv := encrypted[:aes.BlockSize] 326 ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size] 327 authenticated := encrypted[:len(encrypted)-sha256.Size] 328 macBytes := encrypted[len(encrypted)-sha256.Size:] 329 330 if _, err := io.ReadFull(c.rand(), iv); err != nil { 331 return nil, err 332 } 333 key := ticketKeys[0] 334 block, err := aes.NewCipher(key.aesKey[:]) 335 if err != nil { 336 return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) 337 } 338 cipher.NewCTR(block, iv).XORKeyStream(ciphertext, state) 339 340 mac := hmac.New(sha256.New, key.hmacKey[:]) 341 mac.Write(authenticated) 342 mac.Sum(macBytes[:0]) 343 344 return encrypted, nil 345 } 346 347 // DecryptTicket decrypts a ticket encrypted by [Config.EncryptTicket]. It can 348 // be used as a [Config.UnwrapSession] implementation. 349 // 350 // If the ticket can't be decrypted or parsed, DecryptTicket returns (nil, nil). 351 func (c *Config) DecryptTicket(identity []byte, cs ConnectionState) (*SessionState, error) { 352 ticketKeys := c.ticketKeys(nil) 353 stateBytes := c.decryptTicket(identity, ticketKeys) 354 if stateBytes == nil { 355 return nil, nil 356 } 357 s, err := ParseSessionState(stateBytes) 358 if err != nil { 359 return nil, nil // drop unparsable tickets on the floor 360 } 361 return s, nil 362 } 363 364 func (c *Config) decryptTicket(encrypted []byte, ticketKeys []ticketKey) []byte { 365 if len(encrypted) < aes.BlockSize+sha256.Size { 366 return nil 367 } 368 369 iv := encrypted[:aes.BlockSize] 370 ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size] 371 authenticated := encrypted[:len(encrypted)-sha256.Size] 372 macBytes := encrypted[len(encrypted)-sha256.Size:] 373 374 for _, key := range ticketKeys { 375 mac := hmac.New(sha256.New, key.hmacKey[:]) 376 mac.Write(authenticated) 377 expected := mac.Sum(nil) 378 379 if subtle.ConstantTimeCompare(macBytes, expected) != 1 { 380 continue 381 } 382 383 block, err := aes.NewCipher(key.aesKey[:]) 384 if err != nil { 385 return nil 386 } 387 plaintext := make([]byte, len(ciphertext)) 388 cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) 389 390 return plaintext 391 } 392 393 return nil 394 } 395 396 // ClientSessionState contains the state needed by a client to 397 // resume a previous TLS session. 398 type ClientSessionState struct { 399 ticket []byte 400 session *SessionState 401 } 402 403 // ResumptionState returns the session ticket sent by the server (also known as 404 // the session's identity) and the state necessary to resume this session. 405 // 406 // It can be called by [ClientSessionCache.Put] to serialize (with 407 // [SessionState.Bytes]) and store the session. 408 func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionState, err error) { 409 return cs.ticket, cs.session, nil 410 } 411 412 // NewResumptionState returns a state value that can be returned by 413 // [ClientSessionCache.Get] to resume a previous session. 414 // 415 // state needs to be returned by [ParseSessionState], and the ticket and session 416 // state must have been returned by [ClientSessionState.ResumptionState]. 417 func NewResumptionState(ticket []byte, state *SessionState) (*ClientSessionState, error) { 418 return &ClientSessionState{ 419 ticket: ticket, session: state, 420 }, nil 421 }