Schakelt FIPS 140-3 post-quantum-TLS uit? Het voert stilzwijgend een downgrade uit

Het korte antwoord op "schakelt FIPS post-quantum-TLS uit" is: het levert geen compliant post-quantum-TLS op, en het kan dit stilzwijgend uitschakelen. In ons eigen lab, on the wire, deden twee grote stacks het tegenovergestelde toen we ze in FIPS-modus zetten, en geen van beide bood standaard de FIPS-goedgekeurde post-quantum-groep aan. Go 1.24, onder GODEBUG=fips140=on en =only, stripte elke post-quantum-groep uit de ClientHello en onderhandelde stilzwijgend klassieke P-256, waardoor een verbinding die "slaagde" nul kwantumresistente sleuteluitwisseling bevatte. De FIPS-provider van OpenSSL 3.5.2 deed het tegenovergestelde: deze bood nog steeds X25519MLKEM768, de hybride waarvan de X25519-helft niet FIPS-goedgekeurd is. De FIPS-provider geeft die helft door via een goedkeuringsindicator in plaats van deze te blokkeren. FIPS 140-3 post-quantum-TLS eindigt dus in een van twee foutmodi: zet FIPS aan en óf de post-quantum-bescherming gaat uit (Go), óf er blijft een niet-compliante groep actief (OpenSSL). Harvest-now-decrypt-later-bescherming staat stilzwijgend verkeerd ingesteld voor precies die gereguleerde organisaties die verplicht FIPS moeten gebruiken.
Wat we ontdekten toen we de FIPS-schakelaar omzetten
We bouwden twee clients en twee servers, één paar op Go 1.24, één paar op OpenSSL 3.5.2, en bekeken hun TLS 1.3-handshakes on the wire met FIPS-modus uit en daarna aan. TLS 1.3 verstuurt de supported_groups en key_share extensies in de clear, dus de ClientHello is de absolute bron van waarheid: je kunt exact aflezen welke sleuteluitwisselingsgroepen een client wil gebruiken en voor welke groep hij een share heeft voorbereid. Geen gissingen op basis van de documentatie van een library, gewoon de bytes die op de socket zijn geplaatst.
Met Go 1.24 in FIPS-modus viel de ClientHello terug naar uitsluitend de NIST-curves. De supported_groups-lijst was secp256r1, secp384r1, secp521r1 en niets anders: geen losse x25519, geen X25519MLKEM768, en opvallend genoeg niet eens de FIPS-goedgekeurde SecP256r1MLKEM768. De key_share was secp256r1 en de onderhandelde groep was secp256r1, klassieke elliptic-curve Diffie-Hellman zonder enig post-quantum-component. Het gedrag was identiek voor fips140=on en het strengere fips140=only. Een Go-server in FIPS-modus waaraan een post-quantum-groep werd aangeboden door een niet-FIPS peer, antwoordde met een HelloRetryRequest en dwong de handshake af naar secp256r1. In elk geval werd de handshake succesvol voltooid. Dat is het gevaarlijke gedeelte: er faalde niets, er kwam geen waarschuwing, de verbinding verloor simpelweg stilzwijgend haar kwantumresistentie.
Met OpenSSL 3.5.2 ging de FIPS-provider de andere kant op. De ClientHello in FIPS-modus begon met X25519MLKEM768 en bevatte daarvoor een key_share, gevolgd door P-256, P-384, P-521, en de finite-field-groepen. Vergeleken met de niet-FIPS-nulmeting waren de enige groepen die de FIPS-modus verwijderde de losse curves x25519 en x448; de hybride X25519MLKEM768 bleef bovenaan de lijst staan met een actieve key_share, en onderhandelde die groep met een peer die deze ondersteunde. De OpenSSL-server accepteerde X25519MLKEM768 eveneens. OpenSSL in FIPS-modus blijft dus een groep aanbieden waarvan het de klassieke helft niet zelfstandig laat gebruiken.
De waarheidstabel, on the wire
Hier is elke situatie die we hebben gemeten, met de groepen die elke stack aanbood, de onderhandelde groep, en wat dat voor jou betekent. De Go-rijen en de OpenSSL-rijen vertellen het verhaal: dezelfde intentie, "maak TLS FIPS-compliant", tegenovergesteld resultaat.
| Stack | Rol | FIPS-modus | Aangeboden groepen | Onderhandelde groep | Resultaat |
|---|---|---|---|---|---|
| Go 1.24 | Client | fips140=on / =only | secp256r1, secp384r1, secp521r1 | secp256r1 | Alleen klassiek, geen post-quantum |
| Go 1.24 | Server | fips on | NIST-curves; stuurt HelloRetryRequest | secp256r1 | Dwingt peer af naar klassiek |
| OpenSSL 3.5.2 | Client | fips on | X25519MLKEM768, secp256r1/384/521, ffdhe2048/3072 | X25519MLKEM768 | Post-quantum, maar niet-goedgekeurde hybride |
| OpenSSL 3.5.2 | Server | fips on | Accepteert X25519MLKEM768 | X25519MLKEM768 | Post-quantum, maar niet-goedgekeurde hybride |
| OpenSSL 3.5.2 | Beide, geforceerd | fips on | X25519MLKEM768 (geforceerd) | X25519MLKEM768 | Handshake slaagt onder FIPS |
| OpenSSL 3.5.2 | Beide, geforceerd | fips on | SecP256r1MLKEM768 (geforceerd) | SecP256r1MLKEM768 | Goedgekeurde hybride werkt, maar is nooit de standaard |
Lees de laatste twee rijen in de context van alles wat erboven staat. Beide post-quantum-hybrides voeren een schone handshake uit met beide peers in FIPS-modus, inclusief de volledig goedgekeurde SecP256r1MLKEM768. De stacks zijn in staat om het juiste te doen. Ze kiezen het alleen niet voor je: Go verwijdert ze allemaal, OpenSSL valt terug op de niet-goedgekeurde hybride.
Hoe we dit hebben gemeten, zodat een scepticus de cijfers kan vertrouwen
De dataset is van ons eigen lab, opgebouwd op onze eigen systemen, uitsluitend geaggregeerd. We voerden alles uit in zelfgebouwde Docker-containers, op een tijdelijke cloud-VM, pratend met elkaar via loopback. Er werd geen server van derden aangeraakt, geen extern eindpunt gecontacteerd, en er werd niets over individuen verzameld. Dit is een lab, geen scan van de infrastructuur van anderen.
We hebben drie onafhankelijke controles gebruikt, zodat geen enkele tool op goed geloof vertrouwd hoeft te worden:
- De wire zelf. TLS 1.3 supported_groups en key_share zijn in cleartext, dus we hebben de exacte groepscodepunten rechtstreeks uit de handshake afgelezen. X25519MLKEM768 is 0x11ec, SecP256r1MLKEM768 is 0x11eb, x25519 is 0x001d, en secp256r1 (P-256) is 0x0017. Wat een client aanbood en wat er werd onderhandeld, kwam rechtstreeks uit die bytes.
- OpenSSL's eigen rapportage. De OpenSSL-client print ook de "Negotiated TLS1.3 group", wat in elk geval overeenkwam met wat we on the wire zagen.
- Bewijs dat FIPS daadwerkelijk actief was. Onder de OpenSSL FIPS-configuratie waren alleen de base- en fips-providers geladen, zonder default-provider. Standalone X25519-sleutelgeneratie faalde als niet-ondersteund met een non-zero exitcode, terwijl dezelfde operatie slaagde onder de default-provider, en ML-KEM-768-sleutelgeneratie slaagde onder FIPS. Dit is een module die zich exact gedraagt zoals een echte FIPS-module hoort te doen: X25519 niet-goedgekeurd en geweigerd op zichzelf, ML-KEM uit FIPS 203 goedgekeurd en toegestaan.
Waarom FIPS dit doet: X25519 is niet goedgekeurd, ML-KEM wel
Het mechanisme is een mismatch tussen wat de standaarden goedkeuren en wat het ecosysteem standaard gebruikt. Onder NIST's regels voor key-agreement in SP 800-56A is X25519 geen FIPS-goedgekeurd schema, wat verklaart waarom een strikte module het op zichzelf weigert. ML-KEM, gestandaardiseerd als FIPS 203, is goedgekeurd. De enige breed gespecificeerde hybride die op beide helften FIPS-legaal is, is SecP256r1MLKEM768: NIST P-256, een goedgekeurde curve, gekoppeld aan ML-KEM-768. De concurrerende hybride X25519MLKEM768 combineert het goedgekeurde ML-KEM-768 met de niet-goedgekeurde X25519, waardoor de helft niet op de lijst staat.
Het probleem is dat browsers, Go en OpenSSL allemaal standaard X25519MLKEM768 gebruiken, en niet de goedgekeurde SecP256r1MLKEM768, omdat X25519 snel en alomtegenwoordig is buiten de FIPS-wereld. Beide hybrides zijn gespecificeerd in dezelfde IETF-draft voor ECDHE-MLKEM sleuteluitwisseling. Een FIPS-schakelaar die X25519 verwijdert, verwijdert dus ook de post-quantum-hybride die daarop gebouwd is, tenzij de stack een uitzondering maakt voor de hybride. Dat is precies de splitsing die we gemeten hebben. Go beperkt te streng: het verwijdert elke post-quantum-groep en valt terug op klassiek, wat veilig is voor compliance maar kwantumresistentie weggooit. OpenSSL beperkt onvoldoende: het houdt de niet-goedgekeurde hybride actief en geeft deze door via een FIPS-goedkeuringsindicator in plaats van deze te blokkeren, een ontwerp dat wordt bijgehouden in openssl/openssl #27061. Geen van beide gedragingen is een bug in de traditionele zin; het zijn beide verdedigbare keuzes binnen de library die een niet-triviaal resultaat opleveren zodra je daadwerkelijk naar de bytes on the wire kijkt. Het Go-gedrag wordt besproken in golang/go #78178 en #78298, en de post-quantum-ondersteuning van OpenSSL 3.5 verscheen in haar release van april 2025.
Wat te doen als je FIPS draait en geeft om harvest-now-decrypt-later
Het hele doel van een post-quantum-hybride is het neutraliseren van een "harvest now, decrypt later"-aanvaller: iemand die jouw TLS-verkeer vandaag opslaat en het ontsleutelt zodra er een kwantumcomputer is. Een FIPS-schakelaar die die bescherming stilzwijgend verwijdert, doet het doel teniet voor juist die organisaties die het hoogste risico lopen. Als je FIPS draait, ga er dan niet van uit dat de schakelaar dit heeft geregeld.
- Configureer SecP256r1MLKEM768 expliciet. Het is de FIPS-legale hybride, waarvan beide helften zijn goedgekeurd, en in ons lab voert deze een schone handshake uit met beide peers in FIPS-modus. Maar noch Go 1.24 noch OpenSSL 3.5 biedt deze standaard aan, dus je moet deze zelf opnemen in je groepenlijst.
- Verifieer op het netwerk (on the wire), vertrouw de schakelaar niet. Vang een echte handshake op en lees de onderhandelde groep af. "FIPS aan" vertelde ons in beide stacks niets nuttigs over de daadwerkelijke sleuteluitwisseling; de bytes deden dat wel.
- Wees er in Go van bewust dat
GODEBUG=fips140X25519MLKEM768 verwijdert. Als je de FIPS-modus hebt ingesteld en verder niets hebt gedaan, onderhandelen je Go-services klassieke P-256 zonder post-quantum-sleuteluitwisseling. Test je daadwerkelijk onderhandelde groep voordat je iets anders aanneemt. - Bepaal welk risico je beheert. Als strikte FIPS-goedkeuring de doorslaggevende eis is, vormt de standaard OpenSSL-hybride een compliance-gap. Als kwantumresistentie de eis is, is de Go-standaard de gap. SecP256r1MLKEM768 is de configuratie die aan beide voldoet.
Wat dit niet bewijst
Een resultaat zonder haar beperkingen is marketing, dus hier zijn de grenzen van dit onderzoek.
- Specifieke library-versies. Dit betreft Go 1.24 en OpenSSL 3.5.2. Standaardwaarden, provider-policies en goedkeuringsindicatoren kunnen en zullen veranderen tussen versies, dus een nieuwere release kan zich anders gedragen.
- Onze configuratie. We hebben specifieke FIPS-configuraties gemeten die we zelf hebben opgezet. Een andere FIPS-module, build flag of policybestand kan een andere set groepen aanbieden.
- Standaardinstellingen, geen mogelijkheden. Beide stacks kunnen de goedgekeurde hybride onderhandelen wanneer ze daartoe de opdracht krijgen. De bevinding gaat over wat ze out-of-the-box doen, niet over wat ze kunnen.
- Één transportprotocol. Dit betreft TLS 1.3-sleuteluitwisseling. Het zegt niets over handtekeningen, certificaten of andere protocollen in je stack.
Veelgestelde vragen
Schakelt het inschakelen van FIPS-modus post-quantum-TLS uit?
Dat kan, en in ons lab gebeurde dat ook. Met Go 1.24 onder GODEBUG=fips140=on of fips140=only, liet de ClientHello elke post-quantum-groep vallen en onderhandelde de verbinding klassieke P-256, waardoor een geslaagde handshake nul kwantumresistente sleuteluitwisseling had. OpenSSL 3.5.2 deed het tegenovergestelde: de FIPS-provider bood nog steeds X25519MLKEM768 aan en onderhandelde deze, hoewel de X25519-helft niet FIPS-goedgekeurd is. Geen van beide stacks bood standaard de FIPS-goedgekeurde post-quantum-groep aan.
Is X25519 FIPS-goedgekeurd?
Nee. X25519 is geen goedgekeurd key-agreement-schema onder NIST SP 800-56A, dus een strikte FIPS-module beschouwt het als niet-goedgekeurd. We hebben dit rechtstreeks bevestigd: onder de OpenSSL 3.5.2 FIPS-provider faalde standalone X25519-sleutelgeneratie als niet-ondersteund met een non-zero exitcode, terwijl dezelfde operatie wel slaagde onder de default-provider.
Is X25519MLKEM768 FIPS-goedgekeurd?
Niet zuiver. Het is een hybride: de ML-KEM-768-helft is FIPS 203-goedgekeurd, maar de X25519-helft is niet goedgekeurd voor key agreement. De FIPS-provider van OpenSSL blokkeert de hybride niet; hij geeft hem door via een FIPS-goedkeuringsindicator en biedt en onderhandelt hem standaard nog steeds. De groep werkt onder FIPS, maar de klassieke helft staat niet op de goedgekeurde lijst.
Wat is de FIPS-goedgekeurde post-quantum-TLS-groep?
De breed gespecificeerde FIPS-legale hybride is SecP256r1MLKEM768: NIST P-256, een SP 800-56A goedgekeurde curve, gekoppeld aan ML-KEM-768 uit FIPS 203. Beide helften zijn goedgekeurd. In ons lab leidde het forceren van SecP256r1MLKEM768 met beide peers in FIPS-modus tot een succesvolle handshake, maar noch Go 1.24 noch OpenSSL 3.5.2 bood deze standaard aan.
Waarom verandert mijn Go TLS-handshake onder GODEBUG=fips140?
Omdat de FIPS-modus van Go 1.24 de aangeboden curves beperkt tot de NIST-set. Onder fips140=on of fips140=only, adverteerde de ClientHello van de client die we opvingen alleen secp256r1, secp384r1 en secp521r1, zonder x25519 en zonder post-quantum-hybride, en onderhandelde klassieke P-256. Een Go-server in FIPS-modus stuurde een HelloRetryRequest om een peer af te dwingen naar secp256r1. De handshake slaagt nog steeds, dus de downgrade is stilzwijgend tenzij je de onderhandelde groep inspecteert.
Breekt FIPS de bescherming tegen harvest-now-decrypt-later?
In de door ons geteste standaardconfiguraties wel, in de zin die er toe doet. Go in FIPS-modus verwijderde alle post-quantum-sleuteluitwisseling en viel terug op klassieke cryptografie, precies het verkeer dat een harvest-now-decrypt-later-aanvaller wil opslaan en later wil breken. OpenSSL behield de post-quantum-sleuteluitwisseling, maar via een hybride waarvan de klassieke helft niet FIPS-goedgekeurd is, wat eerder een compliance-probleem is dan een cryptografisch probleem. Hoe dan ook: het inschakelen van FIPS leverde niet standaard compliant post-quantum-bescherming op.
Gerelateerde artikelen
- Wat de certificaten bewijzen. TLS-garanties rechtstreeks uit de bytes (off the wire) lezen in plaats van het etiket op de doos te vertrouwen.
- Hoeveel topdomeinen beperken certificaatuitgifte? Dezelfde passieve methode op basis van onze eigen data toegepast op het publieke certificatenecosysteem.
- Beveiliging van remote MCP-servers. Nog een meting van een standaardinstelling die de meeste teams sneller in gebruik nemen dan auditen.
FIPS draaien en ervan uitgaan dat het post-quantum heeft geregeld?
Onze check van $100 leest je daadwerkelijke cryptografische houding zoals een aanvaller die vastlegt, binnen een scope waarvan je schriftelijk hebt aangetoond dat deze van jou is en geautoriseerd is, met een senior operator bij de toelichting. Wat je services daadwerkelijk onderhandelen on the wire maakt deel uit van dat aanvalsoppervlak.
Boek een check van $100