Czy FIPS 140-3 wyłącza postkwantowy TLS? Cicho obniża poziom zabezpieczeń

Krótka odpowiedź na pytanie „czy FIPS wyłącza postkwantowy TLS” brzmi: nie zapewnia on zgodnego z normami postkwantowego TLS i może go po cichu wyłączyć. W naszym własnym laboratorium, bezpośrednio w ruchu sieciowym, dwa główne stosy zachowały się przeciwstawnie po przełączeniu w tryb FIPS, i żaden z nich domyślnie nie oferował zatwierdzonej przez FIPS grupy postkwantowej. Go 1.24, pod GODEBUG=fips140=on oraz =only, usunął wszystkie grupy postkwantowe z komunikatu ClientHello i po cichu wynegocjował klasyczną grupę P-256. W efekcie połączenie, które „zakończyło się sukcesem”, nie zawierało żadnej odpornej na komputery kwantowe wymiany kluczy. Dostawca FIPS w OpenSSL 3.5.2 zrobił coś odwrotnego: nadal oferował i negocjował X25519MLKEM768, hybrydę, której część X25519 nie jest zatwierdzona przez FIPS. Dostawca FIPS przepuszcza tę część przez wskaźnik zatwierdzenia zamiast ją zablokować. Postkwantowy TLS w FIPS 140-3 kończy więc w jednym z dwóch trybów awarii: włączenie FIPS powoduje wyłączenie ochrony postkwantowej (Go) albo pozostawienie niezgodnej grupy (OpenSSL). Ochrona przed zagrożeniem „zbieraj teraz, odszyfruj później” jest po cichu błędnie skonfigurowana dokładnie u tych regulowanych organizacji, które mają obowiązek stosowania FIPS.
Co odkryliśmy po włączeniu przełącznika FIPS
Zbudowaliśmy dwa klienty i dwa serwery, jedną parę w Go 1.24 i jedną w OpenSSL 3.5.2, a następnie obserwowaliśmy ich uścisk dłoni TLS 1.3 w ruchu sieciowym z wyłączonym i włączonym trybem FIPS. TLS 1.3 przesyła rozszerzenia supported_groups oraz key_share tekstem jawnym, więc ClientHello stanowi bezwzględne źródło prawdy. Można odczytać dokładnie, które grupy wymiany kluczy klient jest gotów zastosować i dla której przygotował udział klucza (key share). Bez zgadywania z dokumentacji biblioteki, wyłącznie bajty wysłane na gniazdo.
W przypadku Go 1.24 w trybie FIPS komunikat ClientHello został zredukowany wyłącznie do krzywych NIST. Lista supported_groups zawierała secp256r1, secp384r1, secp521r1 i nic więcej: żadnego czystego x25519, żadnego X25519MLKEM768, a co istotne, nawet zatwierdzonego przez FIPS SecP256r1MLKEM768. Wartością key_share było secp256r1, a wynegocjowaną grupą secp256r1, czyli klasyczny algorytm Diffiego-Hellmana na krzywych eliptycznych całkowicie bez elementu postkwantowego. Zachowanie było identyczne dla fips140=on oraz bardziej rygorystycznego fips140=only. Serwer Go w trybie FIPS, któremu partner nieobsługujący FIPS zaoferował grupę postkwantową, odpowiedział komunikatem HelloRetryRequest i wymusił obniżenie uścisku dłoni do secp256r1. W każdym przypadku uścisk dłoni zakończył się sukcesem. I to jest właśnie niebezpieczne: nic nie zgłosiło błędu, brak było ostrzeżeń, połączenie po prostu cicho straciło odporność kwantową.
W przypadku OpenSSL 3.5.2 dostawca FIPS zadziałał w drugą stronę. Komunikat ClientHello w trybie FIPS rozpoczynał się od X25519MLKEM768 i zawierał dla niego wartość key_share, a następnie grupy P-256, P-384, P-521 oraz grupy oparte na ciałach skończonych. W porównaniu z bazową konfiguracją bez FIPS, jedynymi grupami usuniętymi przez tryb FIPS były samodzielne krzywe x25519 oraz x448. Natomiast hybryda X25519MLKEM768 pozostała na szczycie listy z aktywnym key_share i wynegocjowała tę grupę z partnerem, który ją obsługiwał. Serwer OpenSSL również zaakceptował X25519MLKEM768. Zatem OpenSSL w trybie FIPS nadal oferuje grupę, której klasycznej połowy nie pozwala użyć samodzielnie.
Tabela prawdy w ruchu sieciowym
Oto każdy zmierzony przypadek wraz z grupami zaoferowanymi przez każdy stos, wynegocjowaną grupą oraz konsekwencjami. Wiersze dotyczące Go oraz OpenSSL mówią same za siebie: ten sam zamiar („zapewnienie zgodności TLS z FIPS”) dał przeciwstawne rezultaty.
| Stos | Rola | Tryb FIPS | Oferowane grupy | Wynegocjowana grupa | Wynik |
|---|---|---|---|---|---|
| Go 1.24 | Klient | fips140=on / =only | secp256r1, secp384r1, secp521r1 | secp256r1 | Tylko klasyczne, brak postkwantowości |
| Go 1.24 | Serwer | fips on | Krzywe NIST; wysyła HelloRetryRequest | secp256r1 | Wymusza obniżenie u partnera do kryptografii klasycznej |
| OpenSSL 3.5.2 | Klient | fips on | X25519MLKEM768, secp256r1/384/521, ffdhe2048/3072 | X25519MLKEM768 | Postkwantowe, ale hybryda niezatwierdzona |
| OpenSSL 3.5.2 | Serwer | fips on | Akceptuje X25519MLKEM768 | X25519MLKEM768 | Postkwantowe, ale hybryda niezatwierdzona |
| OpenSSL 3.5.2 | Oba, wymuszone | fips on | X25519MLKEM768 (wymuszone) | X25519MLKEM768 | Uścisk dłoni powodzi się w FIPS |
| OpenSSL 3.5.2 | Oba, wymuszone | fips on | SecP256r1MLKEM768 (wymuszone) | SecP256r1MLKEM768 | Zatwierdzona hybryda działa, ale nigdy domyślnie |
Zestawienie ostatnich dwóch wierszy z powyższymi wskazuje jasne wnioski. Obie hybrydy postkwantowe przechodzą uścisk dłoni bez problemu z oboma partnerami w trybie FIPS, w tym w pełni zatwierdzona SecP256r1MLKEM768. Stosy są zdolne do poprawnego działania. Po prostu nie wybierają tego rozwiązania domyślnie: Go usuwa wszystkie z nich, a OpenSSL domyślnie wybiera opcję niezatwierdzoną.
Jak to zmierzyliśmy, aby sceptyk mógł zaufać wynikom
Zbiór danych jest nasz własny, zbudowany na naszych systemach i zawiera wyłącznie dane zagregowane. Uruchomiliśmy wszystko w przygotowanych przez nas kontenerach Docker na ulotnej maszynie wirtualnej w chmurze, komunikujących się przez loopback. Nie naruszono żadnego serwera podmiotu trzeciego, nie łączono się z zewnętrznymi punktami końcowymi i nie zbierano żadnych danych osobowych. To test laboratoryjny, a nie skanowanie cudzej infrastruktury.
Zastosowaliśmy trzy niezależne metody weryfikacji, aby nie polegać na ślepo na żadnym pojedynczym narzędziu:
- Sam ruch sieciowy. Rozszerzenia TLS 1.3 supported_groups i key_share są przesyłane tekstem jawnym, więc odczytaliśmy dokładne punkty kodowe grup z uścisku dłoni. X25519MLKEM768 to 0x11ec, SecP256r1MLKEM768 to 0x11eb, x25519 to 0x001d, a secp256r1 (P-256) to 0x0017. To, co klient zaoferował i co wynegocjował, wynikało bezpośrednio z tych bajtów.
- Własne raportowanie OpenSSL. Klient OpenSSL wypisuje również komunikat „Negotiated TLS1.3 group”, który w każdym przypadku zgadzał się z tym, co odczytaliśmy z ruchu sieciowego.
- Dowód na to, że FIPS był faktycznie włączony. W konfiguracji FIPS dla OpenSSL załadowano tylko dostawców base i fips, bez domyślnego dostawcy. Samodzielna generacja klucza X25519 nie powiodła się z powodu braku obsługi z niezerowym kodem wyjścia, podczas gdy ta sama operacja zakończyła się sukcesem pod domyślnym dostawcą, a generacja klucza ML-KEM-768 powiodła się w trybie FIPS. Moduł zachowuje się dokładnie tak, jak powinien zachowywać się prawdziwy moduł FIPS: X25519 nie jest zatwierdzony i jest samodzielnie odrzucany, natomiast ML-KEM z FIPS 203 jest zatwierdzony i dozwolony.
Dlaczego FIPS tak działa: X25519 nie jest zatwierdzony, ML-KEM jest
Mechanizm ten wynika z rozbieżności między tym, co zatwierdzają standardy, a tym, co jest domyślne w ekosystemie. Zgodnie z zasadami uzgadniania kluczy NIST zawartymi w SP 800-56A, X25519 nie jest schematem zatwierdzonym przez FIPS, dlatego rygorystyczny moduł odrzuca go, gdy występuje samodzielnie. ML-KEM, znormalizowany jako FIPS 203, jest zatwierdzony. Jedyną szeroko zdefiniowaną hybrydą zgodną z FIPS w obu częściach jest SecP256r1MLKEM768: NIST P-256 (zatwierdzona krzywa) połączona z ML-KEM-768. Konkurencyjna hybryda X25519MLKEM768 łączy zatwierdzony ML-KEM-768 z niezatwierdzonym X25519, więc połowa z niej znajduje się poza listą.
Problem polega na tym, że przeglądarki, Go i OpenSSL domyślnie stosują X25519MLKEM768, a nie zatwierdzony SecP256r1MLKEM768, ponieważ X25519 jest szybki i powszechny poza światem FIPS. Obie hybrydy są zdefiniowane w tym samym projekcie IETF dotyczącym wymiany kluczy ECDHE-MLKEM. Zatem przełącznik FIPS, który usuwa X25519, usuwa również zbudowaną na nim hybrydę postkwantową, chyba że dany stos specjalnie traktuje taką hybrydę. To dokładnie to rozgałęzienie, które zmierzyliśmy. Go nakłada zbyt duże ograniczenia: odrzuca każdą grupę postkwantową i powraca do kryptografii klasycznej, co jest bezpieczne z punktu widzenia zgodności z normami, ale odrzuca odporność kwantową. OpenSSL nakłada zbyt małe ograniczenia: utrzymuje niezatwierdzoną hybrydę jako aktywną, przepuszczając ją przez wskaźnik zatwierdzenia FIPS zamiast ją zablokować, co stanowi projekt opisany w openssl/openssl #27061. Żadne z tych zachowań nie jest błędem w tradycyjnym rozumieniu. Obie decyzje twórców bibliotek można uzasadnić, jednak dają one nieoczywisty rezultat po przeanalizowaniu ruchu sieciowego. Zachowanie Go omówiono w golang/go #78178 oraz #78298, a obsługa postkwantowa w OpenSSL 3.5 pojawiła się w wydaniu z kwietnia 2025 r..
Co zrobić, jeśli stosujesz FIPS i dbasz o ochronę przed „zbieraj teraz, odszyfruj później”
Głównym celem hybrydy postkwantowej jest ochrona przed atakującym stosującym strategię „zbieraj teraz, odszyfruj później” (harvest now, decrypt later), czyli takim, który rejestruje ruch TLS dzisiaj i odszyfruje go, gdy pojawią się komputery kwantowe. Przełącznik FIPS, który po cichu usuwa tę ochronę, niweczy ten cel w przypadku organizacji najbardziej narażonych na ataki. Jeśli używasz FIPS, nie zakładaj, że sam przełącznik załatwił sprawę.
- Jawnie skonfiguruj SecP256r1MLKEM768. Jest to hybryda zgodna z FIPS (obie części są zatwierdzone), a w naszym laboratorium uścisk dłoni z oboma partnerami w trybie FIPS przebiegł bez przeszkód. Jednak ani Go 1.24, ani OpenSSL 3.5 nie oferują jej domyślnie, więc musisz samodzielnie podać ją na liście grup.
- Weryfikuj w ruchu sieciowym, nie ufaj przełącznikowi. Przechwyć rzeczywisty uścisk dłoni i odczytaj wynegocjowaną grupę. Włączenie FIPS nie przekazało nam żadnych przydatnych informacji o faktycznej wymianie kluczy w żadnym ze stosów, zrobiły to bajty z sieci.
- W Go pamiętaj, że
GODEBUG=fips140usuwa X25519MLKEM768. Jeśli włączysz tryb FIPS i nie zrobisz nic więcej, Twoje usługi w Go będą negocjować klasyczną grupę P-256 bez postkwantowej wymiany kluczy. Sprawdź rzeczywiście wynegocjowaną grupę, zanim założysz inaczej. - Zdecyduj, którym ryzykiem zarządzasz. Jeśli wiążącym wymogiem jest rygorystyczne zatwierdzenie FIPS, domyślna hybryda OpenSSL stanowi lukę w zgodności z normami. Jeśli wymogiem jest odporność kwantowa, lukę stanowi domyślne ustawienie Go. SecP256r1MLKEM768 to konfiguracja, która spełnia oba te wymogi.
Czego to nie dowodzi
Wynik bez określenia jego ograniczeń to marketing, dlatego oto ograniczenia tego badania.
- Pojedyncze wersje bibliotek. Badanie dotyczy Go 1.24 i OpenSSL 3.5.2. Ustawienia domyślne, polityki dostawców i wskaźniki zatwierdzenia mogą się zmieniać i zmieniają między wersjami, więc nowsze wydanie może zachowywać się inaczej.
- Nasza konfiguracja. Zmierzyliśmy konkretne konfiguracje FIPS przygotowane przez nas. Inny moduł FIPS, flaga kompilacji lub plik polityki mogą oferować inny zestaw grup.
- Ustawienia domyślne, a nie możliwości. Oba stosy potrafią wynegocjować zatwierdzoną hybrydę, gdy zostaną do tego poinstruowane. Wniosek dotyczy tego, co robią fabrycznie, a nie tego, do czego są zdolne.
- Jeden transport. Dotyczy to wymiany kluczy TLS 1.3. Nie mówi nic o podpisach, certyfikatach ani innych protokołach w Twoim stosie.
Często zadawane pytania
Czy włączenie trybu FIPS wyłącza postkwantowy TLS?
Może i w naszym laboratorium tak się stało. W przypadku Go 1.24 pod GODEBUG=fips140=on lub fips140=only, komunikat ClientHello odrzucił każdą grupę postkwantową, a połączenie wynegocjowało klasyczne P-256, więc udany uścisk dłoni nie zawierał żadnej odpornej na komputery kwantowe wymiany kluczy. OpenSSL 3.5.2 zrobił coś odwrotnego: jego dostawca FIPS nadal oferował i negocjował X25519MLKEM768, którego część X25519 nie jest zatwierdzona przez FIPS. Żaden ze stosów nie oferował domyślnie zatwierdzonej przez FIPS grupy postkwantowej.
Czy X25519 jest zatwierdzony przez FIPS?
Nie. X25519 nie jest zatwierdzonym schematem uzgadniania kluczy według NIST SP 800-56A, więc rygorystyczny moduł FIPS traktuje go jako niezatwierdzony. Potwierdziliśmy to bezpośrednio: w przypadku dostawcy FIPS w OpenSSL 3.5.2 samodzielna generacja klucza X25519 nie powiodła się z powodu braku obsługi z niezerowym kodem wyjścia, podczas gdy ta sama operacja zakończyła się sukcesem pod dostawcą domyślnym.
Czy X25519MLKEM768 jest zatwierdzony przez FIPS?
Nie jednoznacznie. Jest to hybryda: część ML-KEM-768 jest zatwierdzona przez FIPS 203, ale część X25519 nie jest zatwierdzona do uzgadniania kluczy. Dostawca FIPS w OpenSSL nie blokuje tej hybrydy; przepuszcza ją przez wskaźnik zatwierdzenia FIPS i nadal oferuje oraz negocjuje ją domyślnie. Grupa działa w trybie FIPS, ale jej część klasyczna znajduje się poza listą zatwierdzonych.
Jaka jest zatwierdzona przez FIPS postkwantowa grupa TLS?
Szeroko zdefiniowaną hybrydą zgodną z FIPS jest SecP256r1MLKEM768: NIST P-256 (krzywa zatwierdzona według SP 800-56A) połączona z ML-KEM-768 z FIPS 203. Obie części są zatwierdzone. W naszym laboratorium wymuszenie SecP256r1MLKEM768 przy obu partnerach w trybie FIPS doprowadziło do pomyślnego uścisku dłoni, ale ani Go 1.24, ani OpenSSL 3.5.2 nie oferowały tej grupy domyślnie.
Dlaczego uścisk dłoni TLS w Go zmienia się przy GODEBUG=fips140?
Ponieważ tryb FIPS w Go 1.24 ogranicza oferowane krzywe do zestawu NIST. Pod fips140=on lub fips140=only, zarejestrowany komunikat ClientHello ogłaszał jedynie secp256r1, secp384r1 oraz secp521r1, bez x25519 i bez hybrydy postkwantowej, negocjując klasyczne P-256. Serwer Go w trybie FIPS wysłał HelloRetryRequest, aby wymusić obniżenie u partnera do secp256r1. Uścisk dłoni nadal kończy się sukcesem, więc obniżenie poziomu następuje po cichu, chyba że sprawdzisz wynegocjowaną grupę.
Czy FIPS narusza ochronę przed „zbieraj teraz, odszyfruj później”?
W testowanych przez nas domyślnych konfiguracjach tak, w istotnym zakresie. Go w trybie FIPS usunął całą postkwantową wymianę kluczy i powrócił do kryptografii klasycznej, czyli dokładnie do takiego ruchu, jaki atakujący stosujący strategię „zbieraj teraz, odszyfruj później” chce zarejestrować i odszyfrować w przyszłości. OpenSSL zachował postkwantową wymianę kluczy, ale za pośrednictwem hybrydy, której klasyczna część nie jest zatwierdzona przez FIPS, co stanowi problem ze zgodnością z normami, a nie kryptograficzny. W obu przypadkach włączenie FIPS domyślnie nie zapewniło zgodnej z normami ochrony postkwantowej.
Powiązane artykuły
- Co udowadniają certyfikaty. Odczytywanie zapewnień TLS bezpośrednio z ruchu sieciowego zamiast uciekania się do deklaracji na opakowaniu.
- Ile najpopularniejszych domen ogranicza wydawanie certyfikatów? Ta sama pasywna metoda oparta na własnych danych zastosowana do publicznego ekosystemu certyfikatów.
- Bezpieczeństwo zdalnych serwerów MCP. Kolejny pomiar domyślnego ustawienia, które większość zespołów wdraża szybciej, niż audytuje.
Korzystasz z FIPS i zakładasz, że obsłużył postkwantowość?
Nasza weryfikacja za $100 odczytuje Twoją rzeczywistą postawę kryptograficzną w taki sposób, w jaki rejestruje ją atakujący, w zakresie, którego własność zweryfikowano i upoważniono na piśmie, z udziałem doświadczonego specjalisty podczas omówienia. To, co Twoje usługi faktycznie negocjują w ruchu sieciowym, stanowi część tej powierzchni ataku.
Zamów weryfikację za $100