O Android 9 oferece suporte à rotação de chaves de APK, que permite que os apps mudem a chave de assinatura como parte de uma atualização do APK. Para tornar a rotação prática, os APKs precisam indicar os níveis de confiança entre a chave de assinatura nova e antiga. Para oferecer suporte à rotação de chaves, atualizamos o Esquema de assinatura de APK da v2 para a v3 para permitir que as chaves novas e antigas sejam usadas. A V3 adiciona informações sobre as versões do SDK com suporte e uma estrutura de prova de rotação ao bloco de assinatura do APK.
Bloco de assinatura de APK
Para manter a compatibilidade com o formato v1 do APK, as assinaturas do APK v2 e v3 são armazenadas em um bloco de assinatura de APK, localizado imediatamente antes do diretório central ZIP.
O formato do bloco de assinatura do APK v3 é o mesmo que o v2. A assinatura v3 do APK é armazenada como um par de ID-valor com o ID 0xf05368c0.
Bloco do esquema de assinatura de APK v3
O esquema v3 foi projetado para ser muito semelhante ao esquema v2. Ele tem o mesmo formato geral e oferece suporte aos mesmos IDs de algoritmo de assinatura, tamanhos de chave e curvas EC.
No entanto, o esquema v3 adiciona informações sobre as versões do SDK com suporte e a estrutura de prova de rotação.
Formato
O bloco do esquema de assinatura do APK v3 é armazenado no bloco de assinatura do APK com o ID
0xf05368c0
.
O formato do bloco do esquema de assinatura de APK v3 segue o da v2:
- Sequência com prefixo de comprimento de
signer
com prefixo de comprimento:signed data
com prefixo de comprimento:- Sequência com prefixo de comprimento de
digests
com prefixo de comprimento:signature algorithm ID
(4 bytes)digest
(prefixo de comprimento)
- Sequência com prefixo de comprimento de X.509
certificates
:certificate
X.509 com prefixo de comprimento (forma ASN.1 DER)
minSDK
(uint32): esse assinador precisa ser ignorado se a versão da plataforma for inferior a esse número.maxSDK
(uint32): esse signatário precisa ser ignorado se a versão da plataforma for maior que esse número.- Sequência com prefixo de comprimento de
additional attributes
com prefixo de comprimento:ID
(uint32)value
(comprimento variável: comprimento do atributo extra - 4 bytes)ID - 0x3ba06f8c
- Estrutura de prova de rotação
value -
- Sequência com prefixo de comprimento de
minSDK
(uint32): cópia do valor minSDK na seção de dados assinados, usada para pular a verificação dessa assinatura se a plataforma atual não estiver no intervalo. Precisa corresponder ao valor de dados assinado.maxSDK
(uint32): cópia do valor maxSDK na seção de dados assinados, usada para pular a verificação dessa assinatura se a plataforma atual não estiver no intervalo. Precisa corresponder ao valor de dados assinado.- Sequência com prefixo de comprimento de
signatures
com prefixo de comprimento:signature algorithm ID
(uint32)signature
com prefixo de comprimento sobresigned data
public key
com prefixo de comprimento (SubjectPublicKeyInfo, formato ASN.1 DER)
Estruturas de prova de rotação e certificados antigos de confiança própria
A estrutura de prova de rotação permite que os apps girem o certificado de assinatura sem ser bloqueados em outros apps com os quais eles se comunicam. Para isso, as assinaturas de apps contêm duas novas informações:
- declaração para terceiros de que o certificado de assinatura do app pode ser confiável sempre que os certificados anteriores forem confiáveis
- certificados de assinatura mais antigos do app em que ele ainda confia
O atributo de prova de rotação na seção de dados assinados consiste em uma lista vinculada individualmente, com cada nó contendo um certificado de assinatura usado para assinar versões anteriores do app. Esse atributo tem a finalidade de conter as estruturas de dados conceituais de prova de rotação e de certificados antigos de confiança própria. A lista é ordenada por versão com o certificado de assinatura mais antigo correspondente ao nó raiz. A estrutura de dados de prova de rotação é criada com o certificado em cada nó assinando o próximo na lista, e assim imbuindo cada nova chave com evidências de que ela deve ser confiável como as chaves mais antigas.
A estrutura de dados de certificados autoconfiáveis antigos é construída adicionando flags a cada
nó indicando a associação e as propriedades no conjunto. Por exemplo, uma flag
pode estar presente indicando que o certificado de assinatura em um determinado nó é
confiável para receber permissões de assinatura do Android. Essa flag permite que outros apps
assinados pelo certificado mais antigo ainda recebam uma permissão de assinatura
definida por um app assinado com o novo certificado de assinatura. Como todo
o atributo de prova de rotação reside na seção de dados assinados do campo signer
v3, ele é protegido pela chave usada para assinar o apk que o contém.
Esse formato impede várias chaves de assinatura e a convergência de diferentes certificados de assinatura ancestral para um (vários nós de início para um destino comum).
Formato
A prova de rotação é armazenada no bloco do esquema de assinatura de APK v3 com o
ID 0x3ba06f8c
. O formato é:
- Sequência com prefixo de comprimento de
levels
com prefixo de comprimento:signed data
com prefixo de comprimento (por certificado anterior, se houver)certificate
X.509 com prefixo de comprimento (forma ASN.1 DER)signature algorithm ID
(uint32): algoritmo usado pelo certificado no nível anterior
flags
(uint32): flags que indicam se esse certificado precisa estar na struct de certificados autoconfiáveis antigos e para quais operações.signature algorithm ID
(uint32): precisa corresponder ao da seção de dados assinados no próximo nível.signature
com prefixo de comprimento sobre osigned data
acima
Vários certificados
Não é possível usar vários signatários, e o Google Play não publica apps assinados com vários certificados.
Verificação
No Android 9 e versões mais recentes, os APKs podem ser verificados de acordo com o Esquema de assinatura do APK v3, v2 ou v1. Plataformas mais antigas ignoram as assinaturas v3 e tentam verificar as assinaturas v2 e v1.
Figura 1. Processo de verificação de assinatura de APK
Verificação do esquema de assinatura de APK v3
- Localize o bloco de assinatura do APK e verifique se:
- Dois campos de tamanho do bloco de assinatura do APK contêm o mesmo valor.
- O diretório central ZIP é seguido imediatamente pelo registro ZIP End of Central Directory.
- O fim do diretório central ZIP não é seguido por mais dados.
- Localize o primeiro bloco do esquema de assinatura do APK v3 dentro do bloco de assinatura do APK. Se o bloco v3 estiver presente, prossiga para a etapa 3. Caso contrário, volte a verificar o APK usando o esquema v2.
- Para cada
signer
no bloco do esquema de assinatura de APK v3 com uma versão mínima e máxima do SDK dentro do intervalo da plataforma atual:- Escolha o
signature algorithm ID
mais forte com suporte emsignatures
. A ordem de força depende de cada implementação/versão da plataforma. - Verifique o
signature
correspondente designatures
em relação asigned data
usandopublic key
. Agora é possível analisarsigned data
. - Verifique se as versões mínima e máxima do SDK nos dados assinados correspondem às
especificadas para o
signer
. - Verifique se a lista ordenada de IDs de algoritmos de assinatura em
digests
esignatures
é idêntica. Isso é para evitar a remoção/adição de assinaturas. - Calcule o resumo do conteúdo do APK usando o mesmo algoritmo de resumo usado pelo algoritmo de assinatura.
- Verifique se o resumo computado é idêntico ao
digest
correspondente dedigests
. - Verifique se o SubjectPublicKeyInfo do primeiro
certificate
decertificates
é idêntico apublic key
. - Se o atributo de prova de rotação existir para o
signer
, verifique se a estrutura é válida e se essesigner
é o último certificado na lista.
- Escolha o
- A verificação será bem-sucedida se exatamente um
signer
for encontrado no intervalo da plataforma atual e a etapa 3 tiver sido concluída para essesigner
.
Validação
Para testar se o dispositivo oferece suporte à v3 corretamente, execute os
testes do CTS PkgInstallSignatureVerificationTest.java
em
cts/hostsidetests/appsecurity/src/android/appsecurity/cts/
.