O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Esquema de assinatura de APK v2

O APK Signature Scheme v2 é um esquema de assinatura de arquivo completo que aumenta a velocidade de verificação e fortalece as garantias de integridade , detectando quaisquer alterações nas partes protegidas do APK.

Assinar usando o esquema de assinatura de APK v2 insere um bloco de assinatura de APK no arquivo APK imediatamente antes da seção do diretório central do ZIP. Dentro do APK Signing Block, as assinaturas v2 e as informações de identidade do signatário são armazenadas em um APK Signature Scheme v2 Block .

APK antes e depois da assinatura

Figura 1. APK antes e depois da assinatura

Esquema de assinatura APK v2 foi introduzido no Android 7.0 (Nougat). Para tornar um APK instalável no Android 6.0 (Marshmallow) e em dispositivos mais antigos, o APK deve ser assinado usando a assinatura JAR antes de ser assinado com o esquema v2.

Bloco de assinatura de APK

Para manter a compatibilidade com versões anteriores do formato APK v1, as assinaturas de APK v2 e mais recentes são armazenadas dentro de um bloco de assinatura de APK, um novo contêiner introduzido para oferecer suporte ao esquema de assinatura de APK v2. Em um arquivo APK, o APK Signing Block está localizado imediatamente antes do ZIP Central Directory, que está localizado no final do arquivo.

O bloco contém pares de valor de ID agrupados de uma forma que torna mais fácil localizar o bloco no APK. A assinatura v2 do APK é armazenada como um par de valor de ID com ID 0x7109871a.

Formato

O formato do APK Signing Block é o seguinte (todos os campos numéricos são little-endian):

  • size of block em bytes (excluindo este campo) (uint64)
  • Sequência de pares de valores de ID prefixados com comprimento de uint64:
    • ID (uint32)
    • value (comprimento variável: comprimento do par - 4 bytes)
  • size of block em bytes - mesmo que o primeiro campo (uint64)
  • magic “APK Sig Block 42” (16 bytes)

O APK é analisado encontrando primeiro o início do diretório central do ZIP (encontrando o registro do final do diretório central do ZIP no final do arquivo e, em seguida, lendo o deslocamento inicial do diretório central a partir do registro). O valor magic fornece uma maneira rápida de estabelecer que o que precede o Diretório central é provavelmente o Bloco de assinatura do APK. O size of block valor size of block aponta de forma eficiente para o início do bloco no arquivo.

Pares de valor de ID com IDs desconhecidos devem ser ignorados ao interpretar o bloco.

Bloco de esquema v2 de assinatura de APK

O APK é assinado por um ou mais signatários / identidades, cada um representado por uma chave de assinatura. Essas informações são armazenadas como um bloco APK Signature Scheme v2. Para cada signatário, as seguintes informações são armazenadas:

  • (algoritmo de assinatura, resumo, assinatura) tuplas. O resumo é armazenado para desacoplar a verificação de assinatura da verificação de integridade do conteúdo do APK.
  • Cadeia de certificados X.509 que representa a identidade do signatário.
  • Atributos adicionais como pares de valores-chave.

Para cada signatário, o APK é verificado usando uma assinatura compatível da lista fornecida. As assinaturas com algoritmos de assinatura desconhecidos são ignoradas. Cabe a cada implementação escolher qual assinatura usar quando forem encontradas várias assinaturas com suporte. Isso permite a introdução de métodos de assinatura mais fortes no futuro de uma forma compatível com versões anteriores. A abordagem sugerida é verificar a assinatura mais forte.

Formato

O bloco v2 do esquema de assinatura do APK é armazenado dentro do bloco de assinatura do APK com o ID 0x7109871a .

O formato do bloco APK Signature Scheme v2 é o seguinte (todos os valores numéricos são little-endian, todos os campos com prefixo de comprimento usam uint32 para o comprimento):

  • sequência prefixada de comprimento do signer prefixado por comprimento:
    • signed data prefixo de comprimento:
      • sequência prefixada de comprimento de digests prefixados por comprimento:
      • sequência com prefixo de comprimento de certificates X.509:
        • certificate X.509 com prefixo de comprimento (formato ASN.1 DER)
      • sequência com prefixo de comprimento de additional attributes prefixo de comprimento:
        • ID (uint32)
        • value (comprimento variável: comprimento do atributo adicional - 4 bytes)
    • sequência com prefixo de comprimento de signatures prefixo de comprimento:
      • signature algorithm ID (uint32)
      • signature prefixo de comprimento sobre signed data
    • public key prefixo de comprimento (SubjectPublicKeyInfo, formato ASN.1 DER)

