Moduł kryptograficzny GKI z certyfikatem FIPS 140-3

Jądro GKI zawiera moduł jądra systemu Linux o nazwie fips140.ko, który jest zgodny z wymaganiami FIPS 140-3 dotyczącymi modułów oprogramowania kryptograficznego. Ten moduł można przesłać do certyfikacji FIPS, jeśli wymaga tego produkt z jądrem GKI.

Zanim będzie można używać procedur kryptograficznych, należy spełnić w szczególności te wymagania FIPS 140-3:

  • Zanim moduł udostępni algorytmy kryptograficzne, musi sprawdzić swoją integralność.
  • Zanim moduł udostępni zatwierdzone algorytmy kryptograficzne, musi je przetestować i zweryfikować za pomocą autotestów.

Dlaczego osobny moduł jądra

Walidacja FIPS 140-3 opiera się na założeniu, że po certyfikacji modułu oprogramowania lub sprzętu nigdy nie jest on zmieniany. Jeśli zostanie zmieniony, musi zostać ponownie certyfikowany. Nie jest to zgodne z obecnie stosowanymi procesami tworzenia oprogramowania. W rezultacie tego wymagania moduły oprogramowania FIPS są zwykle projektowane tak, aby jak najbardziej skupiać się na komponentach kryptograficznych. Dzięki temu zmiany niezwiązane z kryptografią nie wymagają ponownej oceny kryptografii.

Jądro GKI ma być regularnie aktualizowane przez cały okres obsługi. Sprawia to, że umieszczenie całego jądra w granicach modułu FIPS jest niemożliwe, ponieważ taki moduł musiałby być ponownie certyfikowany po każdej aktualizacji jądra. Zdefiniowanie „modułu FIPS” jako podzbioru obrazu jądra złagodziłoby ten problem, ale go nie rozwiązało, ponieważ zawartość binarna „modułu FIPS” nadal zmieniałaby się znacznie częściej niż jest to potrzebne.

Przed wprowadzeniem wersji jądra 6.1 trzeba było też pamiętać, że GKI jest kompilowany z włączoną optymalizacją czasu łączenia (LTO), ponieważ LTO była warunkiem wstępnym dla integralności przepływu sterowania, która jest ważną funkcją zabezpieczeń.

Dlatego cały kod objęty wymaganiami FIPS 140-3 jest pakowany w osobny moduł jądra fips140.ko, który korzysta tylko ze stabilnych interfejsów udostępnianych przez źródło jądra GKI, z którego został utworzony. Oznacza to, że moduł może być używany z różnymi wersjami GKI tej samej generacji i musi być aktualizowany i ponownie przesyłany do certyfikacji tylko wtedy, gdy w kodzie zawartym w samym module zostaną naprawione jakieś problemy.

Kiedy używać modułu

Sam kernel GKI zawiera kod, który zależy od procedur kryptograficznych, które są również spakowane w module kernela FIPS 140-3. Wbudowane procedury kryptograficzne nie są więc przenoszone z jądra GKI, ale kopiowane do modułu. Po załadowaniu modułu wbudowane procedury kryptograficzne są wyrejestrowywane z interfejsu Linux CryptoAPI i zastępowane przez procedury zawarte w module.

Oznacza to, że moduł fips140.ko jest całkowicie opcjonalny i warto go wdrożyć tylko wtedy, gdy wymagana jest certyfikacja FIPS 140-3. Poza tym moduł nie zapewnia żadnych dodatkowych funkcji, a jego niepotrzebne wczytywanie może jedynie wpłynąć na czas rozruchu bez żadnych korzyści.

Jak wdrożyć moduł

Moduł można włączyć do kompilacji Androida, wykonując te czynności:

  • Dodaj nazwę modułu do BOARD_VENDOR_RAMDISK_KERNEL_MODULES. Spowoduje to skopiowanie modułu do dysku RAM dostawcy.
  • Dodaj nazwę modułu do BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. Powoduje to dodanie nazwy modułu do modules.load w miejscu docelowym. modules.load zawiera listę modułów, które są wczytywane przez init podczas uruchamiania urządzenia.

Sprawdzanie integralności

