Sprzętowy magazyn kluczy

Dostępność zaufanego środowiska wykonawczego (TEE) w układzie SOC (system on a chip) daje urządzeniom z Androidem możliwość udostępniania sprzętowych, silnych usług bezpieczeństwa systemowi operacyjnemu Android, usługom platformy, a nawet aplikacjom innych firm (w postaci rozszerzeń specyficznych dla Androida w standardowej architekturze Java Cryptography Architecture, patrz KeyGenParameterSpec).

Słowniczek

Oto krótkie omówienie komponentów magazynu kluczy i ich relacji.

AndroidKeyStore
Interfejs API i komponent Android Framework używane przez aplikacje do uzyskiwania dostępu do funkcji magazynu kluczy. Jest to implementacja standardowych interfejsów API Java Cryptography Architecture, ale dodaje też rozszerzenia specyficzne dla Androida i składa się z kodu Java, który działa w przestrzeni procesów aplikacji. AndroidKeyStore realizuje żądania aplikacji dotyczące zachowania magazynu kluczy przekazując je do demona magazynu kluczy.
Demon magazynu kluczy
Demon systemu Android, który zapewnia dostęp do wszystkich funkcji magazynu kluczy za pomocą interfejsu Binder API. Ten demon odpowiada za przechowywanie keyblobs utworzonych przez implementację KeyMint (lub Keymaster), które zawierają tajny materiał klucza, zaszyfrowany tak, aby magazyn kluczy mógł go przechowywać, ale nie używać ani nie ujawniać.
Usługa KeyMint HAL
Serwer AIDL, który implementuje IKeyMintDevice HAL, zapewniając dostęp do bazowej aplikacji KeyMint TA.
Aplikacja KeyMint TA
Oprogramowanie działające w bezpiecznym kontekście, najczęściej w TrustZone na układzie SoC ARM, które zapewnia wszystkie bezpieczne operacje kryptograficzne. Ta aplikacja ma dostęp do surowego materiału klucza i sprawdza wszystkie warunki kontroli dostępu do kluczy, zanim zezwoli na ich użycie.
LockSettingsService
Komponent systemu Android odpowiedzialny za uwierzytelnianie użytkowników za pomocą hasła i odcisku palca. Nie jest częścią magazynu kluczy, ale jest istotny, ponieważ magazyn kluczy obsługuje koncepcję kluczy powiązanych z uwierzytelnianiem: kluczy, których można używać tylko wtedy, gdy użytkownik się uwierzytelnił. LockSettingsService współpracuje z aplikacjami Gatekeeper TA i Fingerprint TA, aby uzyskać tokeny uwierzytelniania, które przekazuje do demona magazynu kluczy, a ten z kolei do aplikacji KeyMint TA.
Aplikacja Gatekeeper TA
Komponent działający w bezpiecznym środowisku, który odpowiada za uwierzytelnianie haseł użytkowników i generowanie tokenów uwierzytelniania używanych do potwierdzania aplikacji KeyMint TA, że uwierzytelnianie zostało przeprowadzone dla konkretnego użytkownika w określonym momencie.
Aplikacja Fingerprint TA
Komponent działający w bezpiecznym środowisku, który odpowiada za uwierzytelnianie odcisków palców użytkowników i generowanie tokenów uwierzytelniania używanych do potwierdzania aplikacji KeyMint TA, że uwierzytelnianie zostało przeprowadzone dla konkretnego użytkownika w określonym momencie.

Architektura

Interfejs Android Keystore API i bazowy interfejs KeyMint HAL zapewniają podstawowy, ale wystarczający zestaw prymitywów kryptograficznych, które umożliwiają implementację protokołów używających kluczy obsługiwanych przez sprzęt i chronionych kontrolą dostępu.

KeyMint HAL to usługa dostarczana przez producenta OEM, która jest używana przez usługę magazynu kluczy do świadczenia usług kryptograficznych obsługiwanych przez sprzęt. Aby chronić materiał klucza prywatnego, implementacje HAL nie wykonują żadnych operacji wrażliwych w przestrzeni użytkownika ani nawet w przestrzeni jądra. Zamiast tego usługa KeyMint HAL działająca w Androidzie przekazuje operacje wrażliwe do aplikacji TA działającej w jakimś bezpiecznym środowisku, zwykle przez marshalling i unmarshalling żądań w formacie przewodowym zdefiniowanym przez implementację.

