Keystore yang didukung perangkat keras

Ketersediaan lingkungan eksekusi tepercaya dalam sistem pada chip (SoC) menawarkan peluang bagi perangkat Android untuk menyediakan layanan keamanan yang kuat dan didukung perangkat keras ke OS Android, ke layanan platform, dan bahkan ke aplikasi pihak ketiga. Pengembang yang mencari ekstensi khusus Android harus membuka android.security.keystore .

Sebelum Android 6.0, Android sudah memiliki API layanan kripto sederhana yang didukung perangkat keras, yang disediakan oleh Keymaster Hardware Abstraction Layer (HAL) versi 0.2 dan 0.3. Keystore menyediakan operasi penandatanganan dan verifikasi digital, ditambah pembuatan dan impor pasangan kunci penandatanganan asimetris. Ini sudah diterapkan di banyak perangkat, tetapi ada banyak tujuan keamanan yang tidak dapat dicapai dengan mudah hanya dengan API tanda tangan. Keystore di Android 6.0 memperluas API Keystore untuk menyediakan jangkauan kemampuan yang lebih luas.

Di Android 6.0, Keystore menambahkan primitif kriptografi simetris , AES dan HMAC, serta sistem kontrol akses untuk kunci yang didukung perangkat keras. Kontrol akses ditentukan selama pembuatan kunci dan diterapkan selama masa pakai kunci. Kunci dapat dibatasi untuk dapat digunakan hanya setelah pengguna diautentikasi, dan hanya untuk tujuan tertentu atau dengan parameter kriptografi tertentu. Untuk informasi selengkapnya, lihat halaman Tag Otorisasi dan Fungsi .

Selain memperluas jangkauan kriptografi primitif, Keystore di Android 6.0 menambahkan yang berikut:

  • Skema kontrol penggunaan untuk memungkinkan penggunaan kunci dibatasi, untuk mengurangi risiko kompromi keamanan karena penyalahgunaan kunci
  • Skema kontrol akses untuk mengaktifkan pembatasan kunci untuk pengguna tertentu, klien, dan rentang waktu yang ditentukan

Di Android 7.0, Keymaster 2 menambahkan dukungan untuk pengesahan kunci dan pengikatan versi. Pengesahan kunci memberikan sertifikat kunci publik yang berisi deskripsi rinci tentang kunci dan kontrol aksesnya, untuk membuat keberadaan kunci dalam perangkat keras yang aman dan konfigurasinya dapat diverifikasi dari jarak jauh.

Pengikatan versi mengikat kunci ke sistem operasi dan versi tingkat tambalan. Ini memastikan bahwa penyerang yang menemukan kelemahan dalam sistem versi lama atau perangkat lunak TEE tidak dapat mengembalikan perangkat ke versi yang rentan dan menggunakan kunci yang dibuat dengan versi yang lebih baru. Selain itu, ketika kunci dengan versi dan level tambalan tertentu digunakan pada perangkat yang telah ditingkatkan ke versi atau tingkat tambalan yang lebih baru, kunci dimutakhirkan sebelum dapat digunakan, dan versi kunci sebelumnya menjadi tidak valid. Saat perangkat ditingkatkan, kunci "bergeser" maju bersama dengan perangkat, tetapi setiap pengembalian perangkat ke rilis sebelumnya menyebabkan kunci tidak dapat digunakan.

Di Android 8.0, Keymaster 3 bertransisi dari Hardware Abstraction Layer (HAL) struktur-C gaya lama ke antarmuka C++ HAL yang dihasilkan dari definisi di Hardware Interface Definition Language (HIDL) baru. Sebagai bagian dari perubahan, banyak tipe argumen berubah, meskipun tipe dan metode memiliki korespondensi satu-ke-satu dengan tipe lama dan metode struct HAL. Lihat halaman Fungsi untuk lebih jelasnya.

