APK 서명 체계 v2

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

APK 서명 체계 v2는 전체 파일 서명 체계로 APK의 보호된 부분에 대한 변경 사항을 감지하여 검증 속도를 높이고 무결성 보장 을 강화합니다.

APK 서명 체계 v2를 사용한 서명은 ZIP 중앙 디렉터리 섹션 바로 앞에 APK 서명 블록 을 APK 파일에 삽입합니다. APK 서명 블록 내에서 v2 서명 및 서명자 ID 정보는 APK 서명 체계 v2 블록 에 저장됩니다.

서명 전후의 APK

그림 1. 서명 전과 후의 APK

APK 서명 체계 v2는 Android 7.0(Nougat)에서 도입되었습니다. Android 6.0(Marshmallow) 및 이전 기기에 APK를 설치할 수 있도록 하려면 v2 체계로 서명하기 전에 JAR 서명 을 사용하여 APK에 서명해야 합니다.

APK 서명 블록

v1 APK 형식과의 역호환성을 유지하기 위해 v2 및 최신 APK 서명은 APK 서명 체계 v2를 지원하기 위해 도입된 새로운 컨테이너인 APK 서명 블록 내부에 저장됩니다. APK 파일에서 APK 서명 블록은 파일 끝에 있는 ZIP Central Directory 바로 앞에 있습니다.

블록에는 APK에서 블록을 더 쉽게 찾을 수 있도록 래핑된 ID-값 쌍이 포함되어 있습니다. APK의 v2 서명은 ID가 0x7109871a인 ID-값 쌍으로 저장됩니다.

체재

APK 서명 블록의 형식은 다음과 같습니다(모든 숫자 필드는 리틀 엔디안입니다).

  • 바이트 단위 size of block (이 필드 제외)(uint64)
  • uint64 길이 접두사가 붙은 ID-값 쌍의 시퀀스:
    • ID (uint32)
    • value (가변 길이: 쌍의 길이 - 4바이트)
  • size of block 바이트) - 첫 번째 필드(uint64)와 동일
  • magic "APK Sig Block 42"(16바이트)

APK는 먼저 ZIP 중앙 디렉토리의 시작을 찾아서 구문 분석됩니다(파일 끝에 있는 ZIP 중앙 디렉토리 레코드를 찾은 다음 레코드에서 중앙 디렉토리의 시작 오프셋을 읽음). magic 값은 중앙 디렉터리 앞에 있는 것이 APK 서명 블록일 가능성이 있다는 것을 빠르게 설정할 수 있는 방법을 제공합니다. 그런 다음 size of block 는 파일에서 블록의 시작을 효율적으로 가리킵니다.

알 수 없는 ID를 가진 ID-값 쌍은 블록을 해석할 때 무시해야 합니다.

APK 서명 체계 v2 블록

APK는 각각 서명 키로 표시되는 하나 이상의 서명자/ID에 의해 서명됩니다. 이 정보는 APK 서명 체계 v2 블록으로 저장됩니다. 각 서명자에 대해 다음 정보가 저장됩니다.

  • (서명 알고리즘, 다이제스트, 서명) 튜플. 다이제스트는 APK 콘텐츠의 무결성 검사에서 서명 확인을 분리하기 위해 저장됩니다.
  • 서명자의 ID를 나타내는 X.509 인증서 체인.
  • 키-값 쌍으로 추가 속성.

각 서명자에 대해 APK는 제공된 목록에서 지원되는 서명을 사용하여 확인됩니다. 알 수 없는 서명 알고리즘이 있는 서명은 무시됩니다. 지원되는 여러 서명이 있을 때 사용할 서명을 선택하는 것은 각 구현에 달려 있습니다. 이를 통해 이전 버전과 호환되는 방식으로 향후 더 강력한 서명 방법을 도입할 수 있습니다. 제안된 접근 방식은 가장 강력한 서명을 확인하는 것입니다.

체재

APK 서명 체계 v2 블록은 ID 0x7109871a 아래의 APK 서명 블록 내부에 저장됩니다.

APK 서명 체계 v2 블록의 형식은 다음과 같습니다(모든 숫자 값은 little-endian이고 길이 접두사가 붙은 모든 필드는 길이에 uint32를 사용합니다).

  • 길이 접두사가 붙은 signer 의 길이 접두사 시퀀스:
    • 길이 접두사가 붙은 signed data :
      • 길이 접두사가 붙은 digests 의 길이 접두사 시퀀스 :
      • 길이 접두사가 붙은 X.509 certificates 시퀀스:
        • 길이 접두사가 붙은 X.509 certificate (ASN.1 DER 형식)
      • 길이 접두사 additional attributes 의 길이 접두사 시퀀스:
        • ID (uint32)
        • value (가변 길이: 추가 속성의 길이 - 4바이트)
    • 길이 접두사가 붙은 signatures 시퀀스:
      • signature algorithm ID (uint32)
      • signed data 에 길이 접두사가 붙은 signature
    • 길이 접두사가 붙은 public key (SubjectPublicKeyInfo, ASN.1 DER 형식)

