Wiązanie wersji

W Keymaster 1 wszystkie klucze Keymaster były kryptograficznie powiązane z urządzeniem Root of Trust , czyli zweryfikowanym kluczem rozruchowym. W Keymaster 2 i 3 wszystkie klucze są również powiązane z systemem operacyjnym i poziomem poprawki obrazu systemu. Dzięki temu osoba atakująca, która odkryje słabość w starej wersji systemu lub oprogramowania TEE, nie będzie mogła przywrócić urządzenia do wersji podatnej na ataki i użyć kluczy utworzonych w nowszej wersji. Dodatkowo, gdy klucz o danej wersji i poziomie poprawki zostanie użyty na urządzeniu, które zostało zaktualizowane do nowszej wersji lub poziomu poprawki, klucz zostanie zaktualizowany zanim będzie można go użyć, a poprzednia wersja klucza unieważnia się. W ten sposób podczas aktualizacji urządzenia klawisze będą „przeskakiwać” do przodu wraz z urządzeniem, ale jakiekolwiek przywrócenie urządzenia do poprzedniej wersji spowoduje, że klucze staną się bezużyteczne.

Aby wesprzeć modułową strukturę Treble i przerwać powiązanie system.img z boot.img, Keymaster 4 zmienił model powiązania wersji klucza, aby mieć oddzielne poziomy poprawek dla każdej partycji. Umożliwia to niezależną aktualizację każdej partycji, zapewniając jednocześnie ochronę przed wycofywaniem zmian.

W systemie Android 9 partycje boot , system i vendor mają swój własny poziom poprawek.

  • Urządzenia z systemem Android Verified Boot (AVB) mogą umieścić wszystkie poziomy poprawek i wersję systemu w vbmeta, dzięki czemu program ładujący może udostępnić je Keymasterowi. W przypadku partycji połączonych informacje o wersji partycji będą znajdować się w połączonym pliku vbmeta. Ogólnie rzecz biorąc, informacje o wersji powinny znajdować się w vbmeta struct , która zawiera dane weryfikacyjne (hash lub hashtree) dla danej partycji.
  • Na urządzeniach bez AVB:
    • Zweryfikowane implementacje Boot muszą dostarczyć skrót metadanych wersji do programu ładującego, aby program ładujący mógł dostarczyć skrót do Keymastera.
    • boot.img może nadal zapisywać poziom poprawki w nagłówku
    • system.img może nadal przechowywać poziom poprawki i wersję systemu operacyjnego we właściwościach tylko do odczytu
    • vendor.img przechowuje poziom poprawki we właściwości tylko do odczytu ro.vendor.build.version.security_patch .
    • Program ładujący może udostępnić kluczowi skrót wszystkich danych zweryfikowanych podczas zweryfikowanego rozruchu.
  • W systemie Android 9 użyj następujących tagów, aby podać informacje o wersji następujących partycji:
    • VENDOR_PATCH_LEVEL : partycja vendor
    • BOOT_PATCH_LEVEL : partycja boot
    • OS_PATCH_LEVEL i OS_VERSION : partycja system . ( OS_VERSION został usunięty z nagłówka boot.img .
  • Implementacje Keymastera powinny traktować wszystkie poziomy poprawek niezależnie. Klucze są użyteczne, jeśli wszystkie informacje o wersji odpowiadają wartościom powiązanym z kluczem, a IKeymaster::upgradeDevice() w razie potrzeby przełącza się na wyższy poziom poprawki.

Zmiany HAL-u

Aby obsługiwać powiązanie wersji i poświadczanie wersji, w systemie Android 7.1 dodano tagi Tag::OS_VERSION i Tag::OS_PATCHLEVEL oraz configure i upgradeKey . Tagi wersji są automatycznie dodawane przez implementacje Keymaster 2+ do wszystkich nowo wygenerowanych (lub zaktualizowanych) kluczy. Co więcej, każda próba użycia klucza, który nie ma wersji systemu operacyjnego lub poziomu poprawki odpowiadającej odpowiednio bieżącej wersji systemu operacyjnego lub poziomowi poprawki, zostanie odrzucona z ErrorCode::KEY_REQUIRES_UPGRADE .

Tag::OS_VERSION to wartość UINT reprezentująca główną, poboczną i podrzędną część wersji systemu Android jako MMmmss, gdzie MM to wersja główna, mm to wersja dodatkowa, a ss to wersja podrzędna. Na przykład 6.1.2 będzie reprezentowane jako 060102.

Tag::OS_PATCHLEVEL to wartość UINT reprezentująca rok i miesiąc ostatniej aktualizacji systemu jako RRRRMM, gdzie RRRR to czterocyfrowy rok, a MM to dwucyfrowy miesiąc. Na przykład marzec 2016 będzie reprezentowany jako 201603.

Klucz aktualizacji

Aby umożliwić aktualizację kluczy do nowej wersji systemu operacyjnego i poziomu poprawki obrazu systemu, w systemie Android 7.1 dodano metodę upgradeKey do warstwy HAL:

Klucznik 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Klucznik 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);
  • dev to struktura urządzenia
  • keyBlobToUpgrade to klucz, który należy zaktualizować
  • upgradeParams to parametry potrzebne do aktualizacji klucza. Będą to m.in. Tag::APPLICATION_ID i Tag::APPLICATION_DATA , które są niezbędne do odszyfrowania klucza BLOB, jeśli zostały podane podczas generowania.
  • upgradedKeyBlob to parametr wyjściowy używany do zwracania nowego kluczowego obiektu BLOB.

