Use FIPS-safe default curve (P-256) instead of X25519#817
Use FIPS-safe default curve (P-256) instead of X25519#817JoTurk merged 3 commits intopion:masterfrom
Conversation
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (16.66%) is below the target coverage (70.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #817 +/- ##
==========================================
- Coverage 82.64% 82.49% -0.15%
==========================================
Files 121 121
Lines 6858 6868 +10
==========================================
- Hits 5668 5666 -2
- Misses 779 787 +8
- Partials 411 415 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
158daa0 to
0e14a77
Compare
theodorsm
left a comment
There was a problem hiding this comment.
Hey, Thanks for discovering this issue and fixing it so fast! Compliance to FIPS is imporant to do right and I'm sure others will be happy for this to be fixed.
I have left some comments on the changing of prefered default order.
| const defaultMTU = 1200 // bytes | ||
|
|
||
| var defaultCurves = []elliptic.Curve{elliptic.X25519, elliptic.P256, elliptic.P384} //nolint:gochecknoglobals | ||
| var defaultCurves = []elliptic.Curve{elliptic.P256, elliptic.P384, elliptic.X25519} //nolint:gochecknoglobals |
There was a problem hiding this comment.
We should not change this order, this is the standard followed by other DTLS-implementations such as NSS (firefox), boringssl (chrome). OpenSSL also seem to have X25519 prefered by default. This might affect interopt and allow the library to be fingerprintable more easily.
There was a problem hiding this comment.
@theodorsm @samthesloth Okay what if we only switch if fips is enabled? https://pkg.go.dev/crypto/fips140#Enabled i think that would be a good compromise.
| cookieLength = 20 | ||
| sessionLength = 32 | ||
| defaultNamedCurve = elliptic.X25519 | ||
| defaultNamedCurve = elliptic.P256 |
There was a problem hiding this comment.
I guess we could remove this const as it's not needed anymore.
There was a problem hiding this comment.
@theodorsm Maybe we use a func instead that goes through the list, skipping X25519 if FIPS is enabled as @JoTurk suggested?
There was a problem hiding this comment.
I agree, that sounds like the way to go!
|
@theodorsm Hello again! Sorry if I'm doing this wrong. I think I implemented a proper change, but please let me know if I need to change how I went about it or how I pushed it! Thank you! |
theodorsm
left a comment
There was a problem hiding this comment.
@samthesloth, no worries! Thinking a bit more about it, we should move the FIPS check as early as possible. Left some comments on how we can approach this.
| if fips140.Enabled() { | ||
| // On FIPS systems, skip non-approved curves | ||
| for _, c := range curves { | ||
| if c != elliptic.X25519 { | ||
| return c | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Let's move this check to just after we set the curves, and drop the function:
Lines 178 to 181 in d0e736c
We are using cfg.ellipticCurves in other flights to set the SupportedEllipticCurves extension, ex:
Lines 297 to 301 in d0e736c
So if we filter earlier, we avoid announcing non-FIPS curves in the extension also.
| state.localEpoch.Store(zeroEpoch) | ||
| state.remoteEpoch.Store(zeroEpoch) | ||
| state.namedCurve = defaultNamedCurve | ||
| state.namedCurve = defaultCurve(cfg.ellipticCurves) |
There was a problem hiding this comment.
After moving the check in conn.go we should check for length here:
if len(cfg.ellipticCurves) < 1 {
return nil,nil,errEmptyEllipticCurves
}
state.namedCurve = cfg.ellipticCurves[0]
| state.localEpoch.Store(zeroEpoch) | ||
| state.remoteEpoch.Store(zeroEpoch) | ||
| state.namedCurve = defaultNamedCurve | ||
| state.namedCurve = defaultCurve(cfg.ellipticCurves) |
There was a problem hiding this comment.
Also check length here if we move check in conn.go.
|
@samthesloth, this looks really good now! Could you also re-try what you reported in your inital issue #816 to verify that this fixes your use case? |
|
Hello! Sorry for the late reply. I was having some issues recreating everything. I tested on Rocky Linux 9 with Go 1.26.1. I confirmed that The exact partial-enforcement scenario from my original report (X25519 blocked, SHA-1 allowed) may have been triggered by an earlier Go build. However, the flight handler change to use |
There was a problem hiding this comment.
@samthesloth thanks! You can add a E2E test for FIPS if you want to, but I don't think it's strictly needed for this small and reasonable fix. Could be useful for later if we want to verify FIPS compliance. Can also be added later in another PR if you want to work on it:)
I see that this branch now is behind the master branch, so please rebase - then we can squash and merge.
10ba769 to
5ed8021
Compare
|
@theodorsm Awesome, thank you! I'd love to! For now, I think I rebased correctly? Let me know if I need to change anything! |
Description
On FIPS 140-enabled Linux systems, DTLS handshakes fail because the initial curve is hardcoded to X25519, which Go 1.24+ rejects at runtime (
crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode).Reference issue
Fixes #816
Changes
conn.go— ChangeddefaultNamedCurvefromX25519toP256config.go— ReordereddefaultCurvesto{P256, P384, X25519}(P-256 first, X25519 kept for non-FIPS compatibility)flight0handler.go/flight1handler.go— Changedstate.namedCurve = defaultNamedCurvetostate.namedCurve = cfg.ellipticCurves[0]so the flight handlers respect the caller's configured curves instead of using a hardcoded constantTesting
I ran into 3 issues when running
golangci-lint runreferring to file formatting pointing at the comments at the top of the files (authentication_type.go,key_exchange_algorithm.go, andutil.go) but they were unmodified files, so I wasn't sure if I should touch them.