APK 서명 체계 v3

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

Android 9는 APK 업데이트의 일부로 서명 키를 변경할 수 있는 기능을 앱에 제공하는 APK 키 순환 을 지원합니다. 순환을 실용적으로 만들려면 APK가 새 서명 키와 이전 서명 키 간의 신뢰 수준을 표시해야 합니다. 키 순환을 지원하기 위해 APK 서명 체계 를 v2에서 v3으로 업데이트하여 새 키와 이전 키를 사용할 수 있습니다. V3는 지원되는 SDK 버전에 대한 정보와 회전 증명 구조체를 APK 서명 블록에 추가합니다.

APK 서명 블록

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

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

APK 서명 체계 v3 블록

v3 방식은 v2 방식 과 매우 유사하도록 설계되었습니다. 동일한 일반 형식을 가지며 동일한 서명 알고리즘 ID , 키 크기 및 EC 곡선을 지원합니다.

그러나 v3 체계는 지원되는 SDK 버전 및 회전 증명 구조에 대한 정보를 추가합니다.

체재

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 - 회전 증명 구조체
    • 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 구조체

회전 증명 구조를 사용하면 앱이 통신하는 다른 앱에서 차단되지 않고 서명 인증서를 회전할 수 있습니다. 이를 위해 앱 서명에는 두 가지 새로운 데이터 조각이 포함됩니다.

  • 앱의 서명 인증서는 전임자가 신뢰할 수 있는 곳이면 어디에서나 신뢰할 수 있다는 제3자를 위한 주장
  • 앱 자체가 여전히 신뢰하는 앱의 이전 서명 인증서

서명된 데이터 섹션의 회전 증명 속성은 단일 연결 목록으로 구성되며, 각 노드에는 앱의 이전 버전에 서명하는 데 사용된 서명 인증서가 포함되어 있습니다. 이 속성은 개념적 회전 증명 및 self-trusted-old-certs 데이터 구조를 포함하기 위한 것입니다. 목록은 루트 노드에 해당하는 가장 오래된 서명 인증서가 있는 버전별로 정렬됩니다. 회전 증명 데이터 구조는 각 노드의 인증서가 목록의 다음 항목에 서명하도록 하여 각 새 키에 이전 키만큼 신뢰할 수 있어야 한다는 증거를 부여하여 구축됩니다.

self-trusted-old-certs 데이터 구조는 집합의 구성원 자격 및 속성을 나타내는 플래그를 각 노드에 추가하여 구성됩니다. 예를 들어, 주어진 노드의 서명 인증서가 Android 서명 권한을 얻기 위해 신뢰할 수 있음을 나타내는 플래그가 있을 수 있습니다. 이 플래그를 사용하면 이전 인증서로 서명된 다른 앱에 새 서명 인증서로 서명된 앱에서 정의한 서명 권한을 계속 부여할 수 있습니다. 전체 회전 증명 속성은 v3 signer 필드의 서명된 데이터 섹션에 있기 때문에 포함하는 apk에 서명하는 데 사용되는 키로 보호됩니다.

이 형식은 여러 서명 키서로 다른 상위 서명 인증서 를 하나로 수렴하는 것을 방지합니다(여러 시작 노드를 공통 싱크로).

체재

회전 증명은 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

여러 인증서

Android는 현재 여러 인증서로 서명된 APK를 구성 인증서와 별개의 고유한 서명 ID가 있는 것으로 취급합니다. 따라서 서명된 데이터 섹션의 회전 증명 속성은 단일 연결 목록으로 더 잘 볼 수 있는 방향성 비순환 그래프를 형성하며, 주어진 버전에 대한 각 서명자 세트가 하나의 노드를 나타냅니다. 이것은 회전 증명 구조체에 추가적인 복잡성을 추가합니다(아래 다중 서명자 버전). 특히 주문이 문제가 됩니다. 또한 회전 증명 구조에는 하나씩 서명하는 대신 새 인증서 집합에 서명하는 이전 서명 인증서가 있어야 하기 때문에 더 이상 APK에 독립적으로 서명할 수 없습니다. 예를 들어, 두 개의 새 키 B와 C로 서명되기를 원하는 키 A로 서명한 APK는 B 서명자가 A 또는 B의 서명만 포함하도록 할 수 없습니다. 이는 B 및 C와 다른 서명 ID이기 때문입니다. 이는 서명자가 그러한 구조체를 구축하기 전에 조정해야 함을 의미합니다.

다중 서명자 회전 증명 속성

  • 길이 접두사 sets 의 길이 접두사 시퀀스 :
    • signed data (이전 세트별 - 존재하는 경우)
      • 길이 접두어가 붙은 certificates 시퀀스
        • 길이 접두사가 붙은 X.509 certificate (ASN.1 DER 형식)
      • signature algorithm IDs 시퀀스(uint32) - 동일한 순서로 이전 세트의 각 인증서에 대해 하나씩.
    • flags (uint32) - 이 인증서 집합이 self-trusted-old-certs 구조체에 있어야 하는지 여부와 해당 작업을 나타내는 플래그입니다.
    • 길이 접두사가 붙은 signatures 시퀀스:
      • signature algorithm ID (uint32) - 서명된 데이터 섹션의 것과 일치해야 합니다.
      • 위의 signed data 에 길이 접두사가 붙은 signature

회전 증명 구조체의 여러 조상

v3 체계는 동일한 앱에 대해 동일한 서명 키로 회전하는 두 개의 다른 키도 처리하지 않습니다. 이는 인수 회사가 인수한 앱을 이동하여 서명 키를 사용하여 권한을 공유하려는 인수의 경우와 다릅니다. 새 앱은 패키지 이름으로 구별되고 자체 회전 증명 구조를 포함할 수 있기 때문에 인수는 지원되는 사용 사례로 간주됩니다. 동일한 인증서에 도달하는 두 개의 다른 경로가 있는 동일한 앱의 지원되지 않는 경우는 키 회전 설계에서 만들어진 많은 가정을 깨뜨립니다.

확인

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

APK 서명 확인 프로세스

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

APK 서명 체계 v3 확인

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

확인

기기가 v3를 제대로 지원하는지 테스트하려면 cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ 에서 PkgInstallSignatureVerificationTest.java CTS 테스트를 실행하세요.