Keystore yang didukung hardware

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:

Akses ke Keymaster

Gambar 1. Akses ke Keymaster

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