Selain revisi antarmuka ini, Android 8.0 memperluas fitur pengesahan Keymaster 2 untuk mendukung pengesahan ID . Pengesahan ID menyediakan mekanisme terbatas dan opsional untuk membuktikan secara kuat pengenal perangkat keras, seperti nomor seri perangkat, nama produk, dan ID telepon (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 untuk menentukan mekanisme untuk menonaktifkan fitur secara aman dan permanen.

Di Android 9, pembaruan termasuk:

  • Perbarui ke Keymaster 4
  • Dukungan untuk Elemen Aman yang disematkan
  • Dukungan untuk impor kunci yang aman
  • Dukungan untuk enkripsi 3DES
  • Perubahan pada pengikatan versi sehingga boot.img dan system.img memiliki versi yang ditetapkan secara terpisah untuk memungkinkan pembaruan independen

Glosarium

Berikut adalah ikhtisar singkat tentang komponen Keystore dan hubungannya.

AndroidKeystore adalah Android Framework API dan komponen yang digunakan oleh aplikasi untuk mengakses fungsionalitas Keystore. Ini diimplementasikan sebagai ekstensi ke API Arsitektur Kriptografi Java 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 fungsionalitas Keystore melalui Binder API . Ini bertanggung jawab untuk menyimpan "gumpalan kunci", yang berisi materi kunci rahasia yang sebenarnya, dienkripsi sehingga Keystore dapat menyimpannya tetapi tidak menggunakan atau mengungkapkannya.

keymasterd adalah server HIDL yang menyediakan akses ke TA Keymaster. (Nama ini tidak standar dan untuk tujuan konseptual.)

Keymaster TA (aplikasi tepercaya) adalah perangkat lunak yang berjalan dalam konteks yang aman, paling sering di TrustZone pada ARM SoC, yang menyediakan semua operasi Keystore yang aman, memiliki akses ke bahan kunci mentah, memvalidasi semua kondisi kontrol akses pada kunci , dll.

LockSettingsService adalah komponen sistem Android yang bertanggung jawab atas otentikasi pengguna, baik kata sandi maupun sidik jari. Ini bukan bagian dari Keystore, tetapi relevan karena banyak operasi kunci Keystore memerlukan otentikasi pengguna. LockSettingsService berinteraksi dengan TA Penjaga Gerbang dan TA Sidik Jari untuk mendapatkan token autentikasi, yang diberikannya 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 kata sandi pengguna dan menghasilkan token autentikasi yang digunakan untuk membuktikan kepada TA Keymaster bahwa autentikasi telah dilakukan untuk pengguna tertentu pada titik waktu tertentu.

Fingerprint TA (aplikasi tepercaya) adalah komponen lain yang berjalan dalam konteks aman yang bertanggung jawab untuk mengautentikasi sidik jari pengguna dan menghasilkan token autentikasi yang digunakan untuk membuktikan kepada TA Keymaster bahwa autentikasi telah dilakukan untuk pengguna tertentu pada titik waktu tertentu.

Arsitektur

Android Keystore API dan Keymaster HAL yang mendasarinya menyediakan seperangkat primitif kriptografik dasar namun memadai untuk memungkinkan penerapan protokol menggunakan kunci yang dikontrol akses dan didukung perangkat keras.

Keymaster HAL adalah perpustakaan yang disediakan OEM dan dapat dimuat secara dinamis yang digunakan oleh layanan Keystore untuk menyediakan layanan kriptografi yang didukung perangkat keras. Untuk menjaga keamanan, implementasi HAL tidak melakukan operasi sensitif apa pun di ruang pengguna, atau bahkan di ruang kernel. Operasi sensitif didelegasikan ke prosesor aman yang dicapai melalui beberapa antarmuka kernel. Arsitektur yang dihasilkan terlihat seperti ini:

Akses ke Keymaster

Gambar 1. Akses ke Keymaster

Dalam perangkat Android, "klien" dari Keymaster HAL terdiri dari beberapa lapisan (misalnya aplikasi, kerangka kerja, daemon Keystore), tetapi itu dapat diabaikan untuk keperluan dokumen ini. Ini berarti bahwa Keymaster HAL API yang dijelaskan adalah level rendah, digunakan oleh komponen internal platform, dan tidak diekspos ke developer aplikasi. API tingkat yang lebih tinggi dijelaskan di situs Pengembang Android .

Tujuan dari Keymaster HAL bukan untuk mengimplementasikan algoritme yang sensitif terhadap keamanan tetapi hanya untuk mengatur dan menghapus permintaan ke dunia yang aman. Format kawat ditentukan oleh implementasi.

Kompatibilitas dengan versi sebelumnya

Keymaster 1 HAL sama sekali 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 mengimplementasikan Keymaster 1 HAL dengan panggilan ke pustaka perangkat keras yang ada. Hasilnya tidak dapat menyediakan fungsionalitas lengkap di Keymaster 1 HAL. Secara khusus, ini hanya mendukung algoritme RSA dan ECDSA, dan semua penegakan otorisasi utama dilakukan oleh adaptor, di dunia yang tidak aman.

Keymaster 2 semakin menyederhanakan antarmuka HAL dengan menghapus metode get_supported_* dan mengizinkan metode finish() untuk menerima input. Ini mengurangi jumlah perjalanan pulang pergi ke TEE dalam kasus di mana input tersedia sekaligus, dan menyederhanakan implementasi dekripsi AEAD.

Di Android 8.0, Keymaster 3 bertransisi dari HAL struktur-C gaya lama ke antarmuka C++ HAL yang dihasilkan dari definisi di Hardware Interface Definition Language (HIDL) baru. Implementasi HAL gaya baru dibuat dengan mensubklasifikasikan kelas IKeymasterDevice yang dihasilkan dan mengimplementasikan metode virtual murni. Sebagai bagian dari perubahan, banyak tipe argumen telah berubah, meskipun tipe dan metode memiliki korespondensi satu-ke-satu dengan tipe lama dan metode struct HAL.

Ikhtisar HIDL

Hardware Interface Definition Language (HIDL) menyediakan mekanisme implementasi bahasa-independen untuk menentukan antarmuka perangkat keras. Perkakas HIDL saat ini mendukung pembuatan antarmuka C++ dan Java. Diharapkan bahwa sebagian besar pelaksana Trusted Execution Environment (TEE) akan menemukan alat C++ lebih nyaman, sehingga dokumen ini hanya membahas representasi C++.

Antarmuka HIDL terdiri dari satu set metode, dinyatakan sebagai:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Ada berbagai tipe yang telah ditentukan sebelumnya, dan HAL dapat menentukan tipe enumerasi dan struktur baru. Untuk 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 yang berikut dari keymaster2 HAL:

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 bukan lagi struct yang berisi pointer yang mereferensikan array objek key_parameter_t , tetapi vec (vektor) yang berisi objek KeyParameter . Nilai kembalian tercantum dalam klausa " generates ", termasuk vektor nilai uint8_t untuk gumpalan kunci.

Metode virtual C++ yang dihasilkan oleh kompiler HIDL adalah:

Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                         generateKey_cb _hidl_cb) override;

