de620d9c87
This change can probably be ported over to upstream crypto/tls. The current Go TLS implementation ignores the signature and hash algorithm lists in CertificateVerify and CertificateRequest. Take these into account so that our tests assert OpenSSL fills them out correctly. Also fix a bug in the original code where 'err' within the switch block get shadowed. Change-Id: I5d9c0b31ebb4662ecc767ed885a20707f0e86216 Reviewed-on: https://boringssl-review.googlesource.com/1253 Reviewed-by: Adam Langley <agl@google.com>
324 lines
9.4 KiB
Go
324 lines
9.4 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 main
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/hmac"
|
|
"crypto/md5"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"crypto/sha512"
|
|
"errors"
|
|
"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
|
|
}
|
|
}
|
|
|
|
// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
|
|
func prf12(hashFunc func() hash.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, hashFunc)
|
|
}
|
|
}
|
|
|
|
// 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, suite *cipherSuite) func(result, secret, label, seed []byte) {
|
|
switch version {
|
|
case VersionSSL30:
|
|
return prf30
|
|
case VersionTLS10, VersionTLS11:
|
|
return prf10
|
|
case VersionTLS12:
|
|
if suite.flags&suiteSHA384 != 0 {
|
|
return prf12(sha512.New384)
|
|
}
|
|
return prf12(sha256.New)
|
|
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, suite *cipherSuite, 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, suite)(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, suite *cipherSuite, 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, suite)(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, cipherSuite *cipherSuite) finishedHash {
|
|
if version >= VersionTLS12 {
|
|
newHash := sha256.New
|
|
if cipherSuite.flags&suiteSHA384 != 0 {
|
|
newHash = sha512.New384
|
|
}
|
|
|
|
return finishedHash{newHash(), newHash(), nil, nil, version, prf12(newHash)}
|
|
}
|
|
return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version, prf10}
|
|
}
|
|
|
|
// 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
|
|
|
|
// 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
|
|
}
|
|
|
|
// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a
|
|
// client's CertificateVerify with, or an error if none can be found.
|
|
func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
|
|
if h.version < VersionTLS12 {
|
|
// Nothing to negotiate before TLS 1.2.
|
|
return signatureAndHash{sigType, 0}, nil
|
|
}
|
|
|
|
for _, v := range serverList {
|
|
if v.signature == sigType && v.hash == hashSHA256 {
|
|
return v, nil
|
|
}
|
|
}
|
|
return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate")
|
|
}
|
|
|
|
// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
|
|
// id suitable for signing by a TLS client certificate.
|
|
func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash) ([]byte, crypto.Hash, error) {
|
|
if h.version >= VersionTLS12 {
|
|
if signatureAndHash.hash != hashSHA256 {
|
|
return nil, 0, errors.New("tls: unsupported hash function for client certificate")
|
|
}
|
|
digest := h.server.Sum(nil)
|
|
return digest, crypto.SHA256, nil
|
|
}
|
|
if signatureAndHash.signature == signatureECDSA {
|
|
digest := h.server.Sum(nil)
|
|
return digest, crypto.SHA1, nil
|
|
}
|
|
|
|
digest := make([]byte, 0, 36)
|
|
digest = h.serverMD5.Sum(digest)
|
|
digest = h.server.Sum(digest)
|
|
return digest, crypto.MD5SHA1, nil
|
|
}
|