1
0
mirror of https://github.com/golang/go synced 2024-11-13 16:20:21 -07:00

crypto/tls: refactor certificate and signature algorithm logic

This refactors a lot of the certificate support logic to make it cleaner
and reusable where possible. These changes will make the following CLs
much simpler.

In particular, the heavily overloaded pickSignatureAlgorithm is gone.
That function used to cover both signing and verifying side, would work
both for pre-signature_algorithms TLS 1.0/1.1 and TLS 1.2, and returned
sigalg, type and hash.

Now, TLS 1.0/1.1 and 1.2 are differentiated at the caller, as they have
effectively completely different logic. TLS 1.0/1.1 simply use
legacyTypeAndHashFromPublicKey as they employ a fixed hash function and
signature algorithm for each public key type. TLS 1.2 is instead routed
through selectSignatureScheme (on the signing side) or
isSupportedSignatureAlgorithm (on the verifying side) and
typeAndHashFromSignatureScheme, like TLS 1.3.

On the signing side, signatureSchemesForCertificate was already version
aware (for PKCS#1 v1.5 vs PSS support), so selectSignatureScheme just
had to learn the Section 7.4.1.4.1 defaults for a missing
signature_algorithms to replace pickSignatureAlgorithm.

On the verifying side, pickSignatureAlgorithm was also checking the
public key type, while isSupportedSignatureAlgorithm +
typeAndHashFromSignatureScheme are not, but that check was redundant
with the one in verifyHandshakeSignature.

There should be no major change in behavior so far. A few minor changes
came from the refactor: we now correctly require signature_algorithms in
TLS 1.3 when using a certificate; we won't use Ed25519 in TLS 1.2 if the
client didn't send signature_algorithms; and we don't send
ec_points_format in the ServerHello (a compatibility measure) if we are
not doing ECDHE anyway because there are no mutually supported curves.

The tests also got simpler because they test simpler functions. The
caller logic switching between TLS 1.0/1.1 and 1.2 is tested by the
transcript tests.

Updates #32426

Change-Id: Ice9dcaea78d204718f661f8d60efdb408ba41577
Reviewed-on: https://go-review.googlesource.com/c/go/+/205061
Reviewed-by: Katie Hockman <katie@golang.org>
This commit is contained in:
Filippo Valsorda 2019-11-01 19:00:33 -04:00
parent 4faada90e1
commit ec732632c2
11 changed files with 398 additions and 348 deletions

View File

@ -18,69 +18,6 @@ import (
"io" "io"
) )
// pickSignatureAlgorithm selects a signature algorithm that is compatible with
// the given public key and the list of algorithms from the peer and this side.
// The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored
// for tlsVersion < VersionTLS12.
//
// The returned SignatureScheme codepoint is only meaningful for TLS 1.2,
// previous TLS versions have a fixed hash function.
func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (sigAlg SignatureScheme, sigType uint8, hashFunc crypto.Hash, err error) {
if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 {
// For TLS 1.1 and before, the signature algorithm could not be
// negotiated and the hash is fixed based on the signature type. For TLS
// 1.2, if the client didn't send signature_algorithms extension then we
// can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
switch pubkey.(type) {
case *rsa.PublicKey:
if tlsVersion < VersionTLS12 {
return 0, signaturePKCS1v15, crypto.MD5SHA1, nil
} else {
return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil
}
case *ecdsa.PublicKey:
return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil
case ed25519.PublicKey:
if tlsVersion < VersionTLS12 {
// RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
// but it requires holding on to a handshake transcript to do a
// full signature, and not even OpenSSL bothers with the
// complexity, so we can't even test it properly.
return 0, 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2")
}
return Ed25519, signatureEd25519, directSigning, nil
default:
return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
}
}
for _, sigAlg := range peerSigAlgs {
if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) {
continue
}
sigType, hashAlg, err := typeAndHashFromSignatureScheme(sigAlg)
if err != nil {
return 0, 0, 0, fmt.Errorf("tls: internal error: %v", err)
}
switch pubkey.(type) {
case *rsa.PublicKey:
if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS {
return sigAlg, sigType, hashAlg, nil
}
case *ecdsa.PublicKey:
if sigType == signatureECDSA {
return sigAlg, sigType, hashAlg, nil
}
case ed25519.PublicKey:
if sigType == signatureEd25519 {
return sigAlg, sigType, hashAlg, nil
}
default:
return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
}
}
return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms")
}
// verifyHandshakeSignature verifies a signature against pre-hashed // verifyHandshakeSignature verifies a signature against pre-hashed
// (if required) handshake contents. // (if required) handshake contents.
func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error { func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error {
@ -164,12 +101,62 @@ func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []
return h.Sum(nil) return h.Sum(nil)
} }
// typeAndHashFromSignatureScheme returns the corresponding signature type and
// crypto.Hash for a given TLS SignatureScheme.
func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
switch signatureAlgorithm {
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
sigType = signaturePKCS1v15
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
sigType = signatureRSAPSS
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
sigType = signatureECDSA
case Ed25519:
sigType = signatureEd25519
default:
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
}
switch signatureAlgorithm {
case PKCS1WithSHA1, ECDSAWithSHA1:
hash = crypto.SHA1
case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
hash = crypto.SHA256
case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
hash = crypto.SHA384
case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
hash = crypto.SHA512
case Ed25519:
hash = directSigning
default:
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
}
return sigType, hash, nil
}
// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for
// a given public key used with TLS 1.0 and 1.1, before the introduction of
// signature algorithm negotiation.
func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) {
switch pub.(type) {
case *rsa.PublicKey:
return signaturePKCS1v15, crypto.MD5SHA1, nil
case *ecdsa.PublicKey:
return signatureECDSA, crypto.SHA1, nil
case ed25519.PublicKey:
// RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
// but it requires holding on to a handshake transcript to do a
// full signature, and not even OpenSSL bothers with the
// complexity, so we can't even test it properly.
return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2")
default:
return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub)
}
}
// signatureSchemesForCertificate returns the list of supported SignatureSchemes // signatureSchemesForCertificate returns the list of supported SignatureSchemes
// for a given certificate, based on the public key and the protocol version. // for a given certificate, based on the public key and the protocol version.
// //
// It does not support the crypto.Decrypter interface, so shouldn't be used for // This function must be kept in sync with supportedSignatureAlgorithms.
// server certificates in TLS 1.2 and earlier, and it must be kept in sync with
// supportedSignatureAlgorithms.
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme { func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
priv, ok := cert.PrivateKey.(crypto.Signer) priv, ok := cert.PrivateKey.(crypto.Signer)
if !ok { if !ok {
@ -201,12 +188,17 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
case *rsa.PublicKey: case *rsa.PublicKey:
if version != VersionTLS13 { if version != VersionTLS13 {
return []SignatureScheme{ return []SignatureScheme{
// Temporarily disable RSA-PSS in TLS 1.2, see Issue 32425.
// PSSWithSHA256,
// PSSWithSHA384,
// PSSWithSHA512,
PKCS1WithSHA256, PKCS1WithSHA256,
PKCS1WithSHA384, PKCS1WithSHA384,
PKCS1WithSHA512, PKCS1WithSHA512,
PKCS1WithSHA1, PKCS1WithSHA1,
} }
} }
// TLS 1.3 dropped support for PKCS#1 v1.5 in favor of RSA-PSS.
return []SignatureScheme{ return []SignatureScheme{
PSSWithSHA256, PSSWithSHA256,
PSSWithSHA384, PSSWithSHA384,
@ -219,6 +211,29 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
} }
} }
// selectSignatureScheme picks a SignatureScheme from the peer's preference list
// that works with the selected certificate. It's only called for protocol
// versions that support signature algorithms, so TLS 1.2 and 1.3.
func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
supportedAlgs := signatureSchemesForCertificate(vers, c)
if supportedAlgs == nil {
return 0, unsupportedCertificateError(c)
}
if len(peerAlgs) == 0 && vers == VersionTLS12 {
// For TLS 1.2, if the client didn't send signature_algorithms then we
// can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1}
}
// Pick signature scheme in the peer's preference order, as our
// preference order is not configurable.
for _, preferredAlg := range peerAlgs {
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
return preferredAlg, nil
}
}
return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms")
}
// unsupportedCertificateError returns a helpful error for certificates with // unsupportedCertificateError returns a helpful error for certificates with
// an unsupported private key. // an unsupported private key.
func unsupportedCertificateError(cert *Certificate) error { func unsupportedCertificateError(cert *Certificate) error {

View File

@ -6,71 +6,62 @@ package tls
import ( import (
"crypto" "crypto"
"crypto/ed25519"
"testing" "testing"
) )
func TestSignatureSelection(t *testing.T) { func TestSignatureSelection(t *testing.T) {
rsaCert := &testRSAPrivateKey.PublicKey rsaCert := &Certificate{
ecdsaCert := &testECDSAPrivateKey.PublicKey Certificate: [][]byte{testRSACertificate},
ed25519Cert := testEd25519PrivateKey.Public().(ed25519.PublicKey) PrivateKey: testRSAPrivateKey,
sigsPKCS1WithSHA := []SignatureScheme{PKCS1WithSHA256, PKCS1WithSHA1} }
sigsPSSWithSHA := []SignatureScheme{PSSWithSHA256, PSSWithSHA384} ecdsaCert := &Certificate{
sigsECDSAWithSHA := []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1} Certificate: [][]byte{testP256Certificate},
PrivateKey: testP256PrivateKey,
}
ed25519Cert := &Certificate{
Certificate: [][]byte{testEd25519Certificate},
PrivateKey: testEd25519PrivateKey,
}
tests := []struct { tests := []struct {
pubkey crypto.PublicKey cert *Certificate
peerSigAlgs []SignatureScheme peerSigAlgs []SignatureScheme
ourSigAlgs []SignatureScheme
tlsVersion uint16 tlsVersion uint16
expectedSigAlg SignatureScheme // if tlsVersion == VersionTLS12 expectedSigAlg SignatureScheme
expectedSigType uint8 expectedSigType uint8
expectedHash crypto.Hash expectedHash crypto.Hash
}{ }{
// Hash is fixed for RSA in TLS 1.1 and before. {rsaCert, []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
// https://tools.ietf.org/html/rfc4346#page-44 {rsaCert, []SignatureScheme{PKCS1WithSHA512, PKCS1WithSHA1}, VersionTLS12, PKCS1WithSHA512, signaturePKCS1v15, crypto.SHA512},
{rsaCert, nil, nil, VersionTLS11, 0, signaturePKCS1v15, crypto.MD5SHA1}, {rsaCert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
{rsaCert, nil, nil, VersionTLS10, 0, signaturePKCS1v15, crypto.MD5SHA1}, {rsaCert, []SignatureScheme{PSSWithSHA384, PKCS1WithSHA1}, VersionTLS13, PSSWithSHA384, signatureRSAPSS, crypto.SHA384},
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
// Before TLS 1.2, there is no signature_algorithms extension {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
// nor field in CertificateRequest and digitally-signed and thus {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS13, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
// it should be ignored. {ed25519Cert, []SignatureScheme{Ed25519}, VersionTLS12, Ed25519, signatureEd25519, directSigning},
{rsaCert, sigsPKCS1WithSHA, nil, VersionTLS11, 0, signaturePKCS1v15, crypto.MD5SHA1}, {ed25519Cert, []SignatureScheme{Ed25519}, VersionTLS13, Ed25519, signatureEd25519, directSigning},
{rsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS11, 0, signaturePKCS1v15, crypto.MD5SHA1},
// Use SHA-1 for TLS 1.0 and 1.1 with ECDSA, see https://tools.ietf.org/html/rfc4492#page-20
{ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS11, 0, signatureECDSA, crypto.SHA1},
{ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS10, 0, signatureECDSA, crypto.SHA1},
// TLS 1.2 without signature_algorithms extension // TLS 1.2 without signature_algorithms extension
// https://tools.ietf.org/html/rfc5246#page-47 {rsaCert, nil, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
{rsaCert, nil, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1}, {ecdsaCert, nil, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
{ecdsaCert, nil, sigsPKCS1WithSHA, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
{rsaCert, []SignatureScheme{PKCS1WithSHA1}, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1}, // TLS 1.2 does not restrict the ECDSA curve (our ecdsaCert is P-256)
{rsaCert, []SignatureScheme{PKCS1WithSHA256}, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256}, {ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS12, ECDSAWithP384AndSHA384, signatureECDSA, crypto.SHA384},
// "sha_hash" may denote hashes other than SHA-1
// https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis-17#page-17
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, sigsECDSAWithSHA, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
{ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, sigsECDSAWithSHA, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
// RSASSA-PSS is defined in TLS 1.3 for TLS 1.2
// https://tools.ietf.org/html/draft-ietf-tls-tls13-21#page-45
{rsaCert, []SignatureScheme{PSSWithSHA256}, sigsPSSWithSHA, VersionTLS12, PSSWithSHA256, signatureRSAPSS, crypto.SHA256},
// All results are fixed for Ed25519. RFC 8422, Section 5.10.
{ed25519Cert, []SignatureScheme{Ed25519}, []SignatureScheme{ECDSAWithSHA1, Ed25519}, VersionTLS12, Ed25519, signatureEd25519, directSigning},
{ed25519Cert, nil, nil, VersionTLS12, Ed25519, signatureEd25519, directSigning},
} }
for testNo, test := range tests { for testNo, test := range tests {
sigAlg, sigType, hashFunc, err := pickSignatureAlgorithm(test.pubkey, test.peerSigAlgs, test.ourSigAlgs, test.tlsVersion) sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
if err != nil { if err != nil {
t.Errorf("test[%d]: unexpected error: %v", testNo, err) t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err)
} }
if test.tlsVersion == VersionTLS12 && test.expectedSigAlg != sigAlg { if test.expectedSigAlg != sigAlg {
t.Errorf("test[%d]: expected signature scheme %#x, got %#x", testNo, test.expectedSigAlg, sigAlg) t.Errorf("test[%d]: expected signature scheme %#x, got %#x", testNo, test.expectedSigAlg, sigAlg)
} }
sigType, hashFunc, err := typeAndHashFromSignatureScheme(sigAlg)
if err != nil {
t.Errorf("test[%d]: unexpected typeAndHashFromSignatureScheme error: %v", testNo, err)
}
if test.expectedSigType != sigType { if test.expectedSigType != sigType {
t.Errorf("test[%d]: expected signature algorithm %#x, got %#x", testNo, test.expectedSigType, sigType) t.Errorf("test[%d]: expected signature algorithm %#x, got %#x", testNo, test.expectedSigType, sigType)
} }
@ -80,26 +71,81 @@ func TestSignatureSelection(t *testing.T) {
} }
badTests := []struct { badTests := []struct {
pubkey crypto.PublicKey cert *Certificate
peerSigAlgs []SignatureScheme peerSigAlgs []SignatureScheme
ourSigAlgs []SignatureScheme
tlsVersion uint16 tlsVersion uint16
}{ }{
{rsaCert, sigsECDSAWithSHA, sigsPKCS1WithSHA, VersionTLS12}, {rsaCert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
{ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS12}, {ecdsaCert, []SignatureScheme{PKCS1WithSHA256, PKCS1WithSHA1}, VersionTLS12},
{ecdsaCert, sigsECDSAWithSHA, sigsPKCS1WithSHA, VersionTLS12}, {rsaCert, []SignatureScheme{0}, VersionTLS12},
{rsaCert, []SignatureScheme{0}, sigsPKCS1WithSHA, VersionTLS12}, {ed25519Cert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
{ed25519Cert, sigsECDSAWithSHA, sigsECDSAWithSHA, VersionTLS12}, {ecdsaCert, []SignatureScheme{Ed25519}, VersionTLS12},
{ed25519Cert, []SignatureScheme{Ed25519}, sigsECDSAWithSHA, VersionTLS12}, // RFC 5246, Section 7.4.1.4.1, says to only consider {sha1,ecdsa} as
{ecdsaCert, []SignatureScheme{Ed25519}, []SignatureScheme{Ed25519}, VersionTLS12}, // default when the extension is missing, and RFC 8422 does not update
{ed25519Cert, nil, nil, VersionTLS11}, // it. Anyway, if a stack supports Ed25519 it better support sigalgs.
{ed25519Cert, nil, nil, VersionTLS10}, {ed25519Cert, nil, VersionTLS12},
// TLS 1.3 has no default signature_algorithms.
{rsaCert, nil, VersionTLS13},
{ecdsaCert, nil, VersionTLS13},
{ed25519Cert, nil, VersionTLS13},
// Wrong curve, which TLS 1.3 checks
{ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS13},
// TLS 1.3 does not support PKCS1v1.5 or SHA-1.
{rsaCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS13},
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS13},
} }
for testNo, test := range badTests { for testNo, test := range badTests {
sigAlg, sigType, hashFunc, err := pickSignatureAlgorithm(test.pubkey, test.peerSigAlgs, test.ourSigAlgs, test.tlsVersion) sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
if err == nil { if err == nil {
t.Errorf("test[%d]: unexpected success, got %#x %#x %#x", testNo, sigAlg, sigType, hashFunc) t.Errorf("test[%d]: unexpected success, got %#x", testNo, sigAlg)
}
}
}
func TestLegacyTypeAndHash(t *testing.T) {
sigType, hashFunc, err := legacyTypeAndHashFromPublicKey(testRSAPrivateKey.Public())
if err != nil {
t.Errorf("RSA: unexpected error: %v", err)
}
if expectedSigType := signaturePKCS1v15; expectedSigType != sigType {
t.Errorf("RSA: expected signature type %#x, got %#x", expectedSigType, sigType)
}
if expectedHashFunc := crypto.MD5SHA1; expectedHashFunc != hashFunc {
t.Errorf("RSA: expected hash %#x, got %#x", expectedHashFunc, sigType)
}
sigType, hashFunc, err = legacyTypeAndHashFromPublicKey(testECDSAPrivateKey.Public())
if err != nil {
t.Errorf("ECDSA: unexpected error: %v", err)
}
if expectedSigType := signatureECDSA; expectedSigType != sigType {
t.Errorf("ECDSA: expected signature type %#x, got %#x", expectedSigType, sigType)
}
if expectedHashFunc := crypto.SHA1; expectedHashFunc != hashFunc {
t.Errorf("ECDSA: expected hash %#x, got %#x", expectedHashFunc, sigType)
}
// Ed25519 is not supported by TLS 1.0 and 1.1.
_, _, err = legacyTypeAndHashFromPublicKey(testEd25519PrivateKey.Public())
if err == nil {
t.Errorf("Ed25519: unexpected success")
}
}
// TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
// have valid type and hash information.
func TestSupportedSignatureAlgorithms(t *testing.T) {
for _, sigAlg := range supportedSignatureAlgorithms {
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
if err != nil {
t.Errorf("%#04x: unexpected error: %v", sigAlg, err)
}
if sigType == 0 {
t.Errorf("%#04x: missing signature type", sigAlg)
}
if hash == 0 && sigAlg != Ed25519 {
t.Errorf("%#04x: missing hash", sigAlg)
} }
} }
} }

View File

@ -38,7 +38,7 @@ type keyAgreement interface {
} }
const ( const (
// suiteECDH indicates that the cipher suite involves elliptic curve // suiteECDHE indicates that the cipher suite involves elliptic curve
// Diffie-Hellman. This means that it should only be selected when the // Diffie-Hellman. This means that it should only be selected when the
// client indicates that it supports ECC with a curve and point format // client indicates that it supports ECC with a curve and point format
// that we're happy with. // that we're happy with.
@ -103,6 +103,24 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteDefaultOff, cipherRC4, macSHA1, nil},
} }
// selectCipherSuite returns the first cipher suite from ids which is also in
// supportedIDs and passes the ok filter.
func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite {
for _, id := range ids {
candidate := cipherSuiteByID(id)
if candidate == nil || !ok(candidate) {
continue
}
for _, suppID := range supportedIDs {
if id == suppID {
return candidate
}
}
}
return nil
}
// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash // A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
// algorithm to be used with HKDF. See RFC 8446, Appendix B.4. // algorithm to be used with HKDF. See RFC 8446, Appendix B.4.
type cipherSuiteTLS13 struct { type cipherSuiteTLS13 struct {

View File

@ -339,40 +339,8 @@ const (
ECDSAWithSHA1 SignatureScheme = 0x0203 ECDSAWithSHA1 SignatureScheme = 0x0203
) )
// typeAndHashFromSignatureScheme returns the corresponding signature type and
// crypto.Hash for a given TLS SignatureScheme.
func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
switch signatureAlgorithm {
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
sigType = signaturePKCS1v15
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
sigType = signatureRSAPSS
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
sigType = signatureECDSA
case Ed25519:
sigType = signatureEd25519
default:
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
}
switch signatureAlgorithm {
case PKCS1WithSHA1, ECDSAWithSHA1:
hash = crypto.SHA1
case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
hash = crypto.SHA256
case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
hash = crypto.SHA384
case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
hash = crypto.SHA512
case Ed25519:
hash = directSigning
default:
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
}
return sigType, hash, nil
}
// ClientHelloInfo contains information from a ClientHello message in order to // ClientHelloInfo contains information from a ClientHello message in order to
// guide certificate selection in the GetCertificate callback. // guide application logic in the GetCertificate and GetConfigForClient callbacks.
type ClientHelloInfo struct { type ClientHelloInfo struct {
// CipherSuites lists the CipherSuites supported by the client (e.g. // CipherSuites lists the CipherSuites supported by the client (e.g.
// TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256). // TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
@ -866,6 +834,15 @@ func (c *Config) curvePreferences() []CurveID {
return c.CurvePreferences return c.CurvePreferences
} }
func (c *Config) supportsCurve(curve CurveID) bool {
for _, cc := range c.curvePreferences() {
if cc == curve {
return true
}
}
return false
}
// mutualVersion returns the protocol version to use given the advertised // mutualVersion returns the protocol version to use given the advertised
// versions of the peer. Priority is given to the peer preference order. // versions of the peer. Priority is given to the peer preference order.
func (c *Config) mutualVersion(peerVersions []uint16) (uint16, bool) { func (c *Config) mutualVersion(peerVersions []uint16) (uint16, bool) {
@ -931,13 +908,9 @@ func (c *Config) BuildNameToCertificate() {
c.NameToCertificate = make(map[string]*Certificate) c.NameToCertificate = make(map[string]*Certificate)
for i := range c.Certificates { for i := range c.Certificates {
cert := &c.Certificates[i] cert := &c.Certificates[i]
x509Cert := cert.Leaf x509Cert, err := cert.leaf()
if x509Cert == nil { if err != nil {
var err error continue
x509Cert, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
continue
}
} }
if len(x509Cert.Subject.CommonName) > 0 { if len(x509Cert.Subject.CommonName) > 0 {
c.NameToCertificate[x509Cert.Subject.CommonName] = cert c.NameToCertificate[x509Cert.Subject.CommonName] = cert
@ -988,13 +961,21 @@ type Certificate struct {
// SignedCertificateTimestamps contains an optional list of Signed // SignedCertificateTimestamps contains an optional list of Signed
// Certificate Timestamps which will be served to clients that request it. // Certificate Timestamps which will be served to clients that request it.
SignedCertificateTimestamps [][]byte SignedCertificateTimestamps [][]byte
// Leaf is the parsed form of the leaf certificate, which may be // Leaf is the parsed form of the leaf certificate, which may be initialized
// initialized using x509.ParseCertificate to reduce per-handshake // using x509.ParseCertificate to reduce per-handshake processing. If nil,
// processing for TLS clients doing client authentication. If nil, the // the leaf certificate will be parsed as needed.
// leaf certificate will be parsed as needed.
Leaf *x509.Certificate Leaf *x509.Certificate
} }
// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing
// the corresponding c.Certificate[0].
func (c *Certificate) leaf() (*x509.Certificate, error) {
if c.Leaf != nil {
return c.Leaf, nil
}
return x509.ParseCertificate(c.Certificate[0])
}
type handshakeMessage interface { type handshakeMessage interface {
marshal() []byte marshal() []byte
unmarshal([]byte) bool unmarshal([]byte) bool

View File

@ -562,9 +562,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
} }
if chainToSend != nil && len(chainToSend.Certificate) > 0 { if chainToSend != nil && len(chainToSend.Certificate) > 0 {
certVerify := &certificateVerifyMsg{ certVerify := &certificateVerifyMsg{}
hasSignatureAlgorithm: c.vers >= VersionTLS12,
}
key, ok := chainToSend.PrivateKey.(crypto.Signer) key, ok := chainToSend.PrivateKey.(crypto.Signer)
if !ok { if !ok {
@ -572,19 +570,32 @@ func (hs *clientHandshakeState) doFullHandshake() error {
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
} }
signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, supportedSignatureAlgorithmsTLS12, c.vers) var sigType uint8
if err != nil { var sigHash crypto.Hash
c.sendAlert(alertInternalError) if c.vers >= VersionTLS12 {
return err signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
} if err != nil {
// SignatureAndHashAlgorithm was introduced in TLS 1.2. c.sendAlert(alertIllegalParameter)
if certVerify.hasSignatureAlgorithm { return err
}
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
if err != nil {
return c.sendAlert(alertInternalError)
}
certVerify.hasSignatureAlgorithm = true
certVerify.signatureAlgorithm = signatureAlgorithm certVerify.signatureAlgorithm = signatureAlgorithm
} else {
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public())
if err != nil {
c.sendAlert(alertIllegalParameter)
return err
}
} }
signed := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
signOpts := crypto.SignerOpts(hashFunc) signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret)
signOpts := crypto.SignerOpts(sigHash)
if sigType == signatureRSAPSS { if sigType == signatureRSAPSS {
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc} signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
} }
certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts) certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts)
if err != nil { if err != nil {

View File

@ -550,24 +550,12 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
certVerifyMsg := new(certificateVerifyMsg) certVerifyMsg := new(certificateVerifyMsg)
certVerifyMsg.hasSignatureAlgorithm = true certVerifyMsg.hasSignatureAlgorithm = true
supportedAlgs := signatureSchemesForCertificate(c.vers, cert) certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms)
if supportedAlgs == nil { if err != nil {
c.sendAlert(alertInternalError)
return unsupportedCertificateError(cert)
}
// Pick signature scheme in server preference order, as the client
// preference order is not configurable.
for _, preferredAlg := range hs.certReq.supportedSignatureAlgorithms {
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
certVerifyMsg.signatureAlgorithm = preferredAlg
break
}
}
if certVerifyMsg.signatureAlgorithm == 0 {
// getClientCertificate returned a certificate incompatible with the // getClientCertificate returned a certificate incompatible with the
// CertificateRequestInfo supported signature algorithms. // CertificateRequestInfo supported signature algorithms.
c.sendAlert(alertHandshakeFailure) c.sendAlert(alertHandshakeFailure)
return errors.New("tls: server doesn't support selected certificate") return err
} }
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm) sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)

View File

@ -24,7 +24,7 @@ type serverHandshakeState struct {
clientHello *clientHelloMsg clientHello *clientHelloMsg
hello *serverHelloMsg hello *serverHelloMsg
suite *cipherSuite suite *cipherSuite
ecdhOk bool ecdheOk bool
ecSignOk bool ecSignOk bool
rsaDecryptOk bool rsaDecryptOk bool
rsaSignOk bool rsaSignOk bool
@ -175,36 +175,6 @@ func (hs *serverHandshakeState) processClientHello() error {
hs.hello = new(serverHelloMsg) hs.hello = new(serverHelloMsg)
hs.hello.vers = c.vers hs.hello.vers = c.vers
supportedCurve := false
preferredCurves := c.config.curvePreferences()
Curves:
for _, curve := range hs.clientHello.supportedCurves {
for _, supported := range preferredCurves {
if supported == curve {
supportedCurve = true
break Curves
}
}
}
supportedPointFormat := false
for _, pointFormat := range hs.clientHello.supportedPoints {
if pointFormat == pointFormatUncompressed {
supportedPointFormat = true
break
}
}
hs.ecdhOk = supportedCurve && supportedPointFormat
if supportedPointFormat {
// Although omiting the ec_point_formats extension is permitted, some
// old OpenSSL version will refuse to handshake if not present.
//
// Per RFC 4492, section 5.1.2, implementations MUST support the
// uncompressed point format. See golang.org/issue/31943.
hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
}
foundCompression := false foundCompression := false
// We only support null compression, so check that the client offered it. // We only support null compression, so check that the client offered it.
for _, compression := range hs.clientHello.compressionMethods { for _, compression := range hs.clientHello.compressionMethods {
@ -264,6 +234,17 @@ Curves:
hs.hello.scts = hs.cert.SignedCertificateTimestamps hs.hello.scts = hs.cert.SignedCertificateTimestamps
} }
hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints)
if hs.ecdheOk {
// Although omiting the ec_point_formats extension is permitted, some
// old OpenSSL version will refuse to handshake if not present.
//
// Per RFC 4492, section 5.1.2, implementations MUST support the
// uncompressed point format. See golang.org/issue/31943.
hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
}
if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok { if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
switch priv.Public().(type) { switch priv.Public().(type) {
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
@ -290,6 +271,28 @@ Curves:
return nil return nil
} }
// supportsECDHE returns whether ECDHE key exchanges can be used with this
// pre-TLS 1.3 client.
func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool {
supportsCurve := false
for _, curve := range supportedCurves {
if c.supportsCurve(curve) {
supportsCurve = true
break
}
}
supportsPointFormat := false
for _, pointFormat := range supportedPoints {
if pointFormat == pointFormatUncompressed {
supportsPointFormat = true
break
}
}
return supportsCurve && supportsPointFormat
}
func (hs *serverHandshakeState) pickCipherSuite() error { func (hs *serverHandshakeState) pickCipherSuite() error {
c := hs.c c := hs.c
@ -302,12 +305,7 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
supportedList = c.config.cipherSuites() supportedList = c.config.cipherSuites()
} }
for _, id := range preferenceList { hs.suite = selectCipherSuite(preferenceList, supportedList, hs.cipherSuiteOk)
if hs.setCipherSuite(id, supportedList, c.vers) {
break
}
}
if hs.suite == nil { if hs.suite == nil {
c.sendAlert(alertHandshakeFailure) c.sendAlert(alertHandshakeFailure)
return errors.New("tls: no cipher suite supported by both client and server") return errors.New("tls: no cipher suite supported by both client and server")
@ -327,6 +325,27 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
return nil return nil
} }
func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool {
if c.flags&suiteECDHE != 0 {
if !hs.ecdheOk {
return false
}
if c.flags&suiteECSign != 0 {
if !hs.ecSignOk {
return false
}
} else if !hs.rsaSignOk {
return false
}
} else if !hs.rsaDecryptOk {
return false
}
if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
return false
}
return true
}
// checkForResumption reports whether we should perform resumption on this connection. // checkForResumption reports whether we should perform resumption on this connection.
func (hs *serverHandshakeState) checkForResumption() bool { func (hs *serverHandshakeState) checkForResumption() bool {
c := hs.c c := hs.c
@ -363,7 +382,9 @@ func (hs *serverHandshakeState) checkForResumption() bool {
} }
// Check that we also support the ciphersuite from the session. // Check that we also support the ciphersuite from the session.
if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) { hs.suite = selectCipherSuite([]uint16{hs.sessionState.cipherSuite},
c.config.cipherSuites(), hs.cipherSuiteOk)
if hs.suite == nil {
return false return false
} }
@ -562,15 +583,27 @@ func (hs *serverHandshakeState) doFullHandshake() error {
return unexpectedMessageError(certVerify, msg) return unexpectedMessageError(certVerify, msg)
} }
// Determine the signature type. var sigType uint8
_, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, certReq.supportedSignatureAlgorithms, c.vers) var sigHash crypto.Hash
if err != nil { if c.vers >= VersionTLS12 {
c.sendAlert(alertIllegalParameter) if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {
return err c.sendAlert(alertIllegalParameter)
return errors.New("tls: client certificate used with invalid signature algorithm")
}
sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
if err != nil {
return c.sendAlert(alertInternalError)
}
} else {
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
if err != nil {
c.sendAlert(alertIllegalParameter)
return err
}
} }
signed := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret) signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret)
if err := verifyHandshakeSignature(sigType, pub, hashFunc, signed, certVerify.signature); err != nil { if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
c.sendAlert(alertDecryptError) c.sendAlert(alertDecryptError)
return errors.New("tls: invalid signature by the client certificate: " + err.Error()) return errors.New("tls: invalid signature by the client certificate: " + err.Error())
} }
@ -753,43 +786,6 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
return nil return nil
} }
// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
// suite if that cipher suite is acceptable to use.
// It returns a bool indicating if the suite was set.
func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool {
for _, supported := range supportedCipherSuites {
if id != supported {
continue
}
candidate := cipherSuiteByID(id)
if candidate == nil {
continue
}
// Don't select a ciphersuite which we can't
// support for this client.
if candidate.flags&suiteECDHE != 0 {
if !hs.ecdhOk {
continue
}
if candidate.flags&suiteECSign != 0 {
if !hs.ecSignOk {
continue
}
} else if !hs.rsaSignOk {
continue
}
} else if !hs.rsaDecryptOk {
continue
}
if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
continue
}
hs.suite = candidate
return true
}
return false
}
func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo { func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
supportedVersions := clientHello.supportedVersions supportedVersions := clientHello.supportedVersions
if len(clientHello.supportedVersions) == 0 { if len(clientHello.supportedVersions) == 0 {

View File

@ -1182,7 +1182,7 @@ func TestHandshakeServerRSAPSS(t *testing.T) {
test := &serverTest{ test := &serverTest{
name: "RSA-RSAPSS", name: "RSA-RSAPSS",
command: []string{"openssl", "s_client", "-no_ticket", "-sigalgs", "rsa_pss_rsae_sha256"}, command: []string{"openssl", "s_client", "-no_ticket", "-sigalgs", "rsa_pss_rsae_sha256"},
expectHandshakeErrorIncluding: "peer doesn't support any common signature algorithms", // See Issue 32425. expectHandshakeErrorIncluding: "peer doesn't support any of the certificate's signature algorithms", // See Issue 32425.
} }
runServerTestTLS12(t, test) runServerTestTLS12(t, test)

View File

@ -356,6 +356,11 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
return nil return nil
} }
// signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3.
if len(hs.clientHello.supportedSignatureAlgorithms) == 0 {
return c.sendAlert(alertMissingExtension)
}
// This implements a very simplistic certificate selection strategy for now: // This implements a very simplistic certificate selection strategy for now:
// getCertificate delegates to the application Config.GetCertificate, or // getCertificate delegates to the application Config.GetCertificate, or
// selects based on the server_name only. If the selected certificate's // selects based on the server_name only. If the selected certificate's
@ -368,24 +373,12 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
c.sendAlert(alertInternalError) c.sendAlert(alertInternalError)
return err return err
} }
supportedAlgs := signatureSchemesForCertificate(c.vers, certificate) hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms)
if supportedAlgs == nil { if err != nil {
c.sendAlert(alertInternalError) // getCertificate returned a certificate that is unsupported or
return unsupportedCertificateError(certificate) // incompatible with the client's signature algorithms.
}
// Pick signature scheme in client preference order, as the server
// preference order is not configurable.
for _, preferredAlg := range hs.clientHello.supportedSignatureAlgorithms {
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
hs.sigAlg = preferredAlg
break
}
}
if hs.sigAlg == 0 {
// getCertificate returned a certificate incompatible with the
// ClientHello supported signature algorithms.
c.sendAlert(alertHandshakeFailure) c.sendAlert(alertHandshakeFailure)
return errors.New("tls: client doesn't support selected certificate") return err
} }
hs.cert = certificate hs.cert = certificate