Di mana generateKey_cb adalah penunjuk fungsi yang didefinisikan sebagai:

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                   const KeyCharacteristics& keyCharacteristics)>

Artinya, generateKey_cb adalah fungsi yang mengambil nilai kembalian yang tercantum dalam klausa generate. Kelas implementasi HAL menimpa metode generateKey ini dan memanggil penunjuk fungsi generateKey_cb untuk mengembalikan hasil operasi ke pemanggil. Perhatikan panggilan penunjuk fungsi sinkron . Pemanggil memanggil generateKey dan generateKey memanggil penunjuk fungsi yang disediakan, yang dijalankan hingga selesai, mengembalikan kontrol ke implementasi generateKey , yang kemudian kembali ke pemanggil.

Untuk contoh detail, lihat implementasi default di hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . Implementasi default menyediakan kompatibilitas mundur untuk perangkat dengan keymaster0, keymaster1, atau keymaster2 HALS gaya lama.

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 berkode keras yang memungkinkan komponen sistem tertentu untuk mengakses ruang nama tertentu lainnya. Ini adalah instrumen yang sangat tumpul karena memberikan satu komponen kontrol penuh atas namespace lain. Dan kemudian ada soal 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 menggeneralisasi kontrol akses tanpa pengecualian hard-code, Keystore 2.0 memperkenalkan domain dan ruang nama SELinux.

