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 형식)
- 길이가 접두사로 지정된 X.509
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) - 이전 수준의 인증서에서 사용한 알고리즘
- 길이가 접두사로 지정된 X.509
flags
(uint32) - 이 인증서가 self-trusted-old-certs 구조에 있어야 하는지, 어떤 작업에 사용되는지를 나타내는 플래그signature algorithm ID
(uint32) - 다음 수준의 서명된 데이터 섹션의 항목과 일치해야 함- 위
signed data
를 통해 길이가 접두사로 지정된signature
- 있는 경우 이전 증명서로 길이가 접두사로 지정된
여러 인증서
Android는 현재 여러 인증서로 서명된 APK에 구성 인증서와 별도의 고유 서명 ID가 포함되어 있다고 간주합니다. 따라서 서명된 데이터 섹션의 proof-of-rotation 속성은 방향성 비순환 그래프를 형성합니다. 이 그래프는 단일 연결 목록으로 보는 것이 훨씬 수월하며, 주어진 버전의 각 서명자 집합이 하나의 노드를 나타냅니다. 이는 proof-of-rotation 구조(아래의 다중 서명자 버전)를 더욱 복잡하게 만듭니다. 특히 순서가 우려사항이 됩니다. 뿐만 아니라 이제는 더 이상 APK를 독립적으로 서명할 수 없습니다. 새로운 인증서에 하나씩 서명하는 대신 새로운 인증서 집합에 서명하는 이전 서명 인증서가 proof-of-rotation 구조에 있어야 하기 때문입니다. 예를 들어 새로운 두 키인 B와 C로 서명되려는 키 A로 서명된 APK에서는 B 서명자가 A 또는 B에 의한 서명을 포함하도록 할 수 없습니다. B 및 C와는 다른 서명 ID이기 때문입니다. 즉, 서명자가 이러한 구조를 빌드하기 전에 조율해야 합니다.
다중 서명자 proof-of-rotation 속성
- 길이가 접두사로 지정된
sets
의 길이가 접두사로 지정된 시퀀스:signed data
(있는 경우 이전 집합 기준)certificates
의 길이가 접두사로 지정된 시퀀스- 길이가 접두사로 지정된 X.509
certificate
(ASN.1 DER 형식)
- 길이가 접두사로 지정된 X.509
signature algorithm IDs
(uint32)의 시퀀스 - 이전 집합의 인증서별로 하나씩(동일 순서)
flags
(uint32) - 이 인증서 집합이 self-trusted-old-certs 구조에 있어야 하는지, 어떤 작업에 사용되는지를 나타내는 플래그- 길이가 접두사로 지정된
signatures
의 길이가 접두사로 지정된 시퀀스:signature algorithm ID
(uint32) - 서명된 데이터 섹션의 항목과 일치해야 함- 위
signed data
를 통해 길이가 접두사로 지정된signature
proof-of-rotation 구조의 여러 상위 요소
v3 체계는 동일한 앱의 동일한 서명 키로 순환하는 두 개의 다른 키도 처리하지 않습니다. 이는 인수 회사에서 자체 서명 키를 사용하여 권한을 공유하도록 인수한 앱을 이동하려는 인수 사례와는 다릅니다. 인수가 지원되는 사용 사례로 간주되는 이유는 새 앱이 패키지 이름으로 구분되고 자체 proof-of-rotation 구조를 포함할 수 있기 때문입니다. 동일한 인증서에 도달하기 위해 두 개의 다른 경로를 보유하는 동일한 앱의 지원되지 않는 사례는 키 순환 설계에서 이루어진 다수의 가정을 파괴합니다.
인증
Android 9 이상에서는 APK 서명 체계 v3, v2 체계 또는 v1 체계에 따라 APK를 확인할 수 있습니다. 이전 플랫폼은 v3 서명을 무시하고 v2 서명에 이어 v1을 확인하려고 시도합니다.
APK 서명 체계 v3 인증
- APK 서명 블록을 찾아 다음을 확인합니다.
- APK 서명 블록의 두 크기 필드 값이 같아야 합니다.
- ZIP 중앙 디렉터리 바로 뒤에 ZIP 중앙 디렉터리 끝의 기록이 위치해야 합니다.
- ZIP 중앙 디렉터리의 끝에 붙는 추가 데이터가 없습니다.
- APK 서명 블록 내에서 첫 번째 APK 서명 체계 v3 블록을 찾습니다. v3 블록이 있으면 3단계로 넘어갑니다. 아니면 v2 체계를 사용하여 APK 인증으로 돌아갑니다.
- 현재 플랫폼의 범위에 있는 최소 및 최대 SDK 버전이 포함된 APK 서명 체계 v3 블록 내 각
signer
의 경우 다음을 실행합니다.- 지원되는 가장 강력한
signature algorithm ID
를signatures
에서 선택합니다. 강도 순서 지정은 각 구현/플랫폼 버전에 따라 결정됩니다. public key
를 사용하여signatures
에서signed data
에 상응하는signature
를 확인합니다. 이제signed data
를 안전하게 파싱할 수 있습니다.- 서명된 데이터의 최소 및 최대 SDK 버전이
signer
에 지정된 버전과 일치하는지 확인합니다. digests
및signatures
의 순서가 지정된 서명 알고리즘 ID 목록이 동일한지 확인합니다. 이는 서명 제거/추가를 방지하기 위함입니다.- 서명 알고리즘에서 사용하는 다이제스트 알고리즘과 동일한 다이제스트 알고리즘을 사용하여 APK 콘텐츠 다이제스트를 계산합니다.
- 계산된 다이제스트가
digests
의 상응하는digest
와 동일한지 확인합니다. certificates
의 첫 번째certificate
의 SubjectPublicKeyInfo가public key
와 동일한지 확인합니다.signer
에 proof-of-rotation 속성이 있다면 구조가 유효한지, 이signer
가 목록에서 마지막 인증서인지 확인합니다.
- 지원되는 가장 강력한
- 현재 플랫폼의 범위 내에서 정확히
signer
하나가 발견되었고 이signer
에 3단계가 성공했다면 인증이 정상적으로 이루어집니다.
유효성 검사
기기가 v3를 올바르게 지원하는지 테스트하려면 cts/hostsidetests/appsecurity/src/android/appsecurity/cts/
에서 PkgInstallSignatureVerificationTest.java
CTS 테스트를 실행합니다.