Wynikowa architektura wygląda tak:

Dostęp do KeyMint

Rysunek 1. Dostęp do KeyMint.

Interfejs KeyMint HAL API jest niskopoziomowy, używany przez komponenty wewnętrzne platformy i niedostępny dla deweloperów aplikacji. Interfejs Java API wyższego poziomu, który jest dostępny dla aplikacji, jest opisany w witrynie dla deweloperów Androida.

Kontrola dostępu

Android Keystore zapewnia centralny komponent do przechowywania i używania kluczy kryptograficznych obsługiwanych przez sprzęt, zarówno w przypadku aplikacji, jak i innych komponentów systemu. Dlatego dostęp do każdego klucza jest zwykle ograniczony do aplikacji lub komponentu systemu, który utworzył klucz.

Domeny magazynu kluczy

Aby obsługiwać tę kontrolę dostępu, klucze są identyfikowane w magazynie kluczy za pomocą deskryptora klucza. Ten deskryptor klucza wskazuje domenę , do której należy deskryptor, oraz tożsamość w tej domenie.

Aplikacje na Androida uzyskują dostęp do magazynu kluczy za pomocą standardowej architektury Java Cryptography Architecture, która identyfikuje klucze za pomocą aliasu ciągu znaków. Ta metoda identyfikacji jest wewnętrznie mapowana na domenę APP magazynu kluczy. Uwzględniany jest też identyfikator UID wywołującego, aby odróżnić klucze z różnych aplikacji i uniemożliwić jednej aplikacji dostęp do kluczy innej aplikacji.

Wewnętrznie kod platformy otrzymuje też unikalny numeryczny identyfikator klucza po załadowaniu klucza. Ten identyfikator numeryczny jest używany jako identyfikator deskryptorów kluczy w domenie KEY_ID. Jednak kontrola dostępu jest nadal wykonywana: nawet jeśli jedna aplikacja wykryje identyfikator klucza innej aplikacji, w normalnych okolicznościach nie będzie mogła go użyć.

Aplikacja może jednak przyznać innej aplikacji (zidentyfikowanej przez UID) prawo do używania klucza. Ta operacja przyznania zwraca unikalny identyfikator przyznania, który jest używany jako identyfikator deskryptorów kluczy w domenie GRANT. Ponownie, kontrola dostępu jest nadal wykonywana: nawet jeśli trzecia aplikacja wykryje identyfikator przyznania klucza odbiorcy, nie będzie mogła go użyć.

Magazyn kluczy obsługuje też 2 inne domeny deskryptorów kluczy, które są używane przez inne komponenty systemu i nie są dostępne w przypadku kluczy utworzonych przez aplikacje:

  • Domena BLOB wskazuje, że w deskryptorze klucza nie ma identyfikatora klucza . Zamiast tego deskryptor klucza zawiera sam keyblob , a klient obsługuje przechowywanie keyblob. Jest to używane przez klientów (np. vold), którzy muszą uzyskać dostęp do magazynu kluczy, zanim zostanie zamontowana partycja danych .
  • Domena SELINUX umożliwia komponentom systemu udostępnianie kluczy, a dostęp podlega identyfikatorowi numerycznemu odpowiadającemu etykiecie SELinux (patrz zasady SELinux dla keystore_key).

Zasady SELinux dla keystore_key

Wartości identyfikatorów używane w przypadku deskryptorów kluczy Domain::SELINUX są konfigurowane w pliku zasad SELinux keystore2_key_context. Każdy wiersz w tych plikach mapuje liczbę na etykietę SELinux, na przykład:

# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and
# Settings to share Keystore keys.
102            u:object_r:wifi_key:s0

Komponent, który potrzebuje dostępu do klucza o identyfikatorze 102 w domenie SELINUX, musi mieć odpowiednie zasady SELinux. Aby na przykład zezwolić wpa_supplicant na pobieranie i używanie tych kluczy, dodaj ten wiersz do hal_wifi_supplicant.te:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Identyfikatory numeryczne kluczy Domain::SELINUX są podzielone na zakresy, aby obsługiwać różne partycje bez kolizji:

Partycja Zakres Pliki konfiguracyjne
System 0 ... 9999 /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Rozszerzony system 10 000 ... 19 999 /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
Produkt 20 000 ... 29 999 /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
Dostawca 30 000 ... 39 999 /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

