1
0
mirror of https://github.com/golang/go synced 2024-11-25 19:17:57 -07:00

crypto/tls: align FIPS-only mode with BoringSSL policy

This enables TLS 1.3, disables P-521, and disables non-ECDHE suites.

Reapplies CL 549975.

Updates #64717
Updates #62372

Change-Id: I6c608704638d59a063a657fbd4eb1126027112dd
Reviewed-on: https://go-review.googlesource.com/c/go/+/603376
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Filippo Valsorda 2023-12-14 22:13:29 +01:00
parent 83d9afefea
commit d36353499f
9 changed files with 93 additions and 44 deletions

View File

@ -228,26 +228,41 @@ func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
if tagSize != gcmTagSize { if tagSize != gcmTagSize {
return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize) return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
} }
return c.newGCM(false) return c.newGCM(0)
} }
const (
VersionTLS12 = 0x0303
VersionTLS13 = 0x0304
)
func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
return c.(*aesCipher).newGCM(true) return c.(*aesCipher).newGCM(VersionTLS12)
} }
func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) { func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
return c.(*aesCipher).newGCM(VersionTLS13)
}
func (c *aesCipher) newGCM(tlsVersion uint16) (cipher.AEAD, error) {
var aead *C.GO_EVP_AEAD var aead *C.GO_EVP_AEAD
switch len(c.key) * 8 { switch len(c.key) * 8 {
case 128: case 128:
if tls { switch tlsVersion {
case VersionTLS12:
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12() aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
} else { case VersionTLS13:
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls13()
default:
aead = C._goboringcrypto_EVP_aead_aes_128_gcm() aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
} }
case 256: case 256:
if tls { switch tlsVersion {
case VersionTLS12:
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12() aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
} else { case VersionTLS13:
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls13()
default:
aead = C._goboringcrypto_EVP_aead_aes_256_gcm() aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
} }
default: default:

View File

@ -50,6 +50,7 @@ func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: no
func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") } func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") }
func NewGCMTLS(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") } func NewGCMTLS(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
func NewGCMTLS13(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
type PublicKeyECDSA struct{ _ int } type PublicKeyECDSA struct{ _ int }
type PrivateKeyECDSA struct{ _ int } type PrivateKeyECDSA struct{ _ int }

View File

@ -25,6 +25,31 @@ import (
"time" "time"
) )
func allCipherSuitesIncludingTLS13() []uint16 {
s := allCipherSuites()
for _, suite := range cipherSuitesTLS13 {
s = append(s, suite.id)
}
return s
}
func isTLS13CipherSuite(id uint16) bool {
for _, suite := range cipherSuitesTLS13 {
if id == suite.id {
return true
}
}
return false
}
func generateKeyShare(group CurveID) keyShare {
key, err := generateECDHEKey(rand.Reader, group)
if err != nil {
panic(err)
}
return keyShare{group: group, data: key.PublicKey().Bytes()}
}
func TestBoringServerProtocolVersion(t *testing.T) { func TestBoringServerProtocolVersion(t *testing.T) {
test := func(t *testing.T, name string, v uint16, msg string) { test := func(t *testing.T, name string, v uint16, msg string) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
@ -60,22 +85,22 @@ func TestBoringServerProtocolVersion(t *testing.T) {
test(t, "VersionTLS10", VersionTLS10, "supported versions") test(t, "VersionTLS10", VersionTLS10, "supported versions")
test(t, "VersionTLS11", VersionTLS11, "supported versions") test(t, "VersionTLS11", VersionTLS11, "supported versions")
test(t, "VersionTLS12", VersionTLS12, "") test(t, "VersionTLS12", VersionTLS12, "")
test(t, "VersionTLS13", VersionTLS13, "supported versions") test(t, "VersionTLS13", VersionTLS13, "")
}) })
} }
func isBoringVersion(v uint16) bool { func isBoringVersion(v uint16) bool {
return v == VersionTLS12 return v == VersionTLS12 || v == VersionTLS13
} }
func isBoringCipherSuite(id uint16) bool { func isBoringCipherSuite(id uint16) bool {
switch id { switch id {
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, case TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384:
return true return true
} }
return false return false
@ -83,7 +108,7 @@ func isBoringCipherSuite(id uint16) bool {
func isBoringCurve(id CurveID) bool { func isBoringCurve(id CurveID) bool {
switch id { switch id {
case CurveP256, CurveP384, CurveP521: case CurveP256, CurveP384:
return true return true
} }
return false return false
@ -95,7 +120,7 @@ func isECDSA(id uint16) bool {
return suite.flags&suiteECSign == suiteECSign return suite.flags&suiteECSign == suiteECSign
} }
} }
panic(fmt.Sprintf("unknown cipher suite %#x", id)) return false // TLS 1.3 cipher suites are not tied to the signature algorithm.
} }
func isBoringSignatureScheme(alg SignatureScheme) bool { func isBoringSignatureScheme(alg SignatureScheme) bool {
@ -107,7 +132,6 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
PKCS1WithSHA384, PKCS1WithSHA384,
ECDSAWithP384AndSHA384, ECDSAWithP384AndSHA384,
PKCS1WithSHA512, PKCS1WithSHA512,
ECDSAWithP521AndSHA512,
PSSWithSHA256, PSSWithSHA256,
PSSWithSHA384, PSSWithSHA384,
PSSWithSHA512: PSSWithSHA512:
@ -118,10 +142,9 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
func TestBoringServerCipherSuites(t *testing.T) { func TestBoringServerCipherSuites(t *testing.T) {
serverConfig := testConfig.Clone() serverConfig := testConfig.Clone()
serverConfig.CipherSuites = allCipherSuites()
serverConfig.Certificates = make([]Certificate, 1) serverConfig.Certificates = make([]Certificate, 1)
for _, id := range allCipherSuites() { for _, id := range allCipherSuitesIncludingTLS13() {
if isECDSA(id) { if isECDSA(id) {
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
@ -130,14 +153,20 @@ func TestBoringServerCipherSuites(t *testing.T) {
serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
} }
serverConfig.BuildNameToCertificate() serverConfig.BuildNameToCertificate()
t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) { t.Run(fmt.Sprintf("suite=%s", CipherSuiteName(id)), func(t *testing.T) {
clientHello := &clientHelloMsg{ clientHello := &clientHelloMsg{
vers: VersionTLS12, vers: VersionTLS12,
random: make([]byte, 32), random: make([]byte, 32),
cipherSuites: []uint16{id}, cipherSuites: []uint16{id},
compressionMethods: []uint8{compressionNone}, compressionMethods: []uint8{compressionNone},
supportedCurves: defaultCurvePreferences(), supportedCurves: defaultCurvePreferences(),
supportedPoints: []uint8{pointFormatUncompressed}, keyShares: []keyShare{generateKeyShare(CurveP256)},
supportedPoints: []uint8{pointFormatUncompressed},
supportedVersions: []uint16{VersionTLS12},
supportedSignatureAlgorithms: defaultSupportedSignatureAlgorithmsFIPS,
}
if isTLS13CipherSuite(id) {
clientHello.supportedVersions = []uint16{VersionTLS13}
} }
testClientHello(t, serverConfig, clientHello) testClientHello(t, serverConfig, clientHello)
@ -156,9 +185,6 @@ func TestBoringServerCipherSuites(t *testing.T) {
func TestBoringServerCurves(t *testing.T) { func TestBoringServerCurves(t *testing.T) {
serverConfig := testConfig.Clone() serverConfig := testConfig.Clone()
serverConfig.Certificates = make([]Certificate, 1)
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
serverConfig.BuildNameToCertificate() serverConfig.BuildNameToCertificate()
for _, curveid := range defaultCurvePreferences() { for _, curveid := range defaultCurvePreferences() {
@ -288,7 +314,7 @@ func TestBoringClientHello(t *testing.T) {
} }
if !isBoringVersion(hello.vers) { if !isBoringVersion(hello.vers) {
t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12) t.Errorf("client vers=%#x", hello.vers)
} }
for _, v := range hello.supportedVersions { for _, v := range hello.supportedVersions {
if !isBoringVersion(v) { if !isBoringVersion(v) {

View File

@ -552,7 +552,13 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead {
if err != nil { if err != nil {
panic(err) panic(err)
} }
aead, err := cipher.NewGCM(aes) var aead cipher.AEAD
if boring.Enabled {
aead, err = boring.NewGCMTLS13(aes)
} else {
boring.Unreachable()
aead, err = cipher.NewGCM(aes)
}
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -90,13 +90,16 @@ var defaultCipherSuitesTLS13NoAES = []uint16{
TLS_AES_256_GCM_SHA384, TLS_AES_256_GCM_SHA384,
} }
// The FIPS-only policies below match BoringSSL's ssl_policy_fips_202205.
var defaultSupportedVersionsFIPS = []uint16{ var defaultSupportedVersionsFIPS = []uint16{
VersionTLS12, VersionTLS12,
VersionTLS13,
} }
// defaultCurvePreferencesFIPS are the FIPS-allowed curves, // defaultCurvePreferencesFIPS are the FIPS-allowed curves,
// in preference order (most preferable first). // in preference order (most preferable first).
var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521} var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384}
// defaultSupportedSignatureAlgorithmsFIPS currently are a subset of // defaultSupportedSignatureAlgorithmsFIPS currently are a subset of
// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1. // defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
@ -109,7 +112,6 @@ var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
PKCS1WithSHA384, PKCS1WithSHA384,
ECDSAWithP384AndSHA384, ECDSAWithP384AndSHA384,
PKCS1WithSHA512, PKCS1WithSHA512,
ECDSAWithP521AndSHA512,
} }
// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites. // defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
@ -118,8 +120,6 @@ var defaultCipherSuitesFIPS = []uint16{
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
} }
// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3. // defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3.

View File

@ -141,13 +141,18 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon
if len(hello.supportedVersions) == 1 { if len(hello.supportedVersions) == 1 {
hello.cipherSuites = nil hello.cipherSuites = nil
} }
if hasAESGCMHardwareSupport { if needFIPS() {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
} else if hasAESGCMHardwareSupport {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...) hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
} else { } else {
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
} }
curveID := config.curvePreferences(maxVersion)[0] if len(hello.supportedCurves) == 0 {
return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE")
}
curveID := hello.supportedCurves[0]
keyShareKeys = &keySharePrivateKeys{curveID: curveID} keyShareKeys = &keySharePrivateKeys{curveID: curveID}
if curveID == x25519Kyber768Draft00 { if curveID == x25519Kyber768Draft00 {
keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519) keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519)

View File

@ -45,10 +45,6 @@ type clientHandshakeStateTLS13 struct {
func (hs *clientHandshakeStateTLS13) handshake() error { func (hs *clientHandshakeStateTLS13) handshake() error {
c := hs.c c := hs.c
if needFIPS() {
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
}
// The server must not select TLS 1.3 in a renegotiation. See RFC 8446, // The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
// sections 4.1.2 and 4.1.3. // sections 4.1.2 and 4.1.3.
if c.handshakes > 0 { if c.handshakes > 0 {

View File

@ -29,6 +29,7 @@ import (
) )
func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
t.Helper()
testClientHelloFailure(t, serverConfig, m, "") testClientHelloFailure(t, serverConfig, m, "")
} }

View File

@ -47,10 +47,6 @@ type serverHandshakeStateTLS13 struct {
func (hs *serverHandshakeStateTLS13) handshake() error { func (hs *serverHandshakeStateTLS13) handshake() error {
c := hs.c c := hs.c
if needFIPS() {
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
}
// For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2. // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
if err := hs.processClientHello(); err != nil { if err := hs.processClientHello(); err != nil {
return err return err
@ -165,6 +161,9 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
preferenceList = defaultCipherSuitesTLS13NoAES preferenceList = defaultCipherSuitesTLS13NoAES
} }
if needFIPS() {
preferenceList = defaultCipherSuitesTLS13FIPS
}
for _, suiteID := range preferenceList { for _, suiteID := range preferenceList {
hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID) hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
if hs.suite != nil { if hs.suite != nil {