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

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

Формат файла

Все числовые поля имеют порядок байтов little endian. Все поля занимают ровно столько байтов, сколько указано в их 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 берется из блока подписи версии 3 APK. Если этот блок отсутствует, он берется из блока версии 2 (см. 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;
};

merkle_tree — это полное дерево Меркла APK-файла, вычисленное в соответствии с описанием в документации fs-verity .

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

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

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

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

При фиксации сеанса установки PackageManagerService выполняет вызов ioctl для получения двоичных данных signing_info из IncFS, анализирует их и проверяет подпись.

Компонент Incremental Data Loader передает часть подписи, содержащую дерево Меркла, через собственный API загрузчика данных. Команда оболочки package service 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. V2, SHA2-512
  5. V2, SHA2-256

См. последовательность подписантов с префиксом длины в схеме подписи APK версии 3.

Проверка и тестирование

Процесс проверки APK-файлов версии 4 показан на следующем рисунке:

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

Рисунок 1. Процесс проверки APK версии 4.

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

  • CtsIncrementalInstallHostTestCases
  • /android/cts/hostsidetests/incrementalinstall

Проверьте формат подписи.

Для проверки формата подписи настройте среду сборки и выполните следующие ручные тесты:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

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

Используйте этот процесс для проверки формата подписи с помощью Android SDK:

  1. Настройте среду сборки и убедитесь, что внедрение IncFS завершено.
  2. Прошейте сборку на целевое физическое устройство или эмулятор.
  3. Сгенерируйте или получите существующий APK-файл, а затем создайте отладочный ключ подписи .
  4. Подпишите и установите 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