Android 11은 APK 서명 체계 v4를 사용한 스트리밍 호환 서명 체계를 지원합니다. v4 서명은 APK의 모든 바이트에 대해 계산된 머클 해시 트리를 기반으로 합니다. 이는 fs-verity 해시 트리의 구조를 정확히 따릅니다(예: 솔트나 마지막 블록을 0으로 채움). Android 11은 서명을 별도의 파일에 저장하며, <apk name>.apk.idsig
v4 서명에는 보완 v2 또는 v3 서명이 필요합니다.
파일 형식
모든 숫자 필드는 리틀 엔디언 방식입니다. 모든 필드는 추가된 암시적 패딩 또는 정렬 없이 sizeof()
의 바이트 수를 정확히 사용합니다.
아래는 정의를 단순화하는 도우미 구조체입니다.
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
기본 파일 콘텐츠:
struct V4Signature { int32 version; // only version 2 is supported as of now sized_bytes<int32> hashing_info; sized_bytes<int32> signing_info; sized_bytes<int32> merkle_tree; // optional };
hashing_info
는 해시 트리 생성 및 루트 해시에 사용되는 매개변수입니다.
struct hashing_info.bytes { int32 hash_algorithm; // only 1 == SHA256 supported int8 log2_blocksize; // only 12 (block size 4096) supported now sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page };
signing_info
는 다음과 같은 구조를 갖습니다.
struct signing_info.bytes { sized_bytes<int32> apk_digest; // used to match with the corresponding APK sized_bytes<int32> x509_certificate; // ASN.1 DER form sized_bytes<int32> additional_data; // a free-form binary data blob sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate int32 signature_algorithm_id; // see the APK v2 doc for the list sized_bytes<int32> signature; };
apk_digest
는 APK의 v3 서명 블록에서 가져오거나 v3에 없는 경우 v2 블록에서 가져옵니다(apk_digest 참고).
signature
코드를 만들고 확인하려면 다음 데이터를 바이너리 BLOB의 형식으로 직렬화하고 서명/확인 알고리즘에 서명된 데이터로 전달해야 합니다.
struct V4DataForSigning { int32 size; int64 file_size; // the size of the file that's been hashed. hashing_info.hash_algorithm; hashing_info.log2_blocksize; hashing_info.salt; hashing_info.raw_root_hash; signing_info.apk_digest; signing_info.x509_certificate; signing_info.additional_data; };
생산자 및 소비자
이제 apksigner
Android SDK 도구를 실행하면 기본 매개변수를 사용하여 v4 서명 파일을 생성합니다. v4 서명은 다른 서명 체계와 동일한 방식으로 사용 중지할 수 있습니다. 또한, v4 서명이 유효한지도 확인할 수 있습니다.
adb
는 adb install --incremental
명령어를 실행할 때 .apk 파일 옆에 .apk.idsig 파일이 있을 것으로 예상합니다.
또한, 기본적으로 .idsig 파일을 사용하여 증분 설치를 시도하고 파일이 누락되거나 유효하지 않으면 일반 설치로 돌아갑니다.
설치 세션이 생성되면 PackageInstaller
의 새 스트리밍 설치 API는 세션에 파일을 추가할 때 stripped v4 서명을 별도의 인수로 허용합니다.
이때, signing_info
는 전체 BLOB의 형식으로 incfs에 전달됩니다. Incfs는 BLOB에서 루트 해시를 추출합니다.
설치 세션이 커밋되고 있을 때 PackageManagerService에서는 ioctl을 실행하여 incfs에서 signing_info blob을 가져오고 가져온 BLOB을 파싱하여 서명을 확인합니다.
증분 데이터 로더 구성요소는 데이터 로더 네이티브 API를 통해 서명의 머클 트리 부분을 스트리밍해야 합니다.
package
서비스 셸 명령어인 install-incremental
은 base64로 인코딩된 머클 트리가 포함되지 않은 v4 서명 파일을 각 추가 파일에 대한 매개변수로 허용합니다. 해당하는 머클 트리를 명령어의 stdin
으로 전송해야 합니다.
apk_digest
apk_digest
는 사용 가능한 첫 번째 콘텐츠 다이제스트입니다.
- V3, 1MB 블록, SHA2-512(CONTENT_DIGEST_CHUNKED_SHA512)
- V3, 4KB 블록, SHA2-256(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)
- V3, 1MB 블록, SHA2-256(CONTENT_DIGEST_CHUNKED_SHA256)
- V2, SHA2-512
- V2, SHA2-256
APK 서명 체계 v3의 길이가 접두사로 지정된 서명의 길이가 접두사로 지정된 시퀀스를 참고하세요.
검증 및 테스트
기능 단위 테스트 및 CTS를 사용하여 구현을 검증합니다.
CtsIncrementalInstallHostTestCases
- /android/cts/hostsidetests/incrementalinstall
서명 형식 테스트
서명 형식을 테스트하려면 개발 환경을 설정하고 다음의 수동 테스트를 실행합니다.
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
Android SDK로 서명 형식 테스트(ADB 및 apksigner)
Android SDK로 서명 형식을 테스트하려면 개발 환경을 설정하고 IncFS의 구현을 완료했는지 확인하세요. 그런 다음, 대상 실제 기기나 에뮬레이터에서 빌드를 플래시합니다. 기존 APK를 생성하거나 가져온 다음 디버그 서명 키를 만들어야 합니다. 마지막으로, build-tools 폴더에서 v4 서명 형식을 사용하여 apk를 서명하고 설치합니다.
서명
$ ./apksigner sign --ks debug.keystore game.apk
설치
$ ./adb install game.apk
테스트는 어디에서 찾을 수 있나요?
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java