diff --git a/internal/crypto/ptls/default.go b/internal/crypto/ptls/default.go deleted file mode 100644 index 98a700155..000000000 --- a/internal/crypto/ptls/default.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -//go:build !fips_strict - -package ptls - -import ( - "crypto/tls" - "crypto/x509" -) - -func Default(rootCAs *x509.CertPool) *tls.Config { - return &tls.Config{ - // Can't use SSLv3 because of POODLE and BEAST - // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher - // Can't use TLSv1.1 because of RC4 cipher usage - // - // The Kubernetes API Server must use TLS 1.2, at a minimum, - // to protect the confidentiality of sensitive data during electronic dissemination. - // https://stigviewer.com/stig/kubernetes/2021-06-17/finding/V-242378 - MinVersion: tls.VersionTLS12, - - // the order does not matter in go 1.17+ https://go.dev/blog/tls-cipher-suites - // we match crypto/tls.cipherSuitesPreferenceOrder because it makes unit tests easier to write - // this list is ignored when TLS 1.3 is used - // - // as of 2021-10-19, Mozilla Guideline v5.6, Go 1.17.2, intermediate configuration, supports: - // - Firefox 27 - // - Android 4.4.2 - // - Chrome 31 - // - Edge - // - IE 11 on Windows 7 - // - Java 8u31 - // - OpenSSL 1.0.1 - // - Opera 20 - // - Safari 9 - // https://ssl-config.mozilla.org/#server=go&version=1.17.2&config=intermediate&guideline=5.6 - // - // The Kubernetes API server must use approved cipher suites. - // https://stigviewer.com/stig/kubernetes/2021-06-17/finding/V-242418 - CipherSuites: []uint16{ - // these are all AEADs with ECDHE, some use ChaCha20Poly1305 while others use AES-GCM - // this provides forward secrecy, confidentiality and authenticity of data - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - }, - - // enable HTTP2 for go's 1.7 HTTP Server - // setting this explicitly is only required in very specific circumstances - // it is simpler to just set it here than to try and determine if we need to - NextProtos: []string{"h2", "http/1.1"}, - - // optional root CAs, nil means use the host's root CA set - RootCAs: rootCAs, - } -} - -func DefaultLDAP(rootCAs *x509.CertPool) *tls.Config { - c := Default(rootCAs) - // add less secure ciphers to support the default AWS Active Directory config - c.CipherSuites = append(c.CipherSuites, - // CBC with ECDHE - // this provides forward secrecy and confidentiality of data but not authenticity - // MAC-then-Encrypt CBC ciphers are susceptible to padding oracle attacks - // See https://crypto.stackexchange.com/a/205 and https://crypto.stackexchange.com/a/224 - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - ) - return c -} diff --git a/internal/crypto/ptls/profiles.go b/internal/crypto/ptls/profiles.go new file mode 100644 index 000000000..1adb6a4b6 --- /dev/null +++ b/internal/crypto/ptls/profiles.go @@ -0,0 +1,144 @@ +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//go:build !fips_strict + +package ptls + +import ( + "crypto/tls" + "crypto/x509" + "os" + "path/filepath" + "runtime" + + "k8s.io/apiserver/pkg/server/options" + + "go.pinniped.dev/internal/plog" +) + +// init prints a log message to tell the operator how Pinniped was compiled. This makes it obvious +// that they are using Pinniped in FIPS-mode or not, which is otherwise hard to observe. +func init() { //nolint:gochecknoinits + switch filepath.Base(os.Args[0]) { + case "pinniped-server", "pinniped-supervisor", "pinniped-concierge", "pinniped-concierge-kube-cert-agent": + default: + return // do not print FIPS logs if we cannot confirm that we are running a server binary + } + + // this init runs before we have parsed our config to determine our log level + // thus we must use a log statement that will always print instead of conditionally print + plog.Always("this server was not compiled in FIPS-only mode", + "go version", runtime.Version()) +} + +// SecureTLSConfigMinTLSVersion is the minimum tls version in the format expected by tls.Config. +const SecureTLSConfigMinTLSVersion = tls.VersionTLS13 + +// Default TLS profile should be used by: +// A. servers whose clients are outside our control and who may reasonably wish to use TLS 1.2, and +// B. clients who need to interact with servers that might not support TLS 1.3. +// Note that this will behave differently when compiled in FIPS mode (see profiles_fips_strict.go). +func Default(rootCAs *x509.CertPool) *tls.Config { + return &tls.Config{ + // Can't use SSLv3 because of POODLE and BEAST + // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher + // Can't use TLSv1.1 because of RC4 cipher usage + // + // The Kubernetes API Server must use TLS 1.2, at a minimum, + // to protect the confidentiality of sensitive data during electronic dissemination. + // https://stigviewer.com/stig/kubernetes/2021-06-17/finding/V-242378 + MinVersion: tls.VersionTLS12, + + // the order does not matter in go 1.17+ https://go.dev/blog/tls-cipher-suites + // we match crypto/tls.cipherSuitesPreferenceOrder because it makes unit tests easier to write + // this list is ignored when TLS 1.3 is used + // + // as of 2021-10-19, Mozilla Guideline v5.6, Go 1.17.2, intermediate configuration, supports: + // - Firefox 27 + // - Android 4.4.2 + // - Chrome 31 + // - Edge + // - IE 11 on Windows 7 + // - Java 8u31 + // - OpenSSL 1.0.1 + // - Opera 20 + // - Safari 9 + // https://ssl-config.mozilla.org/#server=go&version=1.17.2&config=intermediate&guideline=5.6 + // + // The Kubernetes API server must use approved cipher suites. + // https://stigviewer.com/stig/kubernetes/2021-06-17/finding/V-242418 + CipherSuites: []uint16{ + // these are all AEADs with ECDHE, some use ChaCha20Poly1305 while others use AES-GCM + // this provides forward secrecy, confidentiality and authenticity of data + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + + // enable HTTP2 for go's 1.7 HTTP Server + // setting this explicitly is only required in very specific circumstances + // it is simpler to just set it here than to try and determine if we need to + NextProtos: []string{"h2", "http/1.1"}, + + // optional root CAs, nil means use the host's root CA set + RootCAs: rootCAs, + } +} + +// DefaultLDAP TLS profile should be used by clients who need to interact with potentially old LDAP servers +// that might not support TLS 1.3 and that might use older ciphers. +// Note that this will behave differently when compiled in FIPS mode (see profiles_fips_strict.go). +func DefaultLDAP(rootCAs *x509.CertPool) *tls.Config { + c := Default(rootCAs) + // add less secure ciphers to support the default AWS Active Directory config + c.CipherSuites = append(c.CipherSuites, + // CBC with ECDHE + // this provides forward secrecy and confidentiality of data but not authenticity + // MAC-then-Encrypt CBC ciphers are susceptible to padding oracle attacks + // See https://crypto.stackexchange.com/a/205 and https://crypto.stackexchange.com/a/224 + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + ) + return c +} + +// Secure TLS profile should be used by: +// A. servers whose clients are entirely known by us and who may reasonably be told that they must use TLS 1.3, and +// B. clients who only need to interact with servers that are known by us to support TLS 1.3 (e.g. the Kubernetes API). +// Note that this will behave differently when compiled in FIPS mode (see profiles_fips_strict.go). +func Secure(rootCAs *x509.CertPool) *tls.Config { + // as of 2021-10-19, Mozilla Guideline v5.6, Go 1.17.2, modern configuration, supports: + // - Firefox 63 + // - Android 10.0 + // - Chrome 70 + // - Edge 75 + // - Java 11 + // - OpenSSL 1.1.1 + // - Opera 57 + // - Safari 12.1 + // https://ssl-config.mozilla.org/#server=go&version=1.17.2&config=modern&guideline=5.6 + c := Default(rootCAs) + c.MinVersion = SecureTLSConfigMinTLSVersion // max out the security + c.CipherSuites = nil // TLS 1.3 ciphers are not configurable + return c +} + +// SecureServing modifies the given options to have the appropriate MinTLSVersion and CipherSuites. +// This function should only be used by the implementation of ptls.SecureRecommendedOptions, which +// is called to help configure our aggregated API servers. This exists only because it needs +// to behave differently in FIPS mode. +// This function is only public so we can integration test it in ptls_fips_test.go. +// Note that this will behave differently when compiled in FIPS mode (see profiles_fips_strict.go). +func SecureServing(opts *options.SecureServingOptionsWithLoopback) { + // secureServingOptionsMinTLSVersion is the minimum tls version in the format + // expected by SecureServingOptions.MinTLSVersion from + // k8s.io/apiserver/pkg/server/options. + opts.MinTLSVersion = "VersionTLS13" + opts.CipherSuites = nil +} diff --git a/internal/crypto/ptls/fips_strict.go b/internal/crypto/ptls/profiles_fips_strict.go similarity index 74% rename from internal/crypto/ptls/fips_strict.go rename to internal/crypto/ptls/profiles_fips_strict.go index b040bb12e..03da3b5b7 100644 --- a/internal/crypto/ptls/fips_strict.go +++ b/internal/crypto/ptls/profiles_fips_strict.go @@ -20,9 +20,7 @@ import ( "go.pinniped.dev/internal/plog" ) -// Until goboring supports TLS 1.3, use TLS 1.2. -const SecureTLSConfigMinTLSVersion = tls.VersionTLS12 - +// init: see comment in profiles.go. func init() { switch filepath.Base(os.Args[0]) { case "pinniped-server", "pinniped-supervisor", "pinniped-concierge", "pinniped-concierge-kube-cert-agent": @@ -32,9 +30,16 @@ func init() { // this init runs before we have parsed our config to determine our log level // thus we must use a log statement that will always print instead of conditionally print - plog.Always("using boring crypto in fips only mode", "go version", runtime.Version()) + plog.Always("this server was compiled to use boring crypto in FIPS-only mode", + "go version", runtime.Version()) } +// SecureTLSConfigMinTLSVersion: see comment in profiles.go. +// Until goboring supports TLS 1.3, use TLS 1.2. +const SecureTLSConfigMinTLSVersion = tls.VersionTLS12 + +// Default: see comment in profiles.go. +// This chooses different cipher suites and/or TLS versions compared to non-FIPS mode. func Default(rootCAs *x509.CertPool) *tls.Config { return &tls.Config{ MinVersion: tls.VersionTLS12, @@ -64,16 +69,22 @@ func Default(rootCAs *x509.CertPool) *tls.Config { } } +// DefaultLDAP: see comment in profiles.go. +// This chooses different cipher suites and/or TLS versions compared to non-FIPS mode. +func DefaultLDAP(rootCAs *x509.CertPool) *tls.Config { + return Default(rootCAs) +} + +// Secure: see comment in profiles.go. +// This chooses different cipher suites and/or TLS versions compared to non-FIPS mode. // Until goboring supports TLS 1.3, make the Secure profile the same as the Default profile in FIPS mode. func Secure(rootCAs *x509.CertPool) *tls.Config { return Default(rootCAs) } -func DefaultLDAP(rootCAs *x509.CertPool) *tls.Config { - return Default(rootCAs) -} - -// Until goboring supports TLS 1.3, make secureServing use the same as the defaultServing profile in FIPS mode. -func secureServing(opts *options.SecureServingOptionsWithLoopback) { +// SecureServing: see comment in profiles.go. +// This chooses different cipher suites and/or TLS versions compared to non-FIPS mode. +// Until goboring supports TLS 1.3, make SecureServing use the same as the defaultServing profile in FIPS mode. +func SecureServing(opts *options.SecureServingOptionsWithLoopback) { defaultServing(opts) } diff --git a/internal/crypto/ptls/profiles_fips_strict_test.go b/internal/crypto/ptls/profiles_fips_strict_test.go new file mode 100644 index 000000000..d86699150 --- /dev/null +++ b/internal/crypto/ptls/profiles_fips_strict_test.go @@ -0,0 +1,9 @@ +// Copyright 2024 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package ptls + +// If you are coming here to look for unit tests for the FIPS-mode profiles, +// please instead see test/integration/ptls_fips_test.go. +// CI does not currently run the unit tests in FIPS mode, so these unit tests +// were instead written as integration tests. diff --git a/internal/crypto/ptls/profiles_test.go b/internal/crypto/ptls/profiles_test.go new file mode 100644 index 000000000..ac175c06b --- /dev/null +++ b/internal/crypto/ptls/profiles_test.go @@ -0,0 +1,91 @@ +// Copyright 2024 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package ptls + +import ( + "crypto/tls" + "crypto/x509" + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apiserver/pkg/server/options" +) + +func TestDefault(t *testing.T) { + t.Parallel() + + aCertPool := x509.NewCertPool() + + actual := Default(aCertPool) + expected := &tls.Config{ + MinVersion: tls.VersionTLS12, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + NextProtos: []string{"h2", "http/1.1"}, + RootCAs: aCertPool, + } + + require.Equal(t, expected, actual) +} + +func TestDefaultLDAP(t *testing.T) { + t.Parallel() + + aCertPool := x509.NewCertPool() + + actual := DefaultLDAP(aCertPool) + expected := &tls.Config{ + MinVersion: tls.VersionTLS12, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, //nolint:gosec // this is a test + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + }, + NextProtos: []string{"h2", "http/1.1"}, + RootCAs: aCertPool, + } + + require.Equal(t, expected, actual) +} + +func TestSecure(t *testing.T) { + t.Parallel() + + aCertPool := x509.NewCertPool() + + actual := Secure(aCertPool) + expected := &tls.Config{ + MinVersion: tls.VersionTLS13, + CipherSuites: nil, // TLS 1.3 ciphers are not configurable + NextProtos: []string{"h2", "http/1.1"}, + RootCAs: aCertPool, + } + + require.Equal(t, expected, actual) +} + +func TestSecureServing(t *testing.T) { + t.Parallel() + + opts := &options.SecureServingOptionsWithLoopback{SecureServingOptions: &options.SecureServingOptions{}} + SecureServing(opts) + require.Equal(t, options.SecureServingOptionsWithLoopback{ + SecureServingOptions: &options.SecureServingOptions{ + MinTLSVersion: "VersionTLS13", + }, + }, *opts) +} diff --git a/internal/crypto/ptls/ptls.go b/internal/crypto/ptls/ptls.go index bf2ae4e1f..6ebd86e02 100644 --- a/internal/crypto/ptls/ptls.go +++ b/internal/crypto/ptls/ptls.go @@ -77,7 +77,7 @@ func DefaultRecommendedOptions(opts *options.RecommendedOptions, f RestConfigFun // certain well known clients which we expect will always use modern TLS settings (like the Kube API server). // It returns a PrepareServerConfigFunc which must be used on a RecommendedConfig before passing it to RecommendedOptions.ApplyTo(). func SecureRecommendedOptions(opts *options.RecommendedOptions, f RestConfigFunc) (PrepareServerConfigFunc, error) { - secureServing(opts.SecureServing) + SecureServing(opts.SecureServing) return secureClient(opts, f) } diff --git a/internal/crypto/ptls/ptls_test.go b/internal/crypto/ptls/ptls_test.go index 789b30fbf..e3eff9935 100644 --- a/internal/crypto/ptls/ptls_test.go +++ b/internal/crypto/ptls/ptls_test.go @@ -34,18 +34,6 @@ func TestDefaultServing(t *testing.T) { }, *opts) } -func TestSecureServing(t *testing.T) { - t.Parallel() - - opts := &options.SecureServingOptionsWithLoopback{SecureServingOptions: &options.SecureServingOptions{}} - secureServing(opts) - require.Equal(t, options.SecureServingOptionsWithLoopback{ - SecureServingOptions: &options.SecureServingOptions{ - MinTLSVersion: "VersionTLS13", - }, - }, *opts) -} - func TestMerge(t *testing.T) { t.Parallel() diff --git a/internal/crypto/ptls/secure.go b/internal/crypto/ptls/secure.go deleted file mode 100644 index d08139443..000000000 --- a/internal/crypto/ptls/secure.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -//go:build !fips_strict - -package ptls - -import ( - "crypto/tls" - "crypto/x509" - - "k8s.io/apiserver/pkg/server/options" -) - -// secureServingOptionsMinTLSVersion is the minimum tls version in the format -// expected by SecureServingOptions.MinTLSVersion from -// k8s.io/apiserver/pkg/server/options. -const secureServingOptionsMinTLSVersion = "VersionTLS13" - -// SecureTLSConfigMinTLSVersion is the minimum tls version in the format expected -// by tls.Config. -const SecureTLSConfigMinTLSVersion = tls.VersionTLS13 - -func Secure(rootCAs *x509.CertPool) *tls.Config { - // as of 2021-10-19, Mozilla Guideline v5.6, Go 1.17.2, modern configuration, supports: - // - Firefox 63 - // - Android 10.0 - // - Chrome 70 - // - Edge 75 - // - Java 11 - // - OpenSSL 1.1.1 - // - Opera 57 - // - Safari 12.1 - // https://ssl-config.mozilla.org/#server=go&version=1.17.2&config=modern&guideline=5.6 - c := Default(rootCAs) - c.MinVersion = SecureTLSConfigMinTLSVersion // max out the security - c.CipherSuites = nil // TLS 1.3 ciphers are not configurable - return c -} - -func secureServing(opts *options.SecureServingOptionsWithLoopback) { - opts.MinTLSVersion = secureServingOptionsMinTLSVersion - opts.CipherSuites = nil -} diff --git a/test/integration/ptls_fips_test.go b/test/integration/ptls_fips_test.go new file mode 100644 index 000000000..fcea5fb6c --- /dev/null +++ b/test/integration/ptls_fips_test.go @@ -0,0 +1,144 @@ +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +//go:build fips_strict + +package integration + +import ( + "crypto/tls" + "crypto/x509" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apiserver/pkg/server/options" + "k8s.io/client-go/util/cert" + + "go.pinniped.dev/internal/crypto/ptls" + "go.pinniped.dev/internal/testutil/tlsserver" + "go.pinniped.dev/test/testlib" +) + +// Note: Everything in this file is an integration test only because we do not support build tags on unit tests. +// These are effectively unit tests for the ptls package when compiled in FIPS mode. + +// TestFIPSCipherSuites_Parallel ensures that if the list of default FIPS cipher suites changes, then we will know. +// If this test ever fails during a golang upgrade, then we may need to change which ciphers we are using in +// the ptls package in FIPS mode. +func TestFIPSCipherSuites_Parallel(t *testing.T) { + _ = testlib.IntegrationEnv(t) // this function call is required for integration tests + + server, ca := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // use the default fips config which contains a hard coded list of cipher suites + // that should be equal to the default list of fips cipher suites. + // assert that the client hello response has the same tls config as this test server. + tlsserver.AssertTLS(t, r, ptls.Default) + }), tlsserver.RecordTLSHello) + + pool, err := cert.NewPoolFromBytes(ca) + require.NoError(t, err) + // create a tls config that does not explicitly set cipher suites, + // and therefore uses goboring's default fips ciphers. + defaultConfig := &tls.Config{ + RootCAs: pool, + NextProtos: ptls.Default(nil).NextProtos, // we do not care about field for this test, so just make it match + } + transport := http.Transport{ + TLSClientConfig: defaultConfig, + ForceAttemptHTTP2: true, + } + // make a request against the test server, which will validate that the + // tls config of the client without explicitly set ciphers + // is the same as the tls config of the test server with explicitly + // set ciphers from ptls. + request, _ := http.NewRequest("GET", server.URL, nil) + response, err := transport.RoundTrip(request) + require.NoError(t, err) + require.Equal(t, http.StatusOK, response.StatusCode) +} + +// Every profile should use the same cipher suites in FIPS mode, because FIPS requires these ciphers. +// Please treat this as a read-only const. +var expectedFIPSCipherSuites = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_RSA_WITH_AES_256_GCM_SHA384, +} + +func TestDefault_Parallel(t *testing.T) { + _ = testlib.IntegrationEnv(t) // this function call is required for integration tests + + aCertPool := x509.NewCertPool() + + actual := ptls.Default(aCertPool) + expected := &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS12, // goboring does not currently support TLS 1.3, so prevent its use + CipherSuites: expectedFIPSCipherSuites, + NextProtos: []string{"h2", "http/1.1"}, + RootCAs: aCertPool, + } + + require.Equal(t, expected, actual) +} + +func TestDefaultLDAP_Parallel(t *testing.T) { + _ = testlib.IntegrationEnv(t) // this function call is required for integration tests + + aCertPool := x509.NewCertPool() + + actual := ptls.DefaultLDAP(aCertPool) + expected := &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS12, // goboring does not currently support TLS 1.3, so prevent its use + CipherSuites: expectedFIPSCipherSuites, + NextProtos: []string{"h2", "http/1.1"}, + RootCAs: aCertPool, + } + + require.Equal(t, expected, actual) +} + +func TestSecure_Parallel(t *testing.T) { + _ = testlib.IntegrationEnv(t) // this function call is required for integration tests + + aCertPool := x509.NewCertPool() + + actual := ptls.Secure(aCertPool) + expected := &tls.Config{ + // goboring does not currently support TLS 1.3, so where we would normally require it by making it the + // min version for the secure profile, we cannot do that in FIPS mode + MinVersion: tls.VersionTLS12, + MaxVersion: tls.VersionTLS12, // goboring does not currently support TLS 1.3, so prevent its use + CipherSuites: expectedFIPSCipherSuites, + NextProtos: []string{"h2", "http/1.1"}, + RootCAs: aCertPool, + } + + require.Equal(t, expected, actual) +} + +func TestSecureServing_Parallel(t *testing.T) { + _ = testlib.IntegrationEnv(t) // this function call is required for integration tests + + opts := &options.SecureServingOptionsWithLoopback{SecureServingOptions: &options.SecureServingOptions{}} + ptls.SecureServing(opts) + + expectedFIPSCipherSuiteNames := make([]string, len(expectedFIPSCipherSuites)) + for i, suite := range expectedFIPSCipherSuites { + expectedFIPSCipherSuiteNames[i] = tls.CipherSuiteName(suite) + } + + require.Equal(t, options.SecureServingOptionsWithLoopback{ + SecureServingOptions: &options.SecureServingOptions{ + CipherSuites: expectedFIPSCipherSuiteNames, + // goboring does not currently support TLS 1.3, so where we would normally require it by making it the + // min version for secure serving for aggregated API servers, we cannot do that in FIPS mode + MinTLSVersion: "VersionTLS12", + }, + }, *opts) +} diff --git a/test/integration/securetls_fips_test.go b/test/integration/securetls_fips_test.go deleted file mode 100644 index 63a6d21a3..000000000 --- a/test/integration/securetls_fips_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -//go:build fips_strict - -package integration - -import ( - "crypto/tls" - "net/http" - "testing" - - "github.com/stretchr/testify/require" - "k8s.io/client-go/util/cert" - - "go.pinniped.dev/internal/crypto/ptls" - "go.pinniped.dev/internal/testutil/tlsserver" - "go.pinniped.dev/test/testlib" -) - -// TestFIPSCipherSuites_Parallel ensures that if the list of default fips cipher suites changes, -// we will know. This is an integration test because we do not support build tags on unit tests. -func TestFIPSCipherSuites_Parallel(t *testing.T) { - _ = testlib.IntegrationEnv(t) - - server, ca := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // use the default fips config which contains a hard coded list of cipher suites - // that should be equal to the default list of fips cipher suites. - // assert that the client hello response has the same tls config as this test server. - tlsserver.AssertTLS(t, r, ptls.Default) - }), tlsserver.RecordTLSHello) - - pool, err := cert.NewPoolFromBytes(ca) - require.NoError(t, err) - // create a tls config that does not explicitly set cipher suites, - // and therefore uses goboring's default fips ciphers. - defaultConfig := &tls.Config{ - RootCAs: pool, - NextProtos: ptls.Default(nil).NextProtos, // we do not care about field for this test, so just make it match - } - transport := http.Transport{ - TLSClientConfig: defaultConfig, - ForceAttemptHTTP2: true, - } - // make a request against the test server, which will validate that the - // tls config of the client without explicitly set ciphers - // is the same as the tls config of the test server with explicitly - // set ciphers from ptls. - request, _ := http.NewRequest("GET", server.URL, nil) - response, err := transport.RoundTrip(request) - require.NoError(t, err) - require.Equal(t, http.StatusOK, response.StatusCode) -}