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 domodules.loadw miejscu docelowym.modules.loadzawiera listę modułów, które są wczytywane przezinitpodczas uruchamiania urządzenia.
Sprawdzanie integralności
Moduł jądra FIPS 140-3 oblicza skrót HMAC-SHA256 własnych sekcji .code i .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-arm64 i sha256-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.12 i android17-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) i 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_distTworzenie 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.