APK 서명 체계 v3

Android 9에서는 APK 키 순환을 지원하므로 앱에서 서명 키를 APK 업데이트의 일부로 변경할 수 있습니다. 실용적인 순환을 위해 APK는 신규 및 기존 서명 키 간의 신뢰도를 나타내야 합니다. 키 순환을 지원하기 위해 Google에서는 새 키 및 이전 키를 사용할 수 있도록 APK 서명 체계를 v2에서 v3으로 업데이트했습니다. v3은 지원되는 SDK 버전과 proof-of-rotation 구조에 관한 정보를 APK 서명 블록에 추가합니다.

APK 서명 블록

v1 APK 형식과의 역호환성을 유지하기 위해 v2 및 v3 APK 서명은 ZIP 중앙 디렉터리 바로 앞에 위치한 APK 서명 블록 내에 저장됩니다.

v3 APK 서명 블록 형식은 v2와 동일합니다. APK의 v3 서명은 ID가 0xf05368c0인 ID 값 쌍으로 저장됩니다.

APK 서명 체계 v3 블록

v3 체계는 v2 체계와 매우 유사하게 설계되었으며 동일한 일반 형식을 취하고 동일한 서명 알고리즘 ID, 키 크기 및 EC 곡선을 지원합니다.

하지만 v3 체계는 지원되는 SDK 버전과 proof-of-rotation 구조에 관한 정보를 추가합니다.

형식

APK 서명 체계 v3 블록은 ID가 0xf05368c0인 APK 서명 블록 내에 저장됩니다.

APK 서명 체계 v3 블록의 형식은 v2의 형식을 따릅니다.

  • 길이가 접두사로 지정된 signer의 길이가 접두사로 지정된 시퀀스:
    • 길이가 접두사로 지정된 signed data:
      • 길이가 접두사로 지정된 digests의 길이가 접두사로 지정된 시퀀스:
        • signature algorithm ID(4바이트)
        • digest(길이가 접두사로 지정됨)
      • X.509 certificates의 길이가 접두사로 지정된 시퀀스:
        • 길이가 접두사로 지정된 X.509 certificate(ASN.1 DER 형식)
      • minSDK(uint32) - 플랫폼 버전이 이 숫자보다 낮으면 이 서명자를 무시해야 합니다.
      • maxSDK(uint32) - 플랫폼 버전이 이 숫자보다 높으면 이 서명자를 무시해야 합니다.
      • 길이가 접두사로 지정된 additional attributes의 길이가 접두사로 지정된 시퀀스:
        • ID(uint32)
        • value(가변 길이: 추가 속성 길이 - 4바이트)
        • ID - 0x3ba06f8c
        • value - - Proof-of-rotation 구조
    • minSDK(uint32) - 서명된 데이터 섹션의 minSDK 값의 중복 - 현재 플랫폼이 범위 내에 있지 않은 경우 이 서명 인증을 건너뜁니다. 서명된 데이터 값과 일치해야 합니다.
    • maxSDK(uint32) - 서명된 데이터 섹션의 maxSDK 값의 중복 - 현재 플랫폼이 범위 내에 있지 않은 경우 이 서명 인증을 건너뜁니다. 서명된 데이터 값과 일치해야 합니다.
    • 길이가 접두사로 지정된 signatures의 길이가 접두사로 지정된 시퀀스:
      • signature algorithm ID(uint32)
      • signed data를 통한 길이가 접두사로 지정된 signature
    • 길이가 접두사로 지정된 public key(SubjectPublicKeyInfo, ASN.1 DER 형식)

Proof-of-rotation 및 self-trusted-old-certs 구조

proof-of rotation 구조는 앱이 통신하는 다른 앱에서 차단당하지 않고도 서명 인증서를 회전할 수 있게 해줍니다. 이를 위해서는 앱 서명에 두 가지 데이터가 포함되어야 합니다.

  • 이전 서명 인증서를 신뢰할 수 있을 때마다 앱의 서명 인증서를 신뢰할 수 있다는 타사용 어설션
  • 앱 자체에서 여전히 신뢰하는 앱의 이전 서명 인증서

서명된 데이터 섹션의 proof-of-rotation 속성은 단일 연결 목록으로 구성되며 각 노드에는 이전 버전의 앱에 서명하는 데 사용한 서명 인증서가 포함되어 있습니다. 이 속성은 개념적 proof-of-rotation 및 self-trusted-old-certs 데이터 구조를 포함하도록 되어 있습니다. 목록은 버전을 기준으로 순서가 지정되며 가장 오래된 서명 인증서가 루트 노드에 상응합니다. proof-of-rotation 데이터 구조는 각 노드의 인증서가 목록의 다음 인증서를 서명하도록 하는 방식으로 빌드됩니다. 따라서 새로운 각 키에는 키가 기존 키로 신뢰되어야 한다는 증거가 삽입됩니다.

