github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/crypto/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 "bytes" 9 "crypto/aes" 10 "crypto/cipher" 11 "crypto/hmac" 12 "crypto/sha256" 13 "crypto/subtle" 14 "errors" 15 "io" 16 17 "golang.org/x/crypto/cryptobyte" 18 ) 19 20 // sessionState contains the information that is serialized into a session 21 // ticket in order to later resume a connection. 22 type sessionState struct { 23 vers uint16 24 cipherSuite uint16 25 createdAt uint64 26 masterSecret []byte // opaque master_secret<1..2^16-1>; 27 // struct { opaque certificate<1..2^24-1> } Certificate; 28 certificates [][]byte // Certificate certificate_list<0..2^24-1>; 29 30 // usedOldKey is true if the ticket from which this session came from 31 // was encrypted with an older key and thus should be refreshed. 32 usedOldKey bool 33 } 34 35 func (m *sessionState) marshal() ([]byte, error) { 36 var b cryptobyte.Builder 37 b.AddUint16(m.vers) 38 b.AddUint16(m.cipherSuite) 39 addUint64(&b, m.createdAt) 40 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { 41 b.AddBytes(m.masterSecret) 42 }) 43 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 44 for _, cert := range m.certificates { 45 b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { 46 b.AddBytes(cert) 47 }) 48 } 49 }) 50 return b.Bytes() 51 } 52 53 func (m *sessionState) unmarshal(data []byte) bool { 54 *m = sessionState{usedOldKey: m.usedOldKey} 55 s := cryptobyte.String(data) 56 if ok := s.ReadUint16(&m.vers) && 57 s.ReadUint16(&m.cipherSuite) && 58 readUint64(&s, &m.createdAt) && 59 readUint16LengthPrefixed(&s, &m.masterSecret) && 60 len(m.masterSecret) != 0; !ok { 61 return false 62 } 63 var certList cryptobyte.String 64 if !s.ReadUint24LengthPrefixed(&certList) { 65 return false 66 } 67 for !certList.Empty() { 68 var cert []byte 69 if !readUint24LengthPrefixed(&certList, &cert) { 70 return false 71 } 72 m.certificates = append(m.certificates, cert) 73 } 74 return s.Empty() 75 } 76 77 // sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first 78 // version (revision = 0) doesn't carry any of the information needed for 0-RTT 79 // validation and the nonce is always empty. 80 type sessionStateTLS13 struct { 81 // uint8 version = 0x0304; 82 // uint8 revision = 0; 83 cipherSuite uint16 84 createdAt uint64 85 resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>; 86 certificate Certificate // CertificateEntry certificate_list<0..2^24-1>; 87 } 88 89 func (m *sessionStateTLS13) marshal() ([]byte, error) { 90 var b cryptobyte.Builder 91 b.AddUint16(VersionTLS13) 92 b.AddUint8(0) // revision 93 b.AddUint16(m.cipherSuite) 94 addUint64(&b, m.createdAt) 95 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 96 b.AddBytes(m.resumptionSecret) 97 }) 98 marshalCertificate(&b, m.certificate) 99 return b.Bytes() 100 } 101 102 func (m *sessionStateTLS13) unmarshal(data []byte) bool { 103 *m = sessionStateTLS13{} 104 s := cryptobyte.String(data) 105 var version uint16 106 var revision uint8 107 return s.ReadUint16(&version) && 108 version == VersionTLS13 && 109 s.ReadUint8(&revision) && 110 revision == 0 && 111 s.ReadUint16(&m.cipherSuite) && 112 readUint64(&s, &m.createdAt) && 113 readUint8LengthPrefixed(&s, &m.resumptionSecret) && 114 len(m.resumptionSecret) != 0 && 115 unmarshalCertificate(&s, &m.certificate) && 116 s.Empty() 117 } 118 119 func (c *Conn) encryptTicket(state []byte) ([]byte, error) { 120 if len(c.ticketKeys) == 0 { 121 return nil, errors.New("tls: internal error: session ticket keys unavailable") 122 } 123 124 encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size) 125 keyName := encrypted[:ticketKeyNameLen] 126 iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] 127 macBytes := encrypted[len(encrypted)-sha256.Size:] 128 129 if _, err := io.ReadFull(c.config.rand(), iv); err != nil { 130 return nil, err 131 } 132 key := c.ticketKeys[0] 133 copy(keyName, key.keyName[:]) 134 block, err := aes.NewCipher(key.aesKey[:]) 135 if err != nil { 136 return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) 137 } 138 cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state) 139 140 mac := hmac.New(sha256.New, key.hmacKey[:]) 141 mac.Write(encrypted[:len(encrypted)-sha256.Size]) 142 mac.Sum(macBytes[:0]) 143 144 return encrypted, nil 145 } 146 147 func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) { 148 if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { 149 return nil, false 150 } 151 152 keyName := encrypted[:ticketKeyNameLen] 153 iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] 154 macBytes := encrypted[len(encrypted)-sha256.Size:] 155 ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] 156 157 keyIndex := -1 158 for i, candidateKey := range c.ticketKeys { 159 if bytes.Equal(keyName, candidateKey.keyName[:]) { 160 keyIndex = i 161 break 162 } 163 } 164 if keyIndex == -1 { 165 return nil, false 166 } 167 key := &c.ticketKeys[keyIndex] 168 169 mac := hmac.New(sha256.New, key.hmacKey[:]) 170 mac.Write(encrypted[:len(encrypted)-sha256.Size]) 171 expected := mac.Sum(nil) 172 173 if subtle.ConstantTimeCompare(macBytes, expected) != 1 { 174 return nil, false 175 } 176 177 block, err := aes.NewCipher(key.aesKey[:]) 178 if err != nil { 179 return nil, false 180 } 181 plaintext = make([]byte, len(ciphertext)) 182 cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) 183 184 return plaintext, keyIndex > 0 185 }