Android 11 supports a streaming-compatible signing scheme with the APK
signature scheme v4. The v4 signature is based on the Merkle hash tree
calculated over all bytes of the APK. It follows the structure of the fs-verity hash tree exactly (for example, zero-padding
the salt and zero-padding the last block). Android 11 stores the signature
in a separate file, <apk name>.apk.idsig
A v4 signature
requires a complementary v2 or v3 signature.
File format
All numeric fields are in little endian. All fields occupy exactly the number
of bytes as their sizeof()
, no implicit padding or
alignment added.
Below is a helper struct to simplify the definitions.
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
Main file content:
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
is the parameters used for hash tree
generation + the root hash:
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
is the following struct:
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
is taken from the APK's v3 signing block, or, if not present, from the v2 block (see apk_digest)
To create and verify a signature
code has to serialize
the following data into binary blob and pass it into the
signing / verifying algorithm as the signed data:
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
is the whole Merkle tree of the APK, calculated as described in the fs-verity documentation.
Producers and consumers
apksigner
Android SDK tool now generates the v4 signature file
if you run it with default parameters. v4 signing can be disabled the same way
as the other signing schemes. It can also verify if the v4 signature is
valid.
adb
expects the .apk.idsig file to be present next to the .apk when
running the adb install --incremental
command
It will also use the .idsig file to try Incremental installation by
default, and will fall back to a regular installation if it's missing or
invalid.
When an installation session is created, the new streaming installation API
in the PackageInstaller
accepts the stripped
v4 signature as a separate argument when adding a file to the session.
At this point, signing_info
is passed into incfs as a
whole blob. Incfs extracts root hash from the blob.
When the installation session is being committed, PackageManagerService does
an ioctl to retrieve the signing_info
blob from incfs, parses it and verifies
the signature.
Incremental Data Loader component is expected to stream the Merkle tree part
of the signature through the data loader native API.
package
service shell command install-incremental
accepts the stripped v4 signature file encoded as base64 as a parameter for each
added file. The corresponding Merkle tree has to be sent into the command's
stdin
.
apk_digest
apk_digest
is the first available content digest in order:
- V3, 1MB block, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
- V3, 4KB block, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
- V3, 1MB block, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
- V2, SHA2-512,
- V2, SHA2-256.
See length-prefixed sequence of length-prefixed signatures in APK signature scheme v3.
Validation and testing
Validate the implementation using Feature Unit Tests and CTS.
CtsIncrementalInstallHostTestCases
- /android/cts/hostsidetests/incrementalinstall
Test the signature format
To test the signature format, setup a development environment and run the following manual tests:
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Test the signature format with Android SDK (ADB and apksigner)
To test the signature format with Android SDK, setup a development environment and ensure you have completed the implementation of IncFS. Then flash the build on a target physical device or emulator. You need to generate or obtain an existing APK and then create a debug signing key. Finally, sign and install the apk with v4 signature format from the build-tools folder.
Sign
$ ./apksigner sign --ks debug.keystore game.apk
Install
$ ./adb install game.apk
Where can these tests be found?
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java