IDs de algoritmo de assinatura

  • 0x0101 — RSASSA-PSS com resumo SHA2-256, SHA2-256 MGF1, 32 bytes de sal, trailer: 0xbc
  • 0x0102 — RSASSA-PSS com resumo SHA2-512, SHA2-512 MGF1, 64 bytes de sal, trailer: 0xbc
  • 0x0103 — RSASSA-PKCS1-v1_5 com resumo SHA2-256. Isso é para sistemas de construção que requerem assinaturas determinísticas.
  • 0x0104 — RSASSA-PKCS1-v1_5 com resumo SHA2-512. Isso é para sistemas de construção que requerem assinaturas determinísticas.
  • 0x0201 — ECDSA com resumo SHA2-256
  • 0x0202 — ECDSA com resumo SHA2-512
  • 0x0301 — DSA com resumo SHA2-256

Todos os algoritmos de assinatura acima são suportados pela plataforma Android. As ferramentas de assinatura podem oferecer suporte a um subconjunto dos algoritmos.

Tamanhos de chaves e curvas EC suportados:

  • RSA: 1024, 2048, 4096, 8192, 16384
  • EC: NIST P-256, P-384, P-521
  • DSA: 1024, 2048, 3072

Conteúdo protegido por integridade

Para fins de proteção do conteúdo do APK, um APK consiste em quatro seções:

  1. Conteúdo das entradas ZIP (do deslocamento 0 até o início do bloco de assinatura do APK)
  2. Bloco de assinatura de APK
  3. ZIP Central Directory
  4. ZIP Fim do Diretório Central

Seções do APK após a assinatura

Figura 2. Seções do APK após a assinatura

O Esquema de Assinatura APK v2 protege a integridade das seções 1, 3, 4 e os blocos de signed data Bloco do Esquema de Assinatura APK v2 contido na seção 2.

A integridade das seções 1, 3 e 4 é protegida por um ou mais resumos de seus conteúdos armazenados em blocos de signed data que são, por sua vez, protegidos por uma ou mais assinaturas.

O resumo das seções 1, 3 e 4 é calculado da seguinte maneira, semelhante a uma árvore Merkle de dois níveis. Cada seção é dividida em blocos consecutivos de 1 MB (2 20 bytes). O último pedaço em cada seção pode ser mais curto. O resumo de cada bloco é calculado sobre a concatenação do byte 0xa5 , o comprimento do bloco em bytes (little-endian uint32) e o conteúdo do bloco. O resumo de nível superior é calculado sobre a concatenação do byte 0x5a , o número de blocos (little-endian uint32) e a concatenação dos resumos dos blocos na ordem em que aparecem no APK. O resumo é calculado de maneira fragmentada para permitir acelerar o cálculo paralelizando-o.

Resumo do APK

Figura 3. Resumo do APK

A proteção da seção 4 (ZIP End of Central Directory) é complicada pela seção que contém o deslocamento do ZIP Central Directory. O deslocamento muda quando o tamanho do bloco de assinatura do APK muda, por exemplo, quando uma nova assinatura é adicionada. Portanto, ao calcular o resumo sobre o ZIP End do Diretório Central, o campo que contém o deslocamento do ZIP Central Directory deve ser tratado como contendo o deslocamento do Bloco de Assinatura do APK.

Proteções contra reversão

Um invasor pode tentar que um APK assinado v2 seja verificado como um APK assinado v1 em plataformas Android compatíveis com a verificação de APK assinado v2. Para mitigar esse ataque, os APKs com assinatura v2 que também são assinados com v1 devem conter um atributo X-Android-APK-Signed na seção principal de seus arquivos META-INF / *. SF. O valor do atributo é um conjunto separado por vírgulas de IDs de esquema de assinatura de APK (o ID desse esquema é 2). Ao verificar a assinatura v1, o verificador de APK é necessário para rejeitar APKs que não tenham uma assinatura para o esquema de assinatura de APK que o verificador prefere desse conjunto (por exemplo, esquema v2). Esta proteção se baseia no fato de que os arquivos META-INF / *. SF de conteúdo são protegidos por assinaturas v1. Consulte a seção sobre verificação de APK assinado por JAR .

