github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/core/access_contoller/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 masterSecret []byte 26 certificates [][]byte 27 // usedOldKey is true if the ticket from which this session came from 28 // was encrypted with an older key and thus should be refreshed. 29 usedOldKey bool 30 } 31 32 func (s *sessionState) marshal() []byte { 33 length := 2 + 2 + 2 + len(s.masterSecret) + 2 34 for _, cert := range s.certificates { 35 length += 4 + len(cert) 36 } 37 38 ret := make([]byte, length) 39 x := ret 40 x[0] = byte(s.vers >> 8) 41 x[1] = byte(s.vers) 42 x[2] = byte(s.cipherSuite >> 8) 43 x[3] = byte(s.cipherSuite) 44 x[4] = byte(len(s.masterSecret) >> 8) 45 x[5] = byte(len(s.masterSecret)) 46 x = x[6:] 47 copy(x, s.masterSecret) 48 x = x[len(s.masterSecret):] 49 50 x[0] = byte(len(s.certificates) >> 8) 51 x[1] = byte(len(s.certificates)) 52 x = x[2:] 53 54 for _, cert := range s.certificates { 55 x[0] = byte(len(cert) >> 24) 56 x[1] = byte(len(cert) >> 16) 57 x[2] = byte(len(cert) >> 8) 58 x[3] = byte(len(cert)) 59 copy(x[4:], cert) 60 x = x[4+len(cert):] 61 } 62 63 return ret 64 } 65 66 func (s *sessionState) unmarshal(data []byte) bool { 67 if len(data) < 8 { 68 return false 69 } 70 71 s.vers = uint16(data[0])<<8 | uint16(data[1]) 72 s.cipherSuite = uint16(data[2])<<8 | uint16(data[3]) 73 masterSecretLen := int(data[4])<<8 | int(data[5]) 74 data = data[6:] 75 if len(data) < masterSecretLen { 76 return false 77 } 78 79 s.masterSecret = data[:masterSecretLen] 80 data = data[masterSecretLen:] 81 82 if len(data) < 2 { 83 return false 84 } 85 86 numCerts := int(data[0])<<8 | int(data[1]) 87 data = data[2:] 88 89 s.certificates = make([][]byte, numCerts) 90 for i := range s.certificates { 91 if len(data) < 4 { 92 return false 93 } 94 certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) 95 data = data[4:] 96 if certLen < 0 { 97 return false 98 } 99 if len(data) < certLen { 100 return false 101 } 102 s.certificates[i] = data[:certLen] 103 data = data[certLen:] 104 } 105 106 return len(data) == 0 107 } 108 109 // sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first 110 // version (revision = 0) doesn't carry any of the information needed for 0-RTT 111 // validation and the nonce is always empty. 112 type sessionStateTLS13 struct { 113 // uint8 version = 0x0304; 114 // uint8 revision = 0; 115 cipherSuite uint16 116 createdAt uint64 117 resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>; 118 certificate Certificate // CertificateEntry certificate_list<0..2^24-1>; 119 } 120 121 func (m *sessionStateTLS13) marshal() []byte { 122 var b cryptobyte.Builder 123 b.AddUint16(VersionTLS13) 124 b.AddUint8(0) // revision 125 b.AddUint16(m.cipherSuite) 126 addUint64(&b, m.createdAt) 127 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 128 b.AddBytes(m.resumptionSecret) 129 }) 130 marshalCertificate(&b, m.certificate) 131 return b.BytesOrPanic() 132 } 133 134 func (m *sessionStateTLS13) unmarshal(data []byte) bool { 135 *m = sessionStateTLS13{} 136 s := cryptobyte.String(data) 137 var version uint16 138 var revision uint8 139 return s.ReadUint16(&version) && 140 version == VersionTLS13 && 141 s.ReadUint8(&revision) && 142 revision == 0 && 143 s.ReadUint16(&m.cipherSuite) && 144 readUint64(&s, &m.createdAt) && 145 readUint8LengthPrefixed(&s, &m.resumptionSecret) && 146 len(m.resumptionSecret) != 0 && 147 unmarshalCertificate(&s, &m.certificate) && 148 s.Empty() 149 } 150 151 func (c *Conn) encryptTicket(state []byte) ([]byte, error) { 152 encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size) 153 keyName := encrypted[:ticketKeyNameLen] 154 iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] 155 macBytes := encrypted[len(encrypted)-sha256.Size:] 156 157 if _, err := io.ReadFull(c.config.rand(), iv); err != nil { 158 return nil, err 159 } 160 key := c.config.ticketKeys()[0] 161 copy(keyName, key.keyName[:]) 162 block, err := aes.NewCipher(key.aesKey[:]) 163 if err != nil { 164 return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) 165 } 166 cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state) 167 168 mac := hmac.New(sha256.New, key.hmacKey[:]) 169 mac.Write(encrypted[:len(encrypted)-sha256.Size]) 170 mac.Sum(macBytes[:0]) 171 172 return encrypted, nil 173 } 174 175 func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) { 176 if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { 177 return nil, false 178 } 179 180 keyName := encrypted[:ticketKeyNameLen] 181 iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] 182 macBytes := encrypted[len(encrypted)-sha256.Size:] 183 ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] 184 185 keys := c.config.ticketKeys() 186 keyIndex := -1 187 for i, candidateKey := range keys { 188 if bytes.Equal(keyName, candidateKey.keyName[:]) { 189 keyIndex = i 190 break 191 } 192 } 193 194 if keyIndex == -1 { 195 return nil, false 196 } 197 key := &keys[keyIndex] 198 199 mac := hmac.New(sha256.New, key.hmacKey[:]) 200 mac.Write(encrypted[:len(encrypted)-sha256.Size]) 201 expected := mac.Sum(nil) 202 203 if subtle.ConstantTimeCompare(macBytes, expected) != 1 { 204 return nil, false 205 } 206 207 block, err := aes.NewCipher(key.aesKey[:]) 208 if err != nil { 209 return nil, false 210 } 211 plaintext = make([]byte, len(ciphertext)) 212 cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) 213 214 return plaintext, keyIndex > 0 215 }