Domain Toko Kunci

Dengan domain Keystore, kita dapat memisahkan ruang nama dari UID. Klien yang mengakses kunci di Keystore harus menentukan domain, namespace, dan alias yang ingin mereka akses. Berdasarkan tupel ini dan identitas pemanggil, kita dapat menentukan kunci mana yang ingin diakses pemanggil dan apakah kunci tersebut memiliki izin yang sesuai.

Kami memperkenalkan lima parameter domain yang mengatur bagaimana kunci dapat diakses. Mereka mengontrol semantik parameter namespace dari deskriptor kunci dan bagaimana kontrol akses dilakukan.

  • DOMAIN_APP : Domain aplikasi mencakup perilaku lama. Java Keystore SPI menggunakan domain ini secara default. Ketika domain ini digunakan, argumen namespace diabaikan dan UID pemanggil digunakan sebagai gantinya. Akses ke domain ini dikendalikan oleh label Keystore ke kelas keystore_key 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 panggilan SELinux untuk kelas keystore_key . Ketika izin telah ditetapkan untuk operasi yang diberikan, tupel penuh digunakan untuk pencarian kunci.
  • DOMAIN_GRANT : Domain hibah menunjukkan bahwa parameter namespace adalah pengidentifikasi hibah. Parameter alias diabaikan. Pemeriksaan SELinux dilakukan saat hibah dibuat. Kontrol akses lebih lanjut hanya memeriksa apakah UID pemanggil cocok dengan UID penerima hibah dari hibah yang diminta.
  • DOMAIN_KEY_ID : Domain ini menunjukkan bahwa parameter namespace adalah id kunci yang unik. Kunci itu sendiri mungkin telah dibuat dengan DOMAIN_APP atau DOMAIN_SELINUX . Pemeriksaan izin dilakukan setelah domain dan namespace telah dimuat dari database kunci dengan cara yang sama seperti jika gumpalan dimuat oleh domain, namespace, dan tuple alias. Alasan untuk domain id kunci adalah kontinuitas. Saat mengakses kunci dengan alias, panggilan berikutnya dapat beroperasi pada kunci yang berbeda, karena kunci baru mungkin telah dibuat atau diimpor dan diikat ke alias ini. ID kunci, bagaimanapun, tidak pernah berubah. Jadi ketika menggunakan key by key id setelah di-load dari database Keystore menggunakan alias satu kali, dapat dipastikan bahwa itu adalah key yang sama selama key id tersebut masih ada. Fungsionalitas ini tidak diekspos ke pengembang aplikasi. Sebaliknya, ini digunakan dalam Android Keystore SPI untuk memberikan pengalaman yang lebih konsisten bahkan ketika digunakan secara bersamaan dengan cara yang tidak aman.
  • DOMAIN_BLOB : Domain blob menunjukkan bahwa pemanggil mengelola blob dengan sendirinya. Ini digunakan untuk klien yang perlu mengakses Keystore sebelum partisi data dipasang. Gumpalan kunci termasuk dalam bidang blob dari deskriptor kunci.

Dengan menggunakan domain SELinux, kami dapat memberikan komponen vendor akses ke ruang nama Keystore yang sangat spesifik yang dapat digunakan bersama oleh komponen sistem seperti dialog pengaturan.

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. Sebagai contoh,

# 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 ruang nama kunci baru dengan cara ini, kami dapat memberikan akses ke sana dengan menambahkan kebijakan yang sesuai. Misalnya, untuk mengizinkan wpa_supplicant mendapatkan dan menggunakan kunci di namespace baru, kami 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 bahwa ID namespace harus ditentukan. Untuk memuat dan mengimpor kunci dari dan ke Keystore, id namespace ditentukan menggunakan AndroidKeyStoreLoadStoreParameter . Sebagai contoh,

import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import java.security.KeyStore;

KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(new AndroidKeyStoreLoadStoreParameter(102));