self-trusted-old-certs 데이터 구조는 집합에서 멤버십 및 속성을 나타내는 각 노드에 플래그를 추가하는 방식으로 구성됩니다. 예를 들면 주어진 노드에 위치한 서명 인증서를 Android 서명 권한 획득과 관련하여 신뢰할 수 있음을 나타내는 플래그가 존재할 수 있습니다. 이 플래그를 사용하면 이전 인증서로 서명된 다른 앱에 새 서명 인증서로 서명된 앱에서 정의한 서명 권한을 계속 부여할 수 있습니다. 전체 proof-of-rotation 속성은 v3 signer 필드의 서명된 데이터 섹션에 있으므로 포함된 APK에 서명하는 데 사용된 키로 보호됩니다.

이 형식에서는 여러 서명 키를 사용할 수 없으며 다른 상위 서명 인증서를 하나로 모을 수 없습니다(여러 시작 노드를 공통 싱크로).

형식

proof-of-rotation은 ID가 0x3ba06f8c인 APK 서명 체계 v3 블록 내에 저장됩니다. 형식은 다음과 같습니다.

  • 길이가 접두사로 지정된 levels의 길이가 접두사로 지정된 시퀀스:
    • 있는 경우 이전 증명서로 길이가 접두사로 지정된 signed data
      • 길이가 접두사로 지정된 X.509 certificate(ASN.1 DER 형식)
      • signature algorithm ID(uint32) - 이전 수준의 인증서에서 사용한 알고리즘
    • flags(uint32) - 이 인증서가 self-trusted-old-certs 구조에 있어야 하는지, 어떤 작업에 사용되는지를 나타내는 플래그
    • signature algorithm ID(uint32) - 다음 수준의 서명된 데이터 섹션의 항목과 일치해야 함
    • signed data를 통해 길이가 접두사로 지정된 signature

여러 인증서

여러 signer는 지원되지 않으며 Google Play에서는 여러 인증서로 서명된 앱을 게시하지 않습니다.

인증

Android 9 이상에서는 APK 서명 체계 v3, v2 체계 또는 v1 체계에 따라 APK를 확인할 수 있습니다. 이전 플랫폼은 v3 서명을 무시하고 v2 서명에 이어 v1을 확인하려고 시도합니다.

APK 서명 인증 프로세스

그림 1. APK 서명 인증 프로세스

APK 서명 체계 v3 인증

  1. APK 서명 블록을 찾아 다음을 확인합니다.
    1. APK 서명 블록의 두 크기 필드 값이 같아야 합니다.
    2. ZIP 중앙 디렉터리 바로 뒤에 ZIP 중앙 디렉터리 끝의 기록이 위치해야 합니다.
    3. ZIP 중앙 디렉터리의 끝에 붙는 추가 데이터가 없습니다.
  2. APK 서명 블록 내에서 첫 번째 APK 서명 체계 v3 블록을 찾습니다. v3 블록이 있으면 3단계로 넘어갑니다. 아니면 v2 체계를 사용하여 APK 인증으로 돌아갑니다.
  3. 현재 플랫폼의 범위에 있는 최소 및 최대 SDK 버전이 포함된 APK 서명 체계 v3 블록 내 각 signer의 경우 다음을 실행합니다.
    1. 지원되는 가장 강력한 signature algorithm IDsignatures에서 선택합니다. 강도 순서 지정은 각 구현/플랫폼 버전에 따라 결정됩니다.
    2. public key를 사용하여 signatures에서 signed data에 상응하는 signature를 확인합니다. 이제 signed data를 안전하게 파싱할 수 있습니다.
    3. 서명된 데이터의 최소 및 최대 SDK 버전이 signer에 지정된 버전과 일치하는지 확인합니다.
    4. digestssignatures의 순서가 지정된 서명 알고리즘 ID 목록이 동일한지 확인합니다. 이는 서명 제거/추가를 방지하기 위함입니다.
    5. 서명 알고리즘에서 사용하는 다이제스트 알고리즘과 동일한 다이제스트 알고리즘을 사용하여 APK 콘텐츠 다이제스트를 계산합니다.
    6. 계산된 다이제스트가 digests의 상응하는 digest와 동일한지 확인합니다.
    7. certificates의 첫 번째 certificate의 SubjectPublicKeyInfo가 public key와 동일한지 확인합니다.
    8. signer에 proof-of-rotation 속성이 있다면 구조가 유효한지, 이 signer가 목록에서 마지막 인증서인지 확인합니다.
  4. 현재 플랫폼의 범위 내에서 정확히 signer 하나가 발견되었고 이 signer에 3단계가 성공했다면 인증이 정상적으로 이루어집니다.

유효성 검사

기기가 v3를 올바르게 지원하는지 테스트하려면 cts/hostsidetests/appsecurity/src/android/appsecurity/cts/에서 PkgInstallSignatureVerificationTest.java CTS 테스트를 실행합니다.