mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-01-07 14:05:50 +00:00
some mild refactoring of ptls common.go (mostly renames)
This commit is contained in:
@@ -16,70 +16,83 @@ import (
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
// allowedCiphersForTLSOneDotTwo will only contain ciphers that meet the following criteria:
|
||||
// 1. They are secure
|
||||
// 2. They are returned by tls.CipherSuites
|
||||
// 3. They are returned by cipherSuitesForDefault or cipherSuitesForDefaultLDAP
|
||||
// This is atomic so that it can not be set and read at the same time.
|
||||
// validatedUserConfiguredAllowedCipherSuitesForTLSOneDotTwo is the validated configuration of allowed cipher suites
|
||||
// provided by the user, as set by SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo().
|
||||
// This global variable is atomic so that it can not be set and read at the same time.
|
||||
//
|
||||
//nolint:gochecknoglobals // This needs to be global because it will be set at application startup from configuration values
|
||||
var allowedCiphersForTLSOneDotTwo atomic.Value
|
||||
//nolint:gochecknoglobals // this needs to be global because it will be set at application startup from configuration values
|
||||
var validatedUserConfiguredAllowedCipherSuitesForTLSOneDotTwo atomic.Value
|
||||
|
||||
type SetAllowedCiphers func([]string) error
|
||||
type SetAllowedCiphersFunc func([]string) error
|
||||
|
||||
// SetUserConfiguredCiphersForTLSOneDotTwo allows configuration/setup components to constrain the allowed TLS ciphers
|
||||
// for TLS1.2.
|
||||
func SetUserConfiguredCiphersForTLSOneDotTwo(userConfiguredCiphersForTLSOneDotTwo []string) error {
|
||||
plog.Info("setting user-configured allowed ciphers for TLS 1.2", "userConfiguredAllowedCipherSuites", userConfiguredCiphersForTLSOneDotTwo)
|
||||
// SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo allows configuration/setup components to constrain the
|
||||
// allowed TLS ciphers for TLS1.2. It implements SetAllowedCiphersFunc.
|
||||
func SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo(userConfiguredAllowedCipherSuitesForTLSOneDotTwo []string) error {
|
||||
plog.Info("setting user-configured allowed ciphers for TLS 1.2", "userConfiguredAllowedCipherSuites", userConfiguredAllowedCipherSuitesForTLSOneDotTwo)
|
||||
|
||||
validatedUserConfiguredAllowedCipherSuites, err := validateAllowedCiphers(allHardcodedAllowedCipherSuites(), userConfiguredCiphersForTLSOneDotTwo)
|
||||
validatedSuites, err := validateAllowedCiphers(
|
||||
allHardcodedAllowedCipherSuites(),
|
||||
userConfiguredAllowedCipherSuitesForTLSOneDotTwo,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allowedCiphersForTLSOneDotTwo.Store(validatedUserConfiguredAllowedCipherSuites)
|
||||
|
||||
validatedUserConfiguredAllowedCipherSuitesForTLSOneDotTwo.Store(validatedSuites)
|
||||
return nil
|
||||
}
|
||||
|
||||
// getUserConfiguredCiphersAllowList returns the user-configured list of allowed ciphers for TLS1.2.
|
||||
// getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo returns the user-configured list of allowed ciphers for TLS1.2.
|
||||
// It is not exported so that it is only available to this package.
|
||||
func getUserConfiguredCiphersAllowList() []*tls.CipherSuite {
|
||||
userConfiguredCiphersAllowList, ok := (allowedCiphersForTLSOneDotTwo.Load()).([]*tls.CipherSuite)
|
||||
func getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo() []*tls.CipherSuite {
|
||||
userConfiguredAllowedCipherSuites, ok := (validatedUserConfiguredAllowedCipherSuitesForTLSOneDotTwo.Load()).([]*tls.CipherSuite)
|
||||
if ok {
|
||||
return userConfiguredCiphersAllowList
|
||||
return userConfiguredAllowedCipherSuites
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// constrainCipherSuites returns the intersection of its parameters, as a list of cipher suite IDs.
|
||||
// If userConfiguredCiphersAllowList is empty, it will return all the hardcodedCipherSuites.
|
||||
// If userConfiguredAllowedCipherSuites is empty, it will return the list from cipherSuites as IDs.
|
||||
func constrainCipherSuites(
|
||||
hardcodedCipherSuites []*tls.CipherSuite,
|
||||
cipherSuites []*tls.CipherSuite,
|
||||
userConfiguredAllowedCipherSuites []*tls.CipherSuite,
|
||||
) []uint16 {
|
||||
allowedCipherSuiteIDs := sets.New[uint16]()
|
||||
for _, allowedCipherSuite := range userConfiguredAllowedCipherSuites {
|
||||
allowedCipherSuiteIDs.Insert(allowedCipherSuite.ID)
|
||||
// If the user did not configure any allowed ciphers suites, then return the IDs
|
||||
// for the ciphers in cipherSuites in the same sort order as quickly as possible.
|
||||
if len(userConfiguredAllowedCipherSuites) == 0 {
|
||||
cipherSuiteIDs := make([]uint16, len(cipherSuites))
|
||||
for i := range cipherSuites {
|
||||
cipherSuiteIDs[i] = cipherSuites[i].ID
|
||||
}
|
||||
return cipherSuiteIDs
|
||||
}
|
||||
|
||||
configuredCipherSuiteIDs := sets.New[uint16]()
|
||||
for _, configuredCipherSuite := range hardcodedCipherSuites {
|
||||
configuredCipherSuiteIDs.Insert(configuredCipherSuite.ID)
|
||||
// Make two sets so we can intersect them below.
|
||||
cipherSuiteIDsSet := sets.New[uint16]()
|
||||
for _, s := range cipherSuites {
|
||||
cipherSuiteIDsSet.Insert(s.ID)
|
||||
}
|
||||
userConfiguredAllowedCipherSuiteIDsSet := sets.New[uint16]()
|
||||
for _, s := range userConfiguredAllowedCipherSuites {
|
||||
userConfiguredAllowedCipherSuiteIDsSet.Insert(s.ID)
|
||||
}
|
||||
|
||||
intersection := configuredCipherSuiteIDs.Intersection(allowedCipherSuiteIDs)
|
||||
// Calculate the intersection of sets.
|
||||
intersection := cipherSuiteIDsSet.Intersection(userConfiguredAllowedCipherSuiteIDsSet)
|
||||
|
||||
// If the user did not provide any valid allowed cipher suites, use configuredCipherSuiteIDs.
|
||||
// Note that the user-configured allowed cipher suites are validated elsewhere, so this should only happen when the
|
||||
// user chose not to specify any allowed cipher suites.
|
||||
// If the user did not provide any valid allowed cipher suites, use cipherSuiteIDsSet.
|
||||
// Note that the user-configured allowed cipher suites are validated elsewhere, so
|
||||
// this should only happen when the user chose not to specify any allowed cipher suites.
|
||||
if len(intersection) == 0 {
|
||||
intersection = configuredCipherSuiteIDs
|
||||
intersection = cipherSuiteIDsSet
|
||||
}
|
||||
|
||||
result := intersection.UnsortedList()
|
||||
// Preserve the order as shown in configuredCipherSuites
|
||||
// Preserve the original order as shown in the cipherSuites parameter.
|
||||
slices.SortFunc(result, func(a, b uint16) int {
|
||||
return slices.IndexFunc(hardcodedCipherSuites, func(cipher *tls.CipherSuite) bool { return cipher.ID == a }) -
|
||||
slices.IndexFunc(hardcodedCipherSuites, func(cipher *tls.CipherSuite) bool { return cipher.ID == b })
|
||||
return slices.IndexFunc(cipherSuites, func(cipher *tls.CipherSuite) bool { return cipher.ID == a }) -
|
||||
slices.IndexFunc(cipherSuites, func(cipher *tls.CipherSuite) bool { return cipher.ID == b })
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -90,7 +103,7 @@ func translateIDIntoSecureCipherSuites(ids []uint16) []*tls.CipherSuite {
|
||||
result := make([]*tls.CipherSuite, 0)
|
||||
|
||||
for _, golangSecureCipherSuite := range golangSecureCipherSuites {
|
||||
// As of golang 1.22.2, all cipher suites from tls.CipherSuites are secure, so this is just future-proofing.
|
||||
// As of golang 1.22, all cipher suites from tls.CipherSuites are secure, so this is just future-proofing.
|
||||
if golangSecureCipherSuite.Insecure { // untested
|
||||
continue
|
||||
}
|
||||
@@ -112,11 +125,11 @@ func translateIDIntoSecureCipherSuites(ids []uint16) []*tls.CipherSuite {
|
||||
return result
|
||||
}
|
||||
|
||||
// buildTLSConfig will return a tls.Config with CipherSuites from the intersection of configuredCipherSuites and allowedCipherSuites.
|
||||
// buildTLSConfig will return a tls.Config with CipherSuites from the intersection of cipherSuites and userConfiguredAllowedCipherSuites.
|
||||
func buildTLSConfig(
|
||||
rootCAs *x509.CertPool,
|
||||
hardcodedCipherSuites []*tls.CipherSuite,
|
||||
userConfiguredCiphersAllowList []*tls.CipherSuite,
|
||||
cipherSuites []*tls.CipherSuite,
|
||||
userConfiguredAllowedCipherSuites []*tls.CipherSuite,
|
||||
) *tls.Config {
|
||||
return &tls.Config{
|
||||
// Can't use SSLv3 because of POODLE and BEAST
|
||||
@@ -128,7 +141,7 @@ func buildTLSConfig(
|
||||
// https://stigviewer.com/stig/kubernetes/2021-06-17/finding/V-242378
|
||||
MinVersion: tls.VersionTLS12,
|
||||
|
||||
CipherSuites: constrainCipherSuites(hardcodedCipherSuites, userConfiguredCiphersAllowList),
|
||||
CipherSuites: constrainCipherSuites(cipherSuites, userConfiguredAllowedCipherSuites),
|
||||
|
||||
// enable HTTP2 for go's 1.7 HTTP Server
|
||||
// setting this explicitly is only required in very specific circumstances
|
||||
@@ -140,37 +153,37 @@ func buildTLSConfig(
|
||||
}
|
||||
}
|
||||
|
||||
// validateAllowedCiphers will take in the user-configured allowed cipher names and validate them against Pinniped's configured list of ciphers.
|
||||
// If any allowed cipher names are not configured, return a descriptive error.
|
||||
// An empty list of allowed cipher names is perfectly valid.
|
||||
// Returns the tls.CipherSuite representation when all allowedCipherNames are accepted.
|
||||
// validateAllowedCiphers will take in the user-configured allowed cipher names and validate them against a list of
|
||||
// ciphers. If any userConfiguredAllowedCipherSuites names are not in the cipherSuites, return a descriptive error.
|
||||
// An empty list of userConfiguredAllowedCipherSuites means that the user wants the all default ciphers from cipherSuites.
|
||||
// Returns the tls.CipherSuite representation when all userConfiguredAllowedCipherSuites are valid.
|
||||
func validateAllowedCiphers(
|
||||
hardcodedCipherSuites []*tls.CipherSuite,
|
||||
userConfiguredCiphersAllowList []string,
|
||||
cipherSuites []*tls.CipherSuite,
|
||||
userConfiguredAllowedCipherSuites []string,
|
||||
) ([]*tls.CipherSuite, error) {
|
||||
if len(userConfiguredCiphersAllowList) < 1 {
|
||||
if len(userConfiguredAllowedCipherSuites) < 1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hardcodedCipherSuiteNames := make([]string, len(hardcodedCipherSuites))
|
||||
for i, cipher := range hardcodedCipherSuites {
|
||||
hardcodedCipherSuiteNames[i] = cipher.Name
|
||||
cipherSuiteNames := make([]string, len(cipherSuites))
|
||||
for i, cipher := range cipherSuites {
|
||||
cipherSuiteNames[i] = cipher.Name
|
||||
}
|
||||
|
||||
// Allow some loosening of the names for legacy reasons.
|
||||
for i := range userConfiguredCiphersAllowList {
|
||||
switch userConfiguredCiphersAllowList[i] {
|
||||
for i := range userConfiguredAllowedCipherSuites {
|
||||
switch userConfiguredAllowedCipherSuites[i] {
|
||||
case "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":
|
||||
userConfiguredCiphersAllowList[i] = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
|
||||
userConfiguredAllowedCipherSuites[i] = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
|
||||
case "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":
|
||||
userConfiguredCiphersAllowList[i] = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
|
||||
userConfiguredAllowedCipherSuites[i] = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that all allowedCipherNames are actually configured within Pinniped
|
||||
// Make sure that all allowedCipherNames are actually configured within Pinniped.
|
||||
var invalidCipherNames []string
|
||||
for _, allowedCipherName := range userConfiguredCiphersAllowList {
|
||||
if !slices.Contains(hardcodedCipherSuiteNames, allowedCipherName) {
|
||||
for _, allowedCipherName := range userConfiguredAllowedCipherSuites {
|
||||
if !slices.Contains(cipherSuiteNames, allowedCipherName) {
|
||||
invalidCipherNames = append(invalidCipherNames, allowedCipherName)
|
||||
}
|
||||
}
|
||||
@@ -178,13 +191,13 @@ func validateAllowedCiphers(
|
||||
if len(invalidCipherNames) > 0 {
|
||||
return nil, fmt.Errorf("unrecognized ciphers [%s], ciphers must be from list [%s]",
|
||||
strings.Join(invalidCipherNames, ", "),
|
||||
strings.Join(hardcodedCipherSuiteNames, ", "))
|
||||
strings.Join(cipherSuiteNames, ", "))
|
||||
}
|
||||
|
||||
// Now translate the allowedCipherNames into their *tls.CipherSuite representation
|
||||
// Now translate the allowedCipherNames into their *tls.CipherSuite representation.
|
||||
var validCiphers []*tls.CipherSuite
|
||||
for _, cipher := range hardcodedCipherSuites {
|
||||
if slices.Contains(userConfiguredCiphersAllowList, cipher.Name) {
|
||||
for _, cipher := range cipherSuites {
|
||||
if slices.Contains(userConfiguredAllowedCipherSuites, cipher.Name) {
|
||||
validCiphers = append(validCiphers, cipher)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func TestSetAllowedCiphersForTLSOneDotTwo(t *testing.T) {
|
||||
t.Run("with valid ciphers, mutates the global state", func(t *testing.T) {
|
||||
require.Empty(t, getUserConfiguredCiphersAllowList())
|
||||
require.Empty(t, getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo())
|
||||
// With no user-configured allowed ciphers, expect all the hardcoded ciphers
|
||||
require.Equal(t, []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
@@ -39,9 +39,9 @@ func TestSetAllowedCiphersForTLSOneDotTwo(t *testing.T) {
|
||||
require.Empty(t, Secure(nil).CipherSuites)
|
||||
|
||||
t.Cleanup(func() {
|
||||
err := SetUserConfiguredCiphersForTLSOneDotTwo(nil)
|
||||
err := SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo(nil)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, getUserConfiguredCiphersAllowList())
|
||||
require.Nil(t, getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo())
|
||||
|
||||
require.Equal(t, []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
@@ -71,9 +71,9 @@ func TestSetAllowedCiphersForTLSOneDotTwo(t *testing.T) {
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // this is an LDAP-only cipher
|
||||
}
|
||||
err := SetUserConfiguredCiphersForTLSOneDotTwo(userConfiguredAllowedCipherSuites)
|
||||
err := SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo(userConfiguredAllowedCipherSuites)
|
||||
require.NoError(t, err)
|
||||
stored := getUserConfiguredCiphersAllowList()
|
||||
stored := getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo()
|
||||
var storedNames []string
|
||||
for _, suite := range stored {
|
||||
storedNames = append(storedNames, suite.Name)
|
||||
@@ -92,8 +92,8 @@ func TestSetAllowedCiphersForTLSOneDotTwo(t *testing.T) {
|
||||
require.Empty(t, Secure(nil).CipherSuites)
|
||||
})
|
||||
|
||||
t.Run("SetUserConfiguredCiphersForTLSOneDotTwo calls validateAllowedCiphers and returns error", func(t *testing.T) {
|
||||
err := SetUserConfiguredCiphersForTLSOneDotTwo([]string{"foo"})
|
||||
t.Run("SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo calls validateAllowedCiphers and returns error", func(t *testing.T) {
|
||||
err := SetUserConfiguredAllowedCipherSuitesForTLSOneDotTwo([]string{"foo"})
|
||||
require.Regexp(t, regexp.QuoteMeta("unrecognized ciphers [foo], ciphers must be from list [TLS")+".*"+regexp.QuoteMeta("]"), err.Error())
|
||||
})
|
||||
}
|
||||
@@ -101,7 +101,7 @@ func TestSetAllowedCiphersForTLSOneDotTwo(t *testing.T) {
|
||||
func TestConstrainCipherSuites(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
hardcodedCipherSuites []*tls.CipherSuite
|
||||
cipherSuites []*tls.CipherSuite
|
||||
userConfiguredAllowedCipherSuites []*tls.CipherSuite
|
||||
wantCipherSuites []uint16
|
||||
}{
|
||||
@@ -110,8 +110,8 @@ func TestConstrainCipherSuites(t *testing.T) {
|
||||
wantCipherSuites: make([]uint16, 0),
|
||||
},
|
||||
{
|
||||
name: "with empty userConfiguredAllowedCipherSuites, returns hardcodedCipherSuites",
|
||||
hardcodedCipherSuites: []*tls.CipherSuite{
|
||||
name: "with empty userConfiguredAllowedCipherSuites, returns cipherSuites",
|
||||
cipherSuites: []*tls.CipherSuite{
|
||||
{ID: 0},
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
@@ -120,7 +120,7 @@ func TestConstrainCipherSuites(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "with userConfiguredAllowedCipherSuites, returns only ciphers found in both inputs",
|
||||
hardcodedCipherSuites: []*tls.CipherSuite{
|
||||
cipherSuites: []*tls.CipherSuite{
|
||||
{ID: 0},
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
@@ -135,8 +135,8 @@ func TestConstrainCipherSuites(t *testing.T) {
|
||||
wantCipherSuites: []uint16{1, 3},
|
||||
},
|
||||
{
|
||||
name: "with all invalid userConfiguredAllowedCipherSuites, returns hardcodedCipherSuites",
|
||||
hardcodedCipherSuites: []*tls.CipherSuite{
|
||||
name: "with all invalid userConfiguredAllowedCipherSuites, returns cipherSuites",
|
||||
cipherSuites: []*tls.CipherSuite{
|
||||
{ID: 0},
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
@@ -151,8 +151,8 @@ func TestConstrainCipherSuites(t *testing.T) {
|
||||
wantCipherSuites: []uint16{0, 1, 2, 3, 4},
|
||||
},
|
||||
{
|
||||
name: "preserves order from hardcodedCipherSuites",
|
||||
hardcodedCipherSuites: []*tls.CipherSuite{
|
||||
name: "preserves order from cipherSuites",
|
||||
cipherSuites: []*tls.CipherSuite{
|
||||
{ID: 0},
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
@@ -173,7 +173,7 @@ func TestConstrainCipherSuites(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := constrainCipherSuites(test.hardcodedCipherSuites, test.userConfiguredAllowedCipherSuites)
|
||||
actual := constrainCipherSuites(test.cipherSuites, test.userConfiguredAllowedCipherSuites)
|
||||
require.Equal(t, test.wantCipherSuites, actual)
|
||||
})
|
||||
}
|
||||
@@ -219,16 +219,16 @@ func TestBuildTLSConfig(t *testing.T) {
|
||||
aCertPool := x509.NewCertPool()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
rootCAs *x509.CertPool
|
||||
configuredCipherSuites []*tls.CipherSuite
|
||||
allowedCipherIDs []uint16
|
||||
wantConfig *tls.Config
|
||||
name string
|
||||
rootCAs *x509.CertPool
|
||||
cipherSuites []*tls.CipherSuite
|
||||
userConfiguredAllowedCipherSuiteIDs []uint16
|
||||
wantConfig *tls.Config
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
rootCAs: aCertPool,
|
||||
configuredCipherSuites: tls.CipherSuites(),
|
||||
name: "happy path",
|
||||
rootCAs: aCertPool,
|
||||
cipherSuites: tls.CipherSuites(),
|
||||
wantConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CipherSuites: []uint16{
|
||||
@@ -251,8 +251,8 @@ func TestBuildTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with no allowedCipherSuites, returns configuredCipherSuites",
|
||||
configuredCipherSuites: func() []*tls.CipherSuite {
|
||||
name: "with no userConfiguredAllowedCipherSuites, returns cipherSuites",
|
||||
cipherSuites: func() []*tls.CipherSuite {
|
||||
result := tls.CipherSuites()
|
||||
return result[:2]
|
||||
}(),
|
||||
@@ -266,10 +266,10 @@ func TestBuildTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with allowed Ciphers, restricts CipherSuites to just those ciphers",
|
||||
rootCAs: aCertPool,
|
||||
configuredCipherSuites: tls.CipherSuites(),
|
||||
allowedCipherIDs: []uint16{
|
||||
name: "with allowed Ciphers, restricts CipherSuites to just those ciphers",
|
||||
rootCAs: aCertPool,
|
||||
cipherSuites: tls.CipherSuites(),
|
||||
userConfiguredAllowedCipherSuiteIDs: []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
},
|
||||
@@ -284,9 +284,9 @@ func TestBuildTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with allowed ciphers in random order, returns ciphers in the order from configuredCipherSuites",
|
||||
configuredCipherSuites: tls.CipherSuites(),
|
||||
allowedCipherIDs: []uint16{
|
||||
name: "with allowed ciphers in random order, returns ciphers in the order from cipherSuites",
|
||||
cipherSuites: tls.CipherSuites(),
|
||||
userConfiguredAllowedCipherSuiteIDs: []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
@@ -309,16 +309,16 @@ func TestBuildTLSConfig(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowedCipherSuites := make([]*tls.CipherSuite, 0)
|
||||
for _, allowedCipher := range test.allowedCipherIDs {
|
||||
userConfiguredAllowedCipherSuites := make([]*tls.CipherSuite, 0)
|
||||
for _, allowedCipher := range test.userConfiguredAllowedCipherSuiteIDs {
|
||||
for _, cipherSuite := range tls.CipherSuites() {
|
||||
if allowedCipher == cipherSuite.ID {
|
||||
allowedCipherSuites = append(allowedCipherSuites, cipherSuite)
|
||||
userConfiguredAllowedCipherSuites = append(userConfiguredAllowedCipherSuites, cipherSuite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actualConfig := buildTLSConfig(test.rootCAs, test.configuredCipherSuites, allowedCipherSuites)
|
||||
actualConfig := buildTLSConfig(test.rootCAs, test.cipherSuites, userConfiguredAllowedCipherSuites)
|
||||
require.Equal(t, test.wantConfig, actualConfig)
|
||||
})
|
||||
}
|
||||
@@ -328,19 +328,19 @@ func TestValidateAllowedCiphers(t *testing.T) {
|
||||
cipherSuites := tls.CipherSuites()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
hardCodedCipherSuites []*tls.CipherSuite
|
||||
userConfiguredCiphersAllowList []string
|
||||
wantCipherSuites []*tls.CipherSuite
|
||||
wantErr string
|
||||
name string
|
||||
cipherSuites []*tls.CipherSuite
|
||||
userConfiguredAllowedCipherSuites []string
|
||||
wantCipherSuites []*tls.CipherSuite
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "empty inputs result in empty outputs",
|
||||
},
|
||||
{
|
||||
name: "with all valid inputs, returns the ciphers",
|
||||
hardCodedCipherSuites: cipherSuites,
|
||||
userConfiguredCiphersAllowList: []string{
|
||||
name: "with all valid inputs, returns the ciphers",
|
||||
cipherSuites: cipherSuites,
|
||||
userConfiguredAllowedCipherSuites: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
@@ -360,9 +360,9 @@ func TestValidateAllowedCiphers(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "with all valid inputs, allows some legacy cipher names and returns the ciphers",
|
||||
hardCodedCipherSuites: cipherSuites,
|
||||
userConfiguredCiphersAllowList: []string{
|
||||
name: "with all valid inputs, allows some legacy cipher names and returns the ciphers",
|
||||
cipherSuites: cipherSuites,
|
||||
userConfiguredAllowedCipherSuites: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
},
|
||||
@@ -380,15 +380,15 @@ func TestValidateAllowedCiphers(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "with invalid input, return an error with all known ciphers",
|
||||
hardCodedCipherSuites: cipherSuites[:2],
|
||||
userConfiguredCiphersAllowList: []string{"foo"},
|
||||
wantErr: "unrecognized ciphers [foo], ciphers must be from list [TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384]",
|
||||
name: "with invalid input, return an error with all known ciphers",
|
||||
cipherSuites: cipherSuites[:2],
|
||||
userConfiguredAllowedCipherSuites: []string{"foo"},
|
||||
wantErr: "unrecognized ciphers [foo], ciphers must be from list [TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384]",
|
||||
},
|
||||
{
|
||||
name: "with some valid and some invalid input, return an error with all known ciphers",
|
||||
hardCodedCipherSuites: cipherSuites[6:9],
|
||||
userConfiguredCiphersAllowList: []string{
|
||||
name: "with some valid and some invalid input, return an error with all known ciphers",
|
||||
cipherSuites: cipherSuites[6:9],
|
||||
userConfiguredAllowedCipherSuites: []string{
|
||||
"foo",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"bar",
|
||||
@@ -401,7 +401,7 @@ func TestValidateAllowedCiphers(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual, err := validateAllowedCiphers(test.hardCodedCipherSuites, test.userConfiguredCiphersAllowList)
|
||||
actual, err := validateAllowedCiphers(test.cipherSuites, test.userConfiguredAllowedCipherSuites)
|
||||
if len(test.wantErr) > 0 {
|
||||
require.ErrorContains(t, err, test.wantErr)
|
||||
} else {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
func cipherSuiteNames(ciphers []uint16) []string {
|
||||
func cipherSuiteNamesForCipherSuites(ciphers []uint16) []string {
|
||||
names := make([]string, len(ciphers))
|
||||
for i, suite := range ciphers {
|
||||
names[i] = tls.CipherSuiteName(suite)
|
||||
@@ -17,7 +17,7 @@ func cipherSuiteNames(ciphers []uint16) []string {
|
||||
return names
|
||||
}
|
||||
|
||||
func versionName(tlsVersion uint16) string {
|
||||
func tlsVersionName(tlsVersion uint16) string {
|
||||
if tlsVersion == 0 {
|
||||
return "NONE"
|
||||
}
|
||||
@@ -27,9 +27,9 @@ func versionName(tlsVersion uint16) string {
|
||||
func logProfile(name string, log plog.Logger, profile *tls.Config) {
|
||||
log.Info("tls configuration",
|
||||
"profile name", name,
|
||||
"MinVersion", versionName(profile.MinVersion),
|
||||
"MaxVersion", versionName(profile.MaxVersion),
|
||||
"CipherSuites", cipherSuiteNames(profile.CipherSuites),
|
||||
"MinVersion", tlsVersionName(profile.MinVersion),
|
||||
"MaxVersion", tlsVersionName(profile.MaxVersion),
|
||||
"CipherSuites", cipherSuiteNamesForCipherSuites(profile.CipherSuites),
|
||||
"NextProtos", profile.NextProtos,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ const SecureTLSConfigMinTLSVersion = tls.VersionTLS13
|
||||
// Default returns a tls.Config with a minimum of TLS1.2+ and a few ciphers that can be further constrained by configuration.
|
||||
func Default(rootCAs *x509.CertPool) *tls.Config {
|
||||
ciphers := translateIDIntoSecureCipherSuites(secureCipherSuiteIDs)
|
||||
return buildTLSConfig(rootCAs, ciphers, getUserConfiguredCiphersAllowList())
|
||||
return buildTLSConfig(rootCAs, ciphers, getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo())
|
||||
}
|
||||
|
||||
// DefaultLDAP TLS profile should be used by clients who need to interact with potentially old LDAP servers
|
||||
@@ -108,7 +108,7 @@ func Default(rootCAs *x509.CertPool) *tls.Config {
|
||||
func DefaultLDAP(rootCAs *x509.CertPool) *tls.Config {
|
||||
ciphers := translateIDIntoSecureCipherSuites(secureCipherSuiteIDs)
|
||||
ciphers = append(ciphers, translateIDIntoSecureCipherSuites(additionalSecureCipherSuiteIDsOnlyForLDAPClients)...)
|
||||
return buildTLSConfig(rootCAs, ciphers, getUserConfiguredCiphersAllowList())
|
||||
return buildTLSConfig(rootCAs, ciphers, getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo())
|
||||
}
|
||||
|
||||
// Secure TLS profile should be used by:
|
||||
|
||||
@@ -74,7 +74,7 @@ const SecureTLSConfigMinTLSVersion = tls.VersionTLS12
|
||||
// In FIPS mode, this will use the union of the secureCipherSuiteIDs, additionalSecureCipherSuiteIDsOnlyForLDAPClients,
|
||||
// and insecureCipherSuiteIDs values defined above.
|
||||
func Default(rootCAs *x509.CertPool) *tls.Config {
|
||||
config := buildTLSConfig(rootCAs, allHardcodedAllowedCipherSuites(), getUserConfiguredCiphersAllowList())
|
||||
config := buildTLSConfig(rootCAs, allHardcodedAllowedCipherSuites(), getUserConfiguredAllowedCipherSuitesForTLSOneDotTwo())
|
||||
// Until goboring supports TLS 1.3, make the max version 1.2.
|
||||
config.MaxVersion = tls.VersionTLS12
|
||||
return config
|
||||
|
||||
Reference in New Issue
Block a user