W przypadku partycji systemowej zdefiniowano te konkretne wartości:

Identyfikator przestrzeni nazw Etykieta SEPolicy Użytkownik (UID) Opis
0 su_key Nie dotyczy Klucz superużytkownika. Używany tylko do testowania w kompilacjach userdebug i eng. Nie ma znaczenia w przypadku kompilacji użytkownika.
1 shell_key Nie dotyczy Przestrzeń nazw dostępna dla powłoki. Używana głównie do testowania, ale można jej też używać w kompilacjach użytkownika z wiersza poleceń.
100 vold_key Nie dotyczy Przeznaczona do użytku przez vold.
101 odsign_key Nie dotyczy Używana przez demona podpisywania na urządzeniu.
102 wifi_key AID_WIFI(1010) Używana przez podsystem Wi-Fi Androida, w tym wpa_supplicant.
103 locksettings_key Nie dotyczy Używana przez LockSettingsService.
120 resume_on_reboot_key AID_SYSTEM(1000) Używana przez serwer systemowy Androida do obsługi wznawiania po ponownym uruchomieniu.

Wektory dostępu

Magazyn kluczy umożliwia kontrolowanie, które operacje można wykonywać na kluczu, oprócz kontrolowania ogólnego dostępu do klucza. Uprawnienia keystore2_key są opisane w KeyPermission.aidl pliku.

Uprawnienia systemowe

Oprócz kontroli dostępu do poszczególnych kluczy opisanych w zasadach SELinux dla keystore_key w tej tabeli opisano inne uprawnienia SELinux, które są wymagane do wykonywania różnych operacji systemowych i konserwacyjnych:

Uprawnienie Znaczenie
add_auth Wymagane do dodawania tokenów uwierzytelniania do magazynu kluczy. Używane przez dostawców uwierzytelniania, takich jak Gatekeeper czy BiometricManager.
clear_ns Wymagane do usuwania wszystkich kluczy w określonej przestrzeni nazw. Używane jako operacja konserwacyjna podczas odinstalowywania aplikacji.
list Wymagane przez system do wyliczania kluczy według różnych właściwości, takich jak własność lub to, czy są one powiązane z uwierzytelnianiem. To uprawnienie nie jest wymagane przez wywołujących, którzy wyliczają własne przestrzenie nazw (objęte uprawnieniem get_info).
lock Wymagane do powiadamiania magazynu kluczy o zablokowaniu urządzenia, co z kolei powoduje usunięcie kluczy głównych, aby klucze powiązane z uwierzytelnianiem były niedostępne.
unlock Wymagane do powiadamiania magazynu kluczy o odblokowaniu urządzenia, co przywraca dostęp do kluczy głównych, które chronią klucze powiązane z uwierzytelnianiem.
reset Wymagane do resetowania magazynu kluczy do ustawień fabrycznych, usuwania wszystkich kluczy, które nie są niezbędne do działania systemu operacyjnego Android.

Historia

W Androidzie 5 i starszych wersjach Android miał prosty interfejs API usług kryptograficznych wspieranych sprzętowo, który był udostępniany przez wersje 0.2 i 0.3 warstwy abstrakcji sprzętowej (HAL) Keymaster. Magazyn kluczy zapewniał operacje podpisywania i weryfikacji cyfrowej oraz generowanie i importowanie asymetrycznych par kluczy podpisywania. Jest to już zaimplementowane na wielu urządzeniach, ale istnieje wiele celów związanych z bezpieczeństwem, których nie można łatwo osiągnąć za pomocą samego interfejsu API podpisu. Android 6.0 rozszerzył interfejs Keystore API, aby zapewnić szerszy zakres możliwości.

Android 6.0

W Androidzie 6.0 Keymaster 1.0 dodał symetryczne prymitywy kryptograficzne, AES i HMAC, oraz system kontroli dostępu do kluczy obsługiwanych przez sprzęt. Kontrola dostępu jest określana podczas generowania klucza i egzekwowana przez cały okres jego ważności. Klucze można ograniczyć tak, aby można ich było używać tylko po uwierzytelnieniu użytkownika i tylko do określonych celów lub z określonymi parametrami kryptograficznymi.

