APK Signature Scheme v2

Skema tanda tangan APK v2 adalah skema tanda tangan seluruh file yang meningkatkan kecepatan verifikasi dan memperkuat jaminan integritas dengan mendeteksi perubahan apa pun pada bagian APK yang dilindungi.

Penandatanganan menggunakan APK signature scheme v2 akan menyisipkan blok penandatanganan APK ke dalam file APK tepat sebelum bagian ZIP Central Directory. Di dalam blok penandatanganan APK, tanda tangan v2 dan informasi identitas penanda tangan disimpan dalam blok APK signature scheme v2.

APK sebelum dan setelah penandatanganan

Gambar 1. APK sebelum dan sesudah penandatanganan

APK Signature Scheme v2 diperkenalkan di Android 7.0 (Nougat). Agar APK dapat diinstal di Android 6.0 (Marshmallow) dan perangkat yang lebih lama, APK harus ditandatangani menggunakan penandatanganan JAR sebelum ditandatangani dengan skema v2.

Blok penandatanganan APK

Untuk mempertahankan kompatibilitas mundur dengan format APK v1, tanda tangan APK v2 dan yang lebih baru disimpan di dalam blok penandatanganan APK, penampung baru yang diperkenalkan untuk mendukung APK signature scheme v2. Dalam file APK, blok penandatanganan APK terletak tepat sebelum Direktori Pusat ZIP, yang terletak di akhir file.

Blok ini berisi pasangan nilai ID yang digabungkan dengan cara yang memudahkan penentuan lokasi blok di APK. Tanda tangan v2 APK disimpan sebagai pasangan nilai ID dengan ID 0x7109871a.

Format

Format blok penandatanganan APK adalah sebagai berikut (semua kolom numerik adalah little-endian):

  • size of block dalam byte (tidak termasuk kolom ini) (uint64)
  • Urutan pasangan nilai ID berawalan uint64-length:
    • ID (uint32)
    • value (panjang variabel: panjang pasangan - 4 byte)
  • size of block dalam byte—sama dengan kolom pertama (uint64)
  • magic “APK Sig Block 42” (16 byte)

APK diuraikan dengan terlebih dahulu menemukan awal Direktori Pusat ZIP (dengan menemukan Akhir ZIP dari kumpulan data Central Directory di akhir file, lalu membaca offset awal Central Directory dari kumpulan data). Nilai magic menyediakan cara cepat untuk menetapkan bahwa apa yang mendahului Direktori Pusat kemungkinan adalah blok penandatanganan APK. Nilai size of block kemudian mengarah ke awal blok secara efisien dalam file.

Pasangan nilai ID dengan ID yang tidak diketahui harus diabaikan saat menafsirkan blok.

Blok skema tanda tangan APK v2

APK ditandatangani oleh satu atau beberapa penanda tangan/identitas, yang masing-masing diwakili oleh kunci penandatanganan. Informasi ini disimpan sebagai blok APK signature scheme v2. Untuk setiap penanda tangan, informasi berikut disimpan:

  • (algoritma tanda tangan, digest, tanda tangan). Ringkasan disimpan untuk memisahkan verifikasi tanda tangan dari pemeriksaan integritas konten APK.
  • Rantai sertifikat X.509 yang mewakili identitas penanda tangan.
  • Atribut tambahan sebagai pasangan nilai kunci.

Untuk setiap penanda tangan, APK diverifikasi menggunakan tanda tangan yang didukung dari daftar yang diberikan. Tanda tangan dengan algoritma tanda tangan yang tidak diketahui akan diabaikan. Setiap implementasi dapat memilih tanda tangan yang akan digunakan saat beberapa tanda tangan yang didukung ditemukan. Hal ini memungkinkan pengenalan metode penandatanganan yang lebih kuat di masa mendatang dengan cara yang kompatibel dengan versi lama. Pendekatan yang disarankan adalah memverifikasi tanda tangan terkuat.

Format

Blok APK signature scheme v2 disimpan di dalam blok penandatanganan APK dengan ID 0x7109871a.

Format blok APK signature scheme v2 adalah sebagai berikut (semua nilai numerik adalah little-endian, semua kolom awalan panjang menggunakan uint32 untuk panjang):

  • urutan berawalan panjang dari signer berawalan panjang:
    • signed data dengan awalan panjang:
      • urutan digests yang diawali dengan panjang:
      • urutan certificates X.509 dengan awalan panjang:
        • certificate X.509 dengan awalan panjang (bentuk DER ASN.1)
      • urutan additional attributes yang diawali dengan panjang:
        • ID (uint32)
        • value (panjang variabel: panjang atribut tambahan - 4 byte)
    • urutan signatures yang diawali dengan panjang:
      • signature algorithm ID (uint32)
      • signature dengan awalan panjang di atas signed data
    • public key dengan awalan panjang (SubjectPublicKeyInfo, format ASN.1 DER)

