aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/tls
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/tls')
-rw-r--r--src/crypto/tls/auth.go4
-rw-r--r--src/crypto/tls/auth_test.go2
-rw-r--r--src/crypto/tls/boring.go127
-rw-r--r--src/crypto/tls/boring_test.go630
-rw-r--r--src/crypto/tls/cipher_suites.go22
-rw-r--r--src/crypto/tls/common.go13
-rw-r--r--src/crypto/tls/fipsonly/fipsonly.go27
-rw-r--r--src/crypto/tls/fipsonly/fipsonly_test.go16
-rw-r--r--src/crypto/tls/handshake_client.go7
-rw-r--r--src/crypto/tls/handshake_client_tls13.go6
-rw-r--r--src/crypto/tls/handshake_messages_test.go8
-rw-r--r--src/crypto/tls/handshake_server.go4
-rw-r--r--src/crypto/tls/handshake_server_tls13.go8
13 files changed, 860 insertions, 14 deletions
diff --git a/src/crypto/tls/auth.go b/src/crypto/tls/auth.go
index a9df0da6d62..7c5675c6d93 100644
--- a/src/crypto/tls/auth.go
+++ b/src/crypto/tls/auth.go
@@ -169,6 +169,7 @@ var rsaSignatureSchemes = []struct {
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
//
// This function must be kept in sync with supportedSignatureAlgorithms.
+// FIPS filtering is applied in the caller, selectSignatureScheme.
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
priv, ok := cert.PrivateKey.(crypto.Signer)
if !ok {
@@ -241,6 +242,9 @@ func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureSche
// Pick signature scheme in the peer's preference order, as our
// preference order is not configurable.
for _, preferredAlg := range peerAlgs {
+ if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) {
+ continue
+ }
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
return preferredAlg, nil
}
diff --git a/src/crypto/tls/auth_test.go b/src/crypto/tls/auth_test.go
index c42e3491e46..c23d93f3c08 100644
--- a/src/crypto/tls/auth_test.go
+++ b/src/crypto/tls/auth_test.go
@@ -153,7 +153,7 @@ func TestLegacyTypeAndHash(t *testing.T) {
// TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
// have valid type and hash information.
func TestSupportedSignatureAlgorithms(t *testing.T) {
- for _, sigAlg := range supportedSignatureAlgorithms {
+ for _, sigAlg := range supportedSignatureAlgorithms() {
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
if err != nil {
t.Errorf("%v: unexpected error: %v", sigAlg, err)
diff --git a/src/crypto/tls/boring.go b/src/crypto/tls/boring.go
new file mode 100644
index 00000000000..09f71c1691c
--- /dev/null
+++ b/src/crypto/tls/boring.go
@@ -0,0 +1,127 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/ecdsa"
+ "crypto/internal/boring/fipstls"
+ "crypto/rsa"
+ "crypto/x509"
+)
+
+// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
+func needFIPS() bool {
+ return fipstls.Required()
+}
+
+// fipsMinVersion replaces c.minVersion in FIPS-only mode.
+func fipsMinVersion(c *Config) uint16 {
+ // FIPS requires TLS 1.2.
+ return VersionTLS12
+}
+
+// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
+func fipsMaxVersion(c *Config) uint16 {
+ // FIPS requires TLS 1.2.
+ return VersionTLS12
+}
+
+// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
+// in preference order (most preferable first).
+var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
+func fipsCurvePreferences(c *Config) []CurveID {
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultFIPSCurvePreferences
+ }
+ var list []CurveID
+ for _, id := range c.CurvePreferences {
+ for _, allowed := range defaultFIPSCurvePreferences {
+ if id == allowed {
+ list = append(list, id)
+ break
+ }
+ }
+ }
+ return list
+}
+
+// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
+var defaultCipherSuitesFIPS = []uint16{
+ 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,
+}
+
+// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
+func fipsCipherSuites(c *Config) []uint16 {
+ if c == nil || c.CipherSuites == nil {
+ return defaultCipherSuitesFIPS
+ }
+ list := make([]uint16, 0, len(defaultCipherSuitesFIPS))
+ for _, id := range c.CipherSuites {
+ for _, allowed := range defaultCipherSuitesFIPS {
+ if id == allowed {
+ list = append(list, id)
+ break
+ }
+ }
+ }
+ return list
+}
+
+// isBoringCertificate reports whether a certificate may be used
+// when constructing a verified chain.
+// It is called for each leaf, intermediate, and root certificate.
+func isBoringCertificate(c *x509.Certificate) bool {
+ if !needFIPS() {
+ // Everything is OK if we haven't forced FIPS-only mode.
+ return true
+ }
+
+ // Otherwise the key must be RSA 2048, RSA 3072, or ECDSA P-256.
+ switch k := c.PublicKey.(type) {
+ default:
+ return false
+ case *rsa.PublicKey:
+ if size := k.N.BitLen(); size != 2048 && size != 3072 {
+ return false
+ }
+ case *ecdsa.PublicKey:
+ if name := k.Curve.Params().Name; name != "P-256" && name != "P-384" {
+ return false
+ }
+ }
+
+ return true
+}
+
+// fipsSupportedSignatureAlgorithms currently are a subset of
+// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
+var fipsSupportedSignatureAlgorithms = []SignatureScheme{
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA384,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP521AndSHA512,
+}
+
+// supportedSignatureAlgorithms returns the supported signature algorithms.
+func supportedSignatureAlgorithms() []SignatureScheme {
+ if !needFIPS() {
+ return defaultSupportedSignatureAlgorithms
+ }
+ return fipsSupportedSignatureAlgorithms
+}
+
+var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
diff --git a/src/crypto/tls/boring_test.go b/src/crypto/tls/boring_test.go
new file mode 100644
index 00000000000..6ad72faebf9
--- /dev/null
+++ b/src/crypto/tls/boring_test.go
@@ -0,0 +1,630 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/internal/boring/fipstls"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "fmt"
+ "math/big"
+ "net"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestBoringServerProtocolVersion(t *testing.T) {
+ test := func(name string, v uint16, msg string) {
+ t.Run(name, func(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.MinVersion = VersionSSL30
+ clientHello := &clientHelloMsg{
+ vers: v,
+ random: make([]byte, 32),
+ cipherSuites: allCipherSuites(),
+ compressionMethods: []uint8{compressionNone},
+ supportedVersions: []uint16{v},
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, msg)
+ })
+ }
+
+ test("VersionTLS10", VersionTLS10, "")
+ test("VersionTLS11", VersionTLS11, "")
+ test("VersionTLS12", VersionTLS12, "")
+ test("VersionTLS13", VersionTLS13, "")
+
+ fipstls.Force()
+ defer fipstls.Abandon()
+ test("VersionSSL30", VersionSSL30, "client offered only unsupported versions")
+ test("VersionTLS10", VersionTLS10, "client offered only unsupported versions")
+ test("VersionTLS11", VersionTLS11, "client offered only unsupported versions")
+ test("VersionTLS12", VersionTLS12, "")
+ test("VersionTLS13", VersionTLS13, "client offered only unsupported versions")
+}
+
+func isBoringVersion(v uint16) bool {
+ return v == VersionTLS12
+}
+
+func isBoringCipherSuite(id uint16) bool {
+ switch id {
+ case 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:
+ return true
+ }
+ return false
+}
+
+func isBoringCurve(id CurveID) bool {
+ switch id {
+ case CurveP256, CurveP384, CurveP521:
+ return true
+ }
+ return false
+}
+
+func isECDSA(id uint16) bool {
+ for _, suite := range cipherSuites {
+ if suite.id == id {
+ return suite.flags&suiteECSign == suiteECSign
+ }
+ }
+ panic(fmt.Sprintf("unknown cipher suite %#x", id))
+}
+
+func isBoringSignatureScheme(alg SignatureScheme) bool {
+ switch alg {
+ default:
+ return false
+ case PKCS1WithSHA256,
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA384,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512:
+ // ok
+ }
+ return true
+}
+
+func TestBoringServerCipherSuites(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = allCipherSuites()
+ serverConfig.Certificates = make([]Certificate, 1)
+
+ for _, id := range allCipherSuites() {
+ if isECDSA(id) {
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ } else {
+ serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
+ }
+ serverConfig.BuildNameToCertificate()
+ t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{id},
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: defaultCurvePreferences,
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+
+ testClientHello(t, serverConfig, clientHello)
+ t.Run("fipstls", func(t *testing.T) {
+ fipstls.Force()
+ defer fipstls.Abandon()
+ msg := ""
+ if !isBoringCipherSuite(id) {
+ msg = "no cipher suite supported by both client and server"
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, msg)
+ })
+ })
+ }
+}
+
+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 {
+ t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: []CurveID{curveid},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+
+ testClientHello(t, serverConfig, clientHello)
+
+ // With fipstls forced, bad curves should be rejected.
+ t.Run("fipstls", func(t *testing.T) {
+ fipstls.Force()
+ defer fipstls.Abandon()
+ msg := ""
+ if !isBoringCurve(curveid) {
+ msg = "no cipher suite supported by both client and server"
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, msg)
+ })
+ })
+ }
+}
+
+func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) {
+ c, s := localPipe(t)
+ client := Client(c, clientConfig)
+ server := Server(s, serverConfig)
+ done := make(chan error, 1)
+ go func() {
+ done <- client.Handshake()
+ c.Close()
+ }()
+ serverErr = server.Handshake()
+ s.Close()
+ clientErr = <-done
+ return
+}
+
+func TestBoringServerSignatureAndHash(t *testing.T) {
+ defer func() {
+ testingOnlyForceClientHelloSignatureAlgorithms = nil
+ }()
+
+ for _, sigHash := range defaultSupportedSignatureAlgorithms {
+ t.Run(fmt.Sprintf("%#x", sigHash), func(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.Certificates = make([]Certificate, 1)
+
+ testingOnlyForceClientHelloSignatureAlgorithms = []SignatureScheme{sigHash}
+
+ sigType, _, _ := typeAndHashFromSignatureScheme(sigHash)
+ switch sigType {
+ case signaturePKCS1v15, signatureRSAPSS:
+ serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
+ serverConfig.Certificates[0].Certificate = [][]byte{testRSA2048Certificate}
+ serverConfig.Certificates[0].PrivateKey = testRSA2048PrivateKey
+ case signatureEd25519:
+ serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
+ serverConfig.Certificates[0].Certificate = [][]byte{testEd25519Certificate}
+ serverConfig.Certificates[0].PrivateKey = testEd25519PrivateKey
+ case signatureECDSA:
+ serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ }
+ serverConfig.BuildNameToCertificate()
+ // PKCS#1 v1.5 signature algorithms can't be used standalone in TLS
+ // 1.3, and the ECDSA ones bind to the curve used.
+ serverConfig.MaxVersion = VersionTLS12
+
+ clientErr, serverErr := boringHandshake(t, testConfig, serverConfig)
+ if clientErr != nil {
+ t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr)
+ }
+
+ // With fipstls forced, bad curves should be rejected.
+ t.Run("fipstls", func(t *testing.T) {
+ fipstls.Force()
+ defer fipstls.Abandon()
+ clientErr, _ := boringHandshake(t, testConfig, serverConfig)
+ if isBoringSignatureScheme(sigHash) {
+ if clientErr != nil {
+ t.Fatalf("expected handshake with %#x to succeed; err=%v", sigHash, clientErr)
+ }
+ } else {
+ if clientErr == nil {
+ t.Fatalf("expected handshake with %#x to fail, but it succeeded", sigHash)
+ }
+ }
+ })
+ })
+ }
+}
+
+func TestBoringClientHello(t *testing.T) {
+ // Test that no matter what we put in the client config,
+ // the client does not offer non-FIPS configurations.
+ fipstls.Force()
+ defer fipstls.Abandon()
+
+ c, s := net.Pipe()
+ defer c.Close()
+ defer s.Close()
+
+ clientConfig := testConfig.Clone()
+ // All sorts of traps for the client to avoid.
+ clientConfig.MinVersion = VersionSSL30
+ clientConfig.MaxVersion = VersionTLS13
+ clientConfig.CipherSuites = allCipherSuites()
+ clientConfig.CurvePreferences = defaultCurvePreferences
+
+ go Client(c, testConfig).Handshake()
+ srv := Server(s, testConfig)
+ msg, err := srv.readHandshake()
+ if err != nil {
+ t.Fatal(err)
+ }
+ hello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ t.Fatalf("unexpected message type %T", msg)
+ }
+
+ if !isBoringVersion(hello.vers) {
+ t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
+ }
+ for _, v := range hello.supportedVersions {
+ if !isBoringVersion(v) {
+ t.Errorf("client offered disallowed version %#x", v)
+ }
+ }
+ for _, id := range hello.cipherSuites {
+ if !isBoringCipherSuite(id) {
+ t.Errorf("client offered disallowed suite %#x", id)
+ }
+ }
+ for _, id := range hello.supportedCurves {
+ if !isBoringCurve(id) {
+ t.Errorf("client offered disallowed curve %d", id)
+ }
+ }
+ for _, sigHash := range hello.supportedSignatureAlgorithms {
+ if !isBoringSignatureScheme(sigHash) {
+ t.Errorf("client offered disallowed signature-and-hash %v", sigHash)
+ }
+ }
+}
+
+func TestBoringCertAlgs(t *testing.T) {
+ // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those.
+ if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" {
+ t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH)
+ }
+
+ // Set up some roots, intermediate CAs, and leaf certs with various algorithms.
+ // X_Y is X signed by Y.
+ R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
+ R2 := boringCert(t, "R2", boringRSAKey(t, 4096), nil, boringCertCA)
+
+ M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
+ M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
+
+ I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
+ I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
+ I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
+ I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
+
+ L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
+ L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
+
+ // boringCert checked that isBoringCertificate matches the caller's boringCertFIPSOK bit.
+ // If not, no point in building bigger end-to-end tests.
+ if t.Failed() {
+ t.Fatalf("isBoringCertificate failures; not continuing")
+ }
+
+ // client verifying server cert
+ testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
+ clientConfig := testConfig.Clone()
+ clientConfig.RootCAs = pool
+ clientConfig.InsecureSkipVerify = false
+ clientConfig.ServerName = "example.com"
+
+ serverConfig := testConfig.Clone()
+ serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
+ serverConfig.BuildNameToCertificate()
+
+ clientErr, _ := boringHandshake(t, clientConfig, serverConfig)
+
+ if (clientErr == nil) == ok {
+ if ok {
+ t.Logf("%s: accept", desc)
+ } else {
+ t.Logf("%s: reject", desc)
+ }
+ } else {
+ if ok {
+ t.Errorf("%s: BAD reject (%v)", desc, clientErr)
+ } else {
+ t.Errorf("%s: BAD accept", desc)
+ }
+ }
+ }
+
+ // server verifying client cert
+ testClientCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
+ clientConfig := testConfig.Clone()
+ clientConfig.ServerName = "example.com"
+ clientConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
+
+ serverConfig := testConfig.Clone()
+ serverConfig.ClientCAs = pool
+ serverConfig.ClientAuth = RequireAndVerifyClientCert
+
+ _, serverErr := boringHandshake(t, clientConfig, serverConfig)
+
+ if (serverErr == nil) == ok {
+ if ok {
+ t.Logf("%s: accept", desc)
+ } else {
+ t.Logf("%s: reject", desc)
+ }
+ } else {
+ if ok {
+ t.Errorf("%s: BAD reject (%v)", desc, serverErr)
+ } else {
+ t.Errorf("%s: BAD accept", desc)
+ }
+ }
+ }
+
+ // Run simple basic test with known answers before proceeding to
+ // exhaustive test with computed answers.
+ r1pool := x509.NewCertPool()
+ r1pool.AddCert(R1.cert)
+ testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
+ testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
+ fipstls.Force()
+ testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
+ testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
+ fipstls.Abandon()
+
+ if t.Failed() {
+ t.Fatal("basic test failed, skipping exhaustive test")
+ }
+
+ if testing.Short() {
+ t.Logf("basic test passed; skipping exhaustive test in -short mode")
+ return
+ }
+
+ for l := 1; l <= 2; l++ {
+ leaf := L1_I
+ if l == 2 {
+ leaf = L2_I
+ }
+ for i := 0; i < 64; i++ {
+ reachable := map[string]bool{leaf.parentOrg: true}
+ reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK}
+ list := [][]byte{leaf.der}
+ listName := leaf.name
+ addList := func(cond int, c *boringCertificate) {
+ if cond != 0 {
+ list = append(list, c.der)
+ listName += "," + c.name
+ if reachable[c.org] {
+ reachable[c.parentOrg] = true
+ }
+ if reachableFIPS[c.org] && c.fipsOK {
+ reachableFIPS[c.parentOrg] = true
+ }
+ }
+ }
+ addList(i&1, I_R1)
+ addList(i&2, I_R2)
+ addList(i&4, I_M1)
+ addList(i&8, I_M2)
+ addList(i&16, M1_R1)
+ addList(i&32, M2_R1)
+
+ for r := 1; r <= 3; r++ {
+ pool := x509.NewCertPool()
+ rootName := ","
+ shouldVerify := false
+ shouldVerifyFIPS := false
+ addRoot := func(cond int, c *boringCertificate) {
+ if cond != 0 {
+ rootName += "," + c.name
+ pool.AddCert(c.cert)
+ if reachable[c.org] {
+ shouldVerify = true
+ }
+ if reachableFIPS[c.org] && c.fipsOK {
+ shouldVerifyFIPS = true
+ }
+ }
+ }
+ addRoot(r&1, R1)
+ addRoot(r&2, R2)
+ rootName = rootName[1:] // strip leading comma
+ testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify)
+ testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify)
+ fipstls.Force()
+ testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS)
+ testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS)
+ fipstls.Abandon()
+ }
+ }
+ }
+}
+
+const (
+ boringCertCA = iota
+ boringCertLeaf
+ boringCertFIPSOK = 0x80
+)
+
+func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
+ k, err := rsa.GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
+ k, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+type boringCertificate struct {
+ name string
+ org string
+ parentOrg string
+ der []byte
+ cert *x509.Certificate
+ key interface{}
+ fipsOK bool
+}
+
+func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
+ org := name
+ parentOrg := ""
+ if i := strings.Index(org, "_"); i >= 0 {
+ org = org[:i]
+ parentOrg = name[i+1:]
+ }
+ tmpl := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ Organization: []string{org},
+ },
+ NotBefore: time.Unix(0, 0),
+ NotAfter: time.Unix(0, 0),
+
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
+ BasicConstraintsValid: true,
+ }
+ if mode&^boringCertFIPSOK == boringCertLeaf {
+ tmpl.DNSNames = []string{"example.com"}
+ } else {
+ tmpl.IsCA = true
+ tmpl.KeyUsage |= x509.KeyUsageCertSign
+ }
+
+ var pcert *x509.Certificate
+ var pkey interface{}
+ if parent != nil {
+ pcert = parent.cert
+ pkey = parent.key
+ } else {
+ pcert = tmpl
+ pkey = key
+ }
+
+ var pub interface{}
+ var desc string
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ pub = &k.PublicKey
+ desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
+ case *ecdsa.PrivateKey:
+ pub = &k.PublicKey
+ desc = "ECDSA-" + k.Curve.Params().Name
+ default:
+ t.Fatalf("invalid key %T", key)
+ }
+
+ der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := x509.ParseCertificate(der)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Tell isBoringCertificate to enforce FIPS restrictions for this check.
+ fipstls.Force()
+ defer fipstls.Abandon()
+
+ fipsOK := mode&boringCertFIPSOK != 0
+ if isBoringCertificate(cert) != fipsOK {
+ t.Errorf("isBoringCertificate(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
+ }
+ return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
+}
+
+// A self-signed test certificate with an RSA key of size 2048, for testing
+// RSA-PSS with SHA512. SAN of example.golang.
+var (
+ testRSA2048Certificate []byte
+ testRSA2048PrivateKey *rsa.PrivateKey
+)
+
+func init() {
+ block, _ := pem.Decode([]byte(`
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIRALHHX/kh4+4zMU9DarzBEcQwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xMTAxMDExNTA0MDVaFw0yMDEyMjkxNTA0
+MDVaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCf8fk0N6ieCBX4IOVIfKitt4kGcOQLeimCfsjqqHcysMIVGEtFSM6E
+4Ay141f/7IqdW0UtIqNb4PXhROID7yDxR284xL6XbCuv/t5hP3UcehYc3hmLiyVd
+MkZQiZWtfUUJf/1qOtM+ohNg59LRWp4d+6iX0la1JL3EwCIckkNjJ9hQbF7Pb2CS
++ES9Yo55KAap8KOblpcR8MBSN38bqnwjfQdCXvOEOjam2HUxKzEFX5MA+fA0me4C
+ioCcCRLWKl+GoN9F8fABfoZ+T+2eal4DLuO95rXR8SrOIVBh3XFOr/RVhjtXcNVF
+ZKcvDt6d68V6jAKAYKm5nlj9GPpd4v+rAgMBAAGjUDBOMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBkGA1UdEQQSMBCC
+DmV4YW1wbGUuZ29sYW5nMA0GCSqGSIb3DQEBCwUAA4IBAQCOoYsVcFCBhboqe3WH
+dC6V7XXXECmnjh01r8h80yv0NR379nSD3cw2M+HKvaXysWqrl5hjGVKw0vtwD81r
+V4JzDu7IfIog5m8+QNC+7LqDZsz88vDKOrsoySVOmUCgmCKFXew+LA+eO/iQEJTr
+7ensddOeXJEp27Ed5vW+kmWW3Qmglc2Gwy8wFrMDIqnrnOzBA4oCnDEgtXJt0zog
+nRwbfEMAWi1aQRy5dT9KA3SP9mo5SeTFSzGGHiE4s4gHUe7jvsAFF2qgtD6+wH6s
+z9b6shxnC7g5IlBKhI7SVB/Uqt2ydJ+kH1YbjMcIq6NAM5eNMKgZuJr3+zwsSgwh
+GNaE
+-----END CERTIFICATE-----`))
+ testRSA2048Certificate = block.Bytes
+
+ block, _ = pem.Decode([]byte(`
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAn/H5NDeonggV+CDlSHyorbeJBnDkC3opgn7I6qh3MrDCFRhL
+RUjOhOAMteNX/+yKnVtFLSKjW+D14UTiA+8g8UdvOMS+l2wrr/7eYT91HHoWHN4Z
+i4slXTJGUImVrX1FCX/9ajrTPqITYOfS0VqeHfuol9JWtSS9xMAiHJJDYyfYUGxe
+z29gkvhEvWKOeSgGqfCjm5aXEfDAUjd/G6p8I30HQl7zhDo2pth1MSsxBV+TAPnw
+NJnuAoqAnAkS1ipfhqDfRfHwAX6Gfk/tnmpeAy7jvea10fEqziFQYd1xTq/0VYY7
+V3DVRWSnLw7enevFeowCgGCpuZ5Y/Rj6XeL/qwIDAQABAoIBAQCNpMZifd/vg42h
+HdCvLuZaYS0R7SunFlpoXEsltGdLFsnp0IfoJZ/ugFQBSAIIfLwMumU6oXA1z7Uv
+98aIYV61DePrTCDVDFBsHbNmP8JAo8WtbusEbwd5zyoB7LYG2+clkJklWE73KqUq
+rmI+UJeyScl2Gin7ZTxBXz1WPBk9VwcnwkeaXpgASIBW23fhECM9gnYEEwaBez5T
+6Me8d1tHtYQv7vsKe7ro9w9/HKrRXejqYKK1LxkhfFriyV+m8LZJZn2nXOa6G3gF
+Nb8Qk1Uk5PUBENBmyMFJhT4M/uuSq4YtMrrO2gi8Q+fPhuGzc5SshYKRBp0W4P5r
+mtVCtEFRAoGBAMENBIFLrV2+HsGj0xYFasKov/QPe6HSTR1Hh2IZONp+oK4oszWE
+jBT4VcnITmpl6tC1Wy4GcrxjNgKIFZAj+1x1LUULdorXkuG8yr0tAhG9zNyfWsSy
+PrSovC0UVbzr8Jxxla+kQVxEQQqWQxPlEVuL8kXaIDA6Lyt1Hpua2LvPAoGBANQZ
+c6Lq2T7+BxLxNdi2m8kZzej5kgzBp/XdVsbFWRlebIX2KrFHsrHzT9PUk3DE1vZK
+M6pzTt94nQhWSkDgCaw1SohElJ3HFIFwcusF1SJAc3pQepd8ug6IYdlpDMLtBj/P
+/5P6BVUtgo05E4+I/T3iYatmglQxTtlZ0RkSV2llAoGBALOXkKFX7ahPvf0WksDh
+uTfuFOTPoowgQG0EpgW0wRdCxeg/JLic3lSD0gsttQV2WsRecryWcxaelRg10RmO
+38BbogmhaF4xvgsSvujOfiZTE8oK1T43M+6NKsIlML3YILbpU/9aJxPWy0s2DqDr
+cQJhZrlk+pzjBA7Bnf/URdwxAoGAKR/CNw14D+mrL3YLbbiCXiydqxVwxv5pdZdz
+8thi3TNcsWC4iGURdcVqbfUinVPdJiXe/Kac3WGCeRJaFVgbKAOxLti1RB5MkIhg
+D8eyupBqk4W1L1gkrxqsdj4TFlxkwMywjl2E2S4YyQ8PBt6V04DoVRZsIKzqz+PF
+UionPq0CgYBCYXvqioJhPewkOq/Y5wrDBeZW1FQK5QD9W5M8/5zxd4rdvJtjhbJp
+oOrtvMdrl6upy9Hz4BJD3FXwVFiPFE7jqeNqi0F21viLxBPMMD3UODF6LL5EyLiR
+9V4xVMS8KXxvg7rxsuqzMPscViaWUL6WNVBhsD2+92dHxSXzz5EJKQ==
+-----END RSA PRIVATE KEY-----`))
+ var err error
+ testRSA2048PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 4bf06468c6d..e07d742bd3b 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -4,6 +4,8 @@
package tls
+import "crypto/internal/boring"
+
import (
"crypto"
"crypto/aes"
@@ -422,7 +424,13 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
// macSHA1 returns a SHA-1 based constant time MAC.
func macSHA1(key []byte) hash.Hash {
- return hmac.New(newConstantTimeHash(sha1.New), key)
+ h := sha1.New
+ // The BoringCrypto SHA1 does not have a constant-time
+ // checksum function, so don't try to use it.
+ if !boring.Enabled {
+ h = newConstantTimeHash(h)
+ }
+ return hmac.New(h, key)
}
// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
@@ -510,7 +518,16 @@ func aeadAESGCM(key, noncePrefix []byte) aead {
if err != nil {
panic(err)
}
- aead, err := cipher.NewGCM(aes)
+ type gcmtls interface {
+ NewGCMTLS() (cipher.AEAD, error)
+ }
+ var aead cipher.AEAD
+ if aesTLS, ok := aes.(gcmtls); ok {
+ aead, err = aesTLS.NewGCMTLS()
+ } else {
+ boring.Unreachable()
+ aead, err = cipher.NewGCM(aes)
+ }
if err != nil {
panic(err)
}
@@ -570,6 +587,7 @@ func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+ boring.Unreachable()
return func() hash.Hash {
return &cthWrapper{h().(constantTimeHash)}
}
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index d561e61707e..3e24d746bcf 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -171,11 +171,11 @@ const (
// hash function associated with the Ed25519 signature scheme.
var directSigning crypto.Hash = 0
-// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that
// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+
// CertificateRequest. The two fields are merged to match with TLS 1.3.
// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
-var supportedSignatureAlgorithms = []SignatureScheme{
+var defaultSupportedSignatureAlgorithms = []SignatureScheme{
PSSWithSHA256,
ECDSAWithP256AndSHA256,
Ed25519,
@@ -951,6 +951,9 @@ func (c *Config) time() time.Time {
}
func (c *Config) cipherSuites() []uint16 {
+ if needFIPS() {
+ return fipsCipherSuites(c)
+ }
if c.CipherSuites != nil {
return c.CipherSuites
}
@@ -967,6 +970,9 @@ var supportedVersions = []uint16{
func (c *Config) supportedVersions() []uint16 {
versions := make([]uint16, 0, len(supportedVersions))
for _, v := range supportedVersions {
+ if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) {
+ continue
+ }
if c != nil && c.MinVersion != 0 && v < c.MinVersion {
continue
}
@@ -1003,6 +1009,9 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 {
var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
func (c *Config) curvePreferences() []CurveID {
+ if needFIPS() {
+ return fipsCurvePreferences(c)
+ }
if c == nil || len(c.CurvePreferences) == 0 {
return defaultCurvePreferences
}
diff --git a/src/crypto/tls/fipsonly/fipsonly.go b/src/crypto/tls/fipsonly/fipsonly.go
new file mode 100644
index 00000000000..85b3532d26d
--- /dev/null
+++ b/src/crypto/tls/fipsonly/fipsonly.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fipsonly restricts all TLS configuration to FIPS-approved settings.
+//
+// The effect is triggered by importing the package anywhere in a program, as in:
+//
+// import _ "crypto/tls/fipsonly"
+//
+// This package only exists in the dev.boringcrypto branch of Go.
+package fipsonly
+
+// This functionality is provided as a side effect of an import to make
+// it trivial to add to an existing program. It requires only a single line
+// added to an existing source file, or it can be done by adding a whole
+// new source file and not modifying any existing source files.
+
+import (
+ "crypto/internal/boring/fipstls"
+ "crypto/internal/boring/sig"
+)
+
+func init() {
+ fipstls.Force()
+ sig.FIPSOnly()
+}
diff --git a/src/crypto/tls/fipsonly/fipsonly_test.go b/src/crypto/tls/fipsonly/fipsonly_test.go
new file mode 100644
index 00000000000..facd24807dc
--- /dev/null
+++ b/src/crypto/tls/fipsonly/fipsonly_test.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fipsonly
+
+import (
+ "crypto/internal/boring/fipstls"
+ "testing"
+)
+
+func Test(t *testing.T) {
+ if !fipstls.Required() {
+ t.Fatal("fipstls.Required() = false, must be true")
+ }
+}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 4af3d998a36..cd1b3b1d126 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -117,7 +117,10 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
}
if hello.vers >= VersionTLS12 {
- hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+ hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+ if testingOnlyForceClientHelloSignatureAlgorithms != nil {
+ hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
}
var params ecdheParameters
@@ -856,6 +859,8 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
if !c.config.InsecureSkipVerify {
opts := x509.VerifyOptions{
+ IsBoring: isBoringCertificate,
+
Roots: c.config.RootCAs,
CurrentTime: c.config.time(),
DNSName: c.config.ServerName,
diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
index eb59ac90d11..c7989867f56 100644
--- a/src/crypto/tls/handshake_client_tls13.go
+++ b/src/crypto/tls/handshake_client_tls13.go
@@ -41,6 +41,10 @@ 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 {
@@ -470,7 +474,7 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
}
// See RFC 8446, Section 4.4.3.
- if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: certificate used with invalid signature algorithm")
}
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index bb8aea86700..8821670e9ae 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -147,10 +147,10 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
}
}
if rand.Intn(10) > 5 {
- m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+ m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
}
if rand.Intn(10) > 5 {
- m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms
+ m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
}
for i := 0; i < rand.Intn(5); i++ {
m.alpnProtocols = append(m.alpnProtocols, randomString(rand.Intn(20)+1, rand))
@@ -369,10 +369,10 @@ func (*certificateRequestMsgTLS13) Generate(rand *rand.Rand, size int) reflect.V
m.scts = true
}
if rand.Intn(10) > 5 {
- m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+ m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
}
if rand.Intn(10) > 5 {
- m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms
+ m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
}
if rand.Intn(10) > 5 {
m.certificateAuthorities = make([][]byte, 3)
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index 43f30e2fefd..497e196a856 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -541,7 +541,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
if c.vers >= VersionTLS12 {
certReq.hasSignatureAlgorithm = true
- certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
}
// An empty list of certificateAuthorities signals to
@@ -812,6 +812,8 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
opts := x509.VerifyOptions{
+ IsBoring: isBoringCertificate,
+
Roots: c.config.ClientCAs,
CurrentTime: c.config.time(),
Intermediates: x509.NewCertPool(),
diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
index 6aa52698a3a..1b2bf4dcd3b 100644
--- a/src/crypto/tls/handshake_server_tls13.go
+++ b/src/crypto/tls/handshake_server_tls13.go
@@ -45,6 +45,10 @@ 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
@@ -584,7 +588,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
certReq := new(certificateRequestMsgTLS13)
certReq.ocspStapling = true
certReq.scts = true
- certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
if c.config.ClientCAs != nil {
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
}
@@ -816,7 +820,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
}
// See RFC 8446, Section 4.4.3.
- if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: client certificate used with invalid signature algorithm")
}