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 5package runner 6 7import ( 8 "crypto/aes" 9 "crypto/cipher" 10 "crypto/hmac" 11 "crypto/sha256" 12 "crypto/subtle" 13 "errors" 14 "io" 15 "time" 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. 22type sessionState struct { 23 vers uint16 24 cipherSuite uint16 25 secret []byte 26 handshakeHash []byte 27 certificates [][]byte 28 extendedMasterSecret bool 29 earlyALPN []byte 30 ticketCreationTime time.Time 31 ticketExpiration time.Time 32 ticketFlags uint32 33 ticketAgeAdd uint32 34 hasApplicationSettings bool 35 localApplicationSettings []byte 36 peerApplicationSettings []byte 37 hasApplicationSettingsOld bool 38 localApplicationSettingsOld []byte 39 peerApplicationSettingsOld []byte 40} 41 42func (s *sessionState) marshal() []byte { 43 msg := cryptobyte.NewBuilder(nil) 44 msg.AddUint16(s.vers) 45 msg.AddUint16(s.cipherSuite) 46 addUint16LengthPrefixedBytes(msg, s.secret) 47 addUint16LengthPrefixedBytes(msg, s.handshakeHash) 48 msg.AddUint16(uint16(len(s.certificates))) 49 for _, cert := range s.certificates { 50 addUint24LengthPrefixedBytes(msg, cert) 51 } 52 53 if s.extendedMasterSecret { 54 msg.AddUint8(1) 55 } else { 56 msg.AddUint8(0) 57 } 58 59 if s.vers >= VersionTLS13 { 60 msg.AddUint64(uint64(s.ticketCreationTime.UnixNano())) 61 msg.AddUint64(uint64(s.ticketExpiration.UnixNano())) 62 msg.AddUint32(s.ticketFlags) 63 msg.AddUint32(s.ticketAgeAdd) 64 } 65 66 addUint16LengthPrefixedBytes(msg, s.earlyALPN) 67 68 if s.hasApplicationSettings { 69 msg.AddUint8(1) 70 addUint16LengthPrefixedBytes(msg, s.localApplicationSettings) 71 addUint16LengthPrefixedBytes(msg, s.peerApplicationSettings) 72 } else { 73 msg.AddUint8(0) 74 } 75 76 if s.hasApplicationSettingsOld { 77 msg.AddUint8(1) 78 addUint16LengthPrefixedBytes(msg, s.localApplicationSettingsOld) 79 addUint16LengthPrefixedBytes(msg, s.peerApplicationSettingsOld) 80 } else { 81 msg.AddUint8(0) 82 } 83 84 return msg.BytesOrPanic() 85} 86 87func readBool(reader *cryptobyte.String, out *bool) bool { 88 var value uint8 89 if !reader.ReadUint8(&value) { 90 return false 91 } 92 if value == 0 { 93 *out = false 94 return true 95 } 96 if value == 1 { 97 *out = true 98 return true 99 } 100 return false 101} 102 103func (s *sessionState) unmarshal(data []byte) bool { 104 reader := cryptobyte.String(data) 105 var numCerts uint16 106 if !reader.ReadUint16(&s.vers) || 107 !reader.ReadUint16(&s.cipherSuite) || 108 !readUint16LengthPrefixedBytes(&reader, &s.secret) || 109 !readUint16LengthPrefixedBytes(&reader, &s.handshakeHash) || 110 !reader.ReadUint16(&numCerts) { 111 return false 112 } 113 114 s.certificates = make([][]byte, int(numCerts)) 115 for i := range s.certificates { 116 if !readUint24LengthPrefixedBytes(&reader, &s.certificates[i]) { 117 return false 118 } 119 } 120 121 if !readBool(&reader, &s.extendedMasterSecret) { 122 return false 123 } 124 125 if s.vers >= VersionTLS13 { 126 var ticketCreationTime, ticketExpiration uint64 127 if !reader.ReadUint64(&ticketCreationTime) || 128 !reader.ReadUint64(&ticketExpiration) || 129 !reader.ReadUint32(&s.ticketFlags) || 130 !reader.ReadUint32(&s.ticketAgeAdd) { 131 return false 132 } 133 s.ticketCreationTime = time.Unix(0, int64(ticketCreationTime)) 134 s.ticketExpiration = time.Unix(0, int64(ticketExpiration)) 135 } 136 137 if !readUint16LengthPrefixedBytes(&reader, &s.earlyALPN) || 138 !readBool(&reader, &s.hasApplicationSettings) { 139 return false 140 } 141 142 if s.hasApplicationSettings { 143 if !readUint16LengthPrefixedBytes(&reader, &s.localApplicationSettings) || 144 !readUint16LengthPrefixedBytes(&reader, &s.peerApplicationSettings) { 145 return false 146 } 147 } 148 149 if !readBool(&reader, &s.hasApplicationSettingsOld) { 150 return false 151 } 152 153 if s.hasApplicationSettingsOld { 154 if !readUint16LengthPrefixedBytes(&reader, &s.localApplicationSettingsOld) || 155 !readUint16LengthPrefixedBytes(&reader, &s.peerApplicationSettingsOld) { 156 return false 157 } 158 } 159 160 if len(reader) > 0 { 161 return false 162 } 163 164 return true 165} 166 167func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { 168 key := c.config.SessionTicketKey[:] 169 if c.config.Bugs.EncryptSessionTicketKey != nil { 170 key = c.config.Bugs.EncryptSessionTicketKey[:] 171 } 172 173 serialized := state.marshal() 174 encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size) 175 iv := encrypted[:aes.BlockSize] 176 macBytes := encrypted[len(encrypted)-sha256.Size:] 177 178 if _, err := io.ReadFull(c.config.rand(), iv); err != nil { 179 return nil, err 180 } 181 block, err := aes.NewCipher(key[:16]) 182 if err != nil { 183 return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) 184 } 185 cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized) 186 187 mac := hmac.New(sha256.New, key[16:32]) 188 mac.Write(encrypted[:len(encrypted)-sha256.Size]) 189 mac.Sum(macBytes[:0]) 190 191 return encrypted, nil 192} 193 194func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { 195 if len(encrypted) < aes.BlockSize+sha256.Size { 196 return nil, false 197 } 198 199 iv := encrypted[:aes.BlockSize] 200 macBytes := encrypted[len(encrypted)-sha256.Size:] 201 202 mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32]) 203 mac.Write(encrypted[:len(encrypted)-sha256.Size]) 204 expected := mac.Sum(nil) 205 206 if subtle.ConstantTimeCompare(macBytes, expected) != 1 { 207 return nil, false 208 } 209 210 block, err := aes.NewCipher(c.config.SessionTicketKey[:16]) 211 if err != nil { 212 return nil, false 213 } 214 ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size] 215 plaintext := make([]byte, len(ciphertext)) 216 cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) 217 218 state := new(sessionState) 219 ok := state.unmarshal(plaintext) 220 return state, ok 221} 222