Skip to content

Commit 59afdd3

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/tls: clean up supported/default/allowed parameters
Cleaned up a lot of the plumbing to make it consistently follow this logic: clone the preference order; filter by user preference; filter by FIPS policy. There should be no behavior changes. Updates #71757 Change-Id: I6a6a4656eb02e56d079f0a22f98212275a400000 Reviewed-on: https://go-review.googlesource.com/c/go/+/657096 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> Reviewed-by: Daniel McCarney <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Junyang Shao <[email protected]>
1 parent 0f5d86c commit 59afdd3

11 files changed

+177
-172
lines changed

src/crypto/tls/auth.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import (
1111
"crypto/ed25519"
1212
"crypto/elliptic"
1313
"crypto/rsa"
14-
"crypto/tls/internal/fips140tls"
1514
"errors"
1615
"fmt"
1716
"hash"
1817
"io"
18+
"slices"
1919
)
2020

2121
// verifyHandshakeSignature verifies a signature against pre-hashed
@@ -168,9 +168,6 @@ var rsaSignatureSchemes = []struct {
168168
// signatureSchemesForCertificate returns the list of supported SignatureSchemes
169169
// for a given certificate, based on the public key and the protocol version,
170170
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
171-
//
172-
// This function must be kept in sync with supportedSignatureAlgorithms.
173-
// FIPS filtering is applied in the caller, selectSignatureScheme.
174171
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
175172
priv, ok := cert.PrivateKey.(crypto.Signer)
176173
if !ok {
@@ -216,14 +213,18 @@ func signatureSchemesForCertificate(version uint16, cert *Certificate) []Signatu
216213
}
217214

218215
if cert.SupportedSignatureAlgorithms != nil {
219-
var filteredSigAlgs []SignatureScheme
220-
for _, sigAlg := range sigAlgs {
221-
if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
222-
filteredSigAlgs = append(filteredSigAlgs, sigAlg)
223-
}
224-
}
225-
return filteredSigAlgs
216+
sigAlgs = slices.DeleteFunc(sigAlgs, func(sigAlg SignatureScheme) bool {
217+
return !isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms)
218+
})
226219
}
220+
221+
// Filter out any unsupported signature algorithms, for example due to
222+
// FIPS 140-3 policy, or any downstream changes to defaults.go.
223+
supportedAlgs := supportedSignatureAlgorithms()
224+
sigAlgs = slices.DeleteFunc(sigAlgs, func(sigAlg SignatureScheme) bool {
225+
return !isSupportedSignatureAlgorithm(sigAlg, supportedAlgs)
226+
})
227+
227228
return sigAlgs
228229
}
229230

@@ -243,9 +244,6 @@ func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureSche
243244
// Pick signature scheme in the peer's preference order, as our
244245
// preference order is not configurable.
245246
for _, preferredAlg := range peerAlgs {
246-
if fips140tls.Required() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) {
247-
continue
248-
}
249247
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
250248
return preferredAlg, nil
251249
}

