W Keymaster 1 wszystkie klucze Keymaster były kryptograficznie powiązane z głównym źródłem zaufania urządzenia lub kluczem zweryfikowanego rozruchu. W Keymaster 2 i 3 wszystkie klucze są też powiązane z systemem operacyjnym i poziomem poprawek obrazu systemu. Dzięki temu atakujący, który odkryje słaby punkt w starszej wersji systemu lub oprogramowania TEE, nie będzie mógł przywrócić urządzenia do podatnej na ataki wersji i użyć kluczy utworzonych w nowszej wersji. Ponadto, gdy klucz z daną wersją i poziomem poprawek jest używany na urządzeniu, które zostało uaktualnione do nowszej wersji lub poziomu poprawek, klucz jest uaktualniany przed użyciem, a poprzednia wersja klucza jest unieważniana. W ten sposób, gdy urządzenie jest uaktualniane, klucze są *przesuwane* do przodu wraz z urządzeniem, ale każde przywrócenie urządzenia do poprzedniej wersji powoduje, że klucze stają się bezużyteczne.
Aby obsługiwać modułową strukturę Treble i zerwać powiązanie system.img z boot.img, w Keymaster 4 zmieniono model powiązania wersji klucza, aby mieć oddzielne poziomy poprawek dla każdej partycji. Dzięki temu każda partycja może być aktualizowana niezależnie, a jednocześnie zapewniona jest ochrona przed przywracaniem.
Aby zaimplementować to powiązanie wersji, zaufana aplikacja KeyMint (TA) musi mieć możliwość bezpiecznego otrzymywania bieżącej wersji systemu operacyjnego i poziomów poprawek oraz upewnienia się, że otrzymywane informacje są zgodne ze wszystkimi informacjami o działającym systemie.
- Urządzenia z Android Verified Boot (AVB) mogą umieścić wszystkie poziomy poprawek
i wersję systemu w vbmeta, dzięki czemu program ładujący może przekazać je do
Keymaster. W przypadku partycji połączonych łańcuchowo informacje o wersji partycji znajdują się
w połączonym vbmeta. Ogólnie rzecz biorąc, informacje o wersji powinny znajdować się w
vbmeta structktóra zawiera dane weryfikacyjne (hash lub hashtree) dla danej partycji. - Na urządzeniach bez AVB:
- Implementacje weryfikacji podczas uruchamiania muszą przekazywać do programu rozruchowego hasz metadanych wersji, aby program rozruchowy mógł przekazać hasz do Keymaster.
boot.imgmoże nadal przechowywać poziom poprawek w nagłówku.system.imgmoże nadal przechowywać poziom poprawek i wersję systemu operacyjnego we właściwościach tylko do odczytu .vendor.imgprzechowuje poziom poprawek we właściwości tylko do odczyturo.vendor.build.version.security_patch.- Program rozruchowy może przekazać do Keymaster hasz wszystkich danych zweryfikowanych przez weryfikację podczas uruchamiania.
- W Androidzie 9 użyj tych tagów, aby podać informacje o wersji dla
tych partycji:
VENDOR_PATCH_LEVEL: partycjavendorBOOT_PATCH_LEVEL: partycjabootOS_PATCH_LEVELiOS_VERSION: partycjasystem. (OS_VERSIONjest usuwany z nagłówkaboot.img.
-
Implementacje Keymaster powinny traktować wszystkie poziomy poprawek niezależnie. Klucze są użyteczne, jeśli wszystkie informacje o wersji są zgodne z wartościami powiązanymi z kluczem, a w razie potrzeby
IKeymaster::upgradeDevice()przechodzi na wyższy poziom poprawek.
Zmiany w HAL
Aby obsługiwać powiązanie wersji i potwierdzenie wersji, w Androidzie 7.1 dodano tagi Tag::OS_VERSION i Tag::OS_PATCHLEVEL oraz metody configure i upgradeKey. Tagi wersji są automatycznie dodawane przez implementacje Keymaster 2+ do wszystkich nowo wygenerowanych (lub zaktualizowanych) kluczy. Ponadto każda próba użycia klucza, który nie ma wersji systemu operacyjnego lub poziomu poprawek zgodnego z bieżącą wersją systemu operacyjnego lub poziomem poprawek, jest odrzucana z kodem ErrorCode::KEY_REQUIRES_UPGRADE.
Tag::OS_VERSION to wartość UINT, która reprezentuje główne, podrzędne i dodatkowe części wersji systemu Android w formacie MMmmss, gdzie MM to wersja główna, mm to wersja podrzędna, a ss to wersja dodatkowa. Na przykład wersja 6.1.2 byłaby reprezentowana jako 060102.
Tag::OS_PATCHLEVEL to wartość UINT, która reprezentuje rok i miesiąc ostatniej aktualizacji systemu w formacie RRRRMM, gdzie RRRR to rok (4 cyfry), a MM to miesiąc (2 cyfry). Na przykład marzec 2016 r. byłby reprezentowany jako 201603.
UpgradeKey
Aby umożliwić uaktualnienie kluczy do nowej wersji systemu operacyjnego i poziomu poprawek obrazu systemu, w Androidzie 7.1 dodano do HAL metodę upgradeKey:
Keymaster 3
upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
generates(ErrorCode error, vec upgradedKeyBlob);
Keymaster 2
keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
const keymaster_key_blob_t* key_to_upgrade,
const keymaster_key_param_set_t* upgrade_params,
keymaster_key_blob_t* upgraded_key);
devto struktura urządzenia.keyBlobToUpgradeto klucz, który należy uaktualnić.upgradeParamsto parametry potrzebne do uaktualnienia klucza. Obejmują oneTag::APPLICATION_IDiTag::APPLICATION_DATA, które są niezbędne do odszyfrowania obiektu blob klucza, jeśli zostały podane podczas generowania.upgradedKeyBlobto parametr wyjściowy używany do zwracania nowego obiektu blob klucza.
Jeśli metoda upgradeKey zostanie wywołana z obiektem blob klucza, którego nie można przeanalizować lub który jest nieprawidłowy, zwraca ona kod ErrorCode::INVALID_KEY_BLOB. Jeśli zostanie wywołana z kluczem, którego poziom poprawek jest wyższy niż bieżąca wartość systemu, zwraca kod ErrorCode::INVALID_ARGUMENT. Jeśli zostanie wywołana z kluczem, którego wersja systemu operacyjnego jest wyższa niż bieżąca wartość systemu, a wartość systemu jest różna od zera, zwraca kod ErrorCode::INVALID_ARGUMENT. Uaktualnienia wersji systemu operacyjnego z wartości różnej od zera do zera są dozwolone. W przypadku błędów komunikacji z bezpiecznym środowiskiem zwraca odpowiednią wartość błędu (np. ErrorCode::SECURE_HW_ACCESS_DENIED, ErrorCode::SECURE_HW_BUSY). W przeciwnym razie zwraca kod ErrorCode::OK i nowy obiekt blob klucza w upgradedKeyBlob.
keyBlobToUpgrade pozostaje ważny po wywołaniu upgradeKey i teoretycznie można go ponownie użyć, jeśli urządzenie zostanie przywrócone do poprzedniej wersji. W praktyce magazyn kluczy zwykle wywołuje metodę deleteKey w przypadku obiektu blob keyBlobToUpgrade krótko po wywołaniu upgradeKey. Jeśli keyBlobToUpgrade miał tag Tag::ROLLBACK_RESISTANT, to upgradedKeyBlob też powinien go mieć (i powinien być odporny na przywracanie).
Bezpieczna konfiguracja
Aby zaimplementować powiązanie wersji, zaufana aplikacja Keymaster (TA) musi mieć możliwość bezpiecznego otrzymywania bieżącej wersji systemu operacyjnego i poziomu poprawek (informacji o wersji) oraz upewnienia się, że otrzymywane informacje są zgodne z informacjami o działającym systemie.
Aby obsługiwać bezpieczne dostarczanie informacji o wersji do TA, do nagłówka obrazu rozruchowego dodano OS_VERSION
pole. Skrypt kompilacji obrazu rozruchowego automatycznie wypełnia to pole. Producenci OEM i implementatorzy TA Keymaster muszą współpracować, aby zmodyfikować programy ładujące urządzenia w celu wyodrębnienia informacji o wersji z obrazu rozruchowego i przekazania ich do TA przed uruchomieniem niezabezpieczonego systemu. Dzięki temu atakujący nie mogą ingerować w udostępnianie informacji o wersji do TA.
Konieczne jest też upewnienie się, że obraz systemu ma te same informacje o wersji co obraz rozruchowy. W tym celu do HAL Keymaster dodano metodę configure:
keymaster_error_t (*configure)(const struct keymaster2_device* dev, const keymaster_key_param_set_t* params);
Argument params zawiera Tag::OS_VERSION i Tag::OS_PATCHLEVEL. Ta metoda jest wywoływana przez klientów keymaster2 po otwarciu HAL, ale przed wywołaniem innych metod. Jeśli przed wywołaniem metody configure zostanie wywołana inna metoda, TA zwraca kod ErrorCode::KEYMASTER_NOT_CONFIGURED.
Przy pierwszym wywołaniu metody configure po uruchomieniu urządzenia należy sprawdzić, czy podane informacje o wersji są zgodne z informacjami podanymi przez program rozruchowy. Jeśli informacje o wersji nie są zgodne, metoda configure zwraca kod ErrorCode::INVALID_ARGUMENT, a wszystkie inne metody Keymaster nadal zwracają kod ErrorCode::KEYMASTER_NOT_CONFIGURED. Jeśli informacje są zgodne, metoda configure zwraca kod ErrorCode::OK, a inne metody Keymaster zaczynają działać normalnie.
Kolejne wywołania metody configure zwracają tę samą wartość co pierwsze wywołanie i nie zmieniają stanu Keymaster.
Ponieważ metoda configure jest wywoływana przez system, którego zawartość ma być zweryfikowana, atakujący ma niewielkie okno możliwości, aby naruszyć obraz systemu i wymusić podanie informacji o wersji zgodnych z obrazem rozruchowym, ale nie z rzeczywistą wersją systemu. Połączenie weryfikacji obrazu rozruchowego, weryfikacji dm-verity zawartości obrazu systemu oraz faktu, że metoda configure jest wywoływana bardzo wcześnie podczas uruchamiania systemu, powinno utrudnić wykorzystanie tego okna możliwości.