Jeśli upgradeKey zostanie wywołany z kluczem BLOB, którego nie można przeanalizować lub jest nieprawidłowy z innego powodu, zwróci ErrorCode::INVALID_KEY_BLOB . Jeśli zostanie wywołana z kluczem, którego poziom poprawki jest większy niż bieżąca wartość systemowa, zwróci ErrorCode::INVALID_ARGUMENT . Jeśli zostanie wywołana z kluczem, którego wersja systemu operacyjnego jest większa niż bieżąca wartość systemowa, a wartość systemowa jest różna od zera, zwróci ErrorCode::INVALID_ARGUMENT . Dozwolone są aktualizacje wersji systemu operacyjnego z niezerowej do zerowej. W przypadku błędów komunikacji z bezpiecznym światem zwraca odpowiednią wartość błędu (np. ErrorCode::SECURE_HW_ACCESS_DENIED , ErrorCode::SECURE_HW_BUSY ). W przeciwnym razie zwraca ErrorCode::OK i zwraca nowy kluczowy obiekt blob w upgradedKeyBlob .

keyBlobToUpgrade pozostaje ważny po wywołaniu upgradeKey i teoretycznie może zostać użyty ponownie, jeśli wersja urządzenia zostanie obniżona. W praktyce magazyn kluczy zazwyczaj wywołuje deleteKey w obiekcie blob keyBlobToUpgrade wkrótce po wywołaniu metody upgradeKey . Jeśli keyBlobToUpgrade miał tag Tag::ROLLBACK_RESISTANT , to upgradedKeyBlob również powinien go mieć (i powinien być odporny na wycofywanie zmian).

Bezpieczna konfiguracja

Aby zaimplementować powiązanie wersji, klucznik TA potrzebuje sposobu, aby bezpiecznie otrzymać aktualną wersję systemu operacyjnego i poziom poprawki (informacje o wersji) oraz zapewnić, że otrzymywane informacje w dużym stopniu odpowiadają informacjom o działającym systemie.

Aby zapewnić bezpieczne dostarczanie informacji o wersji do TA, do nagłówka obrazu startowego dodano pole OS_VERSION . Skrypt kompilacji obrazu rozruchowego automatycznie wypełnia to pole. Producenci OEM i klucznicy wdrażający TA muszą współpracować, aby zmodyfikować programy ładujące urządzenia, aby wyodrębnić informacje o wersji z obrazu rozruchowego i przekazać je do TA przed uruchomieniem niezabezpieczonego systemu. Dzięki temu osoby atakujące nie będą mogły ingerować w udostępnianie informacji o wersji TA.

Konieczne jest również upewnienie się, że obraz systemu zawiera te same informacje o wersji, co obraz rozruchowy. W tym celu do warstwy HAL klucza dodano metodę konfiguracji:

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 warstwy HAL, ale przed wywołaniem jakichkolwiek innych metod. Jeśli przed konfiguracją zostanie wywołana jakakolwiek inna metoda, TA zwróci ErrorCode::KEYMASTER_NOT_CONFIGURED .

Przy pierwszym wywołaniu configure po uruchomieniu urządzenia należy sprawdzić, czy podane informacje o wersji zgadzają się z informacjami dostarczonymi przez program ładujący. Jeśli informacje o wersji nie są zgodne, configure zwraca ErrorCode::INVALID_ARGUMENT , a wszystkie inne metody klucza głównego w dalszym ciągu zwracają ErrorCode::KEYMASTER_NOT_CONFIGURED . Jeśli informacje się zgadzają, configure zwraca ErrorCode::OK , a inne metody keymastera zaczynają działać normalnie.

Kolejne wywołania configure zwracają tę samą wartość zwróconą przez pierwsze wywołanie i nie zmieniają stanu klucza głównego. Należy pamiętać, że ten proces wymaga, aby wszystkie OTA zaktualizowały zarówno obrazy systemowe, jak i rozruchowe; nie można ich oddzielnie aktualizować, aby zachować synchronizację informacji o wersji.

Ponieważ configure zostanie wywołana przez system, którego zawartość ma zostać zweryfikowana, istnieje wąskie okno możliwości dla osoby atakującej złamanie zabezpieczeń obrazu systemu i zmuszenie go do dostarczenia informacji o wersji, które odpowiadają obrazowi rozruchowemu, ale które nie są rzeczywistą wersja systemu. Połączenie weryfikacji obrazu rozruchowego, sprawdzania poprawności dm-verity zawartości obrazu systemu oraz faktu, że configure jest wywoływana na bardzo wczesnym etapie uruchamiania systemu, powinno sprawić, że wykorzystanie tej możliwości będzie trudne.