Commit 5b17b657 authored by Filippo Valsorda's avatar Filippo Valsorda

crypto/tls: implement Certificate.SupportedSignatureAlgorithms

This will let applications stop crypto/tls from using a certificate key
with an algorithm that is not supported by its crypto.Signer, like
hardware backed keys that can't do RSA-PSS.

Fixes #28660

Change-Id: I294cc06bddf813fff35c5107540c4a1788e1dace
Reviewed-on: https://go-review.googlesource.com/c/go/+/205062
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarAdam Langley <agl@golang.org>
parent eb93c684
...@@ -154,7 +154,8 @@ func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash c ...@@ -154,7 +154,8 @@ func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash c
} }
// 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,
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
// //
// This function must be kept in sync with supportedSignatureAlgorithms. // This function must be kept in sync with supportedSignatureAlgorithms.
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme { func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
...@@ -163,31 +164,33 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu ...@@ -163,31 +164,33 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
return nil return nil
} }
var sigAlgs []SignatureScheme
switch pub := priv.Public().(type) { switch pub := priv.Public().(type) {
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
if version != VersionTLS13 { if version != VersionTLS13 {
// In TLS 1.2 and earlier, ECDSA algorithms are not // In TLS 1.2 and earlier, ECDSA algorithms are not
// constrained to a single curve. // constrained to a single curve.
return []SignatureScheme{ sigAlgs = []SignatureScheme{
ECDSAWithP256AndSHA256, ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384, ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512, ECDSAWithP521AndSHA512,
ECDSAWithSHA1, ECDSAWithSHA1,
} }
break
} }
switch pub.Curve { switch pub.Curve {
case elliptic.P256(): case elliptic.P256():
return []SignatureScheme{ECDSAWithP256AndSHA256} sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
case elliptic.P384(): case elliptic.P384():
return []SignatureScheme{ECDSAWithP384AndSHA384} sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
case elliptic.P521(): case elliptic.P521():
return []SignatureScheme{ECDSAWithP521AndSHA512} sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
default: default:
return nil return nil
} }
case *rsa.PublicKey: case *rsa.PublicKey:
if version != VersionTLS13 { if version != VersionTLS13 {
return []SignatureScheme{ sigAlgs = []SignatureScheme{
// Temporarily disable RSA-PSS in TLS 1.2, see Issue 32425. // Temporarily disable RSA-PSS in TLS 1.2, see Issue 32425.
// PSSWithSHA256, // PSSWithSHA256,
// PSSWithSHA384, // PSSWithSHA384,
...@@ -197,18 +200,30 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu ...@@ -197,18 +200,30 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
PKCS1WithSHA512, PKCS1WithSHA512,
PKCS1WithSHA1, PKCS1WithSHA1,
} }
break
} }
// TLS 1.3 dropped support for PKCS#1 v1.5 in favor of RSA-PSS. // TLS 1.3 dropped support for PKCS#1 v1.5 in favor of RSA-PSS.
return []SignatureScheme{ sigAlgs = []SignatureScheme{
PSSWithSHA256, PSSWithSHA256,
PSSWithSHA384, PSSWithSHA384,
PSSWithSHA512, PSSWithSHA512,
} }
case ed25519.PublicKey: case ed25519.PublicKey:
return []SignatureScheme{Ed25519} sigAlgs = []SignatureScheme{Ed25519}
default: default:
return nil return nil
} }
if cert.SupportedSignatureAlgorithms != nil {
var filteredSigAlgs []SignatureScheme
for _, sigAlg := range sigAlgs {
if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
filteredSigAlgs = append(filteredSigAlgs, sigAlg)
}
}
return filteredSigAlgs
}
return sigAlgs
} }
// selectSignatureScheme picks a SignatureScheme from the peer's preference list // selectSignatureScheme picks a SignatureScheme from the peer's preference list
...@@ -216,7 +231,7 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu ...@@ -216,7 +231,7 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
// versions that support signature algorithms, so TLS 1.2 and 1.3. // versions that support signature algorithms, so TLS 1.2 and 1.3.
func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) { func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
supportedAlgs := signatureSchemesForCertificate(vers, c) supportedAlgs := signatureSchemesForCertificate(vers, c)
if supportedAlgs == nil { if len(supportedAlgs) == 0 {
return 0, unsupportedCertificateError(c) return 0, unsupportedCertificateError(c)
} }
if len(peerAlgs) == 0 && vers == VersionTLS12 { if len(peerAlgs) == 0 && vers == VersionTLS12 {
...@@ -266,5 +281,9 @@ func unsupportedCertificateError(cert *Certificate) error { ...@@ -266,5 +281,9 @@ func unsupportedCertificateError(cert *Certificate) error {
return fmt.Errorf("tls: unsupported certificate key (%T)", pub) return fmt.Errorf("tls: unsupported certificate key (%T)", pub)
} }
if cert.SupportedSignatureAlgorithms != nil {
return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms")
}
return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey) return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey)
} }
...@@ -14,6 +14,11 @@ func TestSignatureSelection(t *testing.T) { ...@@ -14,6 +14,11 @@ func TestSignatureSelection(t *testing.T) {
Certificate: [][]byte{testRSACertificate}, Certificate: [][]byte{testRSACertificate},
PrivateKey: testRSAPrivateKey, PrivateKey: testRSAPrivateKey,
} }
pkcs1Cert := &Certificate{
Certificate: [][]byte{testRSACertificate},
PrivateKey: testRSAPrivateKey,
SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
}
ecdsaCert := &Certificate{ ecdsaCert := &Certificate{
Certificate: [][]byte{testP256Certificate}, Certificate: [][]byte{testP256Certificate},
PrivateKey: testP256PrivateKey, PrivateKey: testP256PrivateKey,
...@@ -35,6 +40,7 @@ func TestSignatureSelection(t *testing.T) { ...@@ -35,6 +40,7 @@ func TestSignatureSelection(t *testing.T) {
{rsaCert, []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1}, {rsaCert, []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
{rsaCert, []SignatureScheme{PKCS1WithSHA512, PKCS1WithSHA1}, VersionTLS12, PKCS1WithSHA512, signaturePKCS1v15, crypto.SHA512}, {rsaCert, []SignatureScheme{PKCS1WithSHA512, PKCS1WithSHA1}, VersionTLS12, PKCS1WithSHA512, signaturePKCS1v15, crypto.SHA512},
{rsaCert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256}, {rsaCert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
{pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
{rsaCert, []SignatureScheme{PSSWithSHA384, PKCS1WithSHA1}, VersionTLS13, PSSWithSHA384, signatureRSAPSS, crypto.SHA384}, {rsaCert, []SignatureScheme{PSSWithSHA384, PKCS1WithSHA1}, VersionTLS13, PSSWithSHA384, signatureRSAPSS, crypto.SHA384},
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1}, {ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
{ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256}, {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
...@@ -70,6 +76,12 @@ func TestSignatureSelection(t *testing.T) { ...@@ -70,6 +76,12 @@ func TestSignatureSelection(t *testing.T) {
} }
} }
brokenCert := &Certificate{
Certificate: [][]byte{testRSACertificate},
PrivateKey: testRSAPrivateKey,
SupportedSignatureAlgorithms: []SignatureScheme{Ed25519},
}
badTests := []struct { badTests := []struct {
cert *Certificate cert *Certificate
peerSigAlgs []SignatureScheme peerSigAlgs []SignatureScheme
...@@ -80,6 +92,8 @@ func TestSignatureSelection(t *testing.T) { ...@@ -80,6 +92,8 @@ func TestSignatureSelection(t *testing.T) {
{rsaCert, []SignatureScheme{0}, VersionTLS12}, {rsaCert, []SignatureScheme{0}, VersionTLS12},
{ed25519Cert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12}, {ed25519Cert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
{ecdsaCert, []SignatureScheme{Ed25519}, VersionTLS12}, {ecdsaCert, []SignatureScheme{Ed25519}, VersionTLS12},
{brokenCert, []SignatureScheme{Ed25519}, VersionTLS12},
{brokenCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS12},
// RFC 5246, Section 7.4.1.4.1, says to only consider {sha1,ecdsa} as // RFC 5246, Section 7.4.1.4.1, says to only consider {sha1,ecdsa} as
// default when the extension is missing, and RFC 8422 does not update // default when the extension is missing, and RFC 8422 does not update
// it. Anyway, if a stack supports Ed25519 it better support sigalgs. // it. Anyway, if a stack supports Ed25519 it better support sigalgs.
...@@ -92,6 +106,7 @@ func TestSignatureSelection(t *testing.T) { ...@@ -92,6 +106,7 @@ func TestSignatureSelection(t *testing.T) {
{ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS13}, {ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS13},
// TLS 1.3 does not support PKCS1v1.5 or SHA-1. // TLS 1.3 does not support PKCS1v1.5 or SHA-1.
{rsaCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS13}, {rsaCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS13},
{pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS13},
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS13}, {ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS13},
} }
......
...@@ -1174,6 +1174,9 @@ type Certificate struct { ...@@ -1174,6 +1174,9 @@ type Certificate struct {
// For a server up to TLS 1.2, it can also implement crypto.Decrypter with // For a server up to TLS 1.2, it can also implement crypto.Decrypter with
// an RSA PublicKey. // an RSA PublicKey.
PrivateKey crypto.PrivateKey PrivateKey crypto.PrivateKey
// SupportedSignatureAlgorithms is an optional list restricting what
// signature algorithms the PrivateKey can be used for.
SupportedSignatureAlgorithms []SignatureScheme
// OCSPStaple contains an optional OCSP response which will be served // OCSPStaple contains an optional OCSP response which will be served
// to clients that request it. // to clients that request it.
OCSPStaple []byte OCSPStaple []byte
......
...@@ -6,6 +6,7 @@ package tls ...@@ -6,6 +6,7 @@ package tls
import ( import (
"bytes" "bytes"
"crypto"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
"errors" "errors"
...@@ -1051,6 +1052,11 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) { ...@@ -1051,6 +1052,11 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
Certificate: [][]byte{testRSACertificate}, Certificate: [][]byte{testRSACertificate},
PrivateKey: testRSAPrivateKey, PrivateKey: testRSAPrivateKey,
} }
pkcs1Cert := &Certificate{
Certificate: [][]byte{testRSACertificate},
PrivateKey: testRSAPrivateKey,
SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
}
ecdsaCert := &Certificate{ ecdsaCert := &Certificate{
// ECDSA P-256 certificate // ECDSA P-256 certificate
Certificate: [][]byte{testP256Certificate}, Certificate: [][]byte{testP256Certificate},
...@@ -1084,6 +1090,10 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) { ...@@ -1084,6 +1090,10 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384}, SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384},
SupportedVersions: []uint16{VersionTLS13}, SupportedVersions: []uint16{VersionTLS13},
}, "signature algorithms"}, }, "signature algorithms"},
{pkcs1Cert, &ClientHelloInfo{
SignatureSchemes: []SignatureScheme{PSSWithSHA256, ECDSAWithP256AndSHA256},
SupportedVersions: []uint16{VersionTLS13},
}, "signature algorithms"},
{rsaCert, &ClientHelloInfo{ {rsaCert, &ClientHelloInfo{
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
...@@ -1204,3 +1214,38 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) { ...@@ -1204,3 +1214,38 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
} }
} }
} }
type brokenSigner struct{ crypto.Signer }
func (s brokenSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
// Replace opts with opts.HashFunc(), so rsa.PSSOptions are discarded.
return s.Signer.Sign(rand, digest, opts.HashFunc())
}
// TestPKCS1OnlyCert uses a client certificate with a broken crypto.Signer that
// always makes PKCS#1 v1.5 signatures, so can't be used with RSA-PSS.
func TestPKCS1OnlyCert(t *testing.T) {
clientConfig := testConfig.Clone()
clientConfig.Certificates = []Certificate{{
Certificate: [][]byte{testRSACertificate},
PrivateKey: brokenSigner{testRSAPrivateKey},
}}
serverConfig := testConfig.Clone()
serverConfig.MaxVersion = VersionTLS12 // TLS 1.3 doesn't support PKCS#1 v1.5
serverConfig.ClientAuth = RequireAnyClientCert
// If RSA-PSS is selected, the handshake should fail.
if _, _, err := testHandshake(t, clientConfig, serverConfig); err == nil {
// RSA-PSS is temporarily disabled in TLS 1.2. See Issue 32425.
// t.Fatal("expected broken certificate to cause connection to fail")
}
clientConfig.Certificates[0].SupportedSignatureAlgorithms =
[]SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}
// But if the certificate restricts supported algorithms, RSA-PSS should not
// be selected, and the handshake should succeed.
if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil {
t.Error(err)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment