Ketersediaan lingkungan eksekusi tepercaya dalam sistem pada chip (SoC) menawarkan peluang bagi perangkat Android untuk menyediakan dukungan perangkat keras layanan keamanan yang kuat ke OS Android, ke layanan platform, dan bahkan untuk aplikasi pihak ketiga. Developer yang mencari ekstensi khusus Android harus ke android.security.keystore.
Sebelum Android 6.0, Android sudah memiliki kripto sederhana yang didukung perangkat keras services API, yang disediakan oleh Keymaster Hardware versi 0.2 dan 0.3 Lapisan Abstraksi (HAL). Keystore memberikan verifikasi dan penandatanganan digital operasi, ditambah pembuatan dan impor pasangan kunci penandatanganan asimetris. Ini adalah yang sudah diimplementasikan di banyak perangkat, tetapi ada banyak tujuan keamanan yang tidak mudah dicapai hanya dengan API tanda tangan. Keystore di Android 6.0 telah memperluas Keystore API untuk menyediakan berbagai kemampuan yang lebih luas.
Di Android 6.0, Keystore ditambahkan primitif kriptografis simetris, AES dan HMAC, dan sistem kontrol akses untuk kunci yang didukung hardware. Akses ditetapkan selama pembuatan kunci dan diterapkan sepanjang waktu tombolnya. Kunci dapat dibatasi agar hanya dapat digunakan setelah pengguna diotentikasi, dan hanya untuk tujuan tertentu atau dengan kriptografi tertentu. parameter. Untuk informasi selengkapnya, lihat Tag Otorisasi dan Halaman Fungsi.
Selain memperluas rentang primitif kriptografi, Keystore di Android 6.0 menambahkan hal berikut:
- Skema kontrol penggunaan untuk membatasi penggunaan kunci, untuk memitigasi risiko penyusupan keamanan karena penyalahgunaan kunci
- Skema kontrol akses yang memungkinkan pembatasan kunci untuk pengguna tertentu, klien, dan rentang waktu yang ditentukan
Di Android 7.0, Keymaster 2 menambahkan dukungan untuk pengesahan dan versi kunci jaringan. Pengesahan kunci menyediakan public key certificate yang berisi deskripsi terperinci tentang kunci dan kontrol aksesnya, untuk membuat keberadaan kunci dalam perangkat keras yang aman dan konfigurasi yang dapat diverifikasi dari jarak jauh.
Binding versi mengikat kunci ke sistem operasi dan versi {i>patch<i}. Hal ini memastikan bahwa penyerang yang menemukan kelemahan dalam versi sistem lama atau Perangkat lunak 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 tertentu dan level patch digunakan pada perangkat yang telah diupgrade ke versi yang lebih baru atau level patch, kunci tersebut diupgrade sebelum dapat digunakan, dan kunci menjadi tidak valid. Saat perangkat diupgrade, kunci akan "ratchet" maju bersamaan dengan perangkat, tetapi pengembalian perangkat ke akan menyebabkan kunci tidak dapat digunakan.
Di Android 8.0, Keymaster 3 beralih dari C-structure Hardware gaya lama Abstraksi Layer (HAL) ke antarmuka C++ HAL yang dihasilkan dari definisi dalam {i>Hardware Interface Definition Language<i} (HIDL) yang baru. Sebagai bagian dari perubahan tersebut, banyak jenis argumen berubah, meskipun jenis dan metode memiliki pernyataan one-to-one korespondensi dengan tipe lama dan metode struct HAL. Lihat Halaman Functions untuk informasi selengkapnya spesifikasi pendukung.
Selain revisi antarmuka ini, Android 8.0 extended Keymaster 2's pengesahan untuk mendukung Pengesahan tanda pengenal. Pengesahan ID menyediakan mekanisme terbatas dan opsional untuk pengesahan kuat ID hardware, seperti nomor seri perangkat, nama produk, dan telepon ID (IMEI / MEID). Untuk menerapkan penambahan ini, Android 8.0 mengubah ASN.1 skema pengesahan ID untuk menambahkan pengesahan ID. Implementasi Keymaster perlu menemukan beberapa cara aman untuk mengambil item data yang relevan, serta untuk menentukan mekanisme untuk menonaktifkan fitur secara aman dan permanen.
Di Android 9, update mencakup:
- Perbarui ke Keymaster 4
- Dukungan untuk Elemen Pengaman yang disematkan
- 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 Android Framework API dan komponen yang digunakan
oleh aplikasi untuk mengakses fungsi Keystore. Model ini diimplementasikan sebagai ekstensi untuk
Java Cryptography Architecture API standar, dan terdiri dari kode Java yang
berjalan di ruang proses aplikasi itu sendiri. AndroidKeystore
memenuhi aplikasi
untuk perilaku Keystore dengan meneruskannya ke daemon keystore.
Daemon keystore adalah daemon sistem Android yang menyediakan akses ke semua fungsi Keystore melalui Binder API. Ia bertanggung jawab untuk menyimpan "blob kunci", yang berisi materi kunci rahasia yang sebenarnya, dienkripsi sehingga dapat menyimpannya tapi tidak menggunakan atau mengungkapkannya.
keymasterd adalah server HIDL yang memberikan akses ke Keymaster TA. (Nama ini tidak standar dan ditujukan untuk tujuan konseptual.)
Keymaster TA (aplikasi tepercaya) adalah software yang berjalan di yang aman, paling sering di TrustZone di ARM SoC, yang menyediakan semua 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 otentikasi pengguna, yaitu {i>password<i} dan sidik jari. Ini bukan bagian dari
Keystore, tetapi relevan karena banyak operasi kunci Keystore memerlukan
autentikasi. LockSettingsService
berinteraksi dengan Gatekeeper
TA dan Sidik Jari TA untuk memperoleh token otentikasi, yang diberikannya ke
daemon keystore, dan yang akhirnya dipakai oleh Keymaster TA
aplikasi.
Gatekeeper TA (aplikasi tepercaya) adalah komponen lainnya berjalan dalam konteks aman, yang bertanggung jawab untuk mengotentikasi pengguna sandi dan membuat token autentikasi yang digunakan untuk membuktikan kepada Keymaster TA bahwa otentikasi telah dilakukan untuk pengguna tertentu pada titik tertentu dalam baik.
TA sidik jari (aplikasi tepercaya) adalah komponen lainnya berjalan dalam konteks aman yang bertanggung jawab untuk otentikasi pengguna sidik jari dan menghasilkan token autentikasi yang digunakan untuk membuktikan kepada Keymaster TA bahwa otentikasi telah dilakukan untuk pengguna tertentu pada titik tertentu pada waktunya.
Arsitektur
Android Keystore API dan Keymaster HAL yang mendasarinya menyediakan seperangkat dasar kriptografi yang memadai untuk memungkinkan dan implementasi protokol menggunakan kunci yang dikontrol akses dan didukung hardware.
Keymaster HAL adalah library yang disediakan OEM dan dapat dimuat secara dinamis yang digunakan oleh layanan Keystore untuk menyediakan layanan kriptografi yang didukung hardware. Untuk mempertahankan keamanan, implementasi HAL tidak melakukan operasi sensitif di {i>user space<i}, atau bahkan dalam ruang {i>kernel<i}. Operasi sensitif didelegasikan ke prosesor aman yang dijangkau melalui beberapa antarmuka {i>kernel<i}. Arsitektur yang dihasilkan akan terlihat seperti ini:
Dalam perangkat Android, "klien" Keymaster HAL terdiri dari beberapa lapisan (misalnya aplikasi, framework, daemon Keystore), tetapi dapat diabaikan untuk tujuan dokumen ini. Ini berarti bahwa Keymaster HAL yang API memiliki level rendah, digunakan oleh komponen internal platform, dan tidak diekspos ke aplikasi developer. API dengan level yang lebih tinggi dijelaskan di situs Android Developer.
Tujuan Keymaster HAL adalah bukan untuk menerapkan komponen algoritma tetapi hanya untuk melakukan permintaan marshal dan {i>unmarshal<i} ke dunia yang aman. Tujuan {i>wire format<i} ditentukan oleh implementasi.
Kompatibilitas dengan versi sebelumnya versi
Keymaster 1 HAL sepenuhnya tidak kompatibel dengan HAL yang dirilis sebelumnya, misalnya Keymaster 0.2 dan 0.3. Untuk memfasilitasi interoperabilitas pada perangkat yang menjalankan Android 5.0 dan sebelumnya yang diluncurkan dengan Keymaster HALs yang lebih lama, Keystore menyediakan adaptor yang menerapkan Keymaster 1 HAL dengan panggilan ke pustaka perangkat keras yang ada. Hasilnya tidak dapat menyediakan berbagai fungsionalitas dalam Keymaster 1 HAL. Secara khusus, kita akan membuat layanan itu hanya mendukung algoritma RSA dan ECDSA, dan semua otorisasi kunci penegakan kebijakan dilakukan oleh adaptor, di dunia yang tidak aman.
Keymaster 2 semakin menyederhanakan antarmuka HAL dengan menghapus
Metode get_supported_*
dan mengizinkan finish()
untuk menerima input. Hal ini mengurangi jumlah
perjalanan pulang pergi ke TEE di
kasus saat input tersedia sekaligus, dan menyederhanakan penerapan
Dekripsi AEAD.
Di Android 8.0, Keymaster 3 beralih dari C-structure gaya lama
HAL ke antarmuka C++ HAL yang dihasilkan dari definisi dalam
Hardware Interface Definition Language (HIDL). HAL gaya baru
akan dibuat dengan membuat subclass dari
IKeymasterDevice
dan mengimplementasikan virtual murni
metode. Sebagai bagian dari perubahan, banyak
jenis argumen telah berubah,
meskipun jenis dan metodenya memiliki keterkaitan
satu-ke-satu dengan yang lama
dan metode struct HAL.
Ringkasan HIDL
Hardware Interface Definition Language (HIDL) menyediakan implementasi mekanisme independen dari bahasa tertentu untuk menentukan antarmuka perangkat keras. HIDL saat ini mendukung pembuatan antarmuka C++ dan Java. Diharapkan kebanyakan pengimplementasi Trusted Execution Environment (TEE) akan menemukan untuk lebih nyaman, jadi dokumen ini hanya membahas representasi C++.
Antarmuka HIDL terdiri dari serangkaian metode, yang dinyatakan sebagai:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
Ada berbagai tipe yang telah ditentukan, dan HAL bisa mendefinisikan enumerasi baru dan jenis struktur. Untuk mengetahui detail lebih lanjut tentang HIDL, lihat bagian Referensi.
Contoh metode dari Keymaster 3 IKeymasterDevice.hal
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
implisit. Argumen params
tidak lagi merupakan struct yang berisi
pointer yang merujuk ke array objek key_parameter_t
, tetapi
vec
(vektor) yang berisi objek KeyParameter
. Tujuan
nilai yang ditampilkan tercantum dalam "generates
" , yang meliputi
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 menggunakan nilai yang ditampilkan
yang tercantum dalam
klausa generate. Class implementasi HAL mengganti ini
Metode generateKey
dan memanggil fungsi generateKey_cb
untuk mengembalikan hasil operasi ke pemanggil. Perhatikan fungsi
panggilan pointer bersifat sinkron. Penelepon menelepon
generateKey
dan generateKey
memanggil
pointer fungsi, yang dieksekusi hingga selesai, yang menampilkan kontrol
Implementasi generateKey
, yang kemudian ditampilkan kembali ke pemanggil.
Untuk contoh yang terperinci, lihat implementasi default pada
hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
.
Implementasi default memberikan kompatibilitas mundur untuk perangkat dengan
{i> old-style keymaster0, keymaster1, atau keymaster2 HALS<i}.
Kontrol akses
Aturan paling dasar dari kontrol akses Keystore adalah bahwa setiap aplikasi memiliki namespace sendiri. Tetapi untuk setiap aturan ada pengecualian. Keystore memiliki beberapa peta hard code yang memungkinkan komponen sistem tertentu untuk mengakses namespace. Instrumen ini sangat tumpul karena memberikan satu komponen kontrol penuh atas namespace lainnya. Dan kemudian masalah vendor sebagai klien untuk Keystore. Saat ini kami tidak memiliki cara untuk membuat untuk komponen vendor, misalnya, pemohon WPA.
Untuk mengakomodasi komponen vendor dan menggeneralisasi kontrol akses tanpa pengecualian hard code, Keystore 2.0 memperkenalkan domain dan SELinux namespace.
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 mereka akses. Berdasarkan tuple ini dan identitas pemanggil, kita dapat menentukan kunci mana yang ingin diakses oleh pemanggil dan apakah kunci tersebut memiliki izin akses.
Kami memperkenalkan lima parameter domain yang mengatur cara mengakses kunci. Mereka mengontrol semantik parameter namespace dari deskriptor kunci dan bagaimana kontrol akses dilakukan.
DOMAIN_APP
: Domain aplikasi mencakup perilaku yang lalu. Java Keystore SPI menggunakan domain ini secara default. Jika domain digunakan, argumen namespace diabaikan dan UID pemanggil digunakan sebagai gantinya. Akses ke domain ini dikontrol oleh label Keystore kekeystore_key
dalam kebijakan SELinux.DOMAIN_SELINUX
: Domain ini menunjukkan bahwa memiliki label pada kebijakan SELinux. Parameter namespace dilihat dan diterjemahkan ke dalam konteks target, dan pemeriksaan izin dilakukan untuk konteks SELinux panggilan untuk classkeystore_key
. Jika izin akses telah ditetapkan untuk operasi yang diberikan, tuple penuh akan digunakan untuk pencarian tombol.DOMAIN_GRANT
: Domain pemberian menunjukkan bahwa parameter namespace adalah ID pemberian. Parameter alias diabaikan. Pemeriksaan SELinux dilakukan saat hibah dibuat. Kontrol akses lebih lanjut hanya memeriksa apakah UID pemanggil cocok dengan UID penerima hibah dari pemberian 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
. Izin pemeriksaan dilakukan setelahdomain
dannamespace
telah dimuat dari database kunci dengan cara yang sama seperti jika blob dimuat menurut domain, namespace, dan tuple alias. Alasan untuk key-id domain adalah kontinuitas. Ketika mengakses sebuah kunci dengan alias, panggilan berikutnya mungkin dilakukan pada kunci yang berbeda, karena kunci baru mungkin telah dibuat atau diimpor dan diikat ke alias ini. Namun, ID kunci tidak pernah berubah. Jadi, saat menggunakan kunci berdasarkan ID kunci setelah dimuat dari database Keystore menggunakan alias satu kali, satu dapat dipastikan bahwa kunci itu sama selama ID kunci masih ada. Ini tidak diekspos ke developer aplikasi. Sebagai gantinya, model ini digunakan dalam SPI Android Keystore untuk memberikan pengalaman yang lebih konsisten bahkan saat digunakan secara serentak dengan cara yang tidak aman.DOMAIN_BLOB
: Domain blob menunjukkan bahwa pemanggil akan mengelola blob sendiri. Layanan ini digunakan untuk klien yang perlu mengakses Keystore sebelum partisi data dipasang. Blob utamanya adalah disertakan dalam kolomblob
deskripsi kunci.
Dengan menggunakan domain SELinux, kita dapat memberi komponen vendor akses ke namespace Keystore tertentu yang bisa dibagikan oleh komponen sistem seperti dialog setelan.
Kebijakan SELinux untuk keystore_key
Label namespace dikonfigurasi menggunakan 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
dengan menambahkan
kebijakan yang sesuai. Misalnya, untuk mengizinkan
wpa_supplicant
untuk mendapatkan dan menggunakan kunci di namespace baru yang akan kita
tambahkan 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 sebagai
seperti biasa. Satu-satunya perbedaan adalah ID namespace harus ditentukan. Sebagai
memuat dan mengimpor kunci dari dan ke dalam 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 dalam 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 Keystore 2.0 SELinux namespace. Setiap partisi memiliki rentang cadangan 10.000 namespace yang berbeda untuk menghindari tabrakan.
Partisi | Rentang | File konfigurasi |
---|---|---|
Sistem | 0 ... 9.999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
Sistem yang Diperpanjang | 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 alamat IP
namespace virtual, dalam hal ini "wifi_key"
, berdasarkan ID numeriknya.
Di atas itu, namespace berikut telah ditetapkan. Jika mereka mengganti aturan khusus, tabel berikut menunjukkan UID yang mereka gunakan untuk tempat mesin terhubung.
ID Ruangnama | Label Kebijakan SE | UID | Deskripsi |
---|---|---|---|
0 | kunci_su | T/A | Kunci pengguna super. Hanya digunakan untuk pengujian pada userdebug dan build ing. Bukan relevan pada {i> build <i}pengguna. |
1 | kunci_shell | T/A | Namespace tersedia untuk shell. Sebagian besar digunakan untuk pengujian, tetapi dapat digunakan pada dibangun pengguna serta dari baris perintah. |
100 | kunci_vold | T/A | Ditujukan untuk digunakan berdasarkan volume. |
101 | kunci_odsing | T/A | Digunakan oleh daemon penandatanganan di perangkat. |
102 | kunci_wifi | AID_Wi-Fi(1010) | Digunakan oleh sistem Wi-Fi Android, termasuk wpa_supplicant. |
120 | lanjutkan_kunci_mulai ulang_kunci | AID_SYSTEM(1000) | Digunakan oleh server sistem Android untuk mendukung lanjutkan saat reboot. |
Mengakses Vektor
Class SELinux keystore_key
sudah cukup lama dan beberapa
izin, seperti verify
atau sign
telah hilang
artinya. Berikut adalah kumpulan izin baru, keystore2_key
,
yang akan diberlakukan oleh Keystore 2.0.
Izin | Arti |
---|---|
delete
|
Diperiksa saat menghapus kunci dari Keystore. |
get_info
|
Diperiksa saat metadata kunci diminta. |
grant
|
Pemanggil memerlukan izin ini untuk membuat pemberian ke kunci di target konteks tambahan. |
manage_blob
|
Pemanggil dapat menggunakan DOMAIN_BLOB pada namespace SELinux yang diberikan,
sehingga dapat mengelola blob dengan sendirinya. Cara ini secara khusus berguna untuk
vold. |
rebind
|
Izin ini mengontrol apakah alias dapat diikat kembali ke kunci baru. Ini adalah diperlukan untuk penyisipan dan menyiratkan bahwa kunci yang sebelumnya terikat akan dihapus. Ini pada dasarnya adalah izin penyisipan, tetapi menangkap semantik keystore secara 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 diuraikan. |
update
|
Diperlukan untuk memperbarui subkomponen kunci. |
use
|
Diperiksa saat membuat operasi Keymint yang menggunakan materi kunci, misalnya, untuk penandatanganan, {i>en/dekripsi<i}. |
use_dev_id
|
Wajib saat membuat informasi pengidentifikasi perangkat, misalnya ID perangkat pengesahan. |
Selain itu, kami membagi kumpulan izin keystore khusus non-kunci di
class keamanan SELinux keystore2
:
Izin | Arti |
---|---|
add_auth
|
Diperlukan oleh penyedia autentikasi seperti Gatekeeper atau BiometricsManager untuk menambahkan token auth. |
clear_ns
|
Sebelumnya clear_uid, izin ini memungkinkan bukan pemilik namespace untuk menghapus semua kunci dalam namespace itu. |
list
|
Diperlukan oleh sistem untuk menghitung kunci dengan berbagai properti, seperti
kepemilikan atau pembatasan autentikasi. Izin ini tidak diperlukan oleh pemanggil
menghitung namespace mereka sendiri. Hal ini dicakup dalam
Izin get_info . |
lock
|
Izin ini memungkinkan untuk mengunci Keystore, yaitu, mengeluarkan kunci master, seperti kunci yang terikat auth menjadi tidak digunakan dan tidak dapat dibuat. |
reset
|
Izin ini memungkinkan untuk mereset Keystore ke setelan default pabrik, sehingga menghapus semua yang tidak penting untuk fungsi Android OS. |
unlock
|
Izin ini diperlukan untuk mencoba membuka kunci master untuk autentikasi {i>bound key<i}. |