Ketersediaan trusted execution environment dalam sistem pada chip (SoC) menawarkan peluang bagi perangkat Android untuk menyediakan layanan keamanan yang kuat dan didukung hardware ke Android OS, layanan platform, dan bahkan aplikasi pihak ketiga. Developer yang mencari ekstensi khusus Android harus membuka android.security.keystore.
Sebelum Android 6.0, Android sudah memiliki API layanan kripto sederhana yang didukung hardware, yang disediakan oleh Keymaster Hardware Abstraction Layer (HAL) versi 0.2 dan 0.3. Keystore menyediakan operasi penandatanganan dan verifikasi digital, serta pembuatan dan impor pasangan kunci penandatanganan asimetris. Hal ini sudah diterapkan di banyak perangkat, tetapi ada banyak sasaran keamanan yang tidak dapat dicapai dengan mudah hanya dengan API tanda tangan. Keystore di Android 6.0 memperluas Keystore API untuk memberikan berbagai kemampuan yang lebih luas.
Di Android 6.0, Keystore menambahkan primitive kriptografis simetris, AES dan HMAC, serta sistem kontrol akses untuk kunci yang didukung hardware. Kontrol akses ditentukan selama pembuatan kunci dan diterapkan selama masa aktif kunci. Kunci dapat dibatasi agar hanya dapat digunakan setelah pengguna diautentikasi, dan hanya untuk tujuan tertentu atau dengan parameter kriptografis yang ditentukan. Untuk informasi selengkapnya, lihat halaman Tag otorisasi.
Selain memperluas rentang primitif kriptografi, Keystore di Android 6.0 menambahkan hal berikut:
- Skema kontrol penggunaan untuk memungkinkan penggunaan kunci dibatasi, guna mengurangi risiko penyusupan keamanan karena penyalahgunaan kunci
- Skema kontrol akses untuk mengaktifkan pembatasan kunci ke pengguna, klien, dan rentang waktu yang ditentukan
Di Android 7.0, Keymaster 2 menambahkan dukungan untuk pengesahan kunci dan binding versi. Pengesahan kunci menyediakan sertifikat kunci publik yang berisi deskripsi mendetail tentang kunci dan kontrol aksesnya, untuk membuat keberadaan kunci dalam hardware yang aman dan konfigurasinya dapat diverifikasi dari jarak jauh.
Penautan versi mengikat kunci ke sistem operasi dan versi tingkat patch. Hal ini memastikan bahwa penyerang yang menemukan kelemahan dalam versi lama sistem atau software TEE tidak dapat melakukan roll back perangkat ke versi yang rentan dan menggunakan kunci yang dibuat dengan versi yang lebih baru. Selain itu, saat kunci dengan versi dan level patch tertentu digunakan di perangkat yang telah diupgrade ke versi atau level patch yang lebih baru, kunci akan diupgrade sebelum dapat digunakan, dan versi kunci sebelumnya akan dibatalkan validasinya. Saat perangkat diupgrade, kunci akan "ratchet" maju bersama perangkat, tetapi setiap pengembalian perangkat ke rilis sebelumnya akan menyebabkan kunci tidak dapat digunakan.
Di Android 8.0, Keymaster 3 bertransisi dari Hardware Abstraction Layer (HAL) struktur C gaya lama ke antarmuka HAL C++ yang dihasilkan dari definisi di Hardware Interface Definition Language (HIDL) baru. Sebagai bagian dari perubahan, banyak jenis argumen yang berubah, meskipun jenis dan metode memiliki korespondensi satu-satu dengan jenis lama dan metode struct HAL.
Selain revisi antarmuka ini, Android 8.0 memperluas fitur pengesahan Keymaster 2 untuk mendukung pengesahan ID. Pengesahan ID memberikan mekanisme terbatas dan opsional untuk mengesahkan ID hardware dengan kuat, seperti nomor seri perangkat, nama produk, dan ID ponsel (IMEI / MEID). Untuk menerapkan penambahan ini, Android 8.0 mengubah skema pengesahan ASN.1 untuk menambahkan pengesahan ID. Implementasi Keymaster perlu menemukan beberapa cara aman untuk mengambil item data yang relevan, serta menentukan mekanisme untuk menonaktifkan fitur secara aman dan permanen.
Di Android 9, update mencakup:
- Mengupdate ke Keymaster 4
- Dukungan untuk Elemen Aman tersemat
- Dukungan untuk impor kunci yang aman
- Dukungan untuk enkripsi 3DES
- Perubahan pada binding versi sehingga boot.img dan system.img memiliki versi yang ditetapkan secara terpisah untuk memungkinkan update independen
Glosarium
Berikut adalah ringkasan singkat tentang komponen Keystore dan hubungannya.
AndroidKeystore adalah API dan komponen Framework Android yang digunakan
oleh aplikasi untuk mengakses fungsi Keystore. API ini diimplementasikan sebagai ekstensi untuk
API Java Cryptography Architecture standar, dan terdiri dari kode Java yang
berjalan di ruang proses aplikasi itu sendiri. AndroidKeystore
memenuhi permintaan
aplikasi untuk perilaku Keystore dengan meneruskannya ke daemon keystore.
Daemon keystore adalah daemon sistem Android yang menyediakan akses ke semua fungsi Keystore dengan Binder API. Keystore bertanggung jawab untuk menyimpan "blob kunci", yang berisi materi kunci rahasia yang sebenarnya, dienkripsi sehingga Keystore dapat menyimpannya, tetapi tidak menggunakannya atau mengungkapkannya.
keymasterd adalah server HIDL yang menyediakan akses ke Keymaster TA. (Nama ini tidak standar dan digunakan untuk tujuan konseptual.)
Keymaster TA (aplikasi tepercaya) adalah software yang berjalan dalam konteks aman, paling sering di TrustZone pada SoC ARM, yang menyediakan semua operasi Keystore yang aman, memiliki akses ke materi kunci mentah, memvalidasi semua kondisi kontrol akses pada kunci, dll.
LockSettingsService adalah komponen sistem Android yang bertanggung jawab
untuk autentikasi pengguna, baik sandi maupun sidik jari. Ini bukan bagian dari
Keystore, tetapi relevan karena banyak operasi kunci Keystore memerlukan autentikasi
pengguna. LockSettingsService
berinteraksi dengan TA Gatekeeper
dan TA Sidik Jari untuk mendapatkan token autentikasi, yang disediakan ke
daemon keystore, dan yang pada akhirnya digunakan oleh aplikasi
TA Keymaster.
Gatekeeper TA (aplikasi tepercaya) adalah komponen lain yang berjalan dalam konteks aman, yang bertanggung jawab untuk mengautentikasi sandi pengguna dan membuat token autentikasi yang digunakan untuk membuktikan kepada Keymaster TA bahwa autentikasi dilakukan untuk pengguna tertentu pada waktu tertentu.
Fingerprint TA (aplikasi tepercaya) adalah komponen lain yang berjalan dalam konteks aman yang bertanggung jawab untuk mengautentikasi sidik jari pengguna dan membuat token autentikasi yang digunakan untuk membuktikan kepada Keymaster TA bahwa autentikasi dilakukan untuk pengguna tertentu pada waktu tertentu.
Arsitektur
Android Keystore API dan Keymaster HAL yang mendasarinya menyediakan kumpulan primitif kriptografis dasar, tetapi memadai untuk memungkinkan implementasi protokol menggunakan kunci yang didukung hardware dan dikontrol akses.
Keymaster HAL adalah library yang dapat dimuat secara dinamis yang disediakan OEM dan digunakan oleh layanan Keystore untuk menyediakan layanan kriptografis yang didukung hardware. Untuk menjaga keamanan, implementasi HAL tidak melakukan operasi sensitif apa pun di ruang pengguna, atau bahkan di ruang kernel. Operasi sensitif didelegasikan ke pemroses aman yang dijangkau melalui beberapa antarmuka kernel. Arsitektur yang dihasilkan terlihat seperti ini:

Gambar 1. Akses ke Keymaster
Dalam perangkat Android, "klien" Keymaster HAL terdiri dari beberapa lapisan (misalnya, aplikasi, framework, daemon Keystore), tetapi hal tersebut dapat diabaikan untuk tujuan dokumen ini. Ini berarti bahwa Keymaster HAL API yang dijelaskan bersifat tingkat rendah, digunakan oleh komponen internal platform, dan tidak diekspos kepada developer aplikasi. API level yang lebih tinggi dijelaskan di situs Android Developer.
Tujuan HAL Keymaster bukan untuk mengimplementasikan algoritma sensitif keamanan, tetapi hanya untuk mengatur dan membatalkan pengaturan permintaan ke dunia yang aman. Format jaringan ditentukan oleh implementasi.
Kompatibilitas dengan versi sebelumnya
HAL Keymaster 1 sepenuhnya tidak kompatibel dengan HAL yang dirilis sebelumnya, misalnya, Keymaster 0.2 dan 0.3. Untuk memfasilitasi interoperabilitas di perangkat yang menjalankan Android 5.0 dan yang lebih lama yang diluncurkan dengan HAL Keymaster lama, Keystore menyediakan adaptor yang mengimplementasikan HAL Keymaster 1 dengan panggilan ke library hardware yang ada. Hasilnya tidak dapat menyediakan berbagai fungsi di HAL Keymaster 1. Secara khusus, API ini hanya mendukung algoritma RSA dan ECDSA, dan semua penerapan otorisasi kunci dilakukan oleh adaptor, di dunia yang tidak aman.
Keymaster 2 lebih menyederhanakan antarmuka HAL dengan menghapus
metode get_supported_*
dan mengizinkan metode
finish()
menerima input. Hal ini mengurangi jumlah perjalanan bolak-balik ke TEE jika
input tersedia sekaligus, dan menyederhanakan implementasi
dekripsi AEAD.
Di Android 8.0, Keymaster 3 bertransisi dari HAL struktur C gaya lama
ke antarmuka HAL C++ yang dihasilkan dari definisi dalam
Hardware Interface Definition Language (HIDL) baru. Implementasi HAL
gaya baru dibuat dengan membuat subclass class
IKeymasterDevice
yang dihasilkan dan menerapkan metode virtual
murni. Sebagai bagian dari perubahan, banyak jenis argumen yang telah berubah,
meskipun jenis dan metode memiliki korespondensi satu-ke-satu dengan jenis
lama dan metode struct HAL.
Ringkasan HIDL
Hardware Interface Definition Language (HIDL) menyediakan mekanisme yang tidak bergantung pada bahasa implementasi untuk menentukan antarmuka hardware. Alat HIDL saat ini mendukung pembuatan antarmuka C++ dan Java. Kami memperkirakan bahwa sebagian besar pengimplementasi Trusted Execution Environment (TEE) akan merasa lebih mudah menggunakan alat C++, sehingga halaman ini hanya membahas representasi C++.
Antarmuka HIDL terdiri dari serangkaian metode, yang dinyatakan sebagai:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
Ada berbagai jenis yang telah ditentukan sebelumnya, dan HAL dapat menentukan jenis struktur dan enumerated baru. Untuk detail selengkapnya tentang HIDL, lihat Bagian referensi.
Contoh metode dari IKeymasterDevice.hal
Keymaster 3 adalah:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
Ini setara dengan hal berikut dari HAL keymaster2:
keymaster_error_t (*generate_key)( const struct keymaster2_device* dev, const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics);
Dalam versi HIDL, argumen dev
dihapus, karena bersifat
implisit. Argumen params
tidak lagi berupa struct yang berisi
pointer yang mereferensikan array objek key_parameter_t
, tetapi
vec
(vektor) yang berisi objek KeyParameter
. Nilai
yang ditampilkan tercantum dalam klausa "generates
", termasuk
vektor nilai uint8_t
untuk blob kunci.
Metode virtual C++ yang dihasilkan oleh compiler HIDL adalah:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
Dengan generateKey_cb
adalah pointer fungsi yang ditentukan sebagai:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
Artinya, generateKey_cb
adalah fungsi yang mengambil nilai yang ditampilkan
dalam klausa generate. Class implementasi HAL mengganti metode
generateKey
ini dan memanggil pointer fungsi
generateKey_cb
untuk menampilkan hasil operasi kepada pemanggil. Perhatikan bahwa panggilan
pointer fungsi bersifat sinkron. Pemanggil memanggil
generateKey
dan generateKey
memanggil pointer fungsi
yang disediakan, yang dieksekusi hingga selesai, menampilkan kontrol ke
implementasi generateKey
, yang kemudian ditampilkan ke pemanggil.
Untuk contoh mendetail, lihat implementasi default di
hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
.
Implementasi default menyediakan kompatibilitas mundur untuk perangkat dengan
HAL keymaster0, keymaster1, atau keymaster2 gaya lama.
Kontrol akses
Aturan paling dasar dari kontrol akses Keystore adalah setiap aplikasi memiliki namespace-nya sendiri. Namun, untuk setiap aturan, ada pengecualian. Keystore memiliki beberapa peta hard code yang memungkinkan komponen sistem tertentu mengakses namespace tertentu lainnya. Ini adalah instrumen yang sangat tumpul karena memberi satu komponen kontrol penuh atas namespace lain. Kemudian, ada masalah komponen vendor sebagai klien ke Keystore. Saat ini kami tidak memiliki cara untuk membuat namespace untuk komponen vendor, misalnya, pemohon WPA.
Untuk mengakomodasi komponen vendor dan mengeneralisasi kontrol akses tanpa pengecualian hard code, Keystore 2.0 memperkenalkan domain dan namespace SELinux.
Domain keystore
Dengan domain Keystore, kita dapat memisahkan namespace dari UID. Klien yang mengakses kunci di Keystore harus menentukan domain, namespace, dan alias yang ingin diakses. Berdasarkan tuple ini dan identitas pemanggil, kita dapat menentukan kunci yang ingin diakses pemanggil dan apakah kunci tersebut memiliki izin yang sesuai.
Kami memperkenalkan lima parameter domain yang mengatur cara kunci dapat diakses. Fungsi ini mengontrol semantik parameter namespace deskripsi kunci dan cara kontrol akses dilakukan.
DOMAIN_APP
: Domain aplikasi mencakup perilaku lama. SPI Java Keystore menggunakan domain ini secara default. Saat domain ini digunakan, argumen namespace akan diabaikan dan UID pemanggil akan digunakan. Akses ke domain ini dikontrol oleh label Keystore kekeystore_key
class dalam kebijakan SELinux.DOMAIN_SELINUX
: Domain ini menunjukkan bahwa namespace memiliki label dalam kebijakan SELinux. Parameter namespace dicari dan diterjemahkan ke dalam konteks target, dan pemeriksaan izin dilakukan untuk konteks SELinux panggilan untuk classkeystore_key
. Jika izin telah ditetapkan untuk operasi tertentu, tuple lengkap akan digunakan untuk pencarian kunci.DOMAIN_GRANT
: Domain pemberian menunjukkan bahwa parameter namespace adalah ID pemberian. Parameter alias diabaikan. Pemeriksaan SELinux dilakukan saat pemberian dibuat. Kontrol akses lebih lanjut hanya memeriksa apakah UID pemanggil cocok dengan UID penerima hibah yang diminta.DOMAIN_KEY_ID
: Domain ini menunjukkan bahwa parameter namespace adalah ID kunci unik. Kunci itu sendiri mungkin telah dibuat denganDOMAIN_APP
atauDOMAIN_SELINUX
. Pemeriksaan izin dilakukan setelahdomain
dannamespace
dimuat dari database kunci dengan cara yang sama seperti jika blob dimuat oleh tuple domain, namespace, dan alias. Alasan untuk domain ID kunci adalah kontinuitas. Saat mengakses kunci berdasarkan alias, panggilan berikutnya dapat beroperasi pada kunci yang berbeda, karena kunci baru mungkin telah dibuat atau diimpor dan terikat dengan alias ini. Namun, ID kunci tidak pernah berubah. Jadi, saat menggunakan kunci berdasarkan ID kunci setelah dimuat dari database Keystore menggunakan alias sekali, seseorang dapat yakin bahwa kunci tersebut sama selama ID kunci masih ada. Fungsi ini tidak ditampilkan kepada developer aplikasi. Sebagai gantinya, API ini digunakan dalam Android Keystore SPI untuk memberikan pengalaman yang lebih konsisten meskipun digunakan secara serentak dengan cara yang tidak aman.DOMAIN_BLOB
: Domain blob menunjukkan bahwa pemanggil mengelola blob sendiri. Ini digunakan untuk klien yang perlu mengakses Keystore sebelum partisi data dipasang. Blob kunci disertakan dalam kolomblob
deskripsi kunci.
Dengan menggunakan domain SELinux, kita dapat memberi komponen vendor akses ke namespace Keystore yang sangat spesifik yang dapat dibagikan oleh komponen sistem seperti dialog setelan.
Kebijakan SELinux untuk keystore_key
Label namespace dikonfigurasi menggunakan file keystore2_key_context
.
Setiap baris dalam file ini memetakan ID namespace numerik ke label SELinux.
Misalnya,
# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and # Settings to share keystore keys. 102 u:object_r:wifi_key:s0
Setelah menyiapkan namespace kunci baru dengan cara ini, kita dapat memberikan akses ke namespace tersebut
dengan menambahkan kebijakan yang sesuai. Misalnya, untuk mengizinkan
wpa_supplicant
mendapatkan dan menggunakan kunci di namespace baru, kita akan
menambahkan baris berikut ke hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
Setelah menyiapkan namespace baru, AndroidKeyStore dapat digunakan hampir seperti
biasa. Satu-satunya perbedaan adalah ID namespace harus ditentukan. Untuk
memuat dan mengimpor kunci dari dan ke Keystore, ID namespace ditentukan
menggunakan AndroidKeyStoreLoadStoreParameter
. Misalnya,
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
Untuk membuat kunci di namespace tertentu, ID namespace harus diberikan menggunakan KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
File konteks berikut dapat digunakan untuk mengonfigurasi namespace Keystore 2.0 SELinux. Setiap partisi memiliki rentang yang dicadangkan berbeda dari 10.000 ID namespace untuk menghindari konflik.
Partisi | Rentang | File konfigurasi |
---|---|---|
Sistem | 0 ... 9.999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
Sistem yang Diperluas | 10.000 ... 19.999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
Produk | 20.000 ... 29.999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
Vendor | 30.000 ... 39.999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
Klien meminta kunci dengan meminta domain SELinux dan namespace virtual
yang diinginkan, dalam hal ini "wifi_key"
, dengan ID numerik.
Selain itu, namespace berikut telah ditentukan. Jika aturan tersebut menggantikan aturan khusus, tabel berikut menunjukkan UID yang digunakan untuk sesuai dengan aturan tersebut.
ID Ruangnama | Label SEPolicy | UID | Deskripsi |
---|---|---|---|
0 | su_key | T/A | Kunci superuser. Hanya digunakan untuk pengujian pada build userdebug dan eng. Tidak relevan pada build pengguna. |
1 | shell_key | T/A | Namespace yang tersedia untuk shell. Sebagian besar digunakan untuk pengujian, tetapi juga dapat digunakan pada build pengguna dari command line. |
100 | vold_key | T/A | Dimaksudkan untuk digunakan oleh vold. |
101 | odsing_key | T/A | Digunakan oleh daemon penandatanganan di perangkat. |
102 | wifi_key | AID_WIFI(1010) | Digunakan oleh subsistem Wi-Fi Android termasuk wpa_supplicant. |
120 | resume_on_reboot_key | AID_SYSTEM(1000) | Digunakan oleh server sistem Android untuk mendukung kelanjutan saat memulai ulang. |
Vektor akses
Kelas SELinux keystore_key
sudah cukup lama dan beberapa
izin, seperti verify
atau sign
telah kehilangan
maknanya. Berikut adalah kumpulan izin baru, keystore2_key
,
yang diterapkan Keystore 2.0.
Izin | Arti |
---|---|
delete
|
Dicentang saat menghapus kunci dari Keystore. |
get_info
|
Dicek saat metadata kunci diminta. |
grant
|
Pemanggil memerlukan izin ini untuk membuat pemberian ke kunci dalam konteks target. |
manage_blob
|
Pemanggil dapat menggunakan DOMAIN_BLOB pada namespace SELinux yang diberikan,
sehingga mengelola blob dengan sendirinya. Hal ini secara khusus berguna
untuk vold. |
rebind
|
Izin ini mengontrol apakah alias dapat di-bind ulang ke tombol baru. Hal ini diperlukan untuk penyisipan dan menyiratkan bahwa kunci yang sebelumnya terikat akan dihapus. Ini adalah izin penyisipan, tetapi menangkap semantik keystore dengan lebih baik. |
req_forced_op
|
Klien dengan izin ini dapat membuat operasi yang tidak dapat dipangkas, dan pembuatan operasi tidak pernah gagal kecuali jika semua slot operasi diambil oleh operasi yang tidak dapat dipangkas. |
update
|
Diperlukan untuk memperbarui subkomponen kunci. |
use
|
Dicek saat membuat operasi Keymint yang menggunakan materi kunci, misalnya, untuk penandatanganan, enkripsi, dekripsi. |
use_dev_id
|
Diperlukan saat membuat informasi identitas perangkat, seperti pengesahan ID perangkat. |
Selain itu, kami memisahkan serangkaian izin keystore non-kunci tertentu di
keystore2
class keamanan SELinux:
Izin | Arti |
---|---|
add_auth
|
Diperlukan oleh penyedia autentikasi seperti Gatekeeper atau BiometricsManager untuk menambahkan token autentikasi. |
clear_ns
|
Sebelumnya bernama clear_uid, izin ini memungkinkan non-pemilik namespace untuk menghapus semua kunci di namespace tersebut. |
list
|
Diperlukan oleh sistem untuk menghitung kunci berdasarkan berbagai properti, seperti
kepemilikan atau batasan autentikasi. Izin ini tidak diperlukan oleh pemanggil
yang menghitung namespace mereka sendiri. Hal ini tercakup dalam
izin get_info . |
lock
|
Izin ini memungkinkan untuk mengunci Keystore, yaitu mengeluarkan kunci master, sehingga kunci yang terikat autentikasi menjadi tidak dapat digunakan dan tidak dapat dibuat. |
reset
|
Izin ini memungkinkan Keystore direset ke setelan default pabrik, sehingga menghapus semua kunci yang tidak penting untuk fungsi Android OS. |
unlock
|
Izin ini diperlukan untuk mencoba membuka kunci master untuk kunci yang terikat autentikasi. |