Moduł jądra FIPS 140-3 oblicza skrót HMAC-SHA256 własnych sekcji .code.rodata podczas wczytywania modułu i porównuje go ze skrótem zapisanym w module. Dzieje się to po tym, jak moduł ładujący systemu Linux wprowadzi już zwykłe modyfikacje, takie jak przetwarzanie relokacji ELF i łatki alternatywne dotyczące błędów procesora. Aby mieć pewność, że streszczenie można prawidłowo odtworzyć, wykonujemy te dodatkowe czynności:

  • Relokacje ELF są zachowywane w module, aby można było zastosować je w odwrotnej kolejności do danych wejściowych funkcji HMAC.
  • Moduł cofa wszelkie poprawki kodu wprowadzone przez jądro na potrzeby dynamicznego stosu wywołań w cieniu. W szczególności moduł zastępuje wszystkie instrukcje, które umieszczają lub zdejmują elementy ze stosu wywołań cienia, instrukcjami kodu uwierzytelniania wskaźnika (PAC), które były obecne pierwotnie.
  • W przypadku modułu wyłączone jest stosowanie wszystkich innych poprawek kodu, w tym kluczy statycznych, a co za tym idzie – punktów śledzenia i haków dostawcy.

Autotesty algorytmu kryptograficznego

Moduł jądra FIPS 140-3 spełnia wymagania standardu FIPS 140-3 dotyczące autotestu algorytmu kryptograficznego, ponieważ implementuje testy z znanymi odpowiedziami. Wdrożone testy różnią się w zależności od algorytmu i są zgodne z wytycznymi dotyczącymi implementacji FIPS 140-3 10.3.A.

Zwykle wystarczy tylko 1 wektor testowy na algorytm. Autotesty algorytmów kryptograficznych FIPS mają na celu sprawdzenie tylko podstawowej funkcjonalności. Kompleksowe testy są przeprowadzane osobno przy użyciu programu CAVP (Cryptographic Algorithm Validation Program) i zestawu testów kryptograficznych jądra upstream.

Jeśli algorytm ma wiele implementacji dostępnych dla użytkownika lub używanych przez usługi modułu, standard FIPS 140-3 wymaga, aby wszystkie te implementacje były testowane samodzielnie. Ma to znaczenie w przypadku strategii integracji tradycyjnie stosowanej przez interfejs Linux CryptoAPI, w którym każdy algorytm może mieć wiele implementacji dostępnych dla użytkownika. Na przykład w jądrze android16-6.12 algorytm SHA-256 ma 3 implementacje: sha256-generic, sha256-arm64sha256-ce. Na procesorach z rozszerzeniami kryptograficznymi ARMv8 domyślnie używana jest funkcja sha256-ce, ale użytkownicy nadal mogą korzystać z innych funkcji. Dlatego moduł samodzielnie testuje wszystkie 3 implementacje.

W jądrze android17-6.18 i nowszych wersjach niektóre algorytmy korzystają z prostszej strategii integracji. Na przykład w android17-6.18jądrzesha256-lib SHA-256 ma jedną implementację, android17-6.18która automatycznie wybiera odpowiedni kod dla procesora w czasie wczytywania modułu. Dlatego moduł po prostu przeprowadza autotest.sha256-lib

Algorytmy uwzględnione w module

Wszystkie algorytmy zawarte w module FIPS 140-3 są wymienione poniżej. Dotyczy to gałęzi jądra android12-5.10, android13-5.10, android13-5.15, android14-5.15, android14-6.1, android15-6.6, android16-6.12android17-6.18, chociaż w odpowiednich miejscach wskazujemy różnice między wersjami jądra.

