utls/prf.go
Joël Stemmer c1444f153a crypto/tls: return correct hash function when using client certificates in handshake
Commit f1d669aee994b28e1afcfe974680565932d25b70 added support for
AES_256_GCM_SHA384 cipher suites as specified in RFC5289. However, it
did not take the arbitrary hash function into account in the TLS client
handshake when using client certificates.

The hashForClientCertificate method always returned SHA256 as its
hashing function, even if it actually used a different one to calculate
its digest. Setting up the connection would eventually fail with the
error "tls: failed to sign handshake with client certificate:
crypto/rsa: input must be hashed message".

Included is an additional test for this specific situation that uses the
SHA384 hash.

Fixes #9808

Change-Id: Iccbf4ab225633471ef897907c208ad31f92855a3
Reviewed-on: https://go-review.googlesource.com/7040
Reviewed-by: Adam Langley <agl@golang.org>
Run-TryBot: Adam Langley <agl@golang.org>
2015-03-16 23:38:51 +00:00

307 lines
8.9 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"crypto"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"hash"
)
// Split a premaster secret in two as specified in RFC 4346, section 5.
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
s1 = secret[0 : (len(secret)+1)/2]
s2 = secret[len(secret)/2:]
return
}
// pHash implements the P_hash function, as defined in RFC 4346, section 5.
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
h := hmac.New(hash, secret)
h.Write(seed)
a := h.Sum(nil)
j := 0
for j < len(result) {
h.Reset()
h.Write(a)
h.Write(seed)
b := h.Sum(nil)
todo := len(b)
if j+todo > len(result) {
todo = len(result) - j
}
copy(result[j:j+todo], b)
j += todo
h.Reset()
h.Write(a)
a = h.Sum(nil)
}
}
// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
func prf10(result, secret, label, seed []byte) {
hashSHA1 := sha1.New
hashMD5 := md5.New
labelAndSeed := make([]byte, len(label)+len(seed))
copy(labelAndSeed, label)
copy(labelAndSeed[len(label):], seed)
s1, s2 := splitPreMasterSecret(secret)
pHash(result, s1, labelAndSeed, hashMD5)
result2 := make([]byte, len(result))
pHash(result2, s2, labelAndSeed, hashSHA1)
for i, b := range result2 {
result[i] ^= b
}
}
// prf12New returns a function implementing the TLS 1.2 pseudo-random function,
// as defined in RFC 5246, section 5, using the given hash.
func prf12New(tls12Hash crypto.Hash) func(result, secret, label, seed []byte) {
return func(result, secret, label, seed []byte) {
labelAndSeed := make([]byte, len(label)+len(seed))
copy(labelAndSeed, label)
copy(labelAndSeed[len(label):], seed)
pHash(result, secret, labelAndSeed, tls12Hash.New)
}
}
// prf30 implements the SSL 3.0 pseudo-random function, as defined in
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
func prf30(result, secret, label, seed []byte) {
hashSHA1 := sha1.New()
hashMD5 := md5.New()
done := 0
i := 0
// RFC5246 section 6.3 says that the largest PRF output needed is 128
// bytes. Since no more ciphersuites will be added to SSLv3, this will
// remain true. Each iteration gives us 16 bytes so 10 iterations will
// be sufficient.
var b [11]byte
for done < len(result) {
for j := 0; j <= i; j++ {
b[j] = 'A' + byte(i)
}
hashSHA1.Reset()
hashSHA1.Write(b[:i+1])
hashSHA1.Write(secret)
hashSHA1.Write(seed)
digest := hashSHA1.Sum(nil)
hashMD5.Reset()
hashMD5.Write(secret)
hashMD5.Write(digest)
done += copy(result[done:], hashMD5.Sum(nil))
i++
}
}
const (
tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
masterSecretLength = 48 // Length of a master secret in TLS 1.1.
finishedVerifyLength = 12 // Length of verify_data in a Finished message.
)
var masterSecretLabel = []byte("master secret")
var keyExpansionLabel = []byte("key expansion")
var clientFinishedLabel = []byte("client finished")
var serverFinishedLabel = []byte("server finished")
func prfForVersion(version uint16, tls12Hash crypto.Hash) func(result, secret, label, seed []byte) {
switch version {
case VersionSSL30:
return prf30
case VersionTLS10, VersionTLS11:
return prf10
case VersionTLS12:
return prf12New(tls12Hash)
default:
panic("unknown version")
}
}
// masterFromPreMasterSecret generates the master secret from the pre-master
// secret. See http://tools.ietf.org/html/rfc5246#section-8.1
func masterFromPreMasterSecret(version uint16, tls12Hash crypto.Hash, preMasterSecret, clientRandom, serverRandom []byte) []byte {
var seed [tlsRandomLength * 2]byte
copy(seed[0:len(clientRandom)], clientRandom)
copy(seed[len(clientRandom):], serverRandom)
masterSecret := make([]byte, masterSecretLength)
prfForVersion(version, tls12Hash)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
return masterSecret
}
// keysFromMasterSecret generates the connection keys from the master
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
// RFC 2246, section 6.3.
func keysFromMasterSecret(version uint16, tls12Hash crypto.Hash, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
var seed [tlsRandomLength * 2]byte
copy(seed[0:len(clientRandom)], serverRandom)
copy(seed[len(serverRandom):], clientRandom)
n := 2*macLen + 2*keyLen + 2*ivLen
keyMaterial := make([]byte, n)
prfForVersion(version, tls12Hash)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
clientMAC = keyMaterial[:macLen]
keyMaterial = keyMaterial[macLen:]
serverMAC = keyMaterial[:macLen]
keyMaterial = keyMaterial[macLen:]
clientKey = keyMaterial[:keyLen]
keyMaterial = keyMaterial[keyLen:]
serverKey = keyMaterial[:keyLen]
keyMaterial = keyMaterial[keyLen:]
clientIV = keyMaterial[:ivLen]
keyMaterial = keyMaterial[ivLen:]
serverIV = keyMaterial[:ivLen]
return
}
func newFinishedHash(version uint16, tls12Hash crypto.Hash) finishedHash {
if version >= VersionTLS12 {
return finishedHash{tls12Hash.New(), tls12Hash.New(), tls12Hash, nil, nil, version, prfForVersion(version, tls12Hash)}
}
return finishedHash{sha1.New(), sha1.New(), crypto.MD5SHA1, md5.New(), md5.New(), version, prfForVersion(version, tls12Hash)}
}
// A finishedHash calculates the hash of a set of handshake messages suitable
// for including in a Finished message.
type finishedHash struct {
client hash.Hash
server hash.Hash
serverHash crypto.Hash
// Prior to TLS 1.2, an additional MD5 hash is required.
clientMD5 hash.Hash
serverMD5 hash.Hash
version uint16
prf func(result, secret, label, seed []byte)
}
func (h finishedHash) Write(msg []byte) (n int, err error) {
h.client.Write(msg)
h.server.Write(msg)
if h.version < VersionTLS12 {
h.clientMD5.Write(msg)
h.serverMD5.Write(msg)
}
return len(msg), nil
}
// finishedSum30 calculates the contents of the verify_data member of a SSLv3
// Finished message given the MD5 and SHA1 hashes of a set of handshake
// messages.
func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
md5.Write(magic[:])
md5.Write(masterSecret)
md5.Write(ssl30Pad1[:])
md5Digest := md5.Sum(nil)
md5.Reset()
md5.Write(masterSecret)
md5.Write(ssl30Pad2[:])
md5.Write(md5Digest)
md5Digest = md5.Sum(nil)
sha1.Write(magic[:])
sha1.Write(masterSecret)
sha1.Write(ssl30Pad1[:40])
sha1Digest := sha1.Sum(nil)
sha1.Reset()
sha1.Write(masterSecret)
sha1.Write(ssl30Pad2[:40])
sha1.Write(sha1Digest)
sha1Digest = sha1.Sum(nil)
ret := make([]byte, len(md5Digest)+len(sha1Digest))
copy(ret, md5Digest)
copy(ret[len(md5Digest):], sha1Digest)
return ret
}
var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
// clientSum returns the contents of the verify_data member of a client's
// Finished message.
func (h finishedHash) clientSum(masterSecret []byte) []byte {
if h.version == VersionSSL30 {
return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic)
}
out := make([]byte, finishedVerifyLength)
if h.version >= VersionTLS12 {
seed := h.client.Sum(nil)
h.prf(out, masterSecret, clientFinishedLabel, seed)
} else {
seed := make([]byte, 0, md5.Size+sha1.Size)
seed = h.clientMD5.Sum(seed)
seed = h.client.Sum(seed)
h.prf(out, masterSecret, clientFinishedLabel, seed)
}
return out
}
// serverSum returns the contents of the verify_data member of a server's
// Finished message.
func (h finishedHash) serverSum(masterSecret []byte) []byte {
if h.version == VersionSSL30 {
return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic)
}
out := make([]byte, finishedVerifyLength)
if h.version >= VersionTLS12 {
seed := h.server.Sum(nil)
h.prf(out, masterSecret, serverFinishedLabel, seed)
} else {
seed := make([]byte, 0, md5.Size+sha1.Size)
seed = h.serverMD5.Sum(seed)
seed = h.server.Sum(seed)
h.prf(out, masterSecret, serverFinishedLabel, seed)
}
return out
}
// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
// id suitable for signing by a TLS client certificate.
func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) {
if h.version >= VersionTLS12 {
digest := h.server.Sum(nil)
return digest, h.serverHash, tls12HashID(h.serverHash)
}
if sigType == signatureECDSA {
digest := h.server.Sum(nil)
return digest, crypto.SHA1, hashSHA1
}
digest := make([]byte, 0, 36)
digest = h.serverMD5.Sum(digest)
digest = h.server.Sum(digest)
return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */
}
// tls12HashID returns the HashAlgorithm id corresponding to the hash h, as
// specified in RFC 5246, section A.4.1.
func tls12HashID(h crypto.Hash) uint8 {
switch h {
case crypto.SHA256:
return hashSHA256
case crypto.SHA384:
return hashSHA384
}
return 0
}