ID algoritma tanda tangan

  • 0x0101—RSASSA-PSS dengan ringkasan SHA2-256, SHA2-256 MGF1, 32 byte salt, trailer: 0xbc
  • 0x0102—RSASSA-PSS dengan ringkasan SHA2-512, SHA2-512 MGF1, salt 64 byte, trailer: 0xbc
  • 0x0103—RSASSA-PKCS1-v1_5 dengan ringkasan SHA2-256. Ini untuk sistem build yang memerlukan tanda tangan deterministik.
  • 0x0104—RSASSA-PKCS1-v1_5 dengan ringkasan SHA2-512. Ini untuk sistem build yang memerlukan tanda tangan deterministik.
  • 0x0201—ECDSA dengan ringkasan SHA2-256
  • 0x0202—ECDSA dengan ringkasan SHA2-512
  • 0x0301—DSA dengan ringkasan SHA2-256

Semua algoritma tanda tangan di atas didukung oleh platform Android. Alat penandatanganan dapat mendukung sebagian algoritma.

Ukuran kunci dan kurva EC yang didukung:

  • RSA: 1024, 2048, 4096, 8192, 16384
  • EC: NIST P-256, P-384, P-521
  • DSA: 1024, 2048, 3072

Konten yang dilindungi integritas

Untuk tujuan melindungi konten APK, APK terdiri dari empat bagian:

  1. Konten entri ZIP (dari offset 0 hingga awal blok penandatanganan APK)
  2. Blok penandatanganan APK
  3. Direktori Pusat ZIP
  4. ZIP Direktori Pusat

Bagian APK setelah penandatanganan

Gambar 2. Bagian APK setelah penandatanganan

APK Signature Scheme v2 melindungi integritas bagian 1, 3, 4, dan blok signed data dari blok APK Signature Scheme v2 yang terdapat di dalam bagian 2.

Integritas bagian 1, 3, dan 4 dilindungi oleh satu atau beberapa ringkasan kontennya yang disimpan dalam blok signed data yang, pada gilirannya, dilindungi oleh satu atau beberapa tanda tangan.

Ringkasan di bagian 1, 3, dan 4 dihitung sebagai berikut, mirip dengan Merkle tree dua tingkat. Setiap bagian dibagi menjadi beberapa bagian berukuran 1 MB (220 byte) secara berurutan. Bagian terakhir di setiap bagian mungkin lebih pendek. Ringkasan setiap potongan dihitung melalui penyambungan byte 0xa5, panjang potongan dalam byte (little-endian uint32), dan konten potongan tersebut. Ringkasan tingkat atas dihitung berdasarkan penyambungan byte 0x5a, jumlah potongan (uint32 little-endian), dan penyambungan ringkasan potongan dalam urutan kemunculan potongan di APK. Ringkasan dihitung dalam bentuk potongan untuk mempercepat komputasi dengan melakukan paralelisasi.

Ringkasan APK

Gambar 3. Ringkasan APK

Perlindungan bagian 4 (ZIP End of Central Directory) dipersulit oleh bagian yang berisi offset ZIP Central Directory. Offset berubah saat ukuran blok penandatanganan APK berubah, misalnya, saat tanda tangan baru ditambahkan. Dengan demikian, saat menghitung ringkasan di Akhir Direktori Pusat ZIP, kolom yang berisi offset Direktori Pusat ZIP harus diperlakukan sebagai berisi offset blok penandatanganan APK.

Perlindungan rollback

