O Android 11 oferece suporte a um esquema de assinatura compatível com streaming com o esquema de assinatura
de APK v4. A assinatura v4 é baseada na árvore de hash de Merkle
calculada em todos os bytes do APK. Ele segue exatamente a estrutura da árvore de hash fs-verity (por exemplo, preenchimento de zero
do sal e preenchimento de zero do último bloco). O Android 11 armazena a assinatura
em um arquivo separado. A assinatura <apk name>.apk.idsigA v4
requer uma assinatura v2 ou v3 complementar.
Formato do arquivo
Todos os campos numéricos estão em little endian. Todos os campos ocupam exatamente o número
de bytes como sizeof(), sem preenchimento ou
alinhamento implícito.
Confira abaixo uma estrutura auxiliar para simplificar as definições.
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
Conteúdo do arquivo principal:
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 são os parâmetros usados para a geração de árvores de hash
+ o hash raiz:
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 é a seguinte estrutura:
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é retirado do bloco de assinatura v3 do APK ou, se não estiver presente, do bloco v2 (consulte apk_digest).
Para criar e verificar, um código signature precisa serializar
os seguintes dados em um blob binário e transmiti-los ao
algoritmo de assinatura / verificação como os dados assinados:
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é a árvore Merkle completa do APK, calculada conforme descrito na documentação do fs-verity.
Produtores e consumidores
A ferramenta do SDK do Android apksigner agora gera o arquivo de assinatura v4
se você a executar com parâmetros padrão. A assinatura v4 pode ser desativada da mesma forma
que os outros esquemas de assinatura. Ele também pode verificar se a assinatura v4 é
válida.
O adb espera que o arquivo .apk.idsig esteja presente ao lado do .apk ao
executar o comando adb install --incremental
.
Ele também vai usar o arquivo .idsig para tentar a instalação incremental por
padrão e vai voltar para uma instalação regular se ele estiver ausente ou
inválido.
Quando uma sessão de instalação é criada, a nova API de instalação de streaming
no PackageInstaller aceita a assinatura v4 removida
como um argumento separado ao adicionar um arquivo à sessão.
Nesse ponto, signing_info é transmitido para incfs como um
blob inteiro. O Incfs extrai o hash raiz do blob.
Quando a sessão de instalação está sendo confirmada, o PackageManagerService faz
um ioctl para extrair o blob signing_info do incfs, analisar e verificar
a assinatura.
O componente do carregador de dados incrementais precisa transmitir a parte da árvore Merkle
da assinatura pela API nativa do carregador de dados.O comando de shell do serviço
package install-incremental
aceita o arquivo de assinatura v4 simplificado codificado como base64 como um parâmetro para cada
arquivo adicionado. A árvore Merkle correspondente precisa ser enviada para o
stdin do comando.
apk_digest
apk_digest é o primeiro resumo de conteúdo disponível:
- V3, bloco de 1 MB, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
- V3, bloco de 4 KB, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
- V3, bloco de 1 MB, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
- V2, SHA2-512,
- V2, SHA2-256.
Consulte Sequência de assinaturas com prefixo de comprimento no esquema de assinatura de APK v3.
Validação e teste
Valide a implementação usando testes de unidade de recurso e CTS.
CtsIncrementalInstallHostTestCases- /android/cts/hostsidetests/incrementalinstall
Testar o formato da assinatura
Para testar o formato da assinatura, configure um ambiente de desenvolvimento e execute os seguintes testes manuais:
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Testar o formato de assinatura com o SDK do Android (ADB e apksigner)
Para testar o formato de assinatura com o SDK do Android, configure um ambiente de desenvolvimento e verifique se você concluiu a implementação do IncFS. Em seguida, atualize o build em um dispositivo físico ou emulador de destino. Você precisa gerar ou receber um APK e criar uma chave de assinatura de depuração. Por fim, assine e instale o APK com o formato de assinatura v4 na pasta "build-tools".
Assinatura
$ ./apksigner sign --ks debug.keystore game.apk
Instalar
$ ./adb install game.apk
Onde esses testes podem ser encontrados?
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java