Keystore yang didukung hardware

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:

Akses ke Keymaster

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 ke keystore_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 class keystore_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 dengan DOMAIN_APP atau DOMAIN_SELINUX. Pemeriksaan izin dilakukan setelah domain dan namespace 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 kolom blob 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.