Od Androida 12 moduł Android Runtime (ART) jest modułem Mainline. Aktualizacja modułu może wymagać ponownego skompilowania artefaktów kompilacji AOT (z wyprzedzeniem) z bootclasspathjars i serwera systemowego. Ponieważ te artefakty są wrażliwe na zagrożenia, Android 12 korzysta z funkcji podpisywania na urządzeniu, aby zapobiec ich modyfikowaniu. Ta strona zawiera informacje o architekturze podpisywania na urządzeniu i jej interakcji z innymi funkcjami zabezpieczeń Androida.
Projektowanie ogólne
Podpisywanie na urządzeniu składa się z 2 głównych elementów:
odrefresh
jest częścią głównego modułu ART. Jest odpowiedzialny za generowanie artefaktów w czasie działania. Porównuje istniejące artefakty z zainstalowaną wersją modułu ART, plików JAR bootclasspath i plików JAR serwera systemowego, aby określić, czy są one aktualne, czy trzeba je wygenerować ponownie. Jeśli trzeba je wygenerować ponownie,odrefresh
wygeneruje je i zapisze.odsign
to plik binarny, który jest częścią platformy Android. Uruchamia się podczas wczesnego rozruchu, tuż po zamontowaniu partycji/data
. Jego główną odpowiedzialnością jest wywołanieodrefresh
w celu sprawdzenia, czy należy wygenerować lub zaktualizować jakiekolwiek artefakty. W przypadku nowych lub zaktualizowanych artefaktów generowanych przezodrefresh
odsign
oblicza funkcję haszowania. Wynik takiego obliczenia nazywamy sumarycznym wartością haszową pliku. W przypadku wszystkich istniejących artefaktówodsign
sprawdza, czy ich podsumowania są zgodne z podsumowaniami obliczonymi wcześniej przezodsign
. Dzięki temu masz pewność, że artefakty nie zostały zmodyfikowane.
W przypadku błędów, np. gdy skrót pliku nie pasuje, odrefresh
i odsign
odrzucają wszystkie istniejące elementy w /data
i próbują je wygenerować ponownie. Jeśli to się nie uda, system przełączy się na tryb JIT.
odrefresh
i odsign
są chronione przez dm-verity
i są częścią łańcucha weryfikacji podczas uruchamiania Androida.
Obliczanie skrótów plików za pomocą fs-verity
fs-verity to funkcja jądra Linuxa, która weryfikuje dane pliku na podstawie drzewa Merkle. Włączenie fs-verity w pliku powoduje, że system plików tworzy drzewo Merkla na podstawie danych pliku za pomocą funkcji SHA-256, przechowuje je w ukrytej lokalizacji obok pliku i oznacza plik jako tylko do odczytu. fs-verity automatycznie weryfikuje dane pliku na podstawie drzewa Merkla na żądanie, gdy jest on odczytywany. fs-verity udostępnia hasz główny drzewa Merkla jako wartość o nazwie fs-verity file digest (treść pliku w formacie digest) i zapewnia, że wszystkie dane odczytane z pliku są zgodne z tym treścią.
odsign
używa fs-verity, aby poprawić wydajność uruchamiania przez optymalizację uwierzytelniania kryptograficznego artefaktów skompilowanych na urządzeniu w momencie uruchamiania. Po wygenerowaniu artefaktu odsign
włącza fs-verity. Podczas weryfikacji artefaktu odsign
weryfikuje skrót pliku fs-verity zamiast pełnego hasha pliku. Dzięki temu nie trzeba odczytywać i zaszyfrowywać wszystkich danych artefaktu podczas uruchamiania. Zamiast tego dane artefaktu są szyfrowane na żądanie przez fs-verity w miarę ich używania, blok po bloku.
Na urządzeniach, których jądro nie obsługuje fs-verity, odsign
używa domyślnie obliczonych digestów plików w przestrzeni użytkownika. odsign
używa tego samego algorytmu haszowania na podstawie drzewa Merkla co fs-verity, więc w obu przypadkach wyniki są takie same.
fs-verity jest wymagany na wszystkich urządzeniach z Androidem 11 lub nowszym.
przechowywanie skrótów plików;
odsign
przechowuje podsumowania plików artefaktów w osobnym pliku o nazwie odsign.info
. Aby mieć pewność, że odsign.info
nie został zmodyfikowany, odsign.info
jest podpisany kluczem podpisującym, który ma ważne właściwości zabezpieczeń. W szczególności klucz może być generowany i używany tylko podczas wczesnego uruchamiania, gdy działa tylko zaufany kod. Więcej informacji znajdziesz w artykule Zaufane klucze podpisywania.
Weryfikacja skrótów plików
Podczas każdego uruchamiania, jeśli odrefresh
stwierdzi, że istniejące elementy są aktualne, odsign
sprawdza, czy pliki nie zostały zmodyfikowane od momentu ich wygenerowania. odsign
robi to, weryfikując podsumowania plików. Najpierw weryfikuje podpis odsign.info
. Jeśli podpis jest prawidłowy, odsign
sprawdza, czy skrót każdego pliku jest zgodny z odpowiednim skrótem w odsign.info
.
Zaufane klucze podpisywania
Android 12 wprowadza nową funkcję Keystore o nazwie boot stage keys, która rozwiązuje te problemy z bezpieczeństwem:
- Co uniemożliwia atakującemu użycie naszego klucza podpisywania do podpisania własnej wersji
odsign.info
? - Co uniemożliwia atakującemu wygenerowanie własnego klucza podpisywania i używanie go do podpisywania własnej wersji
odsign.info
?
Klucze etapów rozruchu dzielą cykl rozruchu Androida na poziomy i za pomocą kryptografii powiązane są z tworzeniem i używaniem klucza na określonym poziomie. odsign
tworzy klucz podpisywania na wczesnym etapie, gdy działa tylko zaufany kod chroniony przez dm-verity
.
Poziomy etapu rozruchu są numerowane od 0 do magicznej liczby 1000000000. Podczas procesu uruchamiania Androida możesz zwiększyć poziom uruchamiania, ustawiając właściwość systemu z poziomu init.rc
. Na przykład ten kod ustawia poziom rozruchu na 10:
setprop keystore.boot_level 10
Klienci Keystore mogą tworzyć klucze powiązane z określonym poziomem uruchamiania. Jeśli na przykład utworzysz klucz dla poziomu rozruchu 10, będzie on mógł być używany tylko wtedy, gdy urządzenie jest na poziomie rozruchu 10.
odsign
używa poziomu rozruchu 30, a klucz podpisywania, który tworzy, jest powiązany z tym poziomem. Zanim odsign
użyje klucza do podpisania artefaktów, sprawdza, czy klucz jest powiązany z poziomem uruchamiania 30.
Zapobiega to 2 atakom opisanym wcześniej w tej sekcji:
- Użytkownicy atakujący nie mogą używać wygenerowanego klucza, ponieważ do czasu, gdy będą mogli uruchomić złośliwy kod, poziom rozruchu wzrośnie powyżej 30, a Keystore odrzuci operacje korzystające z klucza.
- Atakujący nie mogą utworzyć nowego klucza, ponieważ zanim zdążą uruchomić złośliwy kod, poziom rozruchu wzrośnie powyżej 30, a Keystore odmówi utworzenia nowego klucza na tym poziomie. Jeśli atakujący utworzy nowy klucz, który nie jest powiązany z poziomem rozruchu 30,
odsign
go odrzuci.
Sklep kluczy zapewnia prawidłowe egzekwowanie poziomu rozruchu. W następnych sekcjach znajdziesz więcej informacji o tym, jak to zrobić w przypadku różnych wersji Keymaster.
Implementacja Keymastera 4.0
Różne wersje Keymastera obsługują implementację kluczy na etapie uruchamiania w inny sposób. Na urządzeniach z Keymaster 4.0 TEE/Strongbox implementacja Keymaster działa w ten sposób:
- Podczas pierwszego uruchomienia Keystore tworzy klucz symetryczny K0 z tagiem
MAX_USES_PER_BOOT
ustawionym na1
. Oznacza to, że klucz można użyć tylko raz podczas uruchamiania. - Jeśli podczas uruchamiania zwiększy się poziom rozruchu, z K0 można wygenerować nowy klucz dla tego poziomu za pomocą funkcji HKDF:
Ki+i=HKDF(Ki, "some_fixed_string")
. Jeśli na przykład przechodzisz z poziom boot 0 na boot level 10, HKDF jest wywoływany 10 razy, aby wyprowadzić K10 z K0. Gdy zmieni się poziom rozruchu, klucz poprzedniego poziomu rozruchu zostanie usunięty z pamięci, a klucze powiązane z poprzednimi poziomami rozruchu nie będą już dostępne.
Klucz K0 to klucz
MAX_USES_PER_BOOT=1
. Oznacza to, że nie można też użyć tego klucza później podczas uruchamiania, ponieważ zawsze występuje co najmniej jeden poziom uruchamiania (do ostatniego poziomu).
Gdy klient Keystore, np. odsign
, poprosi o utworzenie klucza na poziomie uruchamiania i
, jego blob zostanie zaszyfrowany kluczem Ki
. Klucz Ki
jest niedostępny po poziomie rozruchu i
, więc nie można go utworzyć ani odszyfrować na późniejszych etapach rozruchu.
Wdrożenie Keymaster 4.1 i KeyMint 1.0
Implementacje Keymaster 4.1 i KeyMint 1.0 są w dużej mierze takie same jak implementacja Keymaster 4.0. Główna różnica polega na tym, że K0 nie jest klawiszem MAX_USES_PER_BOOT
, ale EARLY_BOOT_ONLY
, który został wprowadzony w Keymaster 4.1. Klucz EARLY_BOOT_ONLY
może być używany tylko we wczesnych fazach rozruchu, gdy nie jest wykonywany żaden niesprawdzony kod. Zapewnia to dodatkowy poziom ochrony: w ramach implementacji Keymaster 4.0 atakujący, który skompromituje system plików i SELinux, może zmodyfikować bazę danych Keystore, aby utworzyć własny klucz MAX_USES_PER_BOOT=1
, za pomocą którego będzie podpisywać artefakty. Taki atak jest niemożliwy w przypadku implementacji Keymaster 4.1 i KeyMint 1.0, ponieważ klucze EARLY_BOOT_ONLY
można utworzyć tylko podczas wczesnego uruchamiania.
Publiczny składnik zaufanych kluczy podpisujących
odsign
pobiera komponent klucza publicznego klucza podpisywania z magazynu kluczy.
Keystore nie pobiera jednak tego klucza publicznego z urządzenia TEE/SE, które przechowuje odpowiadający mu klucz prywatny. Zamiast tego pobiera klucz publiczny ze swojej własnej bazy danych na dysku. Oznacza to, że atakujący, który złamie system plików, może zmodyfikować bazę danych Keystore, aby zawierała klucz publiczny, który jest częścią pary kluczy publiczno-prywatnych znajdujących się pod jego kontrolą.
Aby zapobiec temu atakowi, odsign
tworzy dodatkowy klucz HMAC na tym samym poziomie rozruchu co klucz podpisywania. Następnie, podczas tworzenia klucza podpisywania odsign
używa tego klucza HMAC do utworzenia podpisu klucza publicznego i przechowuje go na dysku. Podczas kolejnych rozruchów, pobieranie klucza publicznego klucza podpisującego odbywa się za pomocą klucza HMAC, aby sprawdzić, czy podpis na dysku jest zgodny z podpisem pobranego klucza publicznego. Jeśli są zgodne, klucz publiczny jest wiarygodny, ponieważ klucz HMAC może być używany tylko na wczesnych poziomach uruchamiania, a zatem nie mógł zostać utworzony przez atakującego.