Skip to content

Commit 4106de9

Browse files
FiloSottilerolandshoemaker
authored andcommitted
crypto/tls: align FIPS-only mode with BoringSSL policy
This enables TLS 1.3, disables P-521, and disables non-ECDHE suites. Fixes #64717 Updates #62372 Change-Id: I3a65b239ef0198bbdbe5e55e0810e7128f90a091 Reviewed-on: https://go-review.googlesource.com/c/go/+/549975 Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Than McIntosh <thanm@google.com>
1 parent 7383b2a commit 4106de9

11 files changed

+125
-57
lines changed

src/crypto/internal/boring/aes.go

+22-7
Original file line numberDiff line numberDiff line change
@@ -228,26 +228,41 @@ func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
228228
if tagSize != gcmTagSize {
229229
return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
230230
}
231-
return c.newGCM(false)
231+
return c.newGCM(0)
232232
}
233233

234+
const (
235+
VersionTLS12 = 0x0303
236+
VersionTLS13 = 0x0304
237+
)
238+
234239
func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
235-
return c.(*aesCipher).newGCM(true)
240+
return c.(*aesCipher).newGCM(VersionTLS12)
241+
}
242+
243+
func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
244+
return c.(*aesCipher).newGCM(VersionTLS13)
236245
}
237246