Untuk menghasilkan kunci dalam namespace yang diberikan, 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 ruang nama Keystore 2.0 SELinux. Setiap partisi memiliki rentang yang berbeda dari 10.000 id namespace untuk menghindari tabrakan.

partisi Jangkauan 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
Penjual 30.000 ... 39.999
/vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

Klien meminta kunci dengan meminta domain SELinux dan ruang nama virtual yang diinginkan, dalam hal ini "wifi_key" , dengan id numeriknya.

Di atas itu, ruang nama berikut telah ditentukan. Jika mereka menggantikan aturan khusus, tabel berikut menunjukkan UID yang mereka gunakan untuk berhubungan.

ID ruang nama Label Kebijakan SE UID Keterangan
0 su_key T/A Kunci pengguna super. Hanya digunakan untuk pengujian pada userdebug dan eng build. Tidak relevan pada build pengguna.
1 shell_key T/A Namespace tersedia untuk shell. Sebagian besar digunakan untuk pengujian, tetapi dapat digunakan pada build pengguna juga dari baris perintah.
100 vold_key T/A Ditujukan untuk digunakan oleh vold.
101 odsing_key T/A Digunakan oleh daemon penandatanganan pada perangkat.
102 wifi_key AID_WIFI(1010) Digunakan oleh sistem Wifi Android termasuk wpa_supplicant.
120 resume_on_reboot_key AID_SYSTEM(1000) Digunakan oleh server sistem Android untuk mendukung resume saat reboot.

Akses Vektor

Keystore_key kelas keystore_key telah cukup tua dan beberapa izin, seperti verify atau sign telah kehilangan artinya. Berikut adalah kumpulan izin baru, keystore2_key , yang akan diterapkan oleh Keystore 2.0.

Izin Arti
delete Diperiksa saat melepas kunci dari Keystore.
get_info Diperiksa saat metadata kunci diminta.
grant Penelepon memerlukan izin ini untuk membuat hibah ke kunci dalam konteks target.
manage_blob Penelepon dapat menggunakan DOMAIN_BLOB pada namespace SELinux yang diberikan, sehingga mengelola gumpalan dengan sendirinya. Ini secara khusus berguna untuk vold.
rebind Izin ini mengontrol apakah alias dapat di-rebound ke kunci baru. Ini diperlukan untuk penyisipan dan menyiratkan bahwa kunci yang terikat sebelumnya akan dihapus. Ini pada dasarnya 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 akan pernah gagal kecuali semua slot operasi diambil oleh operasi yang tidak dapat dipangkas.
update Diperlukan untuk memperbarui subkomponen kunci.
use Diperiksa saat membuat operasi Keymint yang menggunakan materi kunci, misalnya untuk penandatanganan, en/dekripsi.
use_dev_id Diperlukan saat membuat informasi pengenal perangkat, seperti pengesahan id perangkat.

Selain itu, kami membagi satu set izin keystore khusus non-kunci di keystore2 kelas keamanan SELinux :

Izin Arti
add_auth Diperlukan oleh penyedia autentikasi seperti Gatekeeper atau BiometricsManager untuk menambahkan token autentikasi.
clear_ns Sebelumnya clear_uid, izin ini memungkinkan yang bukan pemilik namespace untuk menghapus semua kunci di namespace tersebut.
list Diperlukan oleh sistem untuk menghitung kunci dengan berbagai properti, seperti kepemilikan atau batasan auth. Izin ini tidak diperlukan oleh penelepon yang menghitung ruang nama mereka sendiri. Ini dicakup oleh izin get_info .
lock Izin ini memungkinkan untuk mengunci Keystore, yaitu, mengeluarkan kunci master, sehingga kunci terikat auth menjadi tidak dapat digunakan dan tidak dapat dibuat.
reset Izin ini memungkinkan untuk mengatur ulang Keystore ke default pabrik, menghapus semua kunci yang tidak vital untuk berfungsinya OS Android.
unlock Izin ini diperlukan untuk mencoba membuka kunci master untuk kunci terikat autentikasi.