Algorytm Implementacje Możliwość zatwierdzenia Definicja
aes aes-generic, aes-arm64, aes-ce, biblioteka AES Tak Szyfr blokowy AES bez trybu działania: obsługiwane są wszystkie rozmiary kluczy (128 bitów, 192 bity i 256 bitów). Wszystkie implementacje inne niż implementacja biblioteki można tworzyć w trybie działania za pomocą szablonu.
cmac(aes) cmac (szablon), cmac-aes-neon, cmac-aes-ce Tak AES-CMAC: obsługiwane są wszystkie rozmiary kluczy AES. Szablon cmac można utworzyć z dowolną implementacją aes za pomocą cmac(). Pozostałe implementacje są samodzielne.
ecb(aes) ecb (szablon), ecb-aes-neon, ecb-aes-neonbs, ecb-aes-ce Tak AES-ECB: obsługiwane są wszystkie rozmiary kluczy AES. Szablon ecb można utworzyć z dowolną implementacją aes za pomocą ecb(). Pozostałe implementacje są samodzielne.
cbc(aes) cbc (szablon), cbc-aes-neon, cbc-aes-neonbs, cbc-aes-ce Tak AES-CBC: obsługiwane są wszystkie rozmiary kluczy AES. Szablon cbc można utworzyć z dowolną implementacją aes za pomocą cbc(). Pozostałe implementacje są samodzielne.
cts(cbc(aes)) cts (szablon), cts-cbc-aes-neon, cts-cbc-aes-ce Tak AES-CBC-CTS lub AES-CBC z przechwytywaniem tekstu zaszyfrowanego: używana konwencja to CS3; ostatnie 2 bloki tekstu zaszyfrowanego są zamieniane bezwarunkowo. Obsługiwane są wszystkie rozmiary kluczy AES. Szablon cts można utworzyć z dowolną implementacją cbc za pomocą cts(). Pozostałe implementacje są samodzielne.
ctr(aes) ctr (szablon), ctr-aes-neon, ctr-aes-neonbs, ctr-aes-ce Tak AES-CTR: obsługiwane są wszystkie rozmiary kluczy AES. Szablon ctr można utworzyć z dowolną implementacją aes za pomocą ctr(). Pozostałe implementacje są samodzielne.
xts(aes) xts (szablon), xts-aes-neon, xts-aes-neonbs, xts-aes-ce Tak AES-XTS: w jądrze 6.1 i starszych obsługiwane są wszystkie rozmiary kluczy AES, a w jądrze 6.6 i nowszych – tylko AES-128 i AES-256. Szablon xts można utworzyć z dowolną implementacją ecb(aes) za pomocą xts(). Pozostałe implementacje są samodzielne. Wszystkie implementacje przeprowadzają sprawdzanie słabych kluczy wymagane przez FIPS, czyli odrzucają klucze XTS, których pierwsza i druga połowa są równe.
gcm(aes) gcm (szablon), gcm-aes-ce Brak 1 AES-GCM: obsługiwane są wszystkie rozmiary kluczy AES. Obsługiwane są tylko 96-bitowe wektory inicjujące. Podobnie jak w przypadku wszystkich innych trybów AES w tym module, wywołujący odpowiada za podanie wektorów inicjujących. Szablon gcm można utworzyć z dowolnych implementacji ctr(aes)ghash za pomocą gcm_base(,). Pozostałe implementacje są samodzielne.
sha1 Jądro 6.12 i starsze: sha1-generic, sha1-ce Tak Funkcja skrótu SHA-1. Usunięto w jądrze 6.18 i nowszych.
sha224 Jądro 6.18 lub nowsze: sha224-lib. Jądro 6.12 i starsze: sha224-generic, sha224-arm64, sha224-ce Tak Funkcja kryptograficzna SHA-224: kod jest udostępniany w SHA-256.
sha256 Jądro 6.18 lub nowsze: sha256-lib. Jądro 6.12 i starsze: sha256-generic, sha256-arm64, sha256-ce, biblioteka SHA-256 Tak Funkcja kryptograficznego haszowania SHA-256.
sha384 Jądro 6.18 lub nowsze: sha384-lib. Jądro 6.12 i starsze: sha384-generic, sha384-arm64, sha384-ce Tak Algorytm kryptograficzny SHA-384: kod jest udostępniany za pomocą SHA-512.
sha512 Jądro 6.18 lub nowsze: sha512-lib. Jądro 6.12 i starsze: sha512-generic, sha512-arm64, sha512-ce Tak funkcja skrótu SHA-512,
sha3-224 Jądro w wersji 6.6 lub nowszej: sha3-224-generic Tak funkcja skrótu kryptograficznego SHA3-224,
sha3-256 Jądro w wersji 6.6 lub nowszej: sha3-256-generic Tak Tak samo jak powyżej, ale z długością skrótu 256 bitów (SHA3-256). Wszystkie długości skrótu korzystają z tej samej implementacji Keccak.
sha3-384 Jądro w wersji 6.6 lub nowszej: sha3-384-generic Tak To samo co powyżej, ale z długością skrótu 384 bity (SHA3-384). Wszystkie długości skrótu korzystają z tej samej implementacji Keccak.
sha3-512 Jądro w wersji 6.6 lub nowszej: sha3-512-generic Tak To samo co powyżej, ale z długością skrótu 512 bitów (SHA3-512). Wszystkie długości skrótu korzystają z tej samej implementacji Keccak.
hmac hmac (szablon) Tak Kod uwierzytelniania wiadomości przy użyciu wartości hash (HMAC): szablon hmac można utworzyć za pomocą dowolnego algorytmu SHA lub implementacji z użyciem hmac() lub hmac().
stdrng Wszystkie jądra: drbg_pr_hmac_sha256, drbg_pr_hmac_sha384, drbg_pr_hmac_sha512. Jądro 6.6 i starsze: drbg_pr_hmac_sha1 Tak HMAC_DRBG z funkcją skrótu o podanej nazwie i włączoną odpornością na przewidywanie: obejmuje testy stanu. Użytkownicy tego interfejsu otrzymują własne instancje DRBG.
stdrng Wszystkie jądra: drbg_nopr_hmac_sha256, drbg_nopr_hmac_sha384, drbg_nopr_hmac_sha512. Jądro 6.6 i starsze: drbg_nopr_hmac_sha1 Tak Takie same jak algorytmy drbg_pr_*, ale z wyłączoną odpornością na przewidywanie. Kod jest udostępniany w wersji odpornej na prognozowanie. W jądrze 5.10 DRBG o najwyższym priorytecie to drbg_nopr_hmac_sha256. W przypadku jądra w wersji 5.15 i nowszych jest to drbg_pr_hmac_sha512.
jitterentropy_rng jitterentropy_rng Nie Jitter RNG w wersji 2.2.0 (wersja jądra 6.1 i starsze) lub 3.4.0 (wersja jądra 6.6 i nowsze). Użytkownicy tego interfejsu otrzymują własne instancje Jitter RNG. Nie używają ponownie instancji, z których korzystają DRBG.
xcbc(aes) xcbc-aes-neon, xcbc-aes-ce Nie
xctr(aes) Jądro w wersji 5.15 lub nowszej: xctr-aes-neon, xctr-aes-ce Nie
cbcmac(aes) cbcmac-aes-neon, cbcmac-aes-ce Nie
essiv(cbc(aes),sha256) essiv-cbc-aes-sha256-neon, essiv-cbc-aes-sha256-ce Nie