서명 알고리즘 ID

  • 0x0101 - SHA2-256 다이제스트가 있는 RSASSA-PSS, SHA2-256 MGF1, 32바이트 솔트, 트레일러: 0xbc
  • 0x0102 - SHA2-512 다이제스트가 있는 RSASSA-PSS, SHA2-512 MGF1, 64바이트 솔트, 트레일러: 0xbc
  • 0x0103 - SHA2-256 다이제스트가 있는 RSASSA-PKCS1-v1_5. 이것은 결정적 서명이 필요한 빌드 시스템을 위한 것입니다.
  • 0x0104 - SHA2-512 다이제스트가 있는 RSASSA-PKCS1-v1_5. 이것은 결정적 서명이 필요한 빌드 시스템을 위한 것입니다.
  • 0x0201 - SHA2-256 다이제스트가 있는 ECDSA
  • 0x0202 - SHA2-512 다이제스트가 있는 ECDSA
  • 0x0301 - SHA2-256 다이제스트가 있는 DSA

위의 모든 서명 알고리즘은 Android 플랫폼에서 지원됩니다. 서명 도구는 알고리즘의 하위 집합을 지원할 수 있습니다.

지원되는 키 크기 및 EC 곡선:

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

무결성 보호 콘텐츠

APK 콘텐츠를 보호하기 위해 APK는 4개의 섹션으로 구성됩니다.

  1. ZIP 항목의 내용(오프셋 0부터 APK 서명 블록 시작까지)
  2. APK 서명 블록
  3. ZIP 중앙 디렉토리
  4. ZIP 중앙 디렉토리 끝

서명 후 APK 섹션

그림 2. 서명 후 APK 섹션

APK 서명 체계 v2는 섹션 1, 3, 4의 무결성과 섹션 2에 포함된 APK 서명 체계 v2 블록의 signed data 블록을 보호합니다.

섹션 1, 3, 4의 무결성은 하나 이상의 서명으로 보호되는 signed data 블록에 저장된 내용의 하나 이상의 다이제스트에 의해 보호됩니다.

섹션 1, 3, 4에 대한 다이제스트는 2단계 머클 트리 와 유사하게 다음과 같이 계산됩니다. 각 섹션은 연속적인 1MB(2 20 바이트) 청크로 분할됩니다. 각 섹션의 마지막 청크는 더 짧을 수 있습니다. 각 청크의 다이제스트는 바이트 0xa5 , 청크의 길이(바이트 단위)(little-endian uint32) 및 청크의 내용을 통해 계산됩니다. 최상위 다이제스트는 바이트 0x5a 의 연결, 청크 수(little-endian uint32) 및 청크가 APK에 나타나는 순서대로 청크의 다이제스트 연결에 대해 계산됩니다. 다이제스트는 병렬화하여 계산 속도를 높일 수 있도록 청크 방식으로 계산됩니다.

APK 다이제스트

그림 3. APK 다이제스트

섹션 4(중앙 디렉토리의 ZIP 끝) 보호는 ZIP 중앙 디렉토리의 오프셋을 포함하는 섹션으로 인해 복잡합니다. 새 서명이 추가되는 경우와 같이 APK 서명 블록의 크기가 변경되면 오프셋이 변경됩니다. 따라서 ZIP End of Central Directory에서 다이제스트를 계산할 때 ZIP Central Directory의 오프셋을 포함하는 필드는 APK 서명 블록의 오프셋을 포함하는 것으로 처리되어야 합니다.

롤백 보호

공격자는 v2 서명 APK 확인을 지원하는 Android 플랫폼에서 v2 서명 APK를 v1 서명 APK로 확인하도록 시도할 수 있습니다. 이 공격을 완화하기 위해 v1 서명이기도 한 v2 서명 APK는 META-INF/*.SF 파일의 기본 섹션에 X-Android-APK-Signed 속성을 포함해야 합니다. 속성 값은 쉼표로 구분된 APK 서명 체계 ID 집합입니다(이 체계의 ID는 2임). v1 서명을 확인할 때 APK 검증자는 이 세트(예: v2 체계)에서 선호하는 APK 서명 체계에 대한 서명이 없는 APK를 거부해야 합니다. 이 보호는 콘텐츠 META-INF/*.SF 파일이 v1 서명으로 보호된다는 사실에 의존합니다. JAR 서명 APK 확인 섹션을 참조하세요.

공격자는 APK 서명 체계 v2 블록에서 더 강력한 서명을 제거하려고 시도할 수 있습니다. 이 공격을 완화하기 위해 APK에 서명된 서명 알고리즘 ID 목록은 각 서명으로 보호되는 signed data 블록에 저장됩니다.

확인

Android 7.0 이상에서는 APK 서명 체계 v2+ 또는 JAR 서명(v1 체계)에 따라 APK를 확인할 수 있습니다. 이전 플랫폼은 v2 서명을 무시하고 v1 서명만 확인합니다.

APK 서명 확인 프로세스

그림 4. APK 서명 확인 프로세스(빨간색으로 표시된 새 단계)

APK 서명 체계 v2 확인

  1. APK 서명 블록을 찾아 다음을 확인합니다.
    1. APK 서명 블록의 두 크기 필드에는 동일한 값이 포함됩니다.
    2. ZIP 중앙 디렉토리 바로 뒤에 ZIP 중앙 디렉토리 레코드의 끝이 옵니다.
    3. ZIP End of Central Directory 뒤에 더 많은 데이터가 오지 않습니다.
  2. APK 서명 블록 내에서 첫 번째 APK 서명 체계 v2 블록을 찾습니다. v2 블록이 있는 경우 3단계로 진행합니다. 그렇지 않은 경우 v1 체계를 사용 하여 APK를 확인하는 것으로 대체합니다.
  3. APK 서명 체계 v2 블록의 각 signer 에 대해:
    1. 서명에서 지원되는 가장 강력한 signatures signature algorithm ID 를 선택합니다. 강도 순서는 각 구현/플랫폼 버전에 따라 다릅니다.
    2. public key 를 사용하여 서명된 signed data 에 대해 signatures 에서 해당 signature 을 확인합니다. (이제 signed data 를 구문 분석하는 것이 안전합니다.)
    3. digestssignatures 에 있는 서명 알고리즘 ID의 정렬된 목록이 동일한지 확인합니다. (서명 탈거/추가를 방지하기 위함입니다.)
    4. 서명 알고리즘에서 사용하는 다이제스트 알고리즘과 동일한 다이제스트 알고리즘을 사용하여 APK 콘텐츠의 다이제스트를 계산합니다 .
    5. 계산된 다이제스트가 digests 의 해당 digest 와 동일한지 확인합니다.
    6. certificates 의 첫 번째 certificate 의 SubjectPublicKeyInfo가 public key 와 동일한지 확인합니다.
  4. 최소한 한 명의 signer 가 발견되고 발견된 각 signer 에 대해 3단계가 성공하면 확인이 성공합니다.

참고 : 3단계 또는 4단계에서 오류가 발생한 경우 v1 체계를 사용하여 APK를 확인해서는 안 됩니다.

JAR 서명 APK 검증(v1 체계)

JAR 서명 APK는 표준 서명 JAR 이며 META-INF/MANIFEST.MF에 나열된 항목을 정확히 포함해야 하며 모든 항목은 동일한 서명자 세트에 의해 서명되어야 합니다. 무결성은 다음과 같이 확인됩니다.

  1. 각 서명자는 META-INF/<signer>.SF 및 META-INF/<signer>.(RSA|DSA|EC) JAR 항목으로 표시됩니다.
  2. <signer>.(RSA|DSA|EC)는 서명이 <signer>.SF 파일을 통해 확인 되는 SignedData 구조를 가진 PKCS #7 CMS ContentInfo입니다 .
  3. <signer>.SF 파일은 META-INF/MANIFEST.MF의 전체 파일 요약과 META-INF/MANIFEST.MF의 각 섹션의 요약을 포함합니다. MANIFEST.MF의 전체 파일 다이제스트가 확인됩니다. 실패하면 대신 각 MANIFEST.MF 섹션의 다이제스트가 확인됩니다.
  4. META-INF/MANIFEST.MF에는 각 무결성 보호 JAR 항목에 대해 항목의 압축되지 않은 내용의 다이제스트를 포함하는 해당 이름이 지정된 섹션이 포함되어 있습니다. 이 모든 다이제스트가 확인됩니다.
  5. APK에 MANIFEST.MF에 나열되지 않고 JAR 서명의 일부가 아닌 JAR 항목이 포함되어 있으면 APK 확인이 실패합니다.

따라서 보호 체인은 각 무결성 보호 JAR 항목의 <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> 내용입니다.