src/crypto/tls/cipher_suites.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ func CipherSuites() []*CipherSuite {
7878
// Most applications should not use the cipher suites in this list, and should
7979
// only use those returned by [CipherSuites].
8080
func InsecureCipherSuites() []*CipherSuite {
81-
// This list includes RC4, CBC_SHA256, and 3DES cipher suites. See
82-
// cipherSuitesPreferenceOrder for details.
81+
// This list includes legacy RSA kex, RC4, CBC_SHA256, and 3DES cipher
82+
// suites. See cipherSuitesPreferenceOrder for details.
8383
return []*CipherSuite{
8484
{TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
8585
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
@@ -387,9 +387,13 @@ var aesgcmCiphers = map[uint16]bool{
387387
TLS_AES_256_GCM_SHA384: true,
388388
}
389389

390-
// aesgcmPreferred returns whether the first known cipher in the preference list
391-
// is an AES-GCM cipher, implying the peer has hardware support for it.
392-
func aesgcmPreferred(ciphers []uint16) bool {
390+
// isAESGCMPreferred returns whether we have hardware support for AES-GCM, and the
391+
// first known cipher in the peer's preference list is an AES-GCM cipher,
392+
// implying the peer also has hardware support for it.
393+
func isAESGCMPreferred(ciphers []uint16) bool {
394+
if !hasAESGCMHardwareSupport {
395+
return false
396+
}
393397
for _, cID := range ciphers {
394398
if c := cipherSuiteByID(cID); c != nil {
395399
return aesgcmCiphers[cID]

src/crypto/tls/common.go

Lines changed: 33 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,20 +1106,28 @@ func (c *Config) time() time.Time {
11061106
return t()
11071107
}
11081108

1109-
func (c *Config) cipherSuites() []uint16 {
1109+
func (c *Config) cipherSuites(aesGCMPreferred bool) []uint16 {
1110+
var cipherSuites []uint16
11101111
if c.CipherSuites == nil {
1111-
if fips140tls.Required() {
1112-
return defaultCipherSuitesFIPS
1113-
}
1114-
return defaultCipherSuites()
1112+
cipherSuites = defaultCipherSuites(aesGCMPreferred)
1113+
} else {
1114+
cipherSuites = supportedCipherSuites(aesGCMPreferred)
1115+
cipherSuites = slices.DeleteFunc(cipherSuites, func(id uint16) bool {
1116+
return !slices.Contains(c.CipherSuites, id)
1117+
})
11151118
}
11161119
if fips140tls.Required() {
1117-
cipherSuites := slices.Clone(c.CipherSuites)
1118-
return slices.DeleteFunc(cipherSuites, func(id uint16) bool {
1119-
return !slices.Contains(defaultCipherSuitesFIPS, id)
1120+
cipherSuites = slices.DeleteFunc(cipherSuites, func(id uint16) bool {
1121+
return !slices.Contains(allowedCipherSuitesFIPS, id)
11201122
})
11211123
}
1122-
return c.CipherSuites
1124+
return cipherSuites
1125+
}
1126+
1127+
// supportedCipherSuites returns the supported TLS 1.0–1.2 cipher suites in an
1128+
// undefined order. For preference ordering, use [Config.cipherSuites].
1129+
func (c *Config) supportedCipherSuites() []uint16 {
1130+
return c.cipherSuites(false)
11231131
}
11241132

11251133
var supportedVersions = []uint16{
@@ -1139,7 +1147,7 @@ var tls10server = godebug.New("tls10server")
11391147
func (c *Config) supportedVersions(isClient bool) []uint16 {
11401148
versions := make([]uint16, 0, len(supportedVersions))
11411149
for _, v := range supportedVersions {
1142-
if fips140tls.Required() && !slices.Contains(defaultSupportedVersionsFIPS, v) {
1150+
if fips140tls.Required() && !slices.Contains(allowedSupportedVersionsFIPS, v) {
11431151
continue
11441152
}
11451153
if (c == nil || c.MinVersion == 0) && v < VersionTLS12 {
@@ -1184,11 +1192,11 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 {
11841192
}
11851193

11861194
func (c *Config) curvePreferences(version uint16) []CurveID {
1187-
var curvePreferences []CurveID
1195+
curvePreferences := defaultCurvePreferences()
11881196
if fips140tls.Required() {
1189-
curvePreferences = slices.Clone(defaultCurvePreferencesFIPS)
1190-
} else {
1191-
curvePreferences = defaultCurvePreferences()
1197+
curvePreferences = slices.DeleteFunc(curvePreferences, func(x CurveID) bool {
1198+
return !slices.Contains(allowedCurvePreferencesFIPS, x)
1199+
})
11921200
}
11931201
if c != nil && len(c.CurvePreferences) != 0 {
11941202
curvePreferences = slices.DeleteFunc(curvePreferences, func(x CurveID) bool {
@@ -1202,23 +1210,16 @@ func (c *Config) curvePreferences(version uint16) []CurveID {
12021210
}
12031211

12041212
func (c *Config) supportsCurve(version uint16, curve CurveID) bool {
1205-
for _, cc := range c.curvePreferences(version) {
1206-
if cc == curve {
1207-
return true
1208-
}
1209-
}
1210-
return false
1213+
return slices.Contains(c.curvePreferences(version), curve)
12111214
}
12121215

12131216
// mutualVersion returns the protocol version to use given the advertised
12141217
// versions of the peer. Priority is given to the peer preference order.
12151218
func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) {
12161219
supportedVersions := c.supportedVersions(isClient)
1217-
for _, peerVersion := range peerVersions {
1218-
for _, v := range supportedVersions {
1219-
if v == peerVersion {
1220-
return v, true
1221-
}
1220+
for _, v := range peerVersions {
1221+
if slices.Contains(supportedVersions, v) {
1222+
return v, true
12221223
}
12231224
}
12241225
return 0, false
@@ -1339,7 +1340,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
13391340
}
13401341
// Finally, there needs to be a mutual cipher suite that uses the static
13411342
// RSA key exchange instead of ECDHE.
1342-
rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
1343+
rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.supportedCipherSuites(), func(c *cipherSuite) bool {
13431344
if c.flags&suiteECDHE != 0 {
13441345
return false
13451346
}
@@ -1416,7 +1417,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
14161417
// Make sure that there is a mutually supported cipher suite that works with
14171418
// this certificate. Cipher suite selection will then apply the logic in
14181419
// reverse to pick it. See also serverHandshakeState.cipherSuiteOk.
1419-
cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
1420+
cipherSuite := selectCipherSuite(chi.CipherSuites, config.supportedCipherSuites(), func(c *cipherSuite) bool {
14201421
if c.flags&suiteECDHE == 0 {
14211422
return false
14221423
}
@@ -1660,19 +1661,14 @@ func unexpectedMessageError(wanted, got any) error {
16601661

16611662
// supportedSignatureAlgorithms returns the supported signature algorithms.
16621663
func supportedSignatureAlgorithms() []SignatureScheme {
1663-
if !fips140tls.Required() {
1664-
return defaultSupportedSignatureAlgorithms
1664+
if fips140tls.Required() {
1665+
return allowedSupportedSignatureAlgorithmsFIPS
16651666
}
1666-
return defaultSupportedSignatureAlgorithmsFIPS
1667+
return defaultSupportedSignatureAlgorithms
16671668
}
16681669

16691670
func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
1670-
for _, s := range supportedSignatureAlgorithms {
1671-
if s == sigAlg {
1672-
return true
1673-
}
1674-
}
1675-
return false
1671+
return slices.Contains(supportedSignatureAlgorithms, sigAlg)
16761672
}
16771673

16781674
// CertificateVerificationError is returned when certificate verification fails during the handshake.
@@ -1721,24 +1717,10 @@ func fipsAllowChain(chain []*x509.Certificate) bool {
17211717
}
17221718

17231719
for _, cert := range chain {
1724-
if !fipsAllowCert(cert) {
1720+
if !isCertificateAllowedFIPS(cert) {
17251721
return false
17261722
}
17271723
}
17281724

17291725
return true
17301726
}
1731-
1732-
func fipsAllowCert(c *x509.Certificate) bool {
1733-
// The key must be RSA 2048, RSA 3072, RSA 4096,
1734-
// or ECDSA P-256, P-384, P-521.
1735-
switch k := c.PublicKey.(type) {
1736-
case *rsa.PublicKey:
1737-
size := k.N.BitLen()
1738-
return size == 2048 || size == 3072 || size == 4096
1739-
case *ecdsa.PublicKey:
1740-
return k.Curve == elliptic.P256() || k.Curve == elliptic.P384() || k.Curve == elliptic.P521()
1741-
}
1742-
1743-
return false
1744-
}

src/crypto/tls/defaults.go

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,17 @@ var defaultSupportedSignatureAlgorithms = []SignatureScheme{
4646
var tlsrsakex = godebug.New("tlsrsakex")
4747
var tls3des = godebug.New("tls3des")
4848

49-
func defaultCipherSuites() []uint16 {
50-
suites := slices.Clone(cipherSuitesPreferenceOrder)
51-
return slices.DeleteFunc(suites, func(c uint16) bool {
49+
func supportedCipherSuites(aesGCMPreferred bool) []uint16 {
50+
if aesGCMPreferred {
51+
return slices.Clone(cipherSuitesPreferenceOrder)
52+
} else {
53+
return slices.Clone(cipherSuitesPreferenceOrderNoAES)
54+
}
55+
}
56+
57+
func defaultCipherSuites(aesGCMPreferred bool) []uint16 {
58+
cipherSuites := supportedCipherSuites(aesGCMPreferred)
59+
return slices.DeleteFunc(cipherSuites, func(c uint16) bool {
5260
return disabledCipherSuites[c] ||
5361
tlsrsakex.Value() != "1" && rsaKexCiphers[c] ||
5462
tls3des.Value() != "1" && tdesCiphers[c]
@@ -90,45 +98,3 @@ var defaultCipherSuitesTLS13NoAES = []uint16{
9098
TLS_AES_128_GCM_SHA256,
9199
TLS_AES_256_GCM_SHA384,
92100
}
93-
94-
// The FIPS-only policies below match BoringSSL's
95-
// ssl_compliance_policy_fips_202205, which is based on NIST SP 800-52r2, with
96-
// minor changes per https://go.dev/issue/71757.
97-
// https://cs.opensource.google/boringssl/boringssl/+/master:ssl/ssl_lib.cc;l=3289;drc=ea7a88fa
98-
99-
var defaultSupportedVersionsFIPS = []uint16{
100-
VersionTLS12,
101-
VersionTLS13,
102-
}
103-
104-
// defaultCurvePreferencesFIPS are the FIPS-allowed curves,
105-
// in preference order (most preferable first).
106-
var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521}
107-
108-
// defaultSupportedSignatureAlgorithmsFIPS currently are a subset of
109-
// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
110-
var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
111-
PSSWithSHA256,
112-
PSSWithSHA384,
113-
PSSWithSHA512,
114-
PKCS1WithSHA256,
115-
ECDSAWithP256AndSHA256,
116-
PKCS1WithSHA384,
117-
ECDSAWithP384AndSHA384,
118-
PKCS1WithSHA512,
119-
ECDSAWithP521AndSHA512,
120-
}
121-
122-
// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
123-
var defaultCipherSuitesFIPS = []uint16{
124-
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
125-
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
126-
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
127-
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
128-
}
129-
130-
// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3.
131-
var defaultCipherSuitesTLS13FIPS = []uint16{
132-
TLS_AES_128_GCM_SHA256,
133-
TLS_AES_256_GCM_SHA384,
134-
}

src/crypto/tls/defaults_boring.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package tls
6+
7+
import (
8+
"crypto/ecdsa"
9+
"crypto/elliptic"
10+
"crypto/rsa"
11+
"crypto/x509"
12+
)
13+
14+
// These Go+BoringCrypto policies mostly match BoringSSL's
15+
// ssl_compliance_policy_fips_202205, which is based on NIST SP 800-52r2.
16+
// https://cs.opensource.google/boringssl/boringssl/+/master:ssl/ssl_lib.cc;l=3289;drc=ea7a88fa
17+
//
18+
// P-521 is allowed per https://go.dev/issue/71757.
19+
//
20+
// They are applied when crypto/tls/fipsonly is imported with GOEXPERIMENT=boringcrypto.
21+
22+
var (
23+
allowedSupportedVersionsFIPS = []uint16{
24+
VersionTLS12,
25+
VersionTLS13,
26+
}
27+
allowedCurvePreferencesFIPS = []CurveID{
28+
CurveP256,
29+
CurveP384,
30+
CurveP521,
31+
}
32+
allowedSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
33+
PSSWithSHA256,
34+
PSSWithSHA384,
35+
PSSWithSHA512,
36+
PKCS1WithSHA256,
37+
ECDSAWithP256AndSHA256,
38+
PKCS1WithSHA384,
39+
ECDSAWithP384AndSHA384,
40+
PKCS1WithSHA512,
41+
ECDSAWithP521AndSHA512,
42+
}
43+
allowedCipherSuitesFIPS = []uint16{
44+
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
45+
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
46+
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
47+
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
48+
}
49+
allowedCipherSuitesTLS13FIPS = []uint16{
50+
TLS_AES_128_GCM_SHA256,
51+
TLS_AES_256_GCM_SHA384,
52+
}
53+
)
54+
55+
func isCertificateAllowedFIPS(c *x509.Certificate) bool {
56+
// The key must be RSA 2048, RSA 3072, RSA 4096,
57+
// or ECDSA P-256, P-384, P-521.
58+
switch k := c.PublicKey.(type) {
59+
case *rsa.PublicKey:
60+
size := k.N.BitLen()
61+
return size == 2048 || size == 3072 || size == 4096
62+
case *ecdsa.PublicKey:
63+
return k.Curve == elliptic.P256() || k.Curve == elliptic.P384() || k.Curve == elliptic.P521()
64+
}
65+
66+
return false
67+
}

0 commit comments

Comments
 (0)