Esquema de assinatura de APK v3

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 -
    • 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 sobre signed 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 o signed 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.

Processo de verificação de assinatura de APK

Figura 1. Processo de verificação de assinatura de APK

Verificação do esquema de assinatura de APK v3

  1. Localize o bloco de assinatura do APK e verifique se:
    1. Dois campos de tamanho do bloco de assinatura do APK contêm o mesmo valor.
    2. O diretório central ZIP é seguido imediatamente pelo registro ZIP End of Central Directory.
    3. O fim do diretório central ZIP não é seguido por mais dados.
  2. 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.
  3. 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:
    1. Escolha o signature algorithm ID mais forte com suporte em signatures. A ordem de força depende de cada implementação/versão da plataforma.
    2. Verifique o signature correspondente de signatures em relação a signed data usando public key. Agora é possível analisar signed data.
    3. Verifique se as versões mínima e máxima do SDK nos dados assinados correspondem às especificadas para o signer.
    4. Verifique se a lista ordenada de IDs de algoritmos de assinatura em digests e signatures é idêntica. Isso é para evitar a remoção/adição de assinaturas.
    5. Calcule o resumo do conteúdo do APK usando o mesmo algoritmo de resumo usado pelo algoritmo de assinatura.
    6. Verifique se o resumo computado é idêntico ao digest correspondente de digests.
    7. Verifique se o SubjectPublicKeyInfo do primeiro certificate de certificates é idêntico a public key.
    8. Se o atributo de prova de rotação existir para o signer, verifique se a estrutura é válida e se esse signer é o último certificado na lista.
  4. 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 esse signer.

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/.