Skip to content

Commit 2646139

Browse files
authored
[fips] Add FIPS and non-FIPS implementations for allowed TLS curves (#13992)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description This PR introduces a new Go build tag, `requirefips`, that can be used (in the future) to build a FIPS-capable distribution of the OTel Collector. This PR uses this new build tag to create FIPS (`//go:build requirefips`) and non-FIPS (`//go:build !requirefips`) implementations of allowed TLS curves. The FIPS implementation contains all the TLS curves as the non-FIPS implementation except `X25519` and `X25519MLKEM768`. If these two curves were included in the FIPS distribution, running it with Golang >=1.24.6 and `GODEBUG=fips140=only` to surface non-FIPS-compliant algorithm uses will result in errors like so: ``` crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode ``` <!-- Issue number if applicable --> #### Link to tracking issue Fixes #13990 <!--Describe what testing was performed and which tests were added.--> #### Testing Run the existing `confighttp.TestHttpReception` unit test with Go >= 1.24.6 and `GODEBUG=fips140=only` to surface non-FIPS-compliant algorithm uses. ##### Without the `requirefips` build tag ``` $ go version go version go1.25.1 darwin/arm64 $ GODEBUG=fips140=only go test ./... -test.v -test.run TestHttpReception -count 1 === RUN TestHttpReception === RUN TestHttpReception/noTLS === RUN TestHttpReception/TLS server_test.go:267: Error Trace: /Users/shaunak/development/github/opentelemetry-collector/config/confighttp/server_test.go:267 Error: Received unexpected error: Get "https://127.0.0.1:64822": crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode Test: TestHttpReception/TLS === RUN TestHttpReception/TLS_(HTTP/1.1) server_test.go:267: Error Trace: /Users/shaunak/development/github/opentelemetry-collector/config/confighttp/server_test.go:267 Error: Received unexpected error: Get "https://127.0.0.1:64824": crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode Test: TestHttpReception/TLS_(HTTP/1.1) === RUN TestHttpReception/NoServerCertificates === RUN TestHttpReception/mTLS server_test.go:267: Error Trace: /Users/shaunak/development/github/opentelemetry-collector/config/confighttp/server_test.go:267 Error: Received unexpected error: Get "https://127.0.0.1:64828": crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode Test: TestHttpReception/mTLS === RUN TestHttpReception/NoClientCertificate === RUN TestHttpReception/WrongClientCA --- FAIL: TestHttpReception (0.03s) --- PASS: TestHttpReception/noTLS (0.01s) --- FAIL: TestHttpReception/TLS (0.01s) --- FAIL: TestHttpReception/TLS_(HTTP/1.1) (0.00s) --- PASS: TestHttpReception/NoServerCertificates (0.00s) --- FAIL: TestHttpReception/mTLS (0.01s) --- PASS: TestHttpReception/NoClientCertificate (0.00s) --- PASS: TestHttpReception/WrongClientCA (0.01s) FAIL FAIL go.opentelemetry.io/collector/config/confighttp 0.501s ? go.opentelemetry.io/collector/config/confighttp/internal [no test files] FAIL ``` ##### With the `requirefips` build tag ``` $ go version go version go1.25.1 darwin/arm64 $ GODEBUG=fips140=only go test -tags requirefips ./... -test.v -test.run TestHttpReception -count 1 === RUN TestHttpReception === RUN TestHttpReception/noTLS === RUN TestHttpReception/TLS === RUN TestHttpReception/TLS_(HTTP/1.1) === RUN TestHttpReception/NoServerCertificates === RUN TestHttpReception/mTLS === RUN TestHttpReception/NoClientCertificate === RUN TestHttpReception/WrongClientCA --- PASS: TestHttpReception (0.03s) --- PASS: TestHttpReception/noTLS (0.00s) --- PASS: TestHttpReception/TLS (0.01s) --- PASS: TestHttpReception/TLS_(HTTP/1.1) (0.00s) --- PASS: TestHttpReception/NoServerCertificates (0.00s) --- PASS: TestHttpReception/mTLS (0.01s) --- PASS: TestHttpReception/NoClientCertificate (0.00s) --- PASS: TestHttpReception/WrongClientCA (0.01s) PASS ok go.opentelemetry.io/collector/config/confighttp 0.493s ? go.opentelemetry.io/collector/config/confighttp/internal [no test files] ```
1 parent 8b09905 commit 2646139

File tree

6 files changed

+98
-23
lines changed

6 files changed

+98
-23
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: all
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add FIPS and non-FIPS implementations for allowed TLS curves
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [13990]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

.github/workflows/utils/cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"Excalidraw",
2727
"Expvar",
2828
"Fanout",
29+
"FIPS",
2930
"Funcs",
3031
"GHSA",
3132
"GOARCH",

config/configtls/configtls.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import (
99
"crypto/x509"
1010
"errors"
1111
"fmt"
12+
"maps"
1213
"os"
1314
"path/filepath"
15+
"slices"
1416
"sync"
1517
"time"
1618

@@ -268,15 +270,24 @@ func (c Config) loadTLSConfig() (*tls.Config, error) {
268270
if err != nil {
269271
return nil, err
270272
}
273+
274+
allowedCurves := slices.Collect(maps.Values(tlsCurveTypes))
271275
curvePreferences := make([]tls.CurveID, 0, len(c.CurvePreferences))
272276
for _, curve := range c.CurvePreferences {
273277
curveID, ok := tlsCurveTypes[curve]
274278
if !ok {
275-
return nil, fmt.Errorf("invalid curve type: %s. Expected values are [P-256, P-384, P-521, X25519, X25519MLKEM768]", curve)
279+
return nil, fmt.Errorf("invalid curve type: %s. Expected values are %s", curveID, allowedCurves)
276280
}
277281
curvePreferences = append(curvePreferences, curveID)
278282
}
279283

284+
// If no curve preferences were explicitly specified in the configuration, use
285+
// the ones we allow. This helps in particular with FIPS builds where not all curves
286+
// are allowed.
287+
if len(curvePreferences) == 0 {
288+
curvePreferences = allowedCurves
289+
}
290+
280291
return &tls.Config{
281292
RootCAs: certPool,
282293
GetCertificate: getCertificate,
@@ -501,11 +512,3 @@ var tlsVersions = map[string]uint16{
501512
"1.2": tls.VersionTLS12,
502513
"1.3": tls.VersionTLS13,
503514
}
504-
505-
var tlsCurveTypes = map[string]tls.CurveID{
506-
"P256": tls.CurveP256,
507-
"P384": tls.CurveP384,
508-
"P521": tls.CurveP521,
509-
"X25519": tls.X25519,
510-
"X25519MLKEM768": tls.X25519MLKEM768,
511-
}

config/configtls/configtls_test.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"io"
1313
"os"
1414
"path/filepath"
15+
"strings"
1516
"testing"
1617
"time"
1718

@@ -882,22 +883,14 @@ func TestSystemCertPool_loadCert(t *testing.T) {
882883
}
883884

884885
func TestCurvePreferences(t *testing.T) {
885-
tests := []struct {
886+
type testCase struct {
886887
name string
887888
preferences []string
888889
expectedCurveIDs []tls.CurveID
889890
expectedErr string
890-
}{
891-
{
892-
name: "X25519MLKEM768",
893-
preferences: []string{"X25519MLKEM768"},
894-
expectedCurveIDs: []tls.CurveID{tls.X25519MLKEM768},
895-
},
896-
{
897-
name: "X25519",
898-
preferences: []string{"X25519"},
899-
expectedCurveIDs: []tls.CurveID{tls.X25519},
900-
},
891+
}
892+
893+
tests := []testCase{
901894
{
902895
name: "P521",
903896
preferences: []string{"P521"},
@@ -910,8 +903,8 @@ func TestCurvePreferences(t *testing.T) {
910903
},
911904
{
912905
name: "multiple",
913-
preferences: []string{"P256", "P521", "X25519"},
914-
expectedCurveIDs: []tls.CurveID{tls.CurveP256, tls.CurveP521, tls.X25519},
906+
preferences: []string{"P256", "P521"},
907+
expectedCurveIDs: []tls.CurveID{tls.CurveP256, tls.CurveP521},
915908
},
916909
{
917910
name: "invalid-curve",
@@ -920,6 +913,24 @@ func TestCurvePreferences(t *testing.T) {
920913
expectedErr: "invalid curve type",
921914
},
922915
}
916+
917+
// X25519 curves are not supported when GODEBUG=fips140=only is set, so we
918+
// detect if it is and conditionally add test cases for those curves.
919+
if !strings.Contains(os.Getenv("GODEBUG"), "fips140=only") {
920+
tests = append(tests,
921+
testCase{
922+
name: "X25519MLKEM768",
923+
preferences: []string{"X25519MLKEM768"},
924+
expectedCurveIDs: []tls.CurveID{tls.X25519MLKEM768},
925+
},
926+
testCase{
927+
name: "X25519",
928+
preferences: []string{"X25519"},
929+
expectedCurveIDs: []tls.CurveID{tls.X25519},
930+
},
931+
)
932+
}
933+
923934
for _, test := range tests {
924935
t.Run(test.name, func(t *testing.T) {
925936
tlsSetting := ClientConfig{

config/configtls/curves_fips.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//go:build requirefips
5+
6+
package configtls // import "go.opentelemetry.io/collector/config/configtls"
7+
8+
import "crypto/tls"
9+
10+
var tlsCurveTypes = map[string]tls.CurveID{
11+
"P256": tls.CurveP256,
12+
"P384": tls.CurveP384,
13+
"P521": tls.CurveP521,
14+
15+
// The following X25519 curves are not available in FIPS mode, so we remove them from the map.
16+
// See also https://cs.opensource.google/go/go/+/refs/tags/go1.24.6:src/crypto/ecdh/x25519.go
17+
//"X25519": tls.X25519,
18+
//"X25519MLKEM768": tls.X25519MLKEM768,
19+
}

config/configtls/curves_nofips.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//go:build !requirefips
5+
6+
package configtls // import "go.opentelemetry.io/collector/config/configtls"
7+
8+
import "crypto/tls"
9+
10+
var tlsCurveTypes = map[string]tls.CurveID{
11+
"P256": tls.CurveP256,
12+
"P384": tls.CurveP384,
13+
"P521": tls.CurveP521,
14+
"X25519": tls.X25519,
15+
"X25519MLKEM768": tls.X25519MLKEM768,
16+
}

0 commit comments

Comments
 (0)