Skip to content

Commit 31a870b

Browse files
lmpnjcsf
authored andcommitted
TUN-8855: Update PQ curve preferences
## Summary Nowadays, Cloudflared only supports X25519Kyber768Draft00 (0x6399,25497) but older versions may use different preferences. For FIPS compliance we are required to use P256Kyber768Draft00 (0xfe32,65074) which is supported in our internal fork of [Go-Boring-1.22.10](https://bitbucket.cfdata.org/projects/PLAT/repos/goboring/browse?at=refs/heads/go-boring/1.22.10 "Follow link"). In the near future, Go will support by default the X25519MLKEM768 (0x11ec,4588) given this we may drop the usage of our public fork of GO. To summarise: * Cloudflared FIPS: QUIC_CURVE_PREFERENCES=65074 * Cloudflared non-FIPS: QUIC_CURVE_PREFERENCES=4588 Closes TUN-8855
1 parent bfdb0c7 commit 31a870b

File tree

11 files changed

+150
-41
lines changed

11 files changed

+150
-41
lines changed

Makefile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,9 @@ clean:
133133
cloudflared:
134134
ifeq ($(FIPS), true)
135135
$(info Building cloudflared with go-fips)
136-
cp -f fips/fips.go.linux-amd64 cmd/cloudflared/fips.go
137136
endif
138137
GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) $(ARM_COMMAND) go build -mod=vendor $(GO_BUILD_TAGS) $(LDFLAGS) $(IMPORT_PATH)/cmd/cloudflared
139138
ifeq ($(FIPS), true)
140-
rm -f cmd/cloudflared/fips.go
141139
./check-fips.sh cloudflared
142140
endif
143141

