1 // Copyright 2009 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.
18 // Split a premaster secret in two as specified in RFC 4346, section 5.
19 func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
20 s1 = secret[0 : (len(secret)+1)/2]
21 s2 = secret[len(secret)/2:]
25 // pHash implements the P_hash function, as defined in RFC 4346, section 5.
26 func pHash(result, secret, seed []byte, hash func() hash.Hash) {
27 h := hmac.New(hash, secret)
38 if j+todo > len(result) {
39 todo = len(result) - j
41 copy(result[j:j+todo], b)
50 // prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
51 func prf10(result, secret, label, seed []byte) {
55 labelAndSeed := make([]byte, len(label)+len(seed))
56 copy(labelAndSeed, label)
57 copy(labelAndSeed[len(label):], seed)
59 s1, s2 := splitPreMasterSecret(secret)
60 pHash(result, s1, labelAndSeed, hashMD5)
61 result2 := make([]byte, len(result))
62 pHash(result2, s2, labelAndSeed, hashSHA1)
64 for i, b := range result2 {
69 // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
70 func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
71 return func(result, secret, label, seed []byte) {
72 labelAndSeed := make([]byte, len(label)+len(seed))
73 copy(labelAndSeed, label)
74 copy(labelAndSeed[len(label):], seed)
76 pHash(result, secret, labelAndSeed, hashFunc)
80 // prf30 implements the SSL 3.0 pseudo-random function, as defined in
81 // www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
82 func prf30(result, secret, label, seed []byte) {
83 hashSHA1 := sha1.New()
88 // RFC5246 section 6.3 says that the largest PRF output needed is 128
89 // bytes. Since no more ciphersuites will be added to SSLv3, this will
90 // remain true. Each iteration gives us 16 bytes so 10 iterations will
93 for done < len(result) {
94 for j := 0; j <= i; j++ {
99 hashSHA1.Write(b[:i+1])
100 hashSHA1.Write(secret)
102 digest := hashSHA1.Sum(nil)
105 hashMD5.Write(secret)
106 hashMD5.Write(digest)
108 done += copy(result[done:], hashMD5.Sum(nil))
114 tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
115 masterSecretLength = 48 // Length of a master secret in TLS 1.1.
116 finishedVerifyLength = 12 // Length of verify_data in a Finished message.
119 var masterSecretLabel = []byte("master secret")
120 var extendedMasterSecretLabel = []byte("extended master secret")
121 var keyExpansionLabel = []byte("key expansion")
122 var clientFinishedLabel = []byte("client finished")
123 var serverFinishedLabel = []byte("server finished")
124 var channelIDLabel = []byte("TLS Channel ID signature\x00")
125 var channelIDResumeLabel = []byte("Resumption\x00")
127 func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
131 case VersionTLS10, VersionTLS11:
134 if suite.flags&suiteSHA384 != 0 {
135 return prf12(sha512.New384)
137 return prf12(sha256.New)
139 panic("unknown version")
143 // masterFromPreMasterSecret generates the master secret from the pre-master
144 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
145 func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
146 var seed [tlsRandomLength * 2]byte
147 copy(seed[0:len(clientRandom)], clientRandom)
148 copy(seed[len(clientRandom):], serverRandom)
149 masterSecret := make([]byte, masterSecretLength)
150 prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
154 // extendedMasterFromPreMasterSecret generates the master secret from the
155 // pre-master secret when the Triple Handshake fix is in effect. See
156 // https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
157 func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, h finishedHash) []byte {
158 masterSecret := make([]byte, masterSecretLength)
159 prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, h.Sum())
163 // keysFromMasterSecret generates the connection keys from the master
164 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
165 // RFC 2246, section 6.3.
166 func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
167 var seed [tlsRandomLength * 2]byte
168 copy(seed[0:len(clientRandom)], serverRandom)
169 copy(seed[len(serverRandom):], clientRandom)
171 n := 2*macLen + 2*keyLen + 2*ivLen
172 keyMaterial := make([]byte, n)
173 prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
174 clientMAC = keyMaterial[:macLen]
175 keyMaterial = keyMaterial[macLen:]
176 serverMAC = keyMaterial[:macLen]
177 keyMaterial = keyMaterial[macLen:]
178 clientKey = keyMaterial[:keyLen]
179 keyMaterial = keyMaterial[keyLen:]
180 serverKey = keyMaterial[:keyLen]
181 keyMaterial = keyMaterial[keyLen:]
182 clientIV = keyMaterial[:ivLen]
183 keyMaterial = keyMaterial[ivLen:]
184 serverIV = keyMaterial[:ivLen]
188 func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
189 if version >= VersionTLS12 {
190 newHash := sha256.New
191 if cipherSuite.flags&suiteSHA384 != 0 {
192 newHash = sha512.New384
195 return finishedHash{newHash(), newHash(), nil, nil, []byte{}, version, prf12(newHash)}
197 return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), []byte{}, version, prf10}
200 // A finishedHash calculates the hash of a set of handshake messages suitable
201 // for including in a Finished message.
202 type finishedHash struct {
206 // Prior to TLS 1.2, an additional MD5 hash is required.
210 // In TLS 1.2 (and SSL 3 for implementation convenience), a
211 // full buffer is required.
215 prf func(result, secret, label, seed []byte)
218 func (h *finishedHash) Write(msg []byte) (n int, err error) {
222 if h.version < VersionTLS12 {
223 h.clientMD5.Write(msg)
224 h.serverMD5.Write(msg)
228 h.buffer = append(h.buffer, msg...)
234 func (h finishedHash) Sum() []byte {
235 if h.version >= VersionTLS12 {
236 return h.client.Sum(nil)
239 out := make([]byte, 0, md5.Size+sha1.Size)
240 out = h.clientMD5.Sum(out)
241 return h.client.Sum(out)
244 // finishedSum30 calculates the contents of the verify_data member of a SSLv3
245 // Finished message given the MD5 and SHA1 hashes of a set of handshake
247 func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
249 md5.Write(masterSecret)
250 md5.Write(ssl30Pad1[:])
251 md5Digest := md5.Sum(nil)
254 md5.Write(masterSecret)
255 md5.Write(ssl30Pad2[:])
257 md5Digest = md5.Sum(nil)
260 sha1.Write(masterSecret)
261 sha1.Write(ssl30Pad1[:40])
262 sha1Digest := sha1.Sum(nil)
265 sha1.Write(masterSecret)
266 sha1.Write(ssl30Pad2[:40])
267 sha1.Write(sha1Digest)
268 sha1Digest = sha1.Sum(nil)
270 ret := make([]byte, len(md5Digest)+len(sha1Digest))
272 copy(ret[len(md5Digest):], sha1Digest)
276 var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
277 var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
279 // clientSum returns the contents of the verify_data member of a client's
281 func (h finishedHash) clientSum(masterSecret []byte) []byte {
282 if h.version == VersionSSL30 {
283 return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
286 out := make([]byte, finishedVerifyLength)
287 h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
291 // serverSum returns the contents of the verify_data member of a server's
293 func (h finishedHash) serverSum(masterSecret []byte) []byte {
294 if h.version == VersionSSL30 {
295 return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
298 out := make([]byte, finishedVerifyLength)
299 h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
303 // selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a
304 // client's CertificateVerify with, or an error if none can be found.
305 func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
306 if h.version < VersionTLS12 {
307 // Nothing to negotiate before TLS 1.2.
308 return signatureAndHash{signature: sigType}, nil
311 for _, v := range serverList {
312 if v.signature == sigType && v.hash == hashSHA256 {
316 return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate")
319 // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
320 // id suitable for signing by a TLS client certificate.
321 func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) {
322 if h.version == VersionSSL30 {
323 if signatureAndHash.signature != signatureRSA {
324 return nil, 0, errors.New("tls: unsupported signature type for client certificate")
328 md5Hash.Write(h.buffer)
329 sha1Hash := sha1.New()
330 sha1Hash.Write(h.buffer)
331 return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
333 if h.version >= VersionTLS12 {
334 if signatureAndHash.hash != hashSHA256 {
335 return nil, 0, errors.New("tls: unsupported hash function for client certificate")
337 digest := sha256.Sum256(h.buffer)
338 return digest[:], crypto.SHA256, nil
340 if signatureAndHash.signature == signatureECDSA {
341 return h.server.Sum(nil), crypto.SHA1, nil
344 return h.Sum(), crypto.MD5SHA1, nil
347 // hashForChannelID returns the hash to be signed for TLS Channel
348 // ID. If a resumption, resumeHash has the previous handshake
349 // hash. Otherwise, it is nil.
350 func (h finishedHash) hashForChannelID(resumeHash []byte) []byte {
352 hash.Write(channelIDLabel)
353 if resumeHash != nil {
354 hash.Write(channelIDResumeLabel)
355 hash.Write(resumeHash)
357 hash.Write(h.server.Sum(nil))
361 // discardHandshakeBuffer is called when there is no more need to
362 // buffer the entirety of the handshake messages.
363 func (h *finishedHash) discardHandshakeBuffer() {