Oprócz rozszerzenia zakresu prymitywów kryptograficznych magazyn kluczy w Androidzie 6.0 dodał te funkcje:

  • Schemat kontroli użycia, który umożliwia ograniczenie użycia klucza, aby zmniejszyć ryzyko naruszenia bezpieczeństwa spowodowanego niewłaściwym użyciem kluczy.
  • Schemat kontroli dostępu, który umożliwia ograniczenie kluczy do określonych użytkowników, klientów i zdefiniowanego zakresu czasu.

Android 7.0

W Androidzie 7.0 Keymaster 2 dodał obsługę poświadczania kluczy i powiązania z wersją.

Poświadczanie kluczy zapewnia certyfikaty klucza publicznego, które zawierają szczegółowy opis klucza i jego kontroli dostępu, aby umożliwić zdalne sprawdzenie, czy klucz istnieje w bezpiecznym sprzęcie i czy jest prawidłowo skonfigurowany.

Powiązanie z wersją wiąże klucze z systemem operacyjnym i poziomem poprawek. Dzięki temu atakujący, który odkryje słabość w starej wersji systemu lub oprogramowania TEE, nie będzie mógł przywrócić urządzenia do podatnej na ataki wersji i używać kluczy utworzonych w nowszej wersji. Ponadto, gdy klucz z daną wersją i poziomem poprawek jest używany na urządzeniu, które zostało zaktualizowane do nowszej wersji lub poziomu poprawek, klucz jest aktualizowany przed użyciem, a poprzednia wersja klucza jest unieważniana. W miarę aktualizowania urządzenia klucze są aktualizowane razem z nim, ale przywrócenie urządzenia do poprzedniej wersji powoduje, że klucze stają się bezużyteczne.

Android 8.0

W Androidzie 8.0 Keymaster 3 przeszedł ze starego interfejsu HAL w stylu C na interfejs HAL w C++ wygenerowany na podstawie definicji w nowym języku definiowania interfejsu sprzętowego (HIDL). W ramach tej zmiany zmieniło się wiele typów argumentów, chociaż typy i metody mają bezpośrednie odpowiedniki w starych typach i metodach struktury HAL.

Oprócz tej zmiany interfejsu Android 8.0 rozszerzył funkcję poświadczania Keymaster 2, aby obsługiwać poświadczanie identyfikatora. Poświadczanie identyfikatora zapewnia ograniczony i opcjonalny mechanizm silnego poświadczania identyfikatorów sprzętu, takich jak numer seryjny urządzenia, nazwa produktu i identyfikator telefonu (IMEI lub MEID). Aby zaimplementować to rozszerzenie, Android 8.0 zmienił schemat poświadczania ASN.1, aby dodać poświadczanie identyfikatora. Implementacje Keymaster muszą znaleźć bezpieczny sposób na pobieranie odpowiednich elementów danych oraz zdefiniować mechanizm bezpiecznego i trwałego wyłączania tej funkcji.

Android 9

W Androidzie 9 wprowadzono te aktualizacje:

  • Aktualizacja do Keymaster 4
  • Obsługa wbudowanych bezpiecznych elementów.
  • Obsługa bezpiecznego importowania kluczy.
  • Obsługa szyfrowania 3DES.
  • Zmiany w powiązaniu z wersją, dzięki którym boot.img i system.img mają oddzielnie ustawione wersje, co umożliwia niezależne aktualizacje.

Android 10

W Androidzie 10 wprowadzono wersję 4.1 interfejsu Keymaster HAL, która dodała te funkcje:

Android 12

W Androidzie 12 wprowadzono nowy interfejs KeyMint HAL, który zastępuje interfejs Keymaster HAL, ale zapewnia podobne funkcje. Oprócz wszystkich wymienionych wyżej funkcji interfejs KeyMint HAL obejmuje też:

  • Obsługa uzgadniania kluczy ECDH.
  • Obsługa kluczy poświadczania określonych przez użytkownika.
  • Obsługa kluczy o ograniczonej liczbie użyć.

Android 12 zawiera też nową wersję demona systemowego magazynu kluczy, napisaną w języku Rust i znaną jako keystore2.

Android 13

W Androidzie 13 dodano wersję 2 interfejsu KeyMint HAL, która obsługuje Curve25519 zarówno w przypadku podpisywania, jak i uzgadniania kluczy.