Um invasor pode tentar retirar assinaturas mais fortes do bloco APK Signature Scheme v2. Para atenuar esse ataque, a lista de IDs de algoritmos de assinatura com os quais o APK estava sendo assinado é armazenada no bloco de signed data que é protegido por cada assinatura.

Verificação

No Android 7.0 e posterior, os APKs podem ser verificados de acordo com o esquema de assinatura APK v2 + ou assinatura JAR (esquema v1). As plataformas mais antigas ignoram as assinaturas v2 e verificam apenas as assinaturas v1.

Processo de verificação de assinatura de APK

Figura 4. Processo de verificação de assinatura de APK (novas etapas em vermelho)

Verificação do esquema de assinatura do APK v2

  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 ZIP Central Directory é imediatamente seguido pelo ZIP End of Central Directory record.
    3. ZIP Fim do diretório central não é seguido por mais dados.
  2. Localize o primeiro bloco de esquema de assinatura de APK v2 dentro do bloco de assinatura de APK. Se o bloco v2 estiver presente, vá para a etapa 3. Caso contrário, volte para verificar o APK usando o esquema v1 .
  3. Para cada signer no bloco APK Signature Scheme v2:
    1. Escolha o signature algorithm ID de signatures mais forte com suporte nas signatures . A ordem de força depende de cada versão de implementação / plataforma.
    2. Verifique a signature correspondente das signatures relação aos signed data usando public key . (Agora é seguro analisar os signed data .)
    3. Verifique se a lista ordenada de IDs de algoritmo de assinatura em digests e signatures é idêntica. (Isso evita a remoção / adição de assinaturas.)
    4. Calcule o resumo do conteúdo do APK usando o mesmo algoritmo de resumo que o algoritmo de resumo usado pelo algoritmo de assinatura.
    5. Verifique se o resumo calculado é idêntico ao digest correspondente dos digests .
    6. Verifique se SubjectPublicKeyInfo do primeiro certificate de certificates é idêntico à public key .
  4. A verificação é bem-sucedida se pelo menos um signer for encontrado e a etapa 3 for bem-sucedida para cada signer encontrado.

Observação : o APK não deve ser verificado usando o esquema v1 se ocorrer uma falha na etapa 3 ou 4.

Verificação de APK com assinatura de JAR (esquema v1)

O APK assinado por JAR é um JAR assinado padrão , que deve conter exatamente as entradas listadas em META-INF / MANIFEST.MF e onde todas as entradas devem ser assinadas pelo mesmo conjunto de assinantes. Sua integridade é verificada da seguinte forma:

  1. Cada signatário é representado por uma entrada JAR META-INF / <signer> .SF e META-INF / <signer>. (RSA | DSA | EC).
  2. <signer>. (RSA | DSA | EC) é uma estrutura PKCS # 7 CMS ContentInfo com SignedData cuja assinatura é verificada no arquivo <signer> .SF.
  3. O arquivo <signer> .SF contém um resumo do arquivo completo do META-INF / MANIFEST.MF e resumos de cada seção do META-INF / MANIFEST.MF. O resumo do arquivo inteiro do MANIFEST.MF é verificado. Se isso falhar, o resumo de cada seção MANIFEST.MF é verificado.
  4. META-INF / MANIFEST.MF contém, para cada entrada JAR protegida por integridade, uma seção com o nome correspondente contendo o resumo do conteúdo descompactado da entrada. Todos esses resumos são verificados.
  5. A verificação do APK falhará se o APK contiver entradas JAR que não estão listadas no MANIFEST.MF e não fazem parte da assinatura JAR.

A cadeia de proteção é, portanto, <signer>. (RSA | DSA | EC) -> <signer> .SF -> MANIFEST.MF -> conteúdo de cada entrada JAR protegida por integridade.