238-
func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
247+
func (c *aesCipher) newGCM(tlsVersion uint16) (cipher.AEAD, error) {
239248
var aead *C.GO_EVP_AEAD
240249
switch len(c.key) * 8 {
241250
case 128:
242-
if tls {
251+
switch tlsVersion {
252+
case VersionTLS12:
243253
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
244-
} else {
254+
case VersionTLS13:
255+
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls13()
256+
default:
245257
aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
246258
}
247259
case 256:
248-
if tls {
260+
switch tlsVersion {
261+
case VersionTLS12:
249262
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
250-
} else {
263+
case VersionTLS13:
264+
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls13()
265+
default:
251266
aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
252267
}
253268
default:

src/crypto/internal/boring/notboring.go

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: no
5050

5151
func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") }
5252
func NewGCMTLS(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
53+
func NewGCMTLS13(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
5354

5455
type PublicKeyECDSA struct{ _ int }
5556
type PrivateKeyECDSA struct{ _ int }

src/crypto/tls/boring.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
package tls
88

9-
import (
10-
"crypto/internal/boring/fipstls"
11-
)
9+
import "crypto/internal/boring/fipstls"
10+
11+
// The FIPS-only policies enforced here currently match BoringSSL's
12+
// ssl_policy_fips_202205.
1213

1314
// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
1415
func needFIPS() bool {
@@ -17,19 +18,19 @@ func needFIPS() bool {
1718

1819
// fipsMinVersion replaces c.minVersion in FIPS-only mode.
1920
func fipsMinVersion(c *Config) uint16 {
20-
// FIPS requires TLS 1.2.
21+
// FIPS requires TLS 1.2 or TLS 1.3.
2122
return VersionTLS12
2223
}
2324

2425
// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
2526
func fipsMaxVersion(c *Config) uint16 {
26-
// FIPS requires TLS 1.2.
27-
return VersionTLS12
27+
// FIPS requires TLS 1.2 or TLS 1.3.
28+
return VersionTLS13
2829
}
2930

3031
// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
3132
// in preference order (most preferable first).
32-
var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
33+
var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384}
3334

3435
// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
3536
func fipsCurvePreferences(c *Config) []CurveID {
@@ -54,8 +55,6 @@ var defaultCipherSuitesFIPS = []uint16{
5455
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
5556
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
5657
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
57-
TLS_RSA_WITH_AES_128_GCM_SHA256,
58-
TLS_RSA_WITH_AES_256_GCM_SHA384,
5958
}
6059

6160
// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
@@ -75,8 +74,14 @@ func fipsCipherSuites(c *Config) []uint16 {
7574
return list
7675
}
7776

77+
// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3.
78+
var defaultCipherSuitesTLS13FIPS = []uint16{
79+
TLS_AES_128_GCM_SHA256,
80+
TLS_AES_256_GCM_SHA384,
81+
}
82+
7883
// fipsSupportedSignatureAlgorithms currently are a subset of
79-
// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
84+
// defaultSupportedSignatureAlgorithms without Ed25519, SHA-1, and P-521.
8085
var fipsSupportedSignatureAlgorithms = []SignatureScheme{
8186
PSSWithSHA256,
8287
PSSWithSHA384,
@@ -86,7 +91,6 @@ var fipsSupportedSignatureAlgorithms = []SignatureScheme{
8691
PKCS1WithSHA384,
8792
ECDSAWithP384AndSHA384,
8893
PKCS1WithSHA512,
89-
ECDSAWithP521AndSHA512,
9094
}
9195

9296
// supportedSignatureAlgorithms returns the supported signature algorithms.

src/crypto/tls/boring_test.go

+51-18
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,31 @@ import (
2525
"time"
2626
)
2727

28+
func allCipherSuitesIncludingTLS13() []uint16 {
29+
s := allCipherSuites()
30+
for _, suite := range cipherSuitesTLS13 {
31+
s = append(s, suite.id)
32+
}
33+
return s
34+
}
35+
36+
func isTLS13CipherSuite(id uint16) bool {
37+
for _, suite := range cipherSuitesTLS13 {
38+
if id == suite.id {
39+
return true
40+
}
41+
}
42+
return false
43+
}
44+
45+
func generateKeyShare(group CurveID) keyShare {
46+
key, err := generateECDHEKey(rand.Reader, group)
47+
if err != nil {
48+
panic(err)
49+
}
50+
return keyShare{group: group, data: key.PublicKey().Bytes()}
51+
}
52+
2853
func TestBoringServerProtocolVersion(t *testing.T) {
2954
test := func(name string, v uint16, msg string) {
3055
t.Run(name, func(t *testing.T) {
@@ -33,8 +58,11 @@ func TestBoringServerProtocolVersion(t *testing.T) {
3358
clientHello := &clientHelloMsg{
3459
vers: v,
3560
random: make([]byte, 32),
36-
cipherSuites: allCipherSuites(),
61+
cipherSuites: allCipherSuitesIncludingTLS13(),
3762
compressionMethods: []uint8{compressionNone},
63+
supportedCurves: defaultCurvePreferences,
64+
keyShares: []keyShare{generateKeyShare(CurveP256)},
65+
supportedPoints: []uint8{pointFormatUncompressed},
3866
supportedVersions: []uint16{v},
3967
}
4068
testClientHelloFailure(t, serverConfig, clientHello, msg)
@@ -48,33 +76,33 @@ func TestBoringServerProtocolVersion(t *testing.T) {
4876

4977
fipstls.Force()
5078
defer fipstls.Abandon()
51-
test("VersionSSL30", VersionSSL30, "client offered only unsupported versions")
52-
test("VersionTLS10", VersionTLS10, "client offered only unsupported versions")
53-
test("VersionTLS11", VersionTLS11, "client offered only unsupported versions")
54-
test("VersionTLS12", VersionTLS12, "")
55-
test("VersionTLS13", VersionTLS13, "client offered only unsupported versions")
79+
test("VersionSSL30/fipstls", VersionSSL30, "client offered only unsupported versions")
80+
test("VersionTLS10/fipstls", VersionTLS10, "client offered only unsupported versions")
81+
test("VersionTLS11/fipstls", VersionTLS11, "client offered only unsupported versions")
82+
test("VersionTLS12/fipstls", VersionTLS12, "")
83+
test("VersionTLS13/fipstls", VersionTLS13, "")
5684
}
5785

5886
func isBoringVersion(v uint16) bool {
59-
return v == VersionTLS12
87+
return v == VersionTLS12 || v == VersionTLS13
6088
}
6189

6290
func isBoringCipherSuite(id uint16) bool {
6391
switch id {
64-
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
92+
case TLS_AES_128_GCM_SHA256,
93+
TLS_AES_256_GCM_SHA384,
94+
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
6595
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
6696
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
67-
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
68-
TLS_RSA_WITH_AES_128_GCM_SHA256,
69-
TLS_RSA_WITH_AES_256_GCM_SHA384:
97+
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
7098
return true
7199
}
72100
return false
73101
}
74102

75103
func isBoringCurve(id CurveID) bool {
76104
switch id {
77-
case CurveP256, CurveP384, CurveP521:
105+
case CurveP256, CurveP384:
78106
return true
79107
}
80108
return false
@@ -86,7 +114,7 @@ func isECDSA(id uint16) bool {
86114
return suite.flags&suiteECSign == suiteECSign
87115
}
88116
}
89-
panic(fmt.Sprintf("unknown cipher suite %#x", id))
117+
return false // TLS 1.3 cipher suites are not tied to the signature algorithm.
90118
}
91119

92120
func isBoringSignatureScheme(alg SignatureScheme) bool {
@@ -98,7 +126,6 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
98126
PKCS1WithSHA384,
99127
ECDSAWithP384AndSHA384,
100128
PKCS1WithSHA512,
101-
ECDSAWithP521AndSHA512,
102129
PSSWithSHA256,
103130
PSSWithSHA384,
104131
PSSWithSHA512:
@@ -109,10 +136,9 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
109136

110137
func TestBoringServerCipherSuites(t *testing.T) {
111138
serverConfig := testConfig.Clone()
112-
serverConfig.CipherSuites = allCipherSuites()
113139
serverConfig.Certificates = make([]Certificate, 1)
114140

115-
for _, id := range allCipherSuites() {
141+
for _, id := range allCipherSuitesIncludingTLS13() {
116142
if isECDSA(id) {
117143
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
118144
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
@@ -121,14 +147,19 @@ func TestBoringServerCipherSuites(t *testing.T) {
121147
serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
122148
}
123149
serverConfig.BuildNameToCertificate()
124-
t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
150+
t.Run(fmt.Sprintf("suite=%s", CipherSuiteName(id)), func(t *testing.T) {
125151
clientHello := &clientHelloMsg{
126152
vers: VersionTLS12,
127153
random: make([]byte, 32),
128154
cipherSuites: []uint16{id},
129155
compressionMethods: []uint8{compressionNone},
130156
supportedCurves: defaultCurvePreferences,
157+
keyShares: []keyShare{generateKeyShare(CurveP256)},
131158
supportedPoints: []uint8{pointFormatUncompressed},
159+
supportedVersions: []uint16{VersionTLS12},
160+
}
161+
if isTLS13CipherSuite(id) {
162+
clientHello.supportedVersions = []uint16{VersionTLS13}
132163
}
133164

134165
testClientHello(t, serverConfig, clientHello)
@@ -160,7 +191,9 @@ func TestBoringServerCurves(t *testing.T) {
160191
cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
161192
compressionMethods: []uint8{compressionNone},
162193
supportedCurves: []CurveID{curveid},
194+
keyShares: []keyShare{generateKeyShare(curveid)},
163195
supportedPoints: []uint8{pointFormatUncompressed},
196+
supportedVersions: []uint16{VersionTLS12},
164197
}
165198

166199
testClientHello(t, serverConfig, clientHello)
@@ -279,7 +312,7 @@ func TestBoringClientHello(t *testing.T) {
279312
}
280313

281314
if !isBoringVersion(hello.vers) {
282-
t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
315+
t.Errorf("client vers=%#x", hello.vers)
283316
}
284317
for _, v := range hello.supportedVersions {
285318
if !isBoringVersion(v) {

src/crypto/tls/cipher_suites.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,13 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead {
556556
if err != nil {
557557
panic(err)
558558
}
559-
aead, err := cipher.NewGCM(aes)
559+
var aead cipher.AEAD
560+
if boring.Enabled {
561+
aead, err = boring.NewGCMTLS13(aes)
562+
} else {
563+
boring.Unreachable()
564+
aead, err = cipher.NewGCM(aes)
565+
}
560566
if err != nil {
561567
panic(err)
562568
}

src/crypto/tls/handshake_client.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) {
139139
if len(hello.supportedVersions) == 1 {
140140
hello.cipherSuites = nil
141141
}
142-
if hasAESGCMHardwareSupport {
142+
if needFIPS() {
143+
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
144+
} else if hasAESGCMHardwareSupport {
143145
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
144146
} else {
145147
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)

src/crypto/tls/handshake_client_tls13.go

-4
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ type clientHandshakeStateTLS13 struct {
4141
func (hs *clientHandshakeStateTLS13) handshake() error {
4242
c := hs.c
4343

44-
if needFIPS() {
45-
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
46-
}
47-
4844
// The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
4945
// sections 4.1.2 and 4.1.3.
5046
if c.handshakes > 0 {

src/crypto/tls/handshake_server_test.go

+19-9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
)
2828

2929
func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
30+
t.Helper()
3031
testClientHelloFailure(t, serverConfig, m, "")
3132
}
3233

@@ -52,23 +53,32 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
5253
ctx := context.Background()
5354
conn := Server(s, serverConfig)
5455
ch, err := conn.readClientHello(ctx)
55-
hs := serverHandshakeState{
56-
c: conn,
57-
ctx: ctx,
58-
clientHello: ch,
59-
}
60-
if err == nil {
56+
if err == nil && conn.vers == VersionTLS13 {
57+
hs := serverHandshakeStateTLS13{
58+
c: conn,
59+
ctx: ctx,
60+
clientHello: ch,
61+
}
6162
err = hs.processClientHello()
62-
}
63-
if err == nil {
64-
err = hs.pickCipherSuite()
63+
} else if err == nil {
64+
hs := serverHandshakeState{
65+
c: conn,
66+
ctx: ctx,
67+
clientHello: ch,
68+
}
69+
err = hs.processClientHello()
70+
if err == nil {
71+
err = hs.pickCipherSuite()
72+
}
6573
}
6674
s.Close()
6775
if len(expectedSubStr) == 0 {
6876
if err != nil && err != io.EOF {
77+
t.Helper()
6978
t.Errorf("Got error: %s; expected to succeed", err)
7079
}
7180
} else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
81+
t.Helper()
7282
t.Errorf("Got error: %v; expected to match substring '%s'", err, expectedSubStr)
7383
}
7484
}

src/crypto/tls/handshake_server_tls13.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ type serverHandshakeStateTLS13 struct {
4545
func (hs *serverHandshakeStateTLS13) handshake() error {
4646
c := hs.c
4747

48-
if needFIPS() {
49-
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
50-
}
51-
5248
// For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
5349
if err := hs.processClientHello(); err != nil {
5450
return err
@@ -163,6 +159,9 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
163159
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
164160
preferenceList = defaultCipherSuitesTLS13NoAES
165161
}
162+
if needFIPS() {
163+
preferenceList = defaultCipherSuitesTLS13FIPS
164+
}
166165
for _, suiteID := range preferenceList {
167166
hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
168167
if hs.suite != nil {

0 commit comments

Comments
 (0)