Mulai Android 12, modul Android Runtime (ART) adalah modul Mainline. Mengupdate modul mungkin mengharuskan modul membangun kembali artefak kompilasi ahead-of-time (AOT) dari bootclasspath JAR dan server sistem. Karena artefak ini sensitif terhadap keamanan, Android 12 menggunakan fitur yang disebut penandatanganan di perangkat untuk mencegah artefak ini dirusak. Halaman ini membahas arsitektur penandatanganan di perangkat dan interaksinya dengan fitur keamanan Android lainnya.
Desain tingkat tinggi
Penandatanganan di perangkat memiliki dua komponen inti:
odrefresh
adalah bagian dari modul Mainline ART. Tanggung jawabnya adalah membuat artefak runtime. Alat ini memeriksa artefak yang ada terhadap versi modul ART yang diinstal, JAR bootclasspath, dan JAR server sistem untuk menentukan apakah artefak tersebut sudah terbaru atau perlu dibuat ulang. Jika perlu dibuat ulang,odrefresh
akan membuatnya dan menyimpannya.odsign
adalah biner yang merupakan bagian dari platform Android. Proses ini berjalan selama boot awal, tepat setelah partisi/data
di-mount. Tanggung jawab utamanya adalah memanggilodrefresh
untuk memeriksa apakah ada artefak yang perlu dibuat atau diupdate. Untuk artefak baru atau yang diupdate yang dihasilkanodrefresh
,odsign
menghitung fungsi hash. Hasil komputasi hash tersebut disebut ringkasan file. Untuk artefak yang sudah ada,odsign
memverifikasi bahwa ringkasan artefak yang ada cocok dengan ringkasan yang sebelumnya dihitung olehodsign
. Hal ini memastikan bahwa artefak tidak dirusak.
Dalam kondisi error, seperti saat ringkasan file tidak cocok, odrefresh
dan odsign
akan menghapus semua artefak yang ada di /data
dan mencoba membuatnya ulang. Jika gagal, sistem akan kembali ke mode JIT.
odrefresh
dan odsign
dilindungi oleh dm-verity
, dan merupakan bagian dari
rantai Booting Terverifikasi Android.
Penghitungan ringkasan file dengan fs-verity
fs-verity adalah fitur kernel Linux yang melakukan verifikasi data file berbasis pohon Merkle. Mengaktifkan fs-verity pada file menyebabkan sistem file membuat pohon Merkle pada data file menggunakan hash SHA-256, menyimpannya di lokasi tersembunyi bersama file, dan menandai file sebagai hanya baca. fs-verity secara otomatis memverifikasi data file terhadap pohon Merkle sesuai permintaan saat dibaca. fs-verity membuat hash root pohon Merkle tersedia sebagai nilai yang disebut ringkasan file fs-verity, dan fs-verity memastikan bahwa data apa pun yang dibaca dari file konsisten dengan ringkasan file ini.
odsign
menggunakan fs-verity untuk meningkatkan performa booting dengan mengoptimalkan
autentikasi kriptografi artefak yang dikompilasi di perangkat pada waktu booting. Saat artefak dibuat, odsign
mengaktifkan fs-verity di artefak tersebut. Saat memverifikasi artefak, odsign
memverifikasi ringkasan file fs-verity, bukan hash file
lengkap. Hal ini menghilangkan kebutuhan untuk membaca dan membuat hash data lengkap
artefak saat waktu booting. Data artefak di-hash sesuai permintaan oleh fs-verity
saat digunakan, berdasarkan per blok.
Pada perangkat yang kernelnya tidak mendukung fs-verity, odsign
akan dikembalikan ke
penghitungan ringkasan file di ruang pengguna. odsign
menggunakan algoritma hash berbasis pohon Merkle yang sama dengan fs-verity, sehingga digestnya sama dalam kedua kasus tersebut. fs-verity diperlukan di semua perangkat yang diluncurkan dengan Android 11 dan yang lebih tinggi.
Penyimpanan ringkasan file
odsign
menyimpan ringkasan file artefak dalam file terpisah yang disebut
odsign.info
. Untuk memastikan odsign.info
tidak dimodifikasi, odsign.info
ditandatangani dengan kunci penandatanganan yang memiliki properti keamanan penting. Secara khusus, kunci dapat dibuat dan digunakan hanya selama booting awal, yang pada saat itu hanya kode tepercaya yang berjalan; lihat Kunci penandatanganan tepercaya untuk mengetahui detailnya.
Verifikasi ringkasan file
Pada setiap booting, jika odrefresh
menentukan bahwa artefak yang ada sudah
up-to-date, odsign
memastikan bahwa file tidak dirusak sejak
dibuat. odsign
melakukannya dengan memverifikasi ringkasan file. Pertama, kode ini memverifikasi tanda tangan odsign.info
. Jika tanda tangan valid, odsign
akan memverifikasi bahwa ringkasan setiap file cocok dengan ringkasan yang sesuai di odsign.info
.
Kunci penandatanganan tepercaya
Android 12 memperkenalkan fitur Keystore baru yang disebut kunci tahap booting yang mengatasi masalah keamanan berikut:
- Apa yang mencegah penyerang menggunakan kunci penandatanganan kami untuk menandatangani versi
odsign.info
mereka sendiri? - Apa yang mencegah penyerang membuat kunci penandatanganan sendiri dan menggunakannya
untuk menandatangani versi
odsign.info
miliknya sendiri?
Kunci tahap booting membagi siklus booting Android menjadi beberapa level, dan secara kriptografi mengikat pembuatan dan penggunaan kunci ke level tertentu. odsign
membuat kunci penandatanganannya di tingkat awal, saat hanya kode tepercaya yang berjalan, yang dilindungi melalui dm-verity
.
Level tahap booting diberi nomor dari 0 hingga angka ajaib 1000000000. Selama
proses booting Android, Anda dapat meningkatkan tingkat booting dengan menyetel properti
sistem dari init.rc
. Misalnya, kode berikut menetapkan level booting ke 10:
setprop keystore.boot_level 10
Klien Keystore dapat membuat kunci yang terikat pada level booting tertentu. Misalnya, jika Anda membuat kunci untuk tingkat booting 10, kunci tersebut hanya dapat digunakan saat perangkat berada di tingkat booting 10.
odsign
menggunakan level booting 30, dan kunci penandatanganan yang dibuatnya terikat dengan level booting tersebut. Sebelum menggunakan kunci untuk menandatangani artefak, odsign
memverifikasi bahwa
kunci tersebut terikat ke level booting 30.
Tindakan ini mencegah dua serangan yang dijelaskan sebelumnya di bagian ini:
- Penyerang tidak dapat menggunakan kunci yang dihasilkan, karena pada saat penyerang memiliki kesempatan untuk menjalankan kode berbahaya, level booting telah meningkat di atas 30, dan Keystore menolak operasi yang menggunakan kunci tersebut.
- Penyerang tidak dapat membuat kunci baru, karena pada saat penyerang memiliki kesempatan untuk menjalankan kode berbahaya, level booting telah meningkat di atas 30, dan Keystore menolak untuk membuat kunci baru dengan level booting tersebut. Jika penyerang membuat kunci baru yang tidak terikat ke level booting 30,
odsign
akan menolaknya.
Keystore memastikan bahwa tingkat booting diterapkan dengan benar. Bagian berikut membahas lebih mendetail cara melakukannya untuk berbagai versi KeyMint (sebelumnya Keymaster).
Implementasi Keymaster 4.0
Versi Keymaster yang berbeda menangani implementasi kunci tahap booting secara berbeda. Di perangkat dengan TEE/StrongBox Keymaster 4.0, Keymaster menangani implementasi sebagai berikut:
- Saat booting pertama, Keystore membuat kunci simetris K0 dengan setelan tag
MAX_USES_PER_BOOT
ke1
. Artinya, kunci hanya dapat digunakan sekali per booting. - Selama booting, jika level booting ditingkatkan, kunci baru untuk level booting tersebut dapat dibuat dari K0 menggunakan fungsi HKDF:
Ki+i=HKDF(Ki, "some_fixed_string")
. Misalnya, jika Anda berpindah dari level booting 0 ke level booting 10, HKDF dipanggil 10 kali untuk mendapatkan K10 dari K0. Saat tingkat booting berubah, kunci untuk tingkat booting sebelumnya akan dihapus dari memori, dan kunci yang terkait dengan tingkat booting sebelumnya tidak lagi tersedia.
Kunci K0 adalah kunci
MAX_USES_PER_BOOT=1
. Artinya, kunci tersebut juga tidak dapat digunakan lagi saat booting, karena setidaknya satu transisi tingkat booting (ke tingkat booting akhir) selalu terjadi.
Saat klien Keystore seperti odsign
meminta kunci untuk dibuat di i
tingkat boot, blob-nya dienkripsi dengan kunci Ki
. Karena Ki
tidak tersedia
setelah level booting i
, kunci ini tidak dapat dibuat atau didekripsi pada tahap booting
selanjutnya.
Implementasi Keymaster 4.1 dan KeyMint 1.0
Implementasi Keymaster 4.1 dan KeyMint 1.0 sebagian besar sama dengan implementasi Keymaster 4.0. Perbedaan utamanya adalah K0 bukan kunci
MAX_USES_PER_BOOT
, tetapi kunci EARLY_BOOT_ONLY
, yang diperkenalkan di
Keymaster 4.1. Kunci EARLY_BOOT_ONLY
hanya dapat digunakan selama fase awal
booting, saat tidak ada kode yang tidak tepercaya yang berjalan. Hal ini memberikan tingkat perlindungan tambahan: dalam penerapan Keymaster 4.0, penyerang yang membahayakan sistem file dan SELinux dapat mengubah database Keystore untuk membuat kunci MAX_USES_PER_BOOT=1
-nya sendiri untuk menandatangani artefak. Serangan semacam itu tidak mungkin terjadi dengan penerapan Keymaster 4.1 dan KeyMint 1.0, karena kunci EARLY_BOOT_ONLY
hanya dapat dibuat selama booting awal.
Komponen publik kunci penandatanganan tepercaya
odsign
mengambil komponen kunci publik dari kunci penandatanganan dari Keystore.
Namun, Keystore tidak mengambil kunci publik tersebut dari TEE/SE yang menyimpan
kunci pribadi yang sesuai. Sebagai gantinya, kunci publik diambil dari
database di disknya sendiri. Artinya, penyerang yang membahayakan sistem file dapat mengubah database Keystore agar berisi kunci publik yang merupakan bagian dari pasangan kunci publik/pribadi di bawah kendali mereka.
Untuk mencegah serangan ini, odsign
membuat kunci HMAC tambahan dengan
tingkat booting yang sama dengan kunci penandatanganan. Kemudian, saat membuat kunci penandatanganan, odsign
menggunakan kunci HMAC ini untuk membuat tanda tangan kunci publik dan menyimpannya di
disk. Pada booting berikutnya, saat mengambil kunci publik dari kunci penandatanganan, kunci tersebut menggunakan kunci HMAC untuk memverifikasi bahwa tanda tangan di disk cocok dengan tanda tangan kunci publik yang diambil. Jika cocok, kunci publik dapat dipercaya, karena
kunci HMAC hanya dapat digunakan di level booting awal dan oleh karena itu tidak mungkin
dibuat oleh penyerang.