blob: 10ac54f7a4c25c1318dae1af0ffbfeb0d93caf7e [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001// 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
Adam Langleydc7e9c42015-09-29 15:21:04 -07005package runner
Adam Langley95c29f32014-06-20 12:00:00 -07006
7import (
Adam Langley95c29f32014-06-20 12:00:00 -07008 "crypto/aes"
9 "crypto/cipher"
10 "crypto/hmac"
11 "crypto/sha256"
12 "crypto/subtle"
Nick Harper0b3625b2016-07-25 16:16:28 -070013 "encoding/binary"
Adam Langley95c29f32014-06-20 12:00:00 -070014 "errors"
15 "io"
Nick Harper0b3625b2016-07-25 16:16:28 -070016 "time"
Adam Langley95c29f32014-06-20 12:00:00 -070017)
18
19// sessionState contains the information that is serialized into a session
20// ticket in order to later resume a connection.
21type sessionState struct {
Adam Langley75712922014-10-10 16:23:43 -070022 vers uint16
23 cipherSuite uint16
24 masterSecret []byte
25 handshakeHash []byte
26 certificates [][]byte
27 extendedMasterSecret bool
Steven Valdez2d850622017-01-11 11:34:52 -050028 earlyALPN []byte
Nick Harper0b3625b2016-07-25 16:16:28 -070029 ticketCreationTime time.Time
30 ticketExpiration time.Time
31 ticketFlags uint32
32 ticketAgeAdd uint32
Adam Langley95c29f32014-06-20 12:00:00 -070033}
34
35func (s *sessionState) marshal() []byte {
Nick Harper0b3625b2016-07-25 16:16:28 -070036 msg := newByteBuilder()
37 msg.addU16(s.vers)
38 msg.addU16(s.cipherSuite)
39 masterSecret := msg.addU16LengthPrefixed()
40 masterSecret.addBytes(s.masterSecret)
41 handshakeHash := msg.addU16LengthPrefixed()
42 handshakeHash.addBytes(s.handshakeHash)
43 msg.addU16(uint16(len(s.certificates)))
Adam Langley95c29f32014-06-20 12:00:00 -070044 for _, cert := range s.certificates {
Nick Harper0b3625b2016-07-25 16:16:28 -070045 certMsg := msg.addU32LengthPrefixed()
46 certMsg.addBytes(cert)
Adam Langley95c29f32014-06-20 12:00:00 -070047 }
48
Adam Langley75712922014-10-10 16:23:43 -070049 if s.extendedMasterSecret {
Nick Harper0b3625b2016-07-25 16:16:28 -070050 msg.addU8(1)
51 } else {
52 msg.addU8(0)
Adam Langley75712922014-10-10 16:23:43 -070053 }
Adam Langley75712922014-10-10 16:23:43 -070054
Nick Harper0b3625b2016-07-25 16:16:28 -070055 if s.vers >= VersionTLS13 {
56 msg.addU64(uint64(s.ticketCreationTime.UnixNano()))
57 msg.addU64(uint64(s.ticketExpiration.UnixNano()))
58 msg.addU32(s.ticketFlags)
59 msg.addU32(s.ticketAgeAdd)
60 }
61
Steven Valdez2d850622017-01-11 11:34:52 -050062 earlyALPN := msg.addU16LengthPrefixed()
63 earlyALPN.addBytes(s.earlyALPN)
64
Nick Harper0b3625b2016-07-25 16:16:28 -070065 return msg.finish()
Adam Langley95c29f32014-06-20 12:00:00 -070066}
67
68func (s *sessionState) unmarshal(data []byte) bool {
69 if len(data) < 8 {
70 return false
71 }
72
73 s.vers = uint16(data[0])<<8 | uint16(data[1])
74 s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
75 masterSecretLen := int(data[4])<<8 | int(data[5])
76 data = data[6:]
77 if len(data) < masterSecretLen {
78 return false
79 }
80
81 s.masterSecret = data[:masterSecretLen]
82 data = data[masterSecretLen:]
83
84 if len(data) < 2 {
85 return false
86 }
87
David Benjamind30a9902014-08-24 01:44:23 -040088 handshakeHashLen := int(data[0])<<8 | int(data[1])
89 data = data[2:]
90 if len(data) < handshakeHashLen {
91 return false
92 }
93
94 s.handshakeHash = data[:handshakeHashLen]
95 data = data[handshakeHashLen:]
96
97 if len(data) < 2 {
98 return false
99 }
100
Adam Langley95c29f32014-06-20 12:00:00 -0700101 numCerts := int(data[0])<<8 | int(data[1])
102 data = data[2:]
103
104 s.certificates = make([][]byte, numCerts)
105 for i := range s.certificates {
106 if len(data) < 4 {
107 return false
108 }
109 certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
110 data = data[4:]
111 if certLen < 0 {
112 return false
113 }
114 if len(data) < certLen {
115 return false
116 }
117 s.certificates[i] = data[:certLen]
118 data = data[certLen:]
119 }
120
Adam Langley75712922014-10-10 16:23:43 -0700121 if len(data) < 1 {
122 return false
123 }
124
125 s.extendedMasterSecret = false
126 if data[0] == 1 {
127 s.extendedMasterSecret = true
128 }
129 data = data[1:]
130
Nick Harper0b3625b2016-07-25 16:16:28 -0700131 if s.vers >= VersionTLS13 {
132 if len(data) < 24 {
133 return false
134 }
135 s.ticketCreationTime = time.Unix(0, int64(binary.BigEndian.Uint64(data)))
136 data = data[8:]
137 s.ticketExpiration = time.Unix(0, int64(binary.BigEndian.Uint64(data)))
138 data = data[8:]
139 s.ticketFlags = binary.BigEndian.Uint32(data)
140 data = data[4:]
141 s.ticketAgeAdd = binary.BigEndian.Uint32(data)
142 data = data[4:]
143 }
144
Steven Valdez2d850622017-01-11 11:34:52 -0500145 earlyALPNLen := int(data[0])<<8 | int(data[1])
146 data = data[2:]
147 if len(data) < earlyALPNLen {
148 return false
149 }
150 s.earlyALPN = data[:earlyALPNLen]
151 data = data[earlyALPNLen:]
152
Adam Langley95c29f32014-06-20 12:00:00 -0700153 if len(data) > 0 {
154 return false
155 }
156
157 return true
158}
159
160func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
161 serialized := state.marshal()
162 encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size)
163 iv := encrypted[:aes.BlockSize]
164 macBytes := encrypted[len(encrypted)-sha256.Size:]
165
166 if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
167 return nil, err
168 }
169 block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
170 if err != nil {
171 return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
172 }
173 cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized)
174
175 mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
176 mac.Write(encrypted[:len(encrypted)-sha256.Size])
177 mac.Sum(macBytes[:0])
178
179 return encrypted, nil
180}
181
182func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
183 if len(encrypted) < aes.BlockSize+sha256.Size {
184 return nil, false
185 }
186
187 iv := encrypted[:aes.BlockSize]
188 macBytes := encrypted[len(encrypted)-sha256.Size:]
189
190 mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
191 mac.Write(encrypted[:len(encrypted)-sha256.Size])
192 expected := mac.Sum(nil)
193
194 if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
195 return nil, false
196 }
197
198 block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
199 if err != nil {
200 return nil, false
201 }
202 ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
David Benjaminb61b4de2014-07-22 19:05:46 -0400203 plaintext := make([]byte, len(ciphertext))
Adam Langley95c29f32014-06-20 12:00:00 -0700204 cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
205
206 state := new(sessionState)
207 ok := state.unmarshal(plaintext)
208 return state, ok
209}