Penyerang dapat mencoba memverifikasi APK yang ditandatangani v2 sebagai APK yang ditandatangani v1 di platform Android yang mendukung verifikasi APK yang ditandatangani v2. Untuk mengurangi serangan ini, APK yang ditandatangani v2 yang juga ditandatangani v1 harus berisi atribut X-Android-APK-Signed di bagian utama file META-INF/*.SF. Nilai atribut adalah kumpulan ID skema tanda tangan APK yang dipisahkan koma (ID skema ini adalah 2). Saat memverifikasi tanda tangan v1, verifikasi APK diwajibkan untuk menolak APK yang tidak memiliki tanda tangan untuk skema tanda tangan APK yang lebih disukai verifikasi dari kumpulan ini (misalnya, skema v2). Perlindungan ini bergantung pada fakta bahwa konten file META-INF/*.SF dilindungi oleh tanda tangan v1. Lihat bagian tentang verifikasi APK yang ditandatangani JAR.

Penyerang dapat mencoba menghapus tanda tangan yang lebih kuat dari blok APK Signature Scheme v2. Untuk mengurangi serangan ini, daftar ID algoritma tanda tangan yang digunakan untuk menandatangani APK disimpan dalam blok signed data yang dilindungi oleh setiap tanda tangan.

Verifikasi

Di Android 7.0 dan yang lebih baru, APK dapat diverifikasi sesuai dengan skema tanda tangan APK v2+ atau penandatanganan JAR (skema v1). Platform lama mengabaikan tanda tangan v2 dan hanya memverifikasi tanda tangan v1.

Proses verifikasi tanda tangan APK

Gambar 4. Proses verifikasi tanda tangan APK (langkah baru berwarna merah)

Verifikasi APK Signature Scheme v2

  1. Temukan blok penandatanganan APK dan pastikan bahwa:
    1. Dua kolom ukuran blok penandatanganan APK berisi nilai yang sama.
    2. Direktori Pusat ZIP segera diikuti dengan data Akhir Direktori Pusat ZIP.
    3. Akhir Direktori Pusat ZIP tidak diikuti dengan data lainnya.
  2. Temukan blok APK Signature Scheme v2 pertama di dalam blok penandatanganan APK. Jika blok v2 ada, lanjutkan ke langkah 3. Jika tidak, kembali ke memverifikasi APK menggunakan skema v1.
  3. Untuk setiap signer dalam blok APK signature scheme v2:
    1. Pilih signature algorithm ID terkuat yang didukung dari signatures. Urutan kekuatan bergantung pada setiap versi implementasi/platform.
    2. Verifikasi signature yang sesuai dari signatures terhadap signed data menggunakan public key. (Sekarang menguraikan signed data dengan aman.)
    3. Pastikan daftar ID algoritma tanda tangan yang diurutkan di digests dan signatures identik. (Tindakan ini untuk mencegah penghapusan/penambahan tanda tangan.)
    4. Menghitung ringkasan konten APK menggunakan algoritma ringkasan yang sama dengan algoritma ringkasan yang digunakan oleh algoritma tanda tangan.
    5. Verifikasi bahwa ringkasan yang dihitung identik dengan digest yang sesuai dari digests.
    6. Verifikasi bahwa SubjectPublicKeyInfo dari certificate pertama certificates identik dengan public key.
  4. Verifikasi berhasil jika setidaknya satu signer ditemukan dan langkah 3 berhasil untuk setiap signer yang ditemukan.

Catatan: APK tidak boleh diverifikasi menggunakan skema v1 jika terjadi kegagalan pada langkah 3 atau 4.

Verifikasi APK yang ditandatangani JAR (skema v1)

APK yang ditandatangani JAR adalah JAR yang ditandatangani standar, yang harus berisi entri yang tercantum di META-INF/MANIFEST.MF dan semua entri harus ditandatangani oleh kumpulan penanda tangan yang sama. Integritasnya diverifikasi sebagai berikut:

  1. Setiap penanda tangan diwakili oleh entri JAR META-INF/<signer>.SF dan META-INF/<signer>.(RSA|DSA|EC).
  2. <signer>.(RSA|DSA|EC) adalah PKCS #7 CMS ContentInfo dengan struktur SignedData yang tanda tangannya diverifikasi melalui file <signer>.SF.
  3. File <signer>.SF berisi ringkasan file lengkap META-INF/MANIFEST.MF dan ringkasan setiap bagian META-INF/MANIFEST.MF. Ringkasan seluruh file MANIFEST.MF diverifikasi. Jika gagal, ringkasan setiap bagian MANIFEST.MF akan diverifikasi.
  4. META-INF/MANIFEST.MF berisi, untuk setiap entri JAR yang dilindungi integritas, bagian yang diberi nama sesuai yang berisi ringkasan konten entri yang tidak dikompresi. Semua ringkasan ini telah diverifikasi.
  5. Verifikasi APK gagal jika APK berisi entri JAR yang tidak tercantum dalam MANIFEST.MF dan bukan bagian dari tanda tangan JAR.

Dengan demikian, rantai perlindungannya adalah <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> konten dari setiap entri JAR yang dilindungi integritas.