APK 서명 체계 v4

Android 11은 APK 서명 체계 v4를 사용한 스트리밍 호환 서명 체계를 지원합니다. v4 서명은 APK의 모든 바이트에 대해 계산된 머클 해시 트리를 기반으로 합니다. 이는 fs-verity 해시 트리의 구조를 정확히 따릅니다(예: 솔트나 마지막 블록을 0으로 채움). Android 11은 서명을 별도의 파일에 저장하며, <apk name>.apk.idsigv4 서명에는 보완 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;
};
  1. merkle_treefs-verity 문서에 설명된 대로 계산된 APK의 전체 머클 트리입니다.

생산자 및 소비자

이제 apksigner Android SDK 도구를 실행하면 기본 매개변수를 사용하여 v4 서명 파일을 생성합니다. v4 서명은 다른 서명 체계와 동일한 방식으로 사용 중지할 수 있습니다. 또한, v4 서명이 유효한지도 확인할 수 있습니다.

adbadb 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는 사용 가능한 첫 번째 콘텐츠 다이제스트입니다.

  1. V3, 1MB 블록, SHA2-512(CONTENT_DIGEST_CHUNKED_SHA512)
  2. V3, 4KB 블록, SHA2-256(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)
  3. V3, 1MB 블록, SHA2-256(CONTENT_DIGEST_CHUNKED_SHA256)
  4. V2, SHA2-512
  5. V2, SHA2-256

APK 서명 체계 v3의 길이가 접두사로 지정된 서명의 길이가 접두사로 지정된 시퀀스를 참고하세요.

APK 유효성 검사 절차 v4
그림 1: APK 유효성 검사 절차 v4

검증 및 테스트

기능 단위 테스트 및 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