View File

@ -11,6 +11,7 @@ import (
"crypto/sha1" "crypto/sha1"
"crypto/x509" "crypto/x509"
"errors" "errors"
"fmt"
"io" "io"
) )
@ -142,16 +143,11 @@ type ecdheKeyAgreement struct {
} }
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
preferredCurves := config.curvePreferences()
var curveID CurveID var curveID CurveID
NextCandidate: for _, c := range clientHello.supportedCurves {
for _, candidate := range preferredCurves { if config.supportsCurve(c) {
for _, c := range clientHello.supportedCurves { curveID = c
if candidate == c { break
curveID = c
break NextCandidate
}
} }
} }
@ -170,31 +166,45 @@ NextCandidate:
// See RFC 4492, Section 5.4. // See RFC 4492, Section 5.4.
ecdhePublic := params.PublicKey() ecdhePublic := params.PublicKey()
serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHParams[0] = 3 // named curve serverECDHEParams[0] = 3 // named curve
serverECDHParams[1] = byte(curveID >> 8) serverECDHEParams[1] = byte(curveID >> 8)
serverECDHParams[2] = byte(curveID) serverECDHEParams[2] = byte(curveID)
serverECDHParams[3] = byte(len(ecdhePublic)) serverECDHEParams[3] = byte(len(ecdhePublic))
copy(serverECDHParams[4:], ecdhePublic) copy(serverECDHEParams[4:], ecdhePublic)
priv, ok := cert.PrivateKey.(crypto.Signer) priv, ok := cert.PrivateKey.(crypto.Signer)
if !ok { if !ok {
return nil, errors.New("tls: certificate private key does not implement crypto.Signer") return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey)
} }
signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithmsTLS12, ka.version) var signatureAlgorithm SignatureScheme
if err != nil { var sigType uint8
return nil, err var sigHash crypto.Hash
if ka.version >= VersionTLS12 {
signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)
if err != nil {
return nil, err
}
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
if err != nil {
return nil, err
}
} else {
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public())
if err != nil {
return nil, err
}
} }
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
} }
signed := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, hello.random, serverECDHParams) signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams)
signOpts := crypto.SignerOpts(hashFunc) signOpts := crypto.SignerOpts(sigHash)
if sigType == signatureRSAPSS { if sigType == signatureRSAPSS {
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc} signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
} }
sig, err := priv.Sign(config.rand(), signed, signOpts) sig, err := priv.Sign(config.rand(), signed, signOpts)
if err != nil { if err != nil {
@ -206,9 +216,9 @@ NextCandidate:
if ka.version >= VersionTLS12 { if ka.version >= VersionTLS12 {
sigAndHashLen = 2 sigAndHashLen = 2
} }
skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig)) skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig))
copy(skx.key, serverECDHParams) copy(skx.key, serverECDHEParams)
k := skx.key[len(serverECDHParams):] k := skx.key[len(serverECDHEParams):]
if ka.version >= VersionTLS12 { if ka.version >= VersionTLS12 {
k[0] = byte(signatureAlgorithm >> 8) k[0] = byte(signatureAlgorithm >> 8)
k[1] = byte(signatureAlgorithm) k[1] = byte(signatureAlgorithm)
@ -247,8 +257,8 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if publicLen+4 > len(skx.key) { if publicLen+4 > len(skx.key) {
return errServerKeyExchange return errServerKeyExchange
} }
serverECDHParams := skx.key[:4+publicLen] serverECDHEParams := skx.key[:4+publicLen]
publicKey := serverECDHParams[4:] publicKey := serverECDHEParams[4:]
sig := skx.key[4+publicLen:] sig := skx.key[4+publicLen:]
if len(sig) < 2 { if len(sig) < 2 {
@ -276,18 +286,27 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
ka.ckx.ciphertext[0] = byte(len(ourPublicKey)) ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
copy(ka.ckx.ciphertext[1:], ourPublicKey) copy(ka.ckx.ciphertext[1:], ourPublicKey)
var signatureAlgorithm SignatureScheme var sigType uint8
var sigHash crypto.Hash
if ka.version >= VersionTLS12 { if ka.version >= VersionTLS12 {
// handle SignatureAndHashAlgorithm signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
sig = sig[2:] sig = sig[2:]
if len(sig) < 2 { if len(sig) < 2 {
return errServerKeyExchange return errServerKeyExchange
} }
}
_, sigType, hashFunc, err := pickSignatureAlgorithm(cert.PublicKey, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version) if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) {
if err != nil { return errors.New("tls: certificate used with invalid signature algorithm")
return err }
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
if err != nil {
return err
}
} else {
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey)
if err != nil {
return err
}
} }
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
return errServerKeyExchange return errServerKeyExchange
@ -299,8 +318,8 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
} }
sig = sig[2:] sig = sig[2:]
signed := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, serverHello.random, serverECDHParams) signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams)
if err := verifyHandshakeSignature(sigType, cert.PublicKey, hashFunc, signed, sig); err != nil { if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
return errors.New("tls: invalid signature by the server certificate: " + err.Error()) return errors.New("tls: invalid signature by the server certificate: " + err.Error())
} }
return nil return nil

View File

@ -1045,20 +1045,3 @@ func TestBuildNameToCertificate_doesntModifyCertificates(t *testing.T) {
} }
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
// TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
// have valid type and hash information.
func TestSupportedSignatureAlgorithms(t *testing.T) {
for _, sigAlg := range supportedSignatureAlgorithms {
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
if err != nil {
t.Errorf("%#04x: unexpected error: %v", sigAlg, err)
}
if sigType == 0 {
t.Errorf("%#04x: missing signature type", sigAlg)
}
if hash == 0 && sigAlg != Ed25519 {
t.Errorf("%#04x: missing hash", sigAlg)
}
}
}