cmd/cloudflared/tunnel/cmd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/cloudflare/cloudflared/credentials"
3232
"github.com/cloudflare/cloudflared/diagnostic"
3333
"github.com/cloudflare/cloudflared/edgediscovery"
34+
"github.com/cloudflare/cloudflared/fips"
3435
"github.com/cloudflare/cloudflared/ingress"
3536
"github.com/cloudflare/cloudflared/logger"
3637
"github.com/cloudflare/cloudflared/management"
@@ -925,7 +926,7 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
925926
Usage: "When given creates an experimental post-quantum secure tunnel",
926927
Aliases: []string{"pq"},
927928
EnvVars: []string{"TUNNEL_POST_QUANTUM"},
928-
Hidden: FipsEnabled,
929+
Hidden: fips.IsFipsEnabled(),
929930
}),
930931
altsrc.NewBoolFlag(&cli.BoolFlag{
931932
Name: "management-diagnostics",

cmd/cloudflared/tunnel/configuration.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/cloudflare/cloudflared/edgediscovery"
2424
"github.com/cloudflare/cloudflared/edgediscovery/allregions"
2525
"github.com/cloudflare/cloudflared/features"
26+
"github.com/cloudflare/cloudflared/fips"
2627
"github.com/cloudflare/cloudflared/ingress"
2728
"github.com/cloudflare/cloudflared/orchestration"
2829
"github.com/cloudflare/cloudflared/supervisor"
@@ -124,7 +125,7 @@ func prepareTunnelConfig(
124125

125126
transportProtocol := c.String("protocol")
126127

127-
if c.Bool("post-quantum") && FipsEnabled {
128+
if c.Bool("post-quantum") && fips.IsFipsEnabled() {
128129
return nil, nil, fmt.Errorf("post-quantum not supported in FIPS mode")
129130
}
130131

@@ -140,11 +141,6 @@ func prepareTunnelConfig(
140141
return nil, nil, fmt.Errorf("post-quantum is only supported with the quic transport")
141142
}
142143
transportProtocol = connection.QUIC.String()
143-
144-
log.Info().Msgf(
145-
"Using hybrid post-quantum key agreement %s",
146-
supervisor.PQKexName,
147-
)
148144
}
149145

150146
namedTunnel.Client = pogs.ClientInfo{

cmd/cloudflared/tunnel/fips.go

Lines changed: 0 additions & 3 deletions
This file was deleted.

cmd/cloudflared/tunnel/subcommands.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/cloudflare/cloudflared/config"
3030
"github.com/cloudflare/cloudflared/connection"
3131
"github.com/cloudflare/cloudflared/diagnostic"
32+
"github.com/cloudflare/cloudflared/fips"
3233
"github.com/cloudflare/cloudflared/metrics"
3334
)
3435

@@ -148,7 +149,7 @@ var (
148149
Usage: "When given creates an experimental post-quantum secure tunnel",
149150
Aliases: []string{"pq"},
150151
EnvVars: []string{"TUNNEL_POST_QUANTUM"},
151-
Hidden: FipsEnabled,
152+
Hidden: fips.IsFipsEnabled(),
152153
})
153154
sortInfoByFlag = &cli.StringFlag{
154155
Name: "sort-by",

fips/fips.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build fips
2+
3+
package fips
4+
5+
import (
6+
_ "crypto/tls/fipsonly"
7+
)
8+
9+
func IsFipsEnabled() bool {
10+
return true
11+
}

fips/fips.go.linux-amd64

Lines changed: 0 additions & 12 deletions
This file was deleted.

fips/nofips.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build !fips
2+
3+
package fips
4+
5+
func IsFipsEnabled() bool {
6+
return false
7+
}

supervisor/pqtunnels.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,53 @@ import (
77
"github.com/cloudflare/cloudflared/features"
88
)
99

10-
// When experimental post-quantum tunnels are enabled, and we're hitting an
11-
// issue creating the tunnel, we'll report the first error
12-
// to https://pqtunnels.cloudflareresearch.com.
13-
1410
const (
15-
PQKex = tls.CurveID(0x6399) // X25519Kyber768Draft00
16-
PQKexName = "X25519Kyber768Draft00"
11+
X25519Kyber768Draft00PQKex = tls.CurveID(0x6399) // X25519Kyber768Draft00
12+
X25519Kyber768Draft00PQKexName = "X25519Kyber768Draft00"
13+
P256Kyber768Draft00PQKex = tls.CurveID(0xfe32) // P256Kyber768Draft00
14+
P256Kyber768Draft00PQKexName = "P256Kyber768Draft00"
15+
X25519MLKEM768PQKex = tls.CurveID(0x11ec) // X25519MLKEM768
16+
X25519MLKEM768PQKexName = "X25519MLKEM768"
17+
)
18+
19+
var (
20+
nonFipsPostQuantumStrictPKex []tls.CurveID = []tls.CurveID{X25519MLKEM768PQKex, X25519Kyber768Draft00PQKex}
21+
nonFipsPostQuantumPreferPKex []tls.CurveID = []tls.CurveID{X25519MLKEM768PQKex, X25519Kyber768Draft00PQKex}
22+
fipsPostQuantumStrictPKex []tls.CurveID = []tls.CurveID{P256Kyber768Draft00PQKex}
23+
fipsPostQuantumPreferPKex []tls.CurveID = []tls.CurveID{P256Kyber768Draft00PQKex, tls.CurveP256}
1724
)
1825

19-
func curvePreference(pqMode features.PostQuantumMode, currentCurve []tls.CurveID) ([]tls.CurveID, error) {
26+
func removeDuplicates(curves []tls.CurveID) []tls.CurveID {
27+
bucket := make(map[tls.CurveID]bool)
28+
var result []tls.CurveID
29+
for _, curve := range curves {
30+
if _, ok := bucket[curve]; !ok {
31+
bucket[curve] = true
32+
result = append(result, curve)
33+
}
34+
}
35+
return result
36+
}
37+
38+
func curvePreference(pqMode features.PostQuantumMode, fipsEnabled bool, currentCurve []tls.CurveID) ([]tls.CurveID, error) {
2039
switch pqMode {
2140
case features.PostQuantumStrict:
2241
// If the user passes the -post-quantum flag, we override
2342
// CurvePreferences to only support hybrid post-quantum key agreements.
24-
return []tls.CurveID{PQKex}, nil
25-
case features.PostQuantumPrefer:
26-
if len(currentCurve) == 0 {
27-
return []tls.CurveID{PQKex}, nil
43+
if fipsEnabled {
44+
return fipsPostQuantumStrictPKex, nil
2845
}
29-
30-
if currentCurve[0] != PQKex {
31-
return append([]tls.CurveID{PQKex}, currentCurve...), nil
46+
return nonFipsPostQuantumStrictPKex, nil
47+
case features.PostQuantumPrefer:
48+
if fipsEnabled {
49+
// Ensure that all curves returned are FIPS compliant.
50+
// Moreover the first curves are post-quantum and then the
51+
// non post-quantum.
52+
return fipsPostQuantumPreferPKex, nil
3253
}
33-
return currentCurve, nil
54+
curves := append(nonFipsPostQuantumPreferPKex, currentCurve...)
55+
curves = removeDuplicates(curves)
56+
return curves, nil
3457
default:
3558
return nil, fmt.Errorf("Unexpected post quantum mode")
3659
}

supervisor/pqtunnels_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package supervisor
2+
3+
import (
4+
"crypto/tls"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/cloudflare/cloudflared/features"
11+
)
12+
13+
func TestCurvePreferences(t *testing.T) {
14+
// This tests if the correct curves are returned
15+
// given a PostQuantumMode and a FIPS enabled bool
16+
t.Parallel()
17+
18+
tests := []struct {
19+
name string
20+
currentCurves []tls.CurveID
21+
expectedCurves []tls.CurveID
22+
pqMode features.PostQuantumMode
23+
fipsEnabled bool
24+
}{
25+
{
26+
name: "FIPS with Prefer PQ",
27+
pqMode: features.PostQuantumPrefer,
28+
fipsEnabled: true,
29+
currentCurves: []tls.CurveID{tls.CurveP384},
30+
expectedCurves: []tls.CurveID{P256Kyber768Draft00PQKex, tls.CurveP256},
31+
},
32+
{
33+
name: "FIPS with Strict PQ",
34+
pqMode: features.PostQuantumStrict,
35+
fipsEnabled: true,
36+
currentCurves: []tls.CurveID{tls.CurveP256, tls.CurveP384},
37+
expectedCurves: []tls.CurveID{P256Kyber768Draft00PQKex},
38+
},
39+
{
40+
name: "FIPS with Prefer PQ - no duplicates",
41+
pqMode: features.PostQuantumPrefer,
42+
fipsEnabled: true,
43+
currentCurves: []tls.CurveID{tls.CurveP256},
44+
expectedCurves: []tls.CurveID{P256Kyber768Draft00PQKex, tls.CurveP256},
45+
},
46+
{
47+
name: "Non FIPS with Prefer PQ",
48+
pqMode: features.PostQuantumPrefer,
49+
fipsEnabled: false,
50+
currentCurves: []tls.CurveID{tls.CurveP256},
51+
expectedCurves: []tls.CurveID{X25519MLKEM768PQKex, X25519Kyber768Draft00PQKex, tls.CurveP256},
52+
},
53+
{
54+
name: "Non FIPS with Prefer PQ - no duplicates",
55+
pqMode: features.PostQuantumPrefer,
56+
fipsEnabled: false,
57+
currentCurves: []tls.CurveID{X25519Kyber768Draft00PQKex, tls.CurveP256},
58+
expectedCurves: []tls.CurveID{X25519MLKEM768PQKex, X25519Kyber768Draft00PQKex, tls.CurveP256},
59+
},
60+
{
61+
name: "Non FIPS with Prefer PQ - correct preference order",
62+
pqMode: features.PostQuantumPrefer,
63+
fipsEnabled: false,
64+
currentCurves: []tls.CurveID{tls.CurveP256, X25519Kyber768Draft00PQKex},
65+
expectedCurves: []tls.CurveID{X25519MLKEM768PQKex, X25519Kyber768Draft00PQKex, tls.CurveP256},
66+
},
67+
{
68+
name: "Non FIPS with Strict PQ",
69+
pqMode: features.PostQuantumStrict,
70+
fipsEnabled: false,
71+
currentCurves: []tls.CurveID{tls.CurveP256},
72+
expectedCurves: []tls.CurveID{X25519MLKEM768PQKex, X25519Kyber768Draft00PQKex},
73+
},
74+
}
75+
76+
for _, tcase := range tests {
77+
t.Run(tcase.name, func(t *testing.T) {
78+
t.Parallel()
79+
curves, err := curvePreference(tcase.pqMode, tcase.fipsEnabled, tcase.currentCurves)
80+
require.NoError(t, err)
81+
assert.Equal(t, tcase.expectedCurves, curves)
82+
})
83+
}
84+
}

0 commit comments

Comments
 (0)