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