]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/tls: align FIPS-only mode with BoringSSL policy
authorFilippo Valsorda <filippo@golang.org>
Thu, 14 Dec 2023 21:13:29 +0000 (22:13 +0100)
committerFilippo Valsorda <filippo@golang.org>
Sat, 10 Aug 2024 12:39:48 +0000 (12:39 +0000)
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>
src/crypto/internal/boring/aes.go
src/crypto/internal/boring/notboring.go
src/crypto/tls/boring_test.go
src/crypto/tls/cipher_suites.go
src/crypto/tls/defaults.go
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_client_tls13.go
src/crypto/tls/handshake_server_test.go
src/crypto/tls/handshake_server_tls13.go

index 8819f576f4f4c5bdd3f26079fe54f9b6a8a62f1f..d18ed5cdc5c2593851da677e5608b3d73ec13412 100644 (file)
@@ -228,26 +228,41 @@ func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
        if tagSize != gcmTagSize {
                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) {
-       return c.(*aesCipher).newGCM(true)
+       return c.(*aesCipher).newGCM(VersionTLS12)
+}
+
+func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
+       return c.(*aesCipher).newGCM(VersionTLS13)
 }
 
-func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
+func (c *aesCipher) newGCM(tlsVersion uint16) (cipher.AEAD, error) {
        var aead *C.GO_EVP_AEAD
        switch len(c.key) * 8 {
        case 128:
-               if tls {
+               switch tlsVersion {
+               case VersionTLS12:
                        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()
                }
        case 256:
-               if tls {
+               switch tlsVersion {
+               case VersionTLS12:
                        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()
                }
        default:
index 361dec9672ff553db70c6aa6e925a0bd5da5d67e..02bc468a0de8e7f7dcc39f56de9c3e9faccb6fd5 100644 (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 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 PrivateKeyECDSA struct{ _ int }
index be10b71bd2269b9926c7009ebf99c4ead9758a3e..56050421985927fc038daaf67097c96d4917a87e 100644 (file)
@@ -25,6 +25,31 @@ import (
        "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) {
        test := func(t *testing.T, name string, v uint16, msg string) {
                t.Run(name, func(t *testing.T) {
@@ -60,22 +85,22 @@ func TestBoringServerProtocolVersion(t *testing.T) {
                test(t, "VersionTLS10", VersionTLS10, "supported versions")
                test(t, "VersionTLS11", VersionTLS11, "supported versions")
                test(t, "VersionTLS12", VersionTLS12, "")
-               test(t, "VersionTLS13", VersionTLS13, "supported versions")
+               test(t, "VersionTLS13", VersionTLS13, "")
        })
 }
 
 func isBoringVersion(v uint16) bool {
-       return v == VersionTLS12
+       return v == VersionTLS12 || v == VersionTLS13
 }
 
 func isBoringCipherSuite(id uint16) bool {
        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_ECDSA_WITH_AES_128_GCM_SHA256,
-               TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
-               TLS_RSA_WITH_AES_128_GCM_SHA256,
-               TLS_RSA_WITH_AES_256_GCM_SHA384:
+               TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
                return true
        }
        return false
@@ -83,7 +108,7 @@ func isBoringCipherSuite(id uint16) bool {
 
 func isBoringCurve(id CurveID) bool {
        switch id {
-       case CurveP256, CurveP384, CurveP521:
+       case CurveP256, CurveP384:
                return true
        }
        return false
@@ -95,7 +120,7 @@ func isECDSA(id uint16) bool {
                        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 {
@@ -107,7 +132,6 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
                PKCS1WithSHA384,
                ECDSAWithP384AndSHA384,
                PKCS1WithSHA512,
-               ECDSAWithP521AndSHA512,
                PSSWithSHA256,
                PSSWithSHA384,
                PSSWithSHA512:
@@ -118,10 +142,9 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
 
 func TestBoringServerCipherSuites(t *testing.T) {
        serverConfig := testConfig.Clone()
-       serverConfig.CipherSuites = allCipherSuites()
        serverConfig.Certificates = make([]Certificate, 1)
 
-       for _, id := range allCipherSuites() {
+       for _, id := range allCipherSuitesIncludingTLS13() {
                if isECDSA(id) {
                        serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
                        serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
@@ -130,14 +153,20 @@ func TestBoringServerCipherSuites(t *testing.T) {
                        serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
                }
                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{
-                               vers:               VersionTLS12,
-                               random:             make([]byte, 32),
-                               cipherSuites:       []uint16{id},
-                               compressionMethods: []uint8{compressionNone},
-                               supportedCurves:    defaultCurvePreferences(),
-                               supportedPoints:    []uint8{pointFormatUncompressed},
+                               vers:                         VersionTLS12,
+                               random:                       make([]byte, 32),
+                               cipherSuites:                 []uint16{id},
+                               compressionMethods:           []uint8{compressionNone},
+                               supportedCurves:              defaultCurvePreferences(),
+                               keyShares:                    []keyShare{generateKeyShare(CurveP256)},
+                               supportedPoints:              []uint8{pointFormatUncompressed},
+                               supportedVersions:            []uint16{VersionTLS12},
+                               supportedSignatureAlgorithms: defaultSupportedSignatureAlgorithmsFIPS,
+                       }
+                       if isTLS13CipherSuite(id) {
+                               clientHello.supportedVersions = []uint16{VersionTLS13}
                        }
 
                        testClientHello(t, serverConfig, clientHello)
@@ -156,9 +185,6 @@ func TestBoringServerCipherSuites(t *testing.T) {
 
 func TestBoringServerCurves(t *testing.T) {
        serverConfig := testConfig.Clone()
-       serverConfig.Certificates = make([]Certificate, 1)
-       serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
-       serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
        serverConfig.BuildNameToCertificate()
 
        for _, curveid := range defaultCurvePreferences() {
@@ -288,7 +314,7 @@ func TestBoringClientHello(t *testing.T) {
        }
 
        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 {
                if !isBoringVersion(v) {
index eebc66880d631f841018634f944ec97ae57e9797..917a1eff42d34f75db844e43e263207fed7e9a55 100644 (file)
@@ -552,7 +552,13 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead {
        if err != nil {
                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 {
                panic(err)
        }
index 9b28acdc2d866af5f38997c319626308dd5938a1..ad4070df4a88830fededf64fac4297662c90dbee 100644 (file)
@@ -90,13 +90,16 @@ var defaultCipherSuitesTLS13NoAES = []uint16{
        TLS_AES_256_GCM_SHA384,
 }
 
+// The FIPS-only policies below match BoringSSL's ssl_policy_fips_202205.
+
 var defaultSupportedVersionsFIPS = []uint16{
        VersionTLS12,
+       VersionTLS13,
 }
 
 // defaultCurvePreferencesFIPS are the FIPS-allowed curves,
 // in preference order (most preferable first).
-var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521}
+var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384}
 
 // defaultSupportedSignatureAlgorithmsFIPS currently are a subset of
 // defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
@@ -109,7 +112,6 @@ var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
        PKCS1WithSHA384,
        ECDSAWithP384AndSHA384,
        PKCS1WithSHA512,
-       ECDSAWithP521AndSHA512,
 }
 
 // defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
@@ -118,8 +120,6 @@ var defaultCipherSuitesFIPS = []uint16{
        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
        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.
index 5025657590d32c5a9fab8d4ade234820b123a7dc..760e827f467f153254bee3513e18fb0da1123a0b 100644 (file)
@@ -141,13 +141,18 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon
                if len(hello.supportedVersions) == 1 {
                        hello.cipherSuites = nil
                }
-               if hasAESGCMHardwareSupport {
+               if needFIPS() {
+                       hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
+               } else if hasAESGCMHardwareSupport {
                        hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
                } else {
                        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}
                if curveID == x25519Kyber768Draft00 {
                        keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519)
index db5e35d9a46c2e1deef7ecf05c49eba87a4b56c9..21a501fbfd592be4b0c7130c6053b606dfe48944 100644 (file)
@@ -45,10 +45,6 @@ type clientHandshakeStateTLS13 struct {
 func (hs *clientHandshakeStateTLS13) handshake() error {
        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,
        // sections 4.1.2 and 4.1.3.
        if c.handshakes > 0 {
index 788a26af7559b6fafeccd70499a86c590cab8f6f..01eae15a6b98c09e22ff066b7d43e0448ee52e81 100644 (file)
@@ -29,6 +29,7 @@ import (
 )
 
 func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
+       t.Helper()
        testClientHelloFailure(t, serverConfig, m, "")
 }
 
index 503a732e05765ec86f68027eaa1fd890c8009771..b8cf4c3fa50b242e70fb635a156bff83979b9853 100644 (file)
@@ -47,10 +47,6 @@ type serverHandshakeStateTLS13 struct {
 func (hs *serverHandshakeStateTLS13) handshake() error {
        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.
        if err := hs.processClientHello(); err != nil {
                return err
@@ -165,6 +161,9 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
        if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
                preferenceList = defaultCipherSuitesTLS13NoAES
        }
+       if needFIPS() {
+               preferenceList = defaultCipherSuitesTLS13FIPS
+       }
        for _, suiteID := range preferenceList {
                hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
                if hs.suite != nil {