Схема подписи APK v4

Android 11 поддерживает схему подписи, совместимую с потоковой передачей, с помощью схемы подписи APK v4. Подпись v4 основана на хеш-дереве Меркла, рассчитанном по всем байтам APK. Он точно следует структуре хеш-дерева fs-verity (например, заполнение нулями соли и заполнение нулями последнего блока). Android 11 хранит подпись в отдельном файле <apk name>.apk.idsig . Для подписи версии 4 требуется дополнительная подпись версии 2 или версии 3 .

Формат файла

Все числовые поля имеют обратный порядок байтов. Все поля занимают ровно столько байтов, сколько их sizeof() , без добавления неявного заполнения или выравнивания.

Ниже приведена вспомогательная структура для упрощения определений.

template <class SizeT>
struct sized_bytes {
        SizeT size;
        byte bytes[size];
};

Содержимое основного файла:

struct V4Signature {
        int32 version; // only version 2 is supported as of now
        sized_bytes<int32> hashing_info;
        sized_bytes<int32> signing_info;
        sized_bytes<int32> merkle_tree;  // optional
};

hashing_info — это параметры, используемые для генерации хеш-дерева + корневой хэш:

struct hashing_info.bytes {
    int32 hash_algorithm;    // only 1 == SHA256 supported
    int8 log2_blocksize;     // only 12 (block size 4096) supported now
    sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
    sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};

signing_info представляет собой следующую структуру:

struct signing_info.bytes {
    sized_bytes<int32> apk_digest;  // used to match with the corresponding APK
    sized_bytes<int32> x509_certificate; // ASN.1 DER form
    sized_bytes<int32> additional_data; // a free-form binary data blob
    sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
    int32 signature_algorithm_id; // see the APK v2 doc for the list
    sized_bytes<int32> signature;
};
  • apk_digest берется из блока подписи APK v3 или, если он отсутствует, из блока v2 (см. apk_digest )

Для создания и проверки кода signature необходимо сериализовать следующие данные в двоичный двоичный объект и передать их в алгоритм подписи/проверки в качестве подписанных данных :

struct V4DataForSigning {
        int32 size;
        int64 file_size; // the size of the file that's been hashed.
        hashing_info.hash_algorithm;
        hashing_info.log2_blocksize;
        hashing_info.salt;
        hashing_info.raw_root_hash;
        signing_info.apk_digest;
        signing_info.x509_certificate;
        signing_info.additional_data;
};
  1. merkle_tree — это целое дерево Merkle APK, рассчитанное, как описано в документации fs-verity .

Производители и потребители

Инструмент Android SDK apksigner теперь генерирует файл подписи v4, если вы запускаете его с параметрами по умолчанию. Подпись v4 можно отключить так же, как и другие схемы подписи. Он также может проверить, действительна ли подпись v4.

adb ожидает, что файл .apk.idsig будет присутствовать рядом с .apk при запуске команды adb install --incremental
Он также будет использовать файл .idsig, чтобы попробовать добавочную установку по умолчанию, и вернется к обычной установке, если он отсутствует или недействителен.

При создании сеанса установки новый API потоковой установки в PackageInstaller принимает удаленную подпись v4 в качестве отдельного аргумента при добавлении файла в сеанс. На этом этапе signing_info передается в incfs целиком. Incfs извлекает корневой хэш из большого двоичного объекта.

Когда сеанс установки фиксируется, PackageManagerService выполняет ioctl для извлечения большого двоичного объекта signing_info из incfs, анализирует его и проверяет подпись.

Ожидается, что компонент добавочного загрузчика данных будет передавать часть сигнатуры дерева Меркла через собственный API-интерфейс загрузчика данных.
Команда оболочки службы package install-incremental принимает удаленный файл подписи v4, закодированный как base64, в качестве параметра для каждого добавляемого файла. Соответствующее дерево Меркла должно быть отправлено на стандартный stdin команды.

apk_digest

apk_digest — это первый доступный дайджест контента по порядку:

  1. V3, блок 1 МБ, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
  2. V3, блок 4 КБ, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
  3. V3, блок 1 МБ, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
  4. В2, ША2-512,
  5. В2, ША2-256.

См. последовательность подписей с префиксом длины в APK Signature Scheme v3.

процесс проверки APK v4
Рис. 1. Процесс проверки APK v4

Валидация и тестирование

Проверьте реализацию с помощью функциональных модульных тестов и CTS.

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/incrementalinstall

Тестирование формата подписи

Чтобы протестировать формат подписи, настройте среду разработки и выполните следующие ручные тесты:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

Тестирование формата подписи с помощью Android SDK (ADB и apksigner)

Чтобы протестировать формат подписи с помощью Android SDK, настройте среду разработки и убедитесь, что вы завершили внедрение IncFS . Затем запустите сборку на целевом физическом устройстве или эмуляторе. Вам необходимо сгенерировать или получить существующий APK, а затем создать ключ подписи отладки . Наконец, подпишите и установите apk с форматом подписи v4 из папки build-tools.

Знак

$ ./apksigner sign --ks debug.keystore game.apk

Установить

$ ./adb install game.apk

Где можно найти эти тесты?

/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java