1. Implementacje AES-GCM modułu mogą być zatwierdzone pod kątem algorytmu, ale nie pod kątem modułu. Można je zweryfikować, ale z punktu widzenia modułu FIPS algorytmu AES-GCM nie można uznać za zatwierdzony. Dzieje się tak, ponieważ wymagania modułu FIPS dotyczące trybu GCM są niezgodne z implementacjami trybu GCM, które nie generują własnych wektorów inicjujących.

Tworzenie modułu ze źródła

W przypadku Androida 14 i nowszych wersji (w tym android-mainline) skompiluj moduł fips140.ko ze źródeł, używając tych poleceń:

  • Tworzenie za pomocą Bazel:

    tools/bazel run //common:fips140_dist
  • Tworzenie za pomocą build.sh (starsza wersja):

    BUILD_CONFIG=common/build.config.gki.aarch64.fips140 build/build.sh

Te polecenia wykonują pełną kompilację, w tym jądro i moduł fips140.ko, w którym osadzona jest zawartość skrótu HMAC-SHA256.

Wskazówki dla użytkowników

Wskazówki dla specjalistów ds. kryptowalut

Aby moduł jądra działał, system operacyjny musi być ograniczony do trybu pracy z jednym operatorem. Android obsługuje to automatycznie za pomocą sprzętu do zarządzania pamięcią w procesorze.

Modułu jądra nie można zainstalować osobno. Jest on częścią oprogramowania urządzenia i jest ładowany automatycznie podczas uruchamiania. Działa tylko w zatwierdzonym trybie.

Funkcjonariusz ds. kryptografii może w dowolnym momencie uruchomić autotesty, ponownie uruchamiając urządzenie.

Wskazówki dla użytkowników

Użytkownikami modułu jądra są inne komponenty jądra, które muszą korzystać z algorytmów kryptograficznych. Moduł jądra nie zapewnia dodatkowej logiki w zakresie używania algorytmów i nie przechowuje żadnych parametrów poza czasem potrzebnym do wykonania operacji kryptograficznej.

Używanie algorytmów na potrzeby zgodności z FIPS jest ograniczone do zatwierdzonych algorytmów. Aby spełnić wymaganie „wskaźnika usługi” określone w standardzie FIPS 140-3, moduł udostępnia funkcję fips140_is_approved_service, która wskazuje, czy algorytm jest zatwierdzony.

Błędy autotestu

W przypadku niepowodzenia autotestu moduł jądra powoduje panikę jądra, a urządzenie nie kontynuuje rozruchu. Jeśli ponowne uruchomienie urządzenia nie rozwiąże problemu, należy uruchomić je w trybie odzyskiwania, aby naprawić problem przez ponowne wgranie oprogramowania.