diff --git a/.chloggen/add-curve-preferences-tls.yaml b/.chloggen/add-curve-preferences-tls.yaml new file mode 100644 index 00000000000..82aeb1496f7 --- /dev/null +++ b/.chloggen/add-curve-preferences-tls.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: configtls + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Allow users to mention their preferred curve types for ECDHE handshake + +# One or more tracking issues or pull requests related to the change +issues: [12174] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/config/configtls/README.md b/config/configtls/README.md index b7ea4e84e76..f91636287bb 100644 --- a/config/configtls/README.md +++ b/config/configtls/README.md @@ -14,6 +14,12 @@ By default, TLS is enabled: the exporter's HTTPs or gRPC connection. See [grpc.WithInsecure()](https://godoc.org/google.golang.org/grpc#WithInsecure) for gRPC. +- `curve_preferences` (default = []): specify your curve preferences that will + be used in an ECDHE handshake, in preference order. Accepted values are: + - X25519 + - P521 + - P256 + - P384 As a result, the following parameters are also required: diff --git a/config/configtls/configtls.go b/config/configtls/configtls.go index 0cbcc5f4072..8b2c6ea2674 100644 --- a/config/configtls/configtls.go +++ b/config/configtls/configtls.go @@ -70,6 +70,11 @@ type Config struct { // ReloadInterval specifies the duration after which the certificate will be reloaded // If not set, it will never be reloaded (optional) ReloadInterval time.Duration `mapstructure:"reload_interval"` + + // contains the elliptic curves that will be used in + // an ECDHE handshake, in preference order + // Defaults to empty list and "crypto/tls" defaults are used, internally. + CurvePreferences []string `mapstructure:"curve_preferences"` } // NewDefaultConfig creates a new TLSSetting with any default values set. @@ -231,6 +236,14 @@ func (c Config) loadTLSConfig() (*tls.Config, error) { if err != nil { return nil, err } + curvePreferences := make([]tls.CurveID, 0, len(c.CurvePreferences)) + for _, curve := range c.CurvePreferences { + curveID, ok := tlsCurveTypes[curve] + if !ok { + return nil, fmt.Errorf("invalid curve type: %s. Expected values are [P-256, P-384, P-521, X25519]", curveID) + } + curvePreferences = append(curvePreferences, curveID) + } return &tls.Config{ RootCAs: certPool, @@ -239,6 +252,7 @@ func (c Config) loadTLSConfig() (*tls.Config, error) { MinVersion: minTLS, MaxVersion: maxTLS, CipherSuites: cipherSuites, + CurvePreferences: curvePreferences, }, nil } @@ -448,3 +462,10 @@ var tlsVersions = map[string]uint16{ "1.2": tls.VersionTLS12, "1.3": tls.VersionTLS13, } + +var tlsCurveTypes = map[string]tls.CurveID{ + "P256": tls.CurveP256, + "P384": tls.CurveP384, + "P521": tls.CurveP521, + "X25519": tls.X25519, +} diff --git a/config/configtls/configtls_test.go b/config/configtls/configtls_test.go index 2f1f1fb3439..823c35e7f9a 100644 --- a/config/configtls/configtls_test.go +++ b/config/configtls/configtls_test.go @@ -871,3 +871,53 @@ func TestSystemCertPool_loadCert(t *testing.T) { }) } } + +func TestCurvePreferences(t *testing.T) { + tests := []struct { + name string + preferences []string + expectedCurveIDs []tls.CurveID + expectedErr string + }{ + { + name: "X25519", + preferences: []string{"X25519"}, + expectedCurveIDs: []tls.CurveID{tls.X25519}, + }, + { + name: "P521", + preferences: []string{"P521"}, + expectedCurveIDs: []tls.CurveID{tls.CurveP521}, + }, + { + name: "P-256", + preferences: []string{"P256"}, + expectedCurveIDs: []tls.CurveID{tls.CurveP256}, + }, + { + name: "multiple", + preferences: []string{"P256", "P521", "X25519"}, + expectedCurveIDs: []tls.CurveID{tls.CurveP256, tls.CurveP521, tls.X25519}, + }, + { + name: "invalid-curve", + preferences: []string{"P25223236"}, + expectedCurveIDs: []tls.CurveID{}, + expectedErr: "invalid curve type", + }, + } + for _, test := range tests { + tlsSetting := ClientConfig{ + Config: Config{ + CurvePreferences: test.preferences, + }, + } + config, err := tlsSetting.LoadTLSConfig(context.Background()) + if test.expectedErr == "" { + require.NoError(t, err) + require.ElementsMatchf(t, test.expectedCurveIDs, config.CurvePreferences, "expected %v, got %v", test.expectedCurveIDs, config.CurvePreferences) + } else { + require.ErrorContains(t, err, test.expectedErr) + } + } +}