From 3f9540d41f43f6f085395859009d84f4cc01290d Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 4 Jun 2026 16:02:29 -0400 Subject: [PATCH] tlsprofiles: add SecP256r1MLKEM768, SecP384r1MLKEM1024, and secp256r1 alias Add the two NIST-curve ML-KEM post-quantum hybrids introduced in Go 1.26 to the custom curve map and local constants. Also add "secp256r1" as an alias for "prime256v1" using the IANA name for P-256. Co-Authored-By: Claude Sonnet 4.6 (1M context) Signed-off-by: Todd Short --- .../shared/util/tlsprofiles/tlsprofiles.go | 25 +++++++++++-------- .../util/tlsprofiles/tlsprofiles_test.go | 13 ++++++++-- test/e2e/features/tls.feature | 12 +++++++++ test/e2e/steps/steps.go | 2 ++ test/e2e/steps/tls_steps.go | 13 ++++++---- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/internal/shared/util/tlsprofiles/tlsprofiles.go b/internal/shared/util/tlsprofiles/tlsprofiles.go index b09fd4d125..968ae65b13 100644 --- a/internal/shared/util/tlsprofiles/tlsprofiles.go +++ b/internal/shared/util/tlsprofiles/tlsprofiles.go @@ -69,19 +69,24 @@ func cipherSuiteId(name string) uint16 { // This is primarily so that we don't have to rewrite curve values in mozilla_data.go const ( - X25519MLKEM768 tls.CurveID = tls.X25519MLKEM768 - X25519 tls.CurveID = tls.X25519 - prime256v1 tls.CurveID = tls.CurveP256 - secp384r1 tls.CurveID = tls.CurveP384 - secp521r1 tls.CurveID = tls.CurveP521 + X25519MLKEM768 tls.CurveID = tls.X25519MLKEM768 + X25519 tls.CurveID = tls.X25519 + prime256v1 tls.CurveID = tls.CurveP256 + secp384r1 tls.CurveID = tls.CurveP384 + secp521r1 tls.CurveID = tls.CurveP521 + SecP256r1MLKEM768 tls.CurveID = tls.SecP256r1MLKEM768 + SecP384r1MLKEM1024 tls.CurveID = tls.SecP384r1MLKEM1024 ) var curves = map[string]tls.CurveID{ - "X25519MLKEM768": tls.X25519MLKEM768, - "X25519": tls.X25519, - "prime256v1": tls.CurveP256, - "secp384r1": tls.CurveP384, - "secp521r1": tls.CurveP521, + "X25519MLKEM768": tls.X25519MLKEM768, + "X25519": tls.X25519, + "prime256v1": tls.CurveP256, + "secp256r1": tls.CurveP256, // IANA name for prime256v1 + "secp384r1": tls.CurveP384, + "secp521r1": tls.CurveP521, + "SecP256r1MLKEM768": tls.SecP256r1MLKEM768, + "SecP384r1MLKEM1024": tls.SecP384r1MLKEM1024, } // Returns 0 for an invalid curve name diff --git a/internal/shared/util/tlsprofiles/tlsprofiles_test.go b/internal/shared/util/tlsprofiles/tlsprofiles_test.go index 9c8075f4b0..d218997867 100644 --- a/internal/shared/util/tlsprofiles/tlsprofiles_test.go +++ b/internal/shared/util/tlsprofiles/tlsprofiles_test.go @@ -94,12 +94,15 @@ func TestSetCustomCurves(t *testing.T) { name string result bool }{ - {"X25519MLKEM768", true}, // Post-quantum hybrid curve (Go 1.24+) + {"X25519MLKEM768", true}, // Post-quantum hybrid (Go 1.24+) + {"SecP256r1MLKEM768", true}, // Post-quantum hybrid (Go 1.26+) + {"SecP384r1MLKEM1024", true}, // Post-quantum hybrid (Go 1.26+) {"X25519", true}, {"prime256v1", true}, + {"secp256r1", true}, // IANA alias for prime256v1 {"secp384r1", true}, {"secp521r1", true}, - {"unknown-cuve", false}, + {"unknown-curve", false}, {"X448", false}, // Valid OpenSSL curve, not implemented {"X25519,prime256v1", true}, // Multiple } @@ -115,6 +118,12 @@ func TestSetCustomCurves(t *testing.T) { } } +func TestSecp256r1AliasesPrime256v1(t *testing.T) { + require.Equal(t, curveId("prime256v1"), curveId("secp256r1"), + "secp256r1 and prime256v1 must resolve to the same tls.CurveID") + require.Equal(t, tls.CurveP256, curveId("secp256r1")) +} + func TestSetCustomVersion(t *testing.T) { var version tlsVersion diff --git a/test/e2e/features/tls.feature b/test/e2e/features/tls.feature index ba43f74141..39b399d17a 100644 --- a/test/e2e/features/tls.feature +++ b/test/e2e/features/tls.feature @@ -33,3 +33,15 @@ Feature: TLS profile enforcement on metrics endpoints Given the "catalogd" deployment is configured with custom TLS version "TLSv1.2", ciphers "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", and curves "prime256v1" Then the "catalogd" metrics endpoint accepts a TLS 1.2 connection with cipher "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" and curve "prime256v1" And the "catalogd" metrics endpoint rejects a TLS 1.2 connection with cipher "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" and only curve "secp521r1" + + @TLSProfile + Scenario: catalogd metrics endpoint accepts secp256r1 as the IANA name for prime256v1 + Given the "catalogd" deployment is configured with custom TLS version "TLSv1.2", ciphers "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", and curves "secp256r1" + Then the "catalogd" metrics endpoint accepts a TLS 1.2 connection with cipher "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" and curve "secp256r1" + And the "catalogd" metrics endpoint rejects a TLS 1.2 connection with cipher "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" and only curve "secp521r1" + + @TLSProfile + Scenario: catalogd metrics endpoint accepts connections using post-quantum hybrid curves + Given the "catalogd" deployment is configured with custom TLS version "TLSv1.2", ciphers "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", and curves "SecP256r1MLKEM768,secp256r1" + Then the "catalogd" metrics endpoint accepts a connection using only curve "SecP256r1MLKEM768" + And the "catalogd" metrics endpoint rejects a connection using only curve "secp521r1" diff --git a/test/e2e/steps/steps.go b/test/e2e/steps/steps.go index 3412619fec..00a10ea64f 100644 --- a/test/e2e/steps/steps.go +++ b/test/e2e/steps/steps.go @@ -195,6 +195,8 @@ func RegisterSteps(sc *godog.ScenarioContext) { sc.Step(`^(?i)the "([^"]+)" metrics endpoint rejects a TLS 1\.2 connection offering only cipher "([^"]+)"$`, MetricsEndpointRejectsTLS12ConnectionWithCipher) sc.Step(`^(?i)the "([^"]+)" metrics endpoint accepts a TLS 1\.2 connection with cipher "([^"]+)" and curve "([^"]+)"$`, MetricsEndpointAcceptsTLS12ConnectionWithCurve) sc.Step(`^(?i)the "([^"]+)" metrics endpoint rejects a TLS 1\.2 connection with cipher "([^"]+)" and only curve "([^"]+)"$`, MetricsEndpointRejectsTLS12ConnectionWithCurve) + sc.Step(`^(?i)the "([^"]+)" metrics endpoint accepts a connection using only curve "([^"]+)"$`, MetricsEndpointAcceptsConnectionUsingCurve) + sc.Step(`^(?i)the "([^"]+)" metrics endpoint rejects a connection using only curve "([^"]+)"$`, MetricsEndpointRejectsConnectionUsingOnlyCurve) // Upgrade-specific steps sc.Step(`^(?i)the latest stable OLM release is installed$`, LatestStableOLMReleaseIsInstalled) diff --git a/test/e2e/steps/tls_steps.go b/test/e2e/steps/tls_steps.go index 4fad45d83e..66c381d59c 100644 --- a/test/e2e/steps/tls_steps.go +++ b/test/e2e/steps/tls_steps.go @@ -46,11 +46,14 @@ func tlsCipherSuiteName(id uint16) string { // curveIDByName maps the curve names used in --tls-custom-curves flags to Go CurveID values. var curveIDByName = map[string]tls.CurveID{ - "X25519MLKEM768": tls.X25519MLKEM768, - "X25519": tls.X25519, - "prime256v1": tls.CurveP256, - "secp384r1": tls.CurveP384, - "secp521r1": tls.CurveP521, + "X25519MLKEM768": tls.X25519MLKEM768, + "SecP256r1MLKEM768": tls.SecP256r1MLKEM768, + "SecP384r1MLKEM1024": tls.SecP384r1MLKEM1024, + "X25519": tls.X25519, + "prime256v1": tls.CurveP256, + "secp256r1": tls.CurveP256, // IANA name for prime256v1 + "secp384r1": tls.CurveP384, + "secp521r1": tls.CurveP521, } // getMetricsService returns the full Service object for the named component's metrics service.