Skip to content

Commit 5b17b65

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Adam Langley <[email protected]>
1 parent eb93c68 commit 5b17b65

File tree

4 files changed

+91
-9
lines changed

4 files changed

+91
-9
lines changed

src/crypto/tls/auth.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash c
154154
}
155155

156156
// signatureSchemesForCertificate returns the list of supported SignatureSchemes
157-
// for a given certificate, based on the public key and the protocol version.
157+
// for a given certificate, based on the public key and the protocol version,
158+
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
158159
//
159160
// This function must be kept in sync with supportedSignatureAlgorithms.
160161
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
@@ -163,31 +164,33 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
163164
return nil
164165
}
165166

167+
var sigAlgs []SignatureScheme
166168
switch pub := priv.Public().(type) {
167169
case *ecdsa.PublicKey:
168170
if version != VersionTLS13 {
169171
// In TLS 1.2 and earlier, ECDSA algorithms are not
170172
// constrained to a single curve.
171-
return []SignatureScheme{
173+
sigAlgs = []SignatureScheme{
172174
ECDSAWithP256AndSHA256,
173175
ECDSAWithP384AndSHA384,
174176
ECDSAWithP521AndSHA512,
175177
ECDSAWithSHA1,
176178
}
179+
break
177180
}
178181
switch pub.Curve {
179182
case elliptic.P256():
180-
return []SignatureScheme{ECDSAWithP256AndSHA256}
183+
sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
181184
case elliptic.P384():
182-
return []SignatureScheme{ECDSAWithP384AndSHA384}
185+
sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
183186
case elliptic.P521():
184-
return []SignatureScheme{ECDSAWithP521AndSHA512}
187+
sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
185188
default:
186189
return nil
187190
}
188191
case *rsa.PublicKey:
189192
if version != VersionTLS13 {
190-
return []SignatureScheme{
193+
sigAlgs = []SignatureScheme{
191194
// Temporarily disable RSA-PSS in TLS 1.2, see Issue 32425.
192195
// PSSWithSHA256,
193196
// PSSWithSHA384,
@@ -197,26 +200,38 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
197200
PKCS1WithSHA512,
198201
PKCS1WithSHA1,
199202
}
203+
break
200204
}
201205
// TLS 1.3 dropped support for PKCS#1 v1.5 in favor of RSA-PSS.
202-
return []SignatureScheme{
206+
sigAlgs = []SignatureScheme{
203207
PSSWithSHA256,
204208
PSSWithSHA384,
205209
PSSWithSHA512,
206210
}
207211
case ed25519.PublicKey:
208-
return []SignatureScheme{Ed25519}
212+
sigAlgs = []SignatureScheme{Ed25519}
209213
default:
210214
return nil
211215
}
216+
217+
if cert.SupportedSignatureAlgorithms != nil {
218+
var filteredSigAlgs []SignatureScheme
219+
for _, sigAlg := range sigAlgs {
220+
if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
221+
filteredSigAlgs = append(filteredSigAlgs, sigAlg)
222+
}
223+
}
224+
return filteredSigAlgs
225+
}
226+
return sigAlgs
212227
}
213228

214229
// selectSignatureScheme picks a SignatureScheme from the peer's preference list
215230
// that works with the selected certificate. It's only called for protocol
216231
// versions that support signature algorithms, so TLS 1.2 and 1.3.
217232
func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
218233
supportedAlgs := signatureSchemesForCertificate(vers, c)
219-
if supportedAlgs == nil {
234+
if len(supportedAlgs) == 0 {
220235
return 0, unsupportedCertificateError(c)
221236
}
222237
if len(peerAlgs) == 0 && vers == VersionTLS12 {
@@ -266,5 +281,9 @@ func unsupportedCertificateError(cert *Certificate) error {
266281
return fmt.Errorf("tls: unsupported certificate key (%T)", pub)
267282
}
268283

284+
if cert.SupportedSignatureAlgorithms != nil {
285+
return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms")
286+
}
287+
269288
return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey)
270289
}

src/crypto/tls/auth_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ func TestSignatureSelection(t *testing.T) {
1414
Certificate: [][]byte{testRSACertificate},
1515
PrivateKey: testRSAPrivateKey,
1616
}
17+
pkcs1Cert := &Certificate{
18+
Certificate: [][]byte{testRSACertificate},
19+
PrivateKey: testRSAPrivateKey,
20+
SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
21+
}
1722
ecdsaCert := &Certificate{
1823
Certificate: [][]byte{testP256Certificate},
1924
PrivateKey: testP256PrivateKey,
@@ -35,6 +40,7 @@ func TestSignatureSelection(t *testing.T) {
3540
{rsaCert, []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
3641
{rsaCert, []SignatureScheme{PKCS1WithSHA512, PKCS1WithSHA1}, VersionTLS12, PKCS1WithSHA512, signaturePKCS1v15, crypto.SHA512},
3742
{rsaCert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
43+
{pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
3844
{rsaCert, []SignatureScheme{PSSWithSHA384, PKCS1WithSHA1}, VersionTLS13, PSSWithSHA384, signatureRSAPSS, crypto.SHA384},
3945
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
4046
{ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
@@ -70,6 +76,12 @@ func TestSignatureSelection(t *testing.T) {
7076
}
7177
}
7278

79+
brokenCert := &Certificate{
80+
Certificate: [][]byte{testRSACertificate},
81+
PrivateKey: testRSAPrivateKey,
82+
SupportedSignatureAlgorithms: []SignatureScheme{Ed25519},
83+
}
84+
7385
badTests := []struct {
7486
cert *Certificate
7587
peerSigAlgs []SignatureScheme
@@ -80,6 +92,8 @@ func TestSignatureSelection(t *testing.T) {
8092
{rsaCert, []SignatureScheme{0}, VersionTLS12},
8193
{ed25519Cert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
8294
{ecdsaCert, []SignatureScheme{Ed25519}, VersionTLS12},
95+
{brokenCert, []SignatureScheme{Ed25519}, VersionTLS12},
96+
{brokenCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS12},
8397
// RFC 5246, Section 7.4.1.4.1, says to only consider {sha1,ecdsa} as
8498
// default when the extension is missing, and RFC 8422 does not update
8599
// it. Anyway, if a stack supports Ed25519 it better support sigalgs.
@@ -92,6 +106,7 @@ func TestSignatureSelection(t *testing.T) {
92106
{ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS13},
93107
// TLS 1.3 does not support PKCS1v1.5 or SHA-1.
94108
{rsaCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS13},
109+
{pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS13},
95110
{ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS13},
96111
}
97112

src/crypto/tls/common.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,9 @@ type Certificate struct {
11741174
// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
11751175
// an RSA PublicKey.
11761176
PrivateKey crypto.PrivateKey
1177+
// SupportedSignatureAlgorithms is an optional list restricting what
1178+
// signature algorithms the PrivateKey can be used for.
1179+
SupportedSignatureAlgorithms []SignatureScheme
11771180
// OCSPStaple contains an optional OCSP response which will be served
11781181
// to clients that request it.
11791182
OCSPStaple []byte

src/crypto/tls/tls_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package tls
66

77
import (
88
"bytes"
9+
"crypto"
910
"crypto/x509"
1011
"encoding/json"
1112
"errors"
@@ -1051,6 +1052,11 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
10511052
Certificate: [][]byte{testRSACertificate},
10521053
PrivateKey: testRSAPrivateKey,
10531054
}
1055+
pkcs1Cert := &Certificate{
1056+
Certificate: [][]byte{testRSACertificate},
1057+
PrivateKey: testRSAPrivateKey,
1058+
SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
1059+
}
10541060
ecdsaCert := &Certificate{
10551061
// ECDSA P-256 certificate
10561062
Certificate: [][]byte{testP256Certificate},
@@ -1084,6 +1090,10 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
10841090
SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384},
10851091
SupportedVersions: []uint16{VersionTLS13},
10861092
}, "signature algorithms"},
1093+
{pkcs1Cert, &ClientHelloInfo{
1094+
SignatureSchemes: []SignatureScheme{PSSWithSHA256, ECDSAWithP256AndSHA256},
1095+
SupportedVersions: []uint16{VersionTLS13},
1096+
}, "signature algorithms"},
10871097

10881098
{rsaCert, &ClientHelloInfo{
10891099
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
@@ -1204,3 +1214,38 @@ func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
12041214
}
12051215
}
12061216
}
1217+
1218+
type brokenSigner struct{ crypto.Signer }
1219+
1220+
func (s brokenSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
1221+
// Replace opts with opts.HashFunc(), so rsa.PSSOptions are discarded.
1222+
return s.Signer.Sign(rand, digest, opts.HashFunc())
1223+
}
1224+
1225+
// TestPKCS1OnlyCert uses a client certificate with a broken crypto.Signer that
1226+
// always makes PKCS#1 v1.5 signatures, so can't be used with RSA-PSS.
1227+
func TestPKCS1OnlyCert(t *testing.T) {
1228+
clientConfig := testConfig.Clone()
1229+
clientConfig.Certificates = []Certificate{{
1230+
Certificate: [][]byte{testRSACertificate},
1231+
PrivateKey: brokenSigner{testRSAPrivateKey},
1232+
}}
1233+
serverConfig := testConfig.Clone()
1234+
serverConfig.MaxVersion = VersionTLS12 // TLS 1.3 doesn't support PKCS#1 v1.5
1235+
serverConfig.ClientAuth = RequireAnyClientCert
1236+
1237+
// If RSA-PSS is selected, the handshake should fail.
1238+
if _, _, err := testHandshake(t, clientConfig, serverConfig); err == nil {
1239+
// RSA-PSS is temporarily disabled in TLS 1.2. See Issue 32425.
1240+
// t.Fatal("expected broken certificate to cause connection to fail")
1241+
}
1242+
1243+
clientConfig.Certificates[0].SupportedSignatureAlgorithms =
1244+
[]SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}
1245+
1246+
// But if the certificate restricts supported algorithms, RSA-PSS should not
1247+
// be selected, and the handshake should succeed.
1248+
if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil {
1249+
t.Error(err)
1250+
}
1251+
}

0 commit comments

Comments
 (0)