Ta strona zawiera dodatkowe informacje i wytyczne, które pomogą osobom wdrażającym warstwę abstrakcji sprzętowej (HAL) KeyMint. Podstawową dokumentacją HAL jest specyfikacja interfejsu AIDL.
Niewłaściwe użycie interfejsu API
Wywołujący mogą tworzyć klucze KeyMint z autoryzacjami, które są prawidłowe jako parametry interfejsu API, ale sprawiają, że wynikowe klucze są niebezpieczne lub bezużyteczne. Implementacje KeyMint nie muszą w takich przypadkach kończyć się niepowodzeniem ani wydawać diagnostyki. Używanie zbyt małych kluczy, określanie nieistotnych parametrów wejściowych, ponowne używanie wektorów inicjujących lub liczb jednorazowych, generowanie kluczy bez określonego przeznaczenia (a więc bezużytecznych) itp. nie powinno być diagnozowane przez implementacje.
Aplikacje, platforma i magazyn kluczy Androida są odpowiedzialne za zapewnienie, że wywołania modułów KeyMint są sensowne i użyteczne.
Punkt wejścia addRngEntropy
Punkt wejścia addRngEntropy
dodaje entropię dostarczoną przez dzwoniącego do puli używanej przez implementację KeyMint do generowania liczb losowych na potrzeby kluczy i wektorów inicjujących.
Implementacje KeyMint muszą bezpiecznie mieszać dostarczoną entropię z puli, która musi też zawierać entropię generowaną wewnętrznie przez sprzętowy generator liczb losowych. Mieszanie powinno być przeprowadzane w taki sposób, aby atakujący, który ma pełną kontrolę nad bitami dostarczonymi przez addRngEntropy
lub bitami wygenerowanymi przez sprzęt (ale nie nad oboma), nie miał znaczącej przewagi w przewidywaniu bitów wygenerowanych z puli entropii.
Najważniejsze cechy
Każdy z mechanizmów (generateKey
, importKey
i importWrappedKey
) tworzących klucze KeyMint zwraca charakterystykę nowo utworzonego klucza, podzieloną odpowiednio na poziomy bezpieczeństwa, które wymuszają każdą charakterystykę. Zwrócone charakterystyki obejmują wszystkie parametry określone podczas tworzenia klucza z wyjątkiem Tag::APPLICATION_ID
i Tag::APPLICATION_DATA
.
Jeśli te tagi są uwzględnione w parametrach klucza, są usuwane ze zwracanych charakterystyk, aby nie można było znaleźć ich wartości przez zbadanie zwróconego klucza. Są one jednak powiązane kryptograficznie z obiektem klucza, więc jeśli podczas używania klucza nie zostaną podane prawidłowe wartości, użycie się nie powiedzie. Podobnie Tag::ROOT_OF_TRUST
jest kryptograficznie powiązany z kluczem, ale nie można go określić podczas tworzenia lub importowania klucza i nigdy nie jest zwracany.
Oprócz podanych tagów implementacja KeyMint dodaje też tag Tag::ORIGIN
, który wskazuje sposób utworzenia klucza (KeyOrigin::GENERATED
, KeyOrigin::IMPORTED
lub KeyOrigin::SECURELY_IMPORTED
).
Ochrona przed przywróceniem starszych kluczy
Odporność na przywracanie jest oznaczona symbolem Tag::ROLLBACK_RESISTANCE
i oznacza, że po usunięciu klucza za pomocą funkcji deleteKey
lub deleteAllKeys
bezpieczny sprzęt gwarantuje, że nigdy nie będzie można go ponownie użyć.
Implementacje KeyMint zwracają wygenerowany lub zaimportowany materiał klucza do wywołującego w postaci klucza binarnego, czyli zaszyfrowanej i uwierzytelnionej formy. Gdy Keystore usunie plik klucza, klucz zniknie, ale atakujący, któremu wcześniej udało się pobrać materiał klucza, może go przywrócić na urządzeniu.
Klucz jest odporny na wycofanie, jeśli bezpieczny sprzęt gwarantuje, że usuniętych kluczy nie można później przywrócić. Zwykle polega to na przechowywaniu dodatkowych metadanych klucza w zaufanej lokalizacji, którą osoba przeprowadzająca atak nie może manipulować. Na urządzeniach mobilnych zwykle używa się do tego mechanizmu bloków pamięci chronionych przed powtórzeniem (RPMB). Liczba kluczy, które można utworzyć, jest w zasadzie nieograniczona, a zaufana pamięć używana do ochrony przed wycofaniem może mieć ograniczony rozmiar. W takiej sytuacji implementacja może odrzucać żądania utworzenia kluczy odpornych na wycofanie, gdy pamięć jest pełna.
zacznij
Punkt wejścia begin()
rozpoczyna operację kryptograficzną przy użyciu określonego klucza, w określonym celu i z określonymi parametrami (w odpowiednich przypadkach). Zwraca nowy obiekt IKeyMintOperation
Binder, który służy do ukończenia operacji. Dodatkowo zwracana jest wartość wyzwania, która jest używana jako część tokena uwierzytelniającego w uwierzytelnionych operacjach.
Implementacja KeyMint obsługuje co najmniej 16 operacji równoczesnych. Pamięć kluczy używa maksymalnie 15 kluczy, pozostawiając 1 klucz do szyfrowania haseł przez vold
. Gdy w Keystore trwa 15 operacji (wywołano begin()
, ale nie wywołano finish
ani abort
) i otrzyma on prośbę o rozpoczęcie 16 operacji, wywołuje abort()
w przypadku najrzadziej używanej operacji, aby zmniejszyć liczbę aktywnych operacji do 14, a następnie wywołuje begin()
, aby rozpocząć nową operację.
Jeśli podczas generowania lub importowania klucza określono tagi Tag::APPLICATION_ID
lub Tag::APPLICATION_DATA
, wywołania funkcji begin()
muszą zawierać te tagi z pierwotnie określonymi wartościami w argumencie params
tej metody.
Obsługa błędów
Jeśli metoda w IKeyMintOperation
zwraca kod błędu inny niż ErrorCode::OK
, operacja jest przerywana, a obiekt OperationBinder jest unieważniany. Każde przyszłe użycie obiektu zwróci ErrorCode::INVALID_OPERATION_HANDLE
.
Egzekwowanie autoryzacji
Wymuszanie autoryzacji klucza odbywa się głównie w begin()
. Wyjątkiem jest sytuacja, w której klucz ma co najmniej 1 wartość Tag::USER_SECURE_ID
, a nie ma wartości Tag::AUTH_TIMEOUT
.
W takim przypadku klucz wymaga autoryzacji dla każdej operacji, a metody update()
lub finish()
otrzymują token autoryzacji w argumencie authToken
. Aby mieć pewność, że token jest prawidłowy, implementacja KeyMint:
- Weryfikuje podpis HMAC w tokenie uwierzytelniającym.
- Sprawdza, czy token zawiera bezpieczny identyfikator użytkownika pasujący do identyfikatora powiązanego z kluczem.
- Sprawdza, czy typ autoryzacji tokena jest zgodny z wartością
Tag::USER_AUTH_TYPE
klucza. - Sprawdza, czy token zawiera wartość wyzwania dla bieżącej operacji w polu challenge.
Jeśli te warunki nie zostaną spełnione, KeyMint zwróci wartość ErrorCode::KEY_USER_NOT_AUTHENTICATED
.
Dzwoniący podaje token uwierzytelniania przy każdym połączeniu z numerem update()
i finish()
. Implementacja może zweryfikować token tylko raz.