Merge "Limit the number of key descriptors sent back"
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index d01c67d..ab3e22c 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -59,6 +59,16 @@
constexpr const char keystore2_service_name[] = "android.system.keystore2.IKeystoreService/default";
+std::string string_replace_all(std::string str, const std::string& from,
+ const std::string& to) {
+ size_t start = 0;
+ while ((start = str.find(from, start)) != std::string::npos) {
+ str.replace(start, from.length(), to);
+ start += to.length();
+ }
+ return str;
+}
+
int unwrapError(const ndk::ScopedAStatus& status) {
if (status.isOk()) return 0;
if (status.getExceptionCode() == EX_SERVICE_SPECIFIC) {
@@ -1028,7 +1038,8 @@
auto listener = ndk::SharedRefBase::make<ConfirmationListener>();
auto future = listener->get_future();
- auto rc = apcService->presentPrompt(listener, promptText, extraData, locale, uiOptionsAsFlags);
+ auto rc = apcService->presentPrompt(listener, string_replace_all(promptText, "\\n", "\n"),
+ extraData, locale, uiOptionsAsFlags);
if (!rc.isOk()) {
std::cerr << "Presenting confirmation prompt failed: " << rc.getDescription() << std::endl;
diff --git a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
index 3f33431..e3b7d11 100644
--- a/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
+++ b/keystore2/aidl/android/security/authorization/IKeystoreAuthorization.aidl
@@ -41,8 +41,26 @@
/**
* Unlocks the keystore for the given user id.
+ *
* Callers require 'Unlock' permission.
- * If a password was set, a password must be given on unlock or the operation fails.
+ *
+ * Super-Encryption Key:
+ * When the device is unlocked (and password is non-null), Keystore stores in memory
+ * a super-encryption key derived from the password that protects UNLOCKED_DEVICE_REQUIRED
+ * keys; this key is wiped from memory when the device is locked.
+ *
+ * If unlockingSids is non-empty on lock, then before the super-encryption key is wiped from
+ * memory, a copy of it is stored in memory encrypted with a fresh AES key. This key is then
+ * imported into KM, tagged such that it can be used given a valid, recent auth token for any
+ * of the unlockingSids.
+ *
+ * Options for unlock:
+ * - If the password is non-null, the super-encryption key is re-derived as above.
+ * - If the password is null, then if a suitable auth token to access the encrypted
+ * Super-encryption key stored in KM has been sent to keystore (via addAuthToken), the
+ * encrypted super-encryption key is recovered so that UNLOCKED_DEVICE_REQUIRED keys can
+ * be used once again.
+ * - If neither of these are met, then the operation fails.
*
* ## Error conditions:
* `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'Unlock' permission.
@@ -50,33 +68,10 @@
* `ResponseCode::VALUE_CORRUPTED` - if the super key can not be decrypted.
* `ResponseCode::KEY_NOT_FOUND` - if the super key is not found.
*
- * @lockScreenEvent - Indicates what happened.
- * * LockScreenEvent.UNLOCK if the screen was unlocked.
- * * LockScreenEvent.LOCK if the screen was locked.
- *
- * @param userId - Android user id
- *
- * @param password - synthetic password derived by the user denoted by the user id
- *
- * @param unlockingSids - list of biometric SIDs for this user. This will be null when
- * lockScreenEvent is UNLOCK, but may be non-null when
- * lockScreenEvent is LOCK.
- *
- * When the device is unlocked, Keystore stores in memory
- * a super-encryption key that protects UNLOCKED_DEVICE_REQUIRED
- * keys; this key is wiped from memory when the device is locked.
- *
- * If unlockingSids is non-empty on lock, then before the
- * super-encryption key is wiped from memory, a copy of it
- * is stored in memory encrypted with a fresh AES key.
- * This key is then imported into KM, tagged such that it can be
- * used given a valid, recent auth token for any of the
- * unlockingSids.
- *
- * Then, when the device is unlocked again, if a suitable auth token
- * has been sent to keystore, it is used to recover the
- * super-encryption key, so that UNLOCKED_DEVICE_REQUIRED keys can
- * be used once again.
+ * @param lockScreenEvent whether the lock screen locked or unlocked
+ * @param userId android user id
+ * @param password synthetic password derived from the user's LSKF, must be null on lock
+ * @param unlockingSids list of biometric SIDs for this user, ignored on unlock
*/
void onLockScreenEvent(in LockScreenEvent lockScreenEvent, in int userId,
in @nullable byte[] password, in @nullable long[] unlockingSids);
diff --git a/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
index 4c2419a..1a385e7 100644
--- a/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
+++ b/keystore2/src/fuzzers/keystore2_unsafe_fuzzer.rs
@@ -16,8 +16,6 @@
#![feature(slice_internals)]
#![no_main]
-#[macro_use]
-extern crate libfuzzer_sys;
use core::slice::memchr;
use keystore2::{legacy_blob::LegacyBlobLoader, utils::ui_opts_2_compat};
@@ -31,7 +29,7 @@
};
use keystore2_selinux::{check_access, getpidcon, setcon, Backend, Context, KeystoreKeyBackend};
use keystore2_vintf::{get_aidl_instances, get_hidl_instances};
-use libfuzzer_sys::arbitrary::Arbitrary;
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
use std::{ffi::CString, sync::Arc};
// Avoid allocating too much memory and crashing the fuzzer.
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
index 2d1b23b..d611678 100644
--- a/keystore2/src/rkpd_client.rs
+++ b/keystore2/src/rkpd_client.rs
@@ -14,7 +14,7 @@
//! Helper wrapper around RKPD interface.
-use crate::error::{map_binder_status_code, map_or_log_err, Error, ErrorCode};
+use crate::error::{map_binder_status_code, Error, ErrorCode};
use crate::globals::get_remotely_provisioned_component_name;
use crate::ks_err;
use crate::utils::watchdog as wd;
@@ -23,7 +23,10 @@
IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::IGetKeyCallback,
IGetRegistrationCallback::BnGetRegistrationCallback,
IGetRegistrationCallback::IGetRegistrationCallback, IRegistration::IRegistration,
- IRemoteProvisioning::IRemoteProvisioning, RemotelyProvisionedKey::RemotelyProvisionedKey,
+ IRemoteProvisioning::IRemoteProvisioning,
+ IStoreUpgradedKeyCallback::BnStoreUpgradedKeyCallback,
+ IStoreUpgradedKeyCallback::IStoreUpgradedKeyCallback,
+ RemotelyProvisionedKey::RemotelyProvisionedKey,
};
use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
use anyhow::{Context, Result};
@@ -31,45 +34,36 @@
use futures::executor::block_on;
use std::sync::Mutex;
-type RegistrationSender = oneshot::Sender<Result<binder::Strong<dyn IRegistration>>>;
+/// Thread-safe channel for sending a value once and only once. If a value has
+/// already been send, subsequent calls to send will noop.
+struct SafeSender<T> {
+ inner: Mutex<Option<oneshot::Sender<T>>>,
+}
+
+impl<T> SafeSender<T> {
+ fn new(sender: oneshot::Sender<T>) -> Self {
+ Self { inner: Mutex::new(Some(sender)) }
+ }
+
+ fn send(&self, value: T) {
+ if let Some(inner) = self.inner.lock().unwrap().take() {
+ // assert instead of unwrap, because on failure send returns Err(value)
+ assert!(inner.send(value).is_ok(), "thread state is terminally broken");
+ }
+ }
+}
struct GetRegistrationCallback {
- registration_tx: Mutex<Option<RegistrationSender>>,
+ registration_tx: SafeSender<Result<binder::Strong<dyn IRegistration>>>,
}
impl GetRegistrationCallback {
pub fn new_native_binder(
- registration_tx: RegistrationSender,
- ) -> Result<Strong<dyn IGetRegistrationCallback>> {
+ registration_tx: oneshot::Sender<Result<binder::Strong<dyn IRegistration>>>,
+ ) -> Strong<dyn IGetRegistrationCallback> {
let result: Self =
- GetRegistrationCallback { registration_tx: Mutex::new(Some(registration_tx)) };
- Ok(BnGetRegistrationCallback::new_binder(result, BinderFeatures::default()))
- }
- fn on_success(&self, registration: &binder::Strong<dyn IRegistration>) -> Result<()> {
- if let Some(tx) = self.registration_tx.lock().unwrap().take() {
- tx.send(Ok(registration.clone())).unwrap();
- }
- Ok(())
- }
- fn on_cancel(&self) -> Result<()> {
- if let Some(tx) = self.registration_tx.lock().unwrap().take() {
- tx.send(
- Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
- .context(ks_err!("GetRegistrationCallback cancelled.")),
- )
- .unwrap();
- }
- Ok(())
- }
- fn on_error(&self, error: &str) -> Result<()> {
- if let Some(tx) = self.registration_tx.lock().unwrap().take() {
- tx.send(
- Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
- .context(ks_err!("GetRegistrationCallback failed: {:?}", error)),
- )
- .unwrap();
- }
- Ok(())
+ GetRegistrationCallback { registration_tx: SafeSender::new(registration_tx) };
+ BnGetRegistrationCallback::new_binder(result, BinderFeatures::default())
}
}
@@ -78,15 +72,26 @@
impl IGetRegistrationCallback for GetRegistrationCallback {
fn onSuccess(&self, registration: &Strong<dyn IRegistration>) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetRegistrationCallback::onSuccess", 500);
- map_or_log_err(self.on_success(registration), Ok)
+ self.registration_tx.send(Ok(registration.clone()));
+ Ok(())
}
fn onCancel(&self) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500);
- map_or_log_err(self.on_cancel(), Ok)
+ log::warn!("IGetRegistrationCallback cancelled");
+ self.registration_tx.send(
+ Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
+ .context(ks_err!("GetRegistrationCallback cancelled.")),
+ );
+ Ok(())
}
fn onError(&self, error: &str) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
- map_or_log_err(self.on_error(error), Ok)
+ log::error!("IGetRegistrationCallback failed: '{error}'");
+ self.registration_tx.send(
+ Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+ .context(ks_err!("GetRegistrationCallback failed: {:?}", error)),
+ );
+ Ok(())
}
}
@@ -102,8 +107,7 @@
.context(ks_err!("Trying to get IRPC name."))?;
let (tx, rx) = oneshot::channel();
- let cb = GetRegistrationCallback::new_native_binder(tx)
- .context(ks_err!("Trying to create a IGetRegistrationCallback."))?;
+ let cb = GetRegistrationCallback::new_native_binder(tx);
remote_provisioning
.getRegistration(&rpc_name, &cb)
@@ -112,46 +116,16 @@
rx.await.unwrap()
}
-type KeySender = oneshot::Sender<Result<RemotelyProvisionedKey>>;
-
struct GetKeyCallback {
- key_tx: Mutex<Option<KeySender>>,
+ key_tx: SafeSender<Result<RemotelyProvisionedKey>>,
}
impl GetKeyCallback {
- pub fn new_native_binder(key_tx: KeySender) -> Result<Strong<dyn IGetKeyCallback>> {
- let result: Self = GetKeyCallback { key_tx: Mutex::new(Some(key_tx)) };
- Ok(BnGetKeyCallback::new_binder(result, BinderFeatures::default()))
- }
- fn on_success(&self, key: &RemotelyProvisionedKey) -> Result<()> {
- if let Some(tx) = self.key_tx.lock().unwrap().take() {
- tx.send(Ok(RemotelyProvisionedKey {
- keyBlob: key.keyBlob.clone(),
- encodedCertChain: key.encodedCertChain.clone(),
- }))
- .unwrap();
- }
- Ok(())
- }
- fn on_cancel(&self) -> Result<()> {
- if let Some(tx) = self.key_tx.lock().unwrap().take() {
- tx.send(
- Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
- .context(ks_err!("GetKeyCallback cancelled.")),
- )
- .unwrap();
- }
- Ok(())
- }
- fn on_error(&self, error: &str) -> Result<()> {
- if let Some(tx) = self.key_tx.lock().unwrap().take() {
- tx.send(
- Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
- .context(ks_err!("GetKeyCallback failed: {:?}", error)),
- )
- .unwrap();
- }
- Ok(())
+ pub fn new_native_binder(
+ key_tx: oneshot::Sender<Result<RemotelyProvisionedKey>>,
+ ) -> Strong<dyn IGetKeyCallback> {
+ let result: Self = GetKeyCallback { key_tx: SafeSender::new(key_tx) };
+ BnGetKeyCallback::new_binder(result, BinderFeatures::default())
}
}
@@ -160,15 +134,29 @@
impl IGetKeyCallback for GetKeyCallback {
fn onSuccess(&self, key: &RemotelyProvisionedKey) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetKeyCallback::onSuccess", 500);
- map_or_log_err(self.on_success(key), Ok)
+ self.key_tx.send(Ok(RemotelyProvisionedKey {
+ keyBlob: key.keyBlob.clone(),
+ encodedCertChain: key.encodedCertChain.clone(),
+ }));
+ Ok(())
}
fn onCancel(&self) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500);
- map_or_log_err(self.on_cancel(), Ok)
+ log::warn!("IGetKeyCallback cancelled");
+ self.key_tx.send(
+ Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
+ .context(ks_err!("GetKeyCallback cancelled.")),
+ );
+ Ok(())
}
fn onError(&self, error: &str) -> binder::Result<()> {
let _wp = wd::watch_millis("IGetKeyCallback::onError", 500);
- map_or_log_err(self.on_error(error), Ok)
+ log::error!("IGetKeyCallback failed: {error}");
+ self.key_tx.send(
+ Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+ .context(ks_err!("GetKeyCallback failed: {:?}", error)),
+ );
+ Ok(())
}
}
@@ -181,8 +169,7 @@
.context(ks_err!("Trying to get to IRegistration service."))?;
let (tx, rx) = oneshot::channel();
- let cb = GetKeyCallback::new_native_binder(tx)
- .context(ks_err!("Trying to create a IGetKeyCallback."))?;
+ let cb = GetKeyCallback::new_native_binder(tx);
registration
.getKey(caller_uid.try_into().unwrap(), &cb)
@@ -191,6 +178,39 @@
rx.await.unwrap()
}
+struct StoreUpgradedKeyCallback {
+ completer: SafeSender<Result<()>>,
+}
+
+impl StoreUpgradedKeyCallback {
+ pub fn new_native_binder(
+ completer: oneshot::Sender<Result<()>>,
+ ) -> Strong<dyn IStoreUpgradedKeyCallback> {
+ let result: Self = StoreUpgradedKeyCallback { completer: SafeSender::new(completer) };
+ BnStoreUpgradedKeyCallback::new_binder(result, BinderFeatures::default())
+ }
+}
+
+impl Interface for StoreUpgradedKeyCallback {}
+
+impl IStoreUpgradedKeyCallback for StoreUpgradedKeyCallback {
+ fn onSuccess(&self) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetRegistrationCallback::onSuccess", 500);
+ self.completer.send(Ok(()));
+ Ok(())
+ }
+
+ fn onError(&self, error: &str) -> binder::Result<()> {
+ let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
+ log::error!("IGetRegistrationCallback failed: {error}");
+ self.completer.send(
+ Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+ .context(ks_err!("Failed to store upgraded key: {:?}", error)),
+ );
+ Ok(())
+ }
+}
+
async fn store_rkpd_attestation_key_async(
security_level: &SecurityLevel,
key_blob: &[u8],
@@ -200,10 +220,14 @@
.await
.context(ks_err!("Trying to get to IRegistration service."))?;
+ let (tx, rx) = oneshot::channel();
+ let cb = StoreUpgradedKeyCallback::new_native_binder(tx);
+
registration
- .storeUpgradedKey(key_blob, upgraded_blob)
+ .storeUpgradedKeyAsync(key_blob, upgraded_blob, &cb)
.context(ks_err!("Failed to store upgraded blob with RKPD."))?;
- Ok(())
+
+ rx.await.unwrap()
}
/// Get attestation key from RKPD.
@@ -229,6 +253,7 @@
mod tests {
use super::*;
use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
+ use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
#[derive(Default)]
@@ -257,20 +282,32 @@
todo!()
}
- fn storeUpgradedKey(&self, _: &[u8], _: &[u8]) -> binder::Result<()> {
+ fn storeUpgradedKeyAsync(
+ &self,
+ _: &[u8],
+ _: &[u8],
+ _: &Strong<dyn IStoreUpgradedKeyCallback>,
+ ) -> binder::Result<()> {
todo!()
}
}
fn get_mock_registration() -> Result<binder::Strong<dyn IRegistration>> {
let (tx, rx) = oneshot::channel();
- let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+ let cb = GetRegistrationCallback::new_native_binder(tx);
let mock_registration = MockRegistration::new_native_binder();
assert!(cb.onSuccess(&mock_registration).is_ok());
block_on(rx).unwrap()
}
+ // Using the same key ID makes test cases race with each other. So, we use separate key IDs for
+ // different test cases.
+ fn get_next_key_id() -> u32 {
+ static ID: AtomicU32 = AtomicU32::new(0);
+ ID.fetch_add(1, Ordering::Relaxed)
+ }
+
#[test]
fn test_get_registration_cb_success() {
let registration = get_mock_registration();
@@ -280,7 +317,7 @@
#[test]
fn test_get_registration_cb_cancel() {
let (tx, rx) = oneshot::channel();
- let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+ let cb = GetRegistrationCallback::new_native_binder(tx);
assert!(cb.onCancel().is_ok());
let result = block_on(rx).unwrap();
@@ -293,7 +330,7 @@
#[test]
fn test_get_registration_cb_error() {
let (tx, rx) = oneshot::channel();
- let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+ let cb = GetRegistrationCallback::new_native_binder(tx);
assert!(cb.onError("error").is_ok());
let result = block_on(rx).unwrap();
@@ -308,7 +345,7 @@
let mock_key =
RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
let (tx, rx) = oneshot::channel();
- let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+ let cb = GetKeyCallback::new_native_binder(tx);
assert!(cb.onSuccess(&mock_key).is_ok());
let key = block_on(rx).unwrap().unwrap();
@@ -318,7 +355,7 @@
#[test]
fn test_get_key_cb_cancel() {
let (tx, rx) = oneshot::channel();
- let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+ let cb = GetKeyCallback::new_native_binder(tx);
assert!(cb.onCancel().is_ok());
let result = block_on(rx).unwrap();
@@ -331,7 +368,7 @@
#[test]
fn test_get_key_cb_error() {
let (tx, rx) = oneshot::channel();
- let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+ let cb = GetKeyCallback::new_native_binder(tx);
assert!(cb.onError("error").is_ok());
let result = block_on(rx).unwrap();
@@ -342,46 +379,81 @@
}
#[test]
- #[ignore]
+ fn test_store_upgraded_cb_success() {
+ let (tx, rx) = oneshot::channel();
+ let cb = StoreUpgradedKeyCallback::new_native_binder(tx);
+ assert!(cb.onSuccess().is_ok());
+
+ block_on(rx).unwrap().unwrap();
+ }
+
+ #[test]
+ fn test_store_upgraded_key_cb_error() {
+ let (tx, rx) = oneshot::channel();
+ let cb = StoreUpgradedKeyCallback::new_native_binder(tx);
+ assert!(cb.onError("oh no! it failed").is_ok());
+
+ let result = block_on(rx).unwrap();
+ assert_eq!(
+ result.unwrap_err().downcast::<Error>().unwrap(),
+ Error::Km(ErrorCode::UNKNOWN_ERROR)
+ );
+ }
+
+ #[test]
fn test_get_rkpd_attestation_key() {
+ binder::ProcessState::start_thread_pool();
let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, 0).unwrap();
assert!(!key.keyBlob.is_empty());
assert!(!key.encodedCertChain.is_empty());
}
#[test]
- #[ignore]
fn test_get_rkpd_attestation_key_same_caller() {
+ binder::ProcessState::start_thread_pool();
let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
- let caller_uid = 0;
+ let key_id = get_next_key_id();
// Multiple calls should return the same key.
- let first_key = get_rkpd_attestation_key(&sec_level, caller_uid).unwrap();
- let second_key = get_rkpd_attestation_key(&sec_level, caller_uid).unwrap();
+ let first_key = get_rkpd_attestation_key(&sec_level, key_id).unwrap();
+ let second_key = get_rkpd_attestation_key(&sec_level, key_id).unwrap();
assert_eq!(first_key.keyBlob, second_key.keyBlob);
assert_eq!(first_key.encodedCertChain, second_key.encodedCertChain);
}
#[test]
- #[ignore]
fn test_get_rkpd_attestation_key_different_caller() {
+ binder::ProcessState::start_thread_pool();
let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+ let first_key_id = get_next_key_id();
+ let second_key_id = get_next_key_id();
// Different callers should be getting different keys.
- let first_key = get_rkpd_attestation_key(&sec_level, 1).unwrap();
- let second_key = get_rkpd_attestation_key(&sec_level, 2).unwrap();
+ let first_key = get_rkpd_attestation_key(&sec_level, first_key_id).unwrap();
+ let second_key = get_rkpd_attestation_key(&sec_level, second_key_id).unwrap();
assert_ne!(first_key.keyBlob, second_key.keyBlob);
assert_ne!(first_key.encodedCertChain, second_key.encodedCertChain);
}
#[test]
- #[ignore]
+ // Couple of things to note:
+ // 1. This test must never run with UID of keystore. Otherwise, it can mess up keys stored by
+ // keystore.
+ // 2. Storing and reading the stored key is prone to race condition. So, we only do this in one
+ // test case.
fn test_store_rkpd_attestation_key() {
+ binder::ProcessState::start_thread_pool();
let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
- let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, 0).unwrap();
+ let key_id = get_next_key_id();
+ let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+ let new_blob: [u8; 8] = rand::random();
- assert!(store_rkpd_attestation_key(&sec_level, &key.keyBlob, &key.keyBlob).is_ok());
+ assert!(store_rkpd_attestation_key(&sec_level, &key.keyBlob, &new_blob).is_ok());
+
+ let new_key =
+ get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, key_id).unwrap();
+ assert_eq!(new_key.keyBlob, new_blob);
}
}
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index c2f0279..4608bc5 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -71,15 +71,6 @@
self
}
- /// Add Attestation-ID.
- pub fn attestation_app_id(mut self, b: Vec<u8>) -> Self {
- self.0.push(KeyParameter {
- tag: Tag::ATTESTATION_APPLICATION_ID,
- value: KeyParameterValue::Blob(b),
- });
- self
- }
-
/// Add No_auth_required.
pub fn no_auth_required(mut self) -> Self {
self.0.push(KeyParameter {
@@ -149,6 +140,15 @@
self
}
+ /// Add CALLER_NONCE.
+ pub fn caller_nonce(mut self) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::CALLER_NONCE,
+ value: KeyParameterValue::BoolValue(true),
+ });
+ self
+ }
+
/// Add MAC length.
pub fn mac_length(mut self, l: i32) -> Self {
self.0.push(KeyParameter { tag: Tag::MAC_LENGTH, value: KeyParameterValue::Integer(l) });
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 175d8bb..f9aaabb 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -18,13 +18,14 @@
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
- ErrorCode::ErrorCode, KeyOrigin::KeyOrigin, KeyParameter::KeyParameter,
- KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
- Tag::Tag,
+ ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
+ KeyOrigin::KeyOrigin, KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue,
+ KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, Tag::Tag,
};
use android_system_keystore2::aidl::android::system::keystore2::{
- Authorization::Authorization, Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
- KeyDescriptor::KeyDescriptor, KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
+ AuthenticatorSpec::AuthenticatorSpec, Authorization::Authorization, Domain::Domain,
+ IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
};
use crate::authorizations::AuthSetBuilder;
@@ -57,8 +58,6 @@
pub block_mode: Option<BlockMode>,
/// Attestation challenge.
pub att_challenge: Option<Vec<u8>>,
- /// Attestation app id.
- pub att_app_id: Option<Vec<u8>>,
}
/// DER-encoded PKCS#8 format RSA key. Generated using:
@@ -157,6 +156,131 @@
0xD6, 0x84, 0x98, 0xEA, 0x96, 0x91, 0xFB, 0x78, 0xED, 0x86,
];
+/// DER-encoded PKCS#8 format RSA key -
+/// Size: 2048
+/// Public Exponent: 65537
+/// Purpose: WRAP_KEY, ENCRYPT, DECRYPT
+/// Encryption scheme: RSAES-PKCS1-v1_5
+/// Digest: SHA_2_256
+/// Padding: RSA_OAEP
+/// This sample wrapping_key is taken from KeyMint tests
+/// (see hardware/interfaces/security/keymint/aidl/vts/functional/KeyMintTest.cpp).
+/// Similarly more test keys can be generated with below command -
+/// openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1 "%02X" "\n"'
+pub static WRAPPING_KEY: &[u8] = &[
+ 0x30, 0x82, 0x04, 0xbe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x04, 0xa8, 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01,
+ 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc3, 0x67, 0x93, 0x1d, 0x89, 0x00, 0xce, 0x56, 0xb0,
+ 0x06, 0x7f, 0x7d, 0x70, 0xe1, 0xfc, 0x65, 0x3f, 0x3f, 0x34, 0xd1, 0x94, 0xc1, 0xfe, 0xd5, 0x00,
+ 0x18, 0xfb, 0x43, 0xdb, 0x93, 0x7b, 0x06, 0xe6, 0x73, 0xa8, 0x37, 0x31, 0x3d, 0x56, 0xb1, 0xc7,
+ 0x25, 0x15, 0x0a, 0x3f, 0xef, 0x86, 0xac, 0xbd, 0xdc, 0x41, 0xbb, 0x75, 0x9c, 0x28, 0x54, 0xea,
+ 0xe3, 0x2d, 0x35, 0x84, 0x1e, 0xfb, 0x5c, 0x18, 0xd8, 0x2b, 0xc9, 0x0a, 0x1c, 0xb5, 0xc1, 0xd5,
+ 0x5a, 0xdf, 0x24, 0x5b, 0x02, 0x91, 0x1f, 0x0b, 0x7c, 0xda, 0x88, 0xc4, 0x21, 0xff, 0x0e, 0xba,
+ 0xfe, 0x7c, 0x0d, 0x23, 0xbe, 0x31, 0x2d, 0x7b, 0xd5, 0x92, 0x1f, 0xfa, 0xea, 0x13, 0x47, 0xc1,
+ 0x57, 0x40, 0x6f, 0xef, 0x71, 0x8f, 0x68, 0x26, 0x43, 0xe4, 0xe5, 0xd3, 0x3c, 0x67, 0x03, 0xd6,
+ 0x1c, 0x0c, 0xf7, 0xac, 0x0b, 0xf4, 0x64, 0x5c, 0x11, 0xf5, 0xc1, 0x37, 0x4c, 0x38, 0x86, 0x42,
+ 0x74, 0x11, 0xc4, 0x49, 0x79, 0x67, 0x92, 0xe0, 0xbe, 0xf7, 0x5d, 0xec, 0x85, 0x8a, 0x21, 0x23,
+ 0xc3, 0x67, 0x53, 0xe0, 0x2a, 0x95, 0xa9, 0x6d, 0x7c, 0x45, 0x4b, 0x50, 0x4d, 0xe3, 0x85, 0xa6,
+ 0x42, 0xe0, 0xdf, 0xc3, 0xe6, 0x0a, 0xc3, 0xa7, 0xee, 0x49, 0x91, 0xd0, 0xd4, 0x8b, 0x01, 0x72,
+ 0xa9, 0x5f, 0x95, 0x36, 0xf0, 0x2b, 0xa1, 0x3c, 0xec, 0xcc, 0xb9, 0x2b, 0x72, 0x7d, 0xb5, 0xc2,
+ 0x7e, 0x5b, 0x2f, 0x5c, 0xec, 0x09, 0x60, 0x0b, 0x28, 0x6a, 0xf5, 0xcf, 0x14, 0xc4, 0x20, 0x24,
+ 0xc6, 0x1d, 0xdf, 0xe7, 0x1c, 0x2a, 0x8d, 0x74, 0x58, 0xf1, 0x85, 0x23, 0x4c, 0xb0, 0x0e, 0x01,
+ 0xd2, 0x82, 0xf1, 0x0f, 0x8f, 0xc6, 0x72, 0x1d, 0x2a, 0xed, 0x3f, 0x48, 0x33, 0xcc, 0xa2, 0xbd,
+ 0x8f, 0xa6, 0x28, 0x21, 0xdd, 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x43,
+ 0x14, 0x47, 0xb6, 0x25, 0x19, 0x08, 0x11, 0x2b, 0x1e, 0xe7, 0x6f, 0x99, 0xf3, 0x71, 0x1a, 0x52,
+ 0xb6, 0x63, 0x09, 0x60, 0x04, 0x6c, 0x2d, 0xe7, 0x0d, 0xe1, 0x88, 0xd8, 0x33, 0xf8, 0xb8, 0xb9,
+ 0x1e, 0x4d, 0x78, 0x5c, 0xae, 0xee, 0xaf, 0x4f, 0x0f, 0x74, 0x41, 0x4e, 0x2c, 0xda, 0x40, 0x64,
+ 0x1f, 0x7f, 0xe2, 0x4f, 0x14, 0xc6, 0x7a, 0x88, 0x95, 0x9b, 0xdb, 0x27, 0x76, 0x6d, 0xf9, 0xe7,
+ 0x10, 0xb6, 0x30, 0xa0, 0x3a, 0xdc, 0x68, 0x3b, 0x5d, 0x2c, 0x43, 0x08, 0x0e, 0x52, 0xbe, 0xe7,
+ 0x1e, 0x9e, 0xae, 0xb6, 0xde, 0x29, 0x7a, 0x5f, 0xea, 0x10, 0x72, 0x07, 0x0d, 0x18, 0x1c, 0x82,
+ 0x2b, 0xcc, 0xff, 0x08, 0x7d, 0x63, 0xc9, 0x40, 0xba, 0x8a, 0x45, 0xf6, 0x70, 0xfe, 0xb2, 0x9f,
+ 0xb4, 0x48, 0x4d, 0x1c, 0x95, 0xe6, 0xd2, 0x57, 0x9b, 0xa0, 0x2a, 0xae, 0x0a, 0x00, 0x90, 0x0c,
+ 0x3e, 0xbf, 0x49, 0x0e, 0x3d, 0x2c, 0xd7, 0xee, 0x8d, 0x0e, 0x20, 0xc5, 0x36, 0xe4, 0xdc, 0x5a,
+ 0x50, 0x97, 0x27, 0x28, 0x88, 0xcd, 0xdd, 0x7e, 0x91, 0xf2, 0x28, 0xb1, 0xc4, 0xd7, 0x47, 0x4c,
+ 0x55, 0xb8, 0xfc, 0xd6, 0x18, 0xc4, 0xa9, 0x57, 0xbb, 0xdd, 0xd5, 0xad, 0x74, 0x07, 0xcc, 0x31,
+ 0x2d, 0x8d, 0x98, 0xa5, 0xca, 0xf7, 0xe0, 0x8f, 0x4a, 0x0d, 0x6b, 0x45, 0xbb, 0x41, 0xc6, 0x52,
+ 0x65, 0x9d, 0x5a, 0x5b, 0xa0, 0x5b, 0x66, 0x37, 0x37, 0xa8, 0x69, 0x62, 0x81, 0x86, 0x5b, 0xa2,
+ 0x0f, 0xbd, 0xd7, 0xf8, 0x51, 0xe6, 0xc5, 0x6e, 0x8c, 0xbe, 0x0d, 0xdb, 0xbf, 0x24, 0xdc, 0x03,
+ 0xb2, 0xd2, 0xcb, 0x4c, 0x3d, 0x54, 0x0f, 0xb0, 0xaf, 0x52, 0xe0, 0x34, 0xa2, 0xd0, 0x66, 0x98,
+ 0xb1, 0x28, 0xe5, 0xf1, 0x01, 0xe3, 0xb5, 0x1a, 0x34, 0xf8, 0xd8, 0xb4, 0xf8, 0x61, 0x81, 0x02,
+ 0x81, 0x81, 0x00, 0xde, 0x39, 0x2e, 0x18, 0xd6, 0x82, 0xc8, 0x29, 0x26, 0x6c, 0xc3, 0x45, 0x4e,
+ 0x1d, 0x61, 0x66, 0x24, 0x2f, 0x32, 0xd9, 0xa1, 0xd1, 0x05, 0x77, 0x75, 0x3e, 0x90, 0x4e, 0xa7,
+ 0xd0, 0x8b, 0xff, 0x84, 0x1b, 0xe5, 0xba, 0xc8, 0x2a, 0x16, 0x4c, 0x59, 0x70, 0x00, 0x70, 0x47,
+ 0xb8, 0xc5, 0x17, 0xdb, 0x8f, 0x8f, 0x84, 0xe3, 0x7b, 0xd5, 0x98, 0x85, 0x61, 0xbd, 0xf5, 0x03,
+ 0xd4, 0xdc, 0x2b, 0xdb, 0x38, 0xf8, 0x85, 0x43, 0x4a, 0xe4, 0x2c, 0x35, 0x5f, 0x72, 0x5c, 0x9a,
+ 0x60, 0xf9, 0x1f, 0x07, 0x88, 0xe1, 0xf1, 0xa9, 0x72, 0x23, 0xb5, 0x24, 0xb5, 0x35, 0x7f, 0xdf,
+ 0x72, 0xe2, 0xf6, 0x96, 0xba, 0xb7, 0xd7, 0x8e, 0x32, 0xbf, 0x92, 0xba, 0x8e, 0x18, 0x64, 0xea,
+ 0xb1, 0x22, 0x9e, 0x91, 0x34, 0x61, 0x30, 0x74, 0x8a, 0x6e, 0x3c, 0x12, 0x4f, 0x91, 0x49, 0xd7,
+ 0x1c, 0x74, 0x35, 0x02, 0x81, 0x81, 0x00, 0xc9, 0x53, 0x87, 0xc0, 0xf9, 0xd3, 0x5f, 0x13, 0x7b,
+ 0x57, 0xd0, 0xd6, 0x5c, 0x39, 0x7c, 0x5e, 0x21, 0xcc, 0x25, 0x1e, 0x47, 0x00, 0x8e, 0xd6, 0x2a,
+ 0x54, 0x24, 0x09, 0xc8, 0xb6, 0xb6, 0xac, 0x7f, 0x89, 0x67, 0xb3, 0x86, 0x3c, 0xa6, 0x45, 0xfc,
+ 0xce, 0x49, 0x58, 0x2a, 0x9a, 0xa1, 0x73, 0x49, 0xdb, 0x6c, 0x4a, 0x95, 0xaf, 0xfd, 0xae, 0x0d,
+ 0xae, 0x61, 0x2e, 0x1a, 0xfa, 0xc9, 0x9e, 0xd3, 0x9a, 0x2d, 0x93, 0x4c, 0x88, 0x04, 0x40, 0xae,
+ 0xd8, 0x83, 0x2f, 0x98, 0x43, 0x16, 0x3a, 0x47, 0xf2, 0x7f, 0x39, 0x21, 0x99, 0xdc, 0x12, 0x02,
+ 0xf9, 0xa0, 0xf9, 0xbd, 0x08, 0x30, 0x80, 0x07, 0xcb, 0x1e, 0x4e, 0x7f, 0x58, 0x30, 0x93, 0x66,
+ 0xa7, 0xde, 0x25, 0xf7, 0xc3, 0xc9, 0xb8, 0x80, 0x67, 0x7c, 0x06, 0x8e, 0x1b, 0xe9, 0x36, 0xe8,
+ 0x12, 0x88, 0x81, 0x52, 0x52, 0xa8, 0xa1, 0x02, 0x81, 0x80, 0x57, 0xff, 0x8c, 0xa1, 0x89, 0x50,
+ 0x80, 0xb2, 0xca, 0xe4, 0x86, 0xef, 0x0a, 0xdf, 0xd7, 0x91, 0xfb, 0x02, 0x35, 0xc0, 0xb8, 0xb3,
+ 0x6c, 0xd6, 0xc1, 0x36, 0xe5, 0x2e, 0x40, 0x85, 0xf4, 0xea, 0x5a, 0x06, 0x32, 0x12, 0xa4, 0xf1,
+ 0x05, 0xa3, 0x76, 0x47, 0x43, 0xe5, 0x32, 0x81, 0x98, 0x8a, 0xba, 0x07, 0x3f, 0x6e, 0x00, 0x27,
+ 0x29, 0x8e, 0x1c, 0x43, 0x78, 0x55, 0x6e, 0x0e, 0xfc, 0xa0, 0xe1, 0x4e, 0xce, 0x1a, 0xf7, 0x6a,
+ 0xd0, 0xb0, 0x30, 0xf2, 0x7a, 0xf6, 0xf0, 0xab, 0x35, 0xfb, 0x73, 0xa0, 0x60, 0xd8, 0xb1, 0xa0,
+ 0xe1, 0x42, 0xfa, 0x26, 0x47, 0xe9, 0x3b, 0x32, 0xe3, 0x6d, 0x82, 0x82, 0xae, 0x0a, 0x4d, 0xe5,
+ 0x0a, 0xb7, 0xaf, 0xe8, 0x55, 0x00, 0xa1, 0x6f, 0x43, 0xa6, 0x47, 0x19, 0xd6, 0xe2, 0xb9, 0x43,
+ 0x98, 0x23, 0x71, 0x9c, 0xd0, 0x8b, 0xcd, 0x03, 0x17, 0x81, 0x02, 0x81, 0x81, 0x00, 0xba, 0x73,
+ 0xb0, 0xbb, 0x28, 0xe3, 0xf8, 0x1e, 0x9b, 0xd1, 0xc5, 0x68, 0x71, 0x3b, 0x10, 0x12, 0x41, 0xac,
+ 0xc6, 0x07, 0x97, 0x6c, 0x4d, 0xdc, 0xcc, 0x90, 0xe6, 0x5b, 0x65, 0x56, 0xca, 0x31, 0x51, 0x60,
+ 0x58, 0xf9, 0x2b, 0x6e, 0x09, 0xf3, 0xb1, 0x60, 0xff, 0x0e, 0x37, 0x4e, 0xc4, 0x0d, 0x78, 0xae,
+ 0x4d, 0x49, 0x79, 0xfd, 0xe6, 0xac, 0x06, 0xa1, 0xa4, 0x00, 0xc6, 0x1d, 0xd3, 0x12, 0x54, 0x18,
+ 0x6a, 0xf3, 0x0b, 0x22, 0xc1, 0x05, 0x82, 0xa8, 0xa4, 0x3e, 0x34, 0xfe, 0x94, 0x9c, 0x5f, 0x3b,
+ 0x97, 0x55, 0xba, 0xe7, 0xba, 0xa7, 0xb7, 0xb7, 0xa6, 0xbd, 0x03, 0xb3, 0x8c, 0xef, 0x55, 0xc8,
+ 0x68, 0x85, 0xfc, 0x6c, 0x19, 0x78, 0xb9, 0xce, 0xe7, 0xef, 0x33, 0xda, 0x50, 0x7c, 0x9d, 0xf6,
+ 0xb9, 0x27, 0x7c, 0xff, 0x1e, 0x6a, 0xaa, 0x5d, 0x57, 0xac, 0xa5, 0x28, 0x46, 0x61, 0x02, 0x81,
+ 0x81, 0x00, 0xc9, 0x31, 0x61, 0x7c, 0x77, 0x82, 0x9d, 0xfb, 0x12, 0x70, 0x50, 0x2b, 0xe9, 0x19,
+ 0x5c, 0x8f, 0x28, 0x30, 0x88, 0x5f, 0x57, 0xdb, 0xa8, 0x69, 0x53, 0x68, 0x11, 0xe6, 0x86, 0x42,
+ 0x36, 0xd0, 0xc4, 0x73, 0x6a, 0x00, 0x08, 0xa1, 0x45, 0xaf, 0x36, 0xb8, 0x35, 0x7a, 0x7c, 0x3d,
+ 0x13, 0x99, 0x66, 0xd0, 0x4c, 0x4e, 0x00, 0x93, 0x4e, 0xa1, 0xae, 0xde, 0x3b, 0xb6, 0xb8, 0xec,
+ 0x84, 0x1d, 0xc9, 0x5e, 0x3f, 0x57, 0x97, 0x51, 0xe2, 0xbf, 0xdf, 0xe2, 0x7a, 0xe7, 0x78, 0x98,
+ 0x3f, 0x95, 0x93, 0x56, 0x21, 0x07, 0x23, 0x28, 0x7b, 0x0a, 0xff, 0xcc, 0x9f, 0x72, 0x70, 0x44,
+ 0xd4, 0x8c, 0x37, 0x3f, 0x1b, 0xab, 0xde, 0x07, 0x24, 0xfa, 0x17, 0xa4, 0xfd, 0x4d, 0xa0, 0x90,
+ 0x2c, 0x7c, 0x9b, 0x9b, 0xf2, 0x7b, 0xa6, 0x1b, 0xe6, 0xad, 0x02, 0xdf, 0xdd, 0xda, 0x8f, 0x4e,
+ 0x68, 0x22,
+];
+
+/// WrappedKeyData as ASN.1 DER-encoded data corresponding to the `SecureKeyWrapper` schema
+/// specified in IKeyMintDevice.aidl. Wrapped key parameters are -
+/// Algorithm: AES
+/// Key size: 256
+/// Block mode: ECB
+/// Padding mode: PKCS7
+/// This sample wrapped_key is taken from KeyMint tests (see KeyMintTest.cpp).
+pub static WRAPPED_KEY: &[u8] = &[
+ 0x30, 0x82, 0x01, 0x79, 0x02, 0x01, 0x00, 0x04, 0x82, 0x01, 0x00, 0x93, 0x4b, 0xf9, 0x4e, 0x2a,
+ 0xa2, 0x8a, 0x3f, 0x83, 0xc9, 0xf7, 0x92, 0x97, 0x25, 0x02, 0x62, 0xfb, 0xe3, 0x27, 0x6b, 0x5a,
+ 0x1c, 0x91, 0x15, 0x9b, 0xbf, 0xa3, 0xef, 0x89, 0x57, 0xaa, 0xc8, 0x4b, 0x59, 0xb3, 0x0b, 0x45,
+ 0x5a, 0x79, 0xc2, 0x97, 0x34, 0x80, 0x82, 0x3d, 0x8b, 0x38, 0x63, 0xc3, 0xde, 0xef, 0x4a, 0x8e,
+ 0x24, 0x35, 0x90, 0x26, 0x8d, 0x80, 0xe1, 0x87, 0x51, 0xa0, 0xe1, 0x30, 0xf6, 0x7c, 0xe6, 0xa1,
+ 0xac, 0xe9, 0xf7, 0x9b, 0x95, 0xe0, 0x97, 0x47, 0x4f, 0xeb, 0xc9, 0x81, 0x19, 0x5b, 0x1d, 0x13,
+ 0xa6, 0x90, 0x86, 0xc0, 0x86, 0x3f, 0x66, 0xa7, 0xb7, 0xfd, 0xb4, 0x87, 0x92, 0x22, 0x7b, 0x1a,
+ 0xc5, 0xe2, 0x48, 0x9f, 0xeb, 0xdf, 0x08, 0x7a, 0xb5, 0x48, 0x64, 0x83, 0x03, 0x3a, 0x6f, 0x00,
+ 0x1c, 0xa5, 0xd1, 0xec, 0x1e, 0x27, 0xf5, 0xc3, 0x0f, 0x4c, 0xec, 0x26, 0x42, 0x07, 0x4a, 0x39,
+ 0xae, 0x68, 0xae, 0xe5, 0x52, 0xe1, 0x96, 0x62, 0x7a, 0x8e, 0x3d, 0x86, 0x7e, 0x67, 0xa8, 0xc0,
+ 0x1b, 0x11, 0xe7, 0x5f, 0x13, 0xcc, 0xa0, 0xa9, 0x7a, 0xb6, 0x68, 0xb5, 0x0c, 0xda, 0x07, 0xa8,
+ 0xec, 0xb7, 0xcd, 0x8e, 0x3d, 0xd7, 0x00, 0x9c, 0x96, 0x36, 0x53, 0x4f, 0x6f, 0x23, 0x9c, 0xff,
+ 0xe1, 0xfc, 0x8d, 0xaa, 0x46, 0x6f, 0x78, 0xb6, 0x76, 0xc7, 0x11, 0x9e, 0xfb, 0x96, 0xbc, 0xe4,
+ 0xe6, 0x9c, 0xa2, 0xa2, 0x5d, 0x0b, 0x34, 0xed, 0x9c, 0x3f, 0xf9, 0x99, 0xb8, 0x01, 0x59, 0x7d,
+ 0x52, 0x20, 0xe3, 0x07, 0xea, 0xa5, 0xbe, 0xe5, 0x07, 0xfb, 0x94, 0xd1, 0xfa, 0x69, 0xf9, 0xe5,
+ 0x19, 0xb2, 0xde, 0x31, 0x5b, 0xac, 0x92, 0xc3, 0x6f, 0x2e, 0xa1, 0xfa, 0x1d, 0xf4, 0x47, 0x8c,
+ 0x0d, 0xde, 0xde, 0xae, 0x8c, 0x70, 0xe0, 0x23, 0x3c, 0xd0, 0x98, 0x04, 0x0c, 0xd7, 0x96, 0xb0,
+ 0x2c, 0x37, 0x0f, 0x1f, 0xa4, 0xcc, 0x01, 0x24, 0xf1, 0x30, 0x2e, 0x02, 0x01, 0x03, 0x30, 0x29,
+ 0xa1, 0x08, 0x31, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0xa2, 0x03, 0x02, 0x01, 0x20, 0xa3,
+ 0x04, 0x02, 0x02, 0x01, 0x00, 0xa4, 0x05, 0x31, 0x03, 0x02, 0x01, 0x01, 0xa6, 0x05, 0x31, 0x03,
+ 0x02, 0x01, 0x40, 0xbf, 0x83, 0x77, 0x02, 0x05, 0x00, 0x04, 0x20, 0xcc, 0xd5, 0x40, 0x85, 0x5f,
+ 0x83, 0x3a, 0x5e, 0x14, 0x80, 0xbf, 0xd2, 0xd3, 0x6f, 0xaf, 0x3a, 0xee, 0xe1, 0x5d, 0xf5, 0xbe,
+ 0xab, 0xe2, 0x69, 0x1b, 0xc8, 0x2d, 0xde, 0x2a, 0x7a, 0xa9, 0x10, 0x04, 0x10, 0x64, 0xc9, 0xf6,
+ 0x89, 0xc6, 0x0f, 0xf6, 0x22, 0x3a, 0xb6, 0xe6, 0x99, 0x9e, 0x0e, 0xb6, 0xe5,
+];
+
/// To map Keystore errors.
#[derive(thiserror::Error, Debug, Eq, PartialEq)]
pub enum Error {
@@ -172,6 +296,9 @@
/// This is returned if the C implementation of extractSubjectFromCertificate failed.
#[error("Failed to validate certificate chain.")]
ValidateCertChainFailed,
+ /// Error code to indicate error in ASN.1 DER-encoded data creation.
+ #[error("Failed to create and encode ASN.1 data.")]
+ DerEncodeFailed,
}
/// Keystore2 error mapping.
@@ -209,7 +336,6 @@
nspace: i64,
alias: Option<String>,
att_challenge: Option<&[u8]>,
- att_app_id: Option<&[u8]>,
) -> binder::Result<KeyMetadata> {
let mut key_attest = false;
let mut gen_params = AuthSetBuilder::new()
@@ -225,11 +351,6 @@
gen_params = gen_params.clone().attestation_challenge(challenge.to_vec());
}
- if let Some(app_id) = att_app_id {
- key_attest = true;
- gen_params = gen_params.clone().attestation_app_id(app_id.to_vec());
- }
-
match sec_level.generateKey(
&KeyDescriptor { domain, nspace, alias, blob: None },
None,
@@ -324,9 +445,6 @@
if let Some(value) = &key_params.att_challenge {
gen_params = gen_params.attestation_challenge(value.to_vec())
}
- if let Some(value) = &key_params.att_app_id {
- gen_params = gen_params.attestation_app_id(value.to_vec())
- }
let key_metadata = sec_level.generateKey(
&KeyDescriptor { domain, nspace, alias, blob: None },
@@ -339,8 +457,7 @@
// Must have a public key.
assert!(key_metadata.certificate.is_some());
- if attest_key.is_none() && key_params.att_challenge.is_some() && key_params.att_app_id.is_some()
- {
+ if attest_key.is_none() && key_params.att_challenge.is_some() {
// Should have an attestation record.
assert!(key_metadata.certificateChain.is_some());
} else {
@@ -449,7 +566,6 @@
sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
algorithm: Algorithm,
att_challenge: &[u8],
- att_app_id: &[u8],
) -> binder::Result<KeyMetadata> {
assert!(algorithm == Algorithm::RSA || algorithm == Algorithm::EC);
@@ -468,7 +584,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: Some(att_challenge.to_vec()),
- att_app_id: Some(att_app_id.to_vec()),
},
None,
)
@@ -478,7 +593,6 @@
let metadata = generate_ec_attestation_key(
sec_level,
att_challenge,
- att_app_id,
Digest::SHA_2_256,
EcCurve::P_256,
)
@@ -493,7 +607,6 @@
pub fn generate_ec_attestation_key(
sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
att_challenge: &[u8],
- att_app_id: &[u8],
digest: Digest,
ec_curve: EcCurve,
) -> binder::Result<KeyMetadata> {
@@ -504,8 +617,7 @@
.purpose(KeyPurpose::ATTEST_KEY)
.ec_curve(ec_curve)
.digest(digest)
- .attestation_challenge(att_challenge.to_vec())
- .attestation_app_id(att_app_id.to_vec());
+ .attestation_challenge(att_challenge.to_vec());
let attestation_key_metadata = sec_level.generateKey(
&KeyDescriptor {
@@ -533,7 +645,6 @@
sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
alias: Option<String>,
att_challenge: &[u8],
- att_app_id: &[u8],
attest_key: &KeyDescriptor,
) -> binder::Result<KeyMetadata> {
let ec_gen_params = AuthSetBuilder::new()
@@ -543,8 +654,7 @@
.purpose(KeyPurpose::VERIFY)
.digest(Digest::SHA_2_256)
.ec_curve(EcCurve::P_256)
- .attestation_challenge(att_challenge.to_vec())
- .attestation_app_id(att_app_id.to_vec());
+ .attestation_challenge(att_challenge.to_vec());
let ec_key_metadata = sec_level
.generateKey(
@@ -564,7 +674,8 @@
Ok(ec_key_metadata)
}
-fn check_key_param(authorizations: &[Authorization], key_param: KeyParameter) -> bool {
+/// Verify that given key param is listed in given authorizations list.
+pub fn check_key_param(authorizations: &[Authorization], key_param: KeyParameter) -> bool {
for authrization in authorizations {
if authrization.keyParameter == key_param {
return true;
@@ -836,3 +947,103 @@
Ok(key_metadata)
}
+
+/// Imports RSA encryption key with WRAP_KEY purpose.
+pub fn import_wrapping_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ wrapping_key_data: &[u8],
+ wrapping_key_alias: Option<String>,
+) -> binder::Result<KeyMetadata> {
+ let wrapping_key_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .digest(Digest::SHA_2_256)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT)
+ .purpose(KeyPurpose::WRAP_KEY)
+ .padding_mode(PaddingMode::RSA_OAEP)
+ .key_size(2048)
+ .rsa_public_exponent(65537)
+ .cert_not_before(0)
+ .cert_not_after(253402300799000);
+
+ sec_level.importKey(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: wrapping_key_alias, blob: None },
+ None,
+ &wrapping_key_params,
+ 0,
+ wrapping_key_data,
+ )
+}
+
+/// Import wrapped key using given wrapping key.
+pub fn import_wrapped_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ alias: Option<String>,
+ wrapping_key_metadata: &KeyMetadata,
+ wrapped_key: Option<Vec<u8>>,
+) -> binder::Result<KeyMetadata> {
+ let unwrap_params =
+ AuthSetBuilder::new().digest(Digest::SHA_2_256).padding_mode(PaddingMode::RSA_OAEP);
+
+ let authenticator_spec: &[AuthenticatorSpec] = &[AuthenticatorSpec {
+ authenticatorType: HardwareAuthenticatorType::NONE,
+ authenticatorId: 0,
+ }];
+
+ let key_metadata = sec_level.importWrappedKey(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias, blob: wrapped_key },
+ &wrapping_key_metadata.key,
+ None,
+ &unwrap_params,
+ authenticator_spec,
+ )?;
+
+ Ok(key_metadata)
+}
+
+/// Import wrapping key and then import wrapped key using wrapping key.
+pub fn import_wrapping_key_and_wrapped_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+ wrapping_key_alias: Option<String>,
+ wrapping_key_params: AuthSetBuilder,
+) -> binder::Result<KeyMetadata> {
+ let wrapping_key_metadata = sec_level.importKey(
+ &KeyDescriptor { domain, nspace, alias: wrapping_key_alias, blob: None },
+ None,
+ &wrapping_key_params,
+ 0,
+ WRAPPING_KEY,
+ )?;
+
+ import_wrapped_key(sec_level, alias, &wrapping_key_metadata, Some(WRAPPED_KEY.to_vec()))
+}
+
+/// Import given key material as AES-256-GCM-NONE transport key.
+pub fn import_transport_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ transport_key_alias: Option<String>,
+ transport_key: &[u8],
+) -> binder::Result<KeyMetadata> {
+ let transport_key_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::AES)
+ .block_mode(BlockMode::GCM)
+ .padding_mode(PaddingMode::NONE)
+ .key_size(256)
+ .caller_nonce()
+ .min_mac_length(128)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT);
+
+ sec_level.importKey(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: transport_key_alias, blob: None },
+ None,
+ &transport_key_params,
+ 0,
+ transport_key,
+ )
+}
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index dd5d782..78dd2d7 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -36,7 +36,7 @@
rustlibs: [
"librustutils",
"libkeystore2_test_utils",
- "packagemanager_aidl-rust",
+ "packagemanager_aidl-rust",
"libnix",
"libanyhow",
"libbinder_rs",
@@ -44,8 +44,8 @@
"liblibc",
"libserde",
"libthiserror",
- "libcxx",
- "libopenssl",
+ "libcxx",
+ "libopenssl",
],
static_libs: [
"libkeystore2_ffi_test_utils",
@@ -54,6 +54,9 @@
],
shared_libs: [
"libcrypto",
+ "libkeymaster_portable",
+ "libkeymaster_messages",
+ "libcppbor_external",
],
require_root: true,
}
@@ -67,17 +70,31 @@
],
generated_headers: [
"cxx-bridge-header",
+ "libkeystore2_ffi_test_utils_bridge_header",
],
generated_sources: ["libkeystore2_ffi_test_utils_bridge_code"],
static_libs: [
"libkeymint_vts_test_utils",
],
+ shared_libs: [
+ "libkeymaster_portable",
+ "libkeymaster_messages",
+ "libcppbor_external",
+ ],
}
genrule {
name: "libkeystore2_ffi_test_utils_bridge_code",
tools: ["cxxbridge"],
cmd: "$(location cxxbridge) $(in) >> $(out)",
- srcs: ["keystore2_client_attest_key_tests.rs"],
+ srcs: ["ffi_test_utils.rs"],
out: ["libkeystore2_test_utils_cxx_generated.cc"],
}
+
+genrule {
+ name: "libkeystore2_ffi_test_utils_bridge_header",
+ tools: ["cxxbridge"],
+ cmd: "$(location cxxbridge) $(in) --header >> $(out)",
+ srcs: ["ffi_test_utils.rs"],
+ out: ["ffi_test_utils.rs.h"],
+}
diff --git a/keystore2/tests/ffi_test_utils.cpp b/keystore2/tests/ffi_test_utils.cpp
index fb5a7d2..de20d83 100644
--- a/keystore2/tests/ffi_test_utils.cpp
+++ b/keystore2/tests/ffi_test_utils.cpp
@@ -4,15 +4,86 @@
#include <KeyMintAidlTestBase.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <keymaster/UniquePtr.h>
+#include <memory>
#include <vector>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+
+#include <keymaster/km_openssl/attestation_record.h>
+#include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <openssl/asn1t.h>
+
using aidl::android::hardware::security::keymint::ErrorCode;
#define TAG_SEQUENCE 0x30
#define LENGTH_MASK 0x80
#define LENGTH_VALUE_MASK 0x7F
+/**
+ * ASN.1 structure for `KeyDescription` Schema.
+ * See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
+ * KeyDescription ::= SEQUENCE(
+ * keyFormat INTEGER, # Values from KeyFormat enum.
+ * keyParams AuthorizationList,
+ * )
+ */
+typedef struct key_description {
+ ASN1_INTEGER* key_format;
+ keymaster::KM_AUTH_LIST* key_params;
+} TEST_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(TEST_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(TEST_KEY_DESCRIPTION, key_format, ASN1_INTEGER),
+ ASN1_SIMPLE(TEST_KEY_DESCRIPTION, key_params, keymaster::KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(TEST_KEY_DESCRIPTION);
+DECLARE_ASN1_FUNCTIONS(TEST_KEY_DESCRIPTION);
+
+/**
+ * ASN.1 structure for `SecureKeyWrapper` Schema.
+ * See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper` schema.
+ * SecureKeyWrapper ::= SEQUENCE(
+ * version INTEGER, # Contains value 0
+ * encryptedTransportKey OCTET_STRING,
+ * initializationVector OCTET_STRING,
+ * keyDescription KeyDescription,
+ * encryptedKey OCTET_STRING,
+ * tag OCTET_STRING
+ * )
+ */
+typedef struct secure_key_wrapper {
+ ASN1_INTEGER* version;
+ ASN1_OCTET_STRING* encrypted_transport_key;
+ ASN1_OCTET_STRING* initialization_vector;
+ TEST_KEY_DESCRIPTION* key_desc;
+ ASN1_OCTET_STRING* encrypted_key;
+ ASN1_OCTET_STRING* tag;
+} TEST_SECURE_KEY_WRAPPER;
+
+ASN1_SEQUENCE(TEST_SECURE_KEY_WRAPPER) = {
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, version, ASN1_INTEGER),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, encrypted_transport_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, initialization_vector, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, key_desc, TEST_KEY_DESCRIPTION),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, encrypted_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(TEST_SECURE_KEY_WRAPPER, tag, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(TEST_SECURE_KEY_WRAPPER);
+DECLARE_ASN1_FUNCTIONS(TEST_SECURE_KEY_WRAPPER);
+
+IMPLEMENT_ASN1_FUNCTIONS(TEST_SECURE_KEY_WRAPPER);
+IMPLEMENT_ASN1_FUNCTIONS(TEST_KEY_DESCRIPTION);
+
+struct TEST_KEY_DESCRIPTION_Delete {
+ void operator()(TEST_KEY_DESCRIPTION* p) { TEST_KEY_DESCRIPTION_free(p); }
+};
+struct TEST_SECURE_KEY_WRAPPER_Delete {
+ void operator()(TEST_SECURE_KEY_WRAPPER* p) { TEST_SECURE_KEY_WRAPPER_free(p); }
+};
+
/* This function extracts a certificate from the certs_chain_buffer at the given
* offset. Each DER encoded certificate starts with TAG_SEQUENCE followed by the
* total length of the certificate. The length of the certificate is determined
@@ -118,3 +189,178 @@
return false;
}
+
+/**
+ * Below mentioned key parameters are used to create authorization list of
+ * secure key.
+ * Algorithm: AES-256
+ * Padding: PKCS7
+ * Blockmode: ECB
+ * Purpose: Encrypt, Decrypt
+ */
+keymaster::AuthorizationSet build_wrapped_key_auth_list() {
+ return keymaster::AuthorizationSet(keymaster::AuthorizationSetBuilder()
+ .AesEncryptionKey(256)
+ .Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Authorization(keymaster::TAG_PADDING, KM_PAD_PKCS7)
+ .Authorization(keymaster::TAG_NO_AUTH_REQUIRED));
+}
+
+/**
+ * Creates ASN.1 DER-encoded data corresponding to `KeyDescription` schema as
+ * AAD. See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
+ */
+CxxResult buildAsn1DerEncodedWrappedKeyDescription() {
+ CxxResult cxx_result{};
+ keymaster_error_t error;
+ cxx_result.error = KM_ERROR_OK;
+
+ keymaster::UniquePtr<TEST_KEY_DESCRIPTION, TEST_KEY_DESCRIPTION_Delete> key_description(
+ TEST_KEY_DESCRIPTION_new());
+ if (!key_description.get()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ // Fill secure key authorizations.
+ keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
+ error = build_auth_list(auth_list, key_description->key_params);
+ if (error != KM_ERROR_OK) {
+ cxx_result.error = error;
+ return cxx_result;
+ }
+
+ // Fill secure key format.
+ if (!ASN1_INTEGER_set(key_description->key_format, KM_KEY_FORMAT_RAW)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Perform ASN.1 DER encoding of KeyDescription.
+ int asn1_data_len = i2d_TEST_KEY_DESCRIPTION(key_description.get(), nullptr);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+ std::vector<uint8_t> asn1_data(asn1_data_len, 0);
+
+ if (!asn1_data.data()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ uint8_t* p = asn1_data.data();
+ asn1_data_len = i2d_TEST_KEY_DESCRIPTION(key_description.get(), &p);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ std::move(asn1_data.begin(), asn1_data.end(), std::back_inserter(cxx_result.data));
+
+ return cxx_result;
+}
+
+/**
+ * Creates wrapped key material to import in ASN.1 DER-encoded data corresponding to
+ * `SecureKeyWrapper` schema. See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper`
+ * schema.
+ */
+CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
+ rust::Vec<rust::u8> encrypted_transport_key, rust::Vec<rust::u8> iv,
+ rust::Vec<rust::u8> tag) {
+ CxxResult cxx_result{};
+ keymaster_error_t error;
+ cxx_result.error = KM_ERROR_OK;
+
+ uint8_t* enc_secure_key_data = encrypted_secure_key.data();
+ int enc_secure_key_size = encrypted_secure_key.size();
+
+ uint8_t* iv_data = iv.data();
+ int iv_size = iv.size();
+
+ uint8_t* tag_data = tag.data();
+ int tag_size = tag.size();
+
+ uint8_t* enc_transport_key_data = encrypted_transport_key.data();
+ int enc_transport_key_size = encrypted_transport_key.size();
+
+ keymaster::UniquePtr<TEST_SECURE_KEY_WRAPPER, TEST_SECURE_KEY_WRAPPER_Delete> sec_key_wrapper(
+ TEST_SECURE_KEY_WRAPPER_new());
+ if (!sec_key_wrapper.get()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ // Fill version = 0
+ if (!ASN1_INTEGER_set(sec_key_wrapper->version, 0)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill encrypted transport key.
+ if (enc_transport_key_size &&
+ !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_transport_key, enc_transport_key_data,
+ enc_transport_key_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill encrypted secure key.
+ if (enc_secure_key_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->encrypted_key,
+ enc_secure_key_data, enc_secure_key_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill secure key authorization list.
+ keymaster::AuthorizationSet auth_list = build_wrapped_key_auth_list();
+ error = build_auth_list(auth_list, sec_key_wrapper->key_desc->key_params);
+ if (error != KM_ERROR_OK) {
+ cxx_result.error = error;
+ return cxx_result;
+ }
+
+ // Fill secure key format.
+ if (!ASN1_INTEGER_set(sec_key_wrapper->key_desc->key_format, KM_KEY_FORMAT_RAW)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill initialization vector used for encrypting secure key.
+ if (iv_size &&
+ !ASN1_OCTET_STRING_set(sec_key_wrapper->initialization_vector, iv_data, iv_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // Fill GCM-tag, extracted during secure key encryption.
+ if (tag_size && !ASN1_OCTET_STRING_set(sec_key_wrapper->tag, tag_data, tag_size)) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ // ASN.1 DER-encoding of secure key wrapper.
+ int asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), nullptr);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+ std::vector<uint8_t> asn1_data(asn1_data_len, 0);
+
+ if (!asn1_data.data()) {
+ cxx_result.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return cxx_result;
+ }
+
+ uint8_t* p = asn1_data.data();
+ asn1_data_len = i2d_TEST_SECURE_KEY_WRAPPER(sec_key_wrapper.get(), &p);
+ if (asn1_data_len < 0) {
+ cxx_result.error = keymaster::TranslateLastOpenSslError();
+ return cxx_result;
+ }
+
+ std::move(asn1_data.begin(), asn1_data.end(), std::back_inserter(cxx_result.data));
+
+ return cxx_result;
+}
diff --git a/keystore2/tests/ffi_test_utils.hpp b/keystore2/tests/ffi_test_utils.hpp
index 7f5c3b2..b8c7c48 100644
--- a/keystore2/tests/ffi_test_utils.hpp
+++ b/keystore2/tests/ffi_test_utils.hpp
@@ -1,5 +1,11 @@
#pragma once
#include "rust/cxx.h"
+#include "ffi_test_utils.rs.h"
bool validateCertChain(rust::Vec<rust::u8> cert_buf, uint32_t cert_len, bool strict_issuer_check);
+CxxResult createWrappedKey(rust::Vec<rust::u8> encrypted_secure_key,
+ rust::Vec<rust::u8> encrypted_transport_key,
+ rust::Vec<rust::u8> iv,
+ rust::Vec<rust::u8> tag);
+CxxResult buildAsn1DerEncodedWrappedKeyDescription();
diff --git a/keystore2/tests/ffi_test_utils.rs b/keystore2/tests/ffi_test_utils.rs
new file mode 100644
index 0000000..066d4a1
--- /dev/null
+++ b/keystore2/tests/ffi_test_utils.rs
@@ -0,0 +1,80 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use keystore2_test_utils::key_generations::Error;
+
+#[cxx::bridge]
+mod ffi {
+ struct CxxResult {
+ data: Vec<u8>,
+ error: i32,
+ }
+
+ unsafe extern "C++" {
+ include!("ffi_test_utils.hpp");
+ fn validateCertChain(cert_buf: Vec<u8>, cert_len: u32, strict_issuer_check: bool) -> bool;
+ fn createWrappedKey(
+ encrypted_secure_key: Vec<u8>,
+ encrypted_transport_key: Vec<u8>,
+ iv: Vec<u8>,
+ tag: Vec<u8>,
+ ) -> CxxResult;
+ fn buildAsn1DerEncodedWrappedKeyDescription() -> CxxResult;
+ }
+}
+
+/// Validate given certificate chain.
+pub fn validate_certchain(cert_buf: &[u8]) -> Result<bool, Error> {
+ if ffi::validateCertChain(cert_buf.to_vec(), cert_buf.len().try_into().unwrap(), true) {
+ return Ok(true);
+ }
+
+ Err(Error::ValidateCertChainFailed)
+}
+
+fn get_result(result: ffi::CxxResult) -> Result<Vec<u8>, Error> {
+ if result.error == 0 && !result.data.is_empty() {
+ Ok(result.data)
+ } else {
+ Err(Error::DerEncodeFailed)
+ }
+}
+
+/// Creates wrapped key material to import in ASN.1 DER-encoded data corresponding to
+/// `SecureKeyWrapper`. See `IKeyMintDevice.aidl` for documentation of the `SecureKeyWrapper`
+/// schema.
+pub fn create_wrapped_key(
+ encrypted_secure_key: &[u8],
+ encrypted_transport_key: &[u8],
+ iv: &[u8],
+ tag: &[u8],
+) -> Result<Vec<u8>, Error> {
+ get_result(ffi::createWrappedKey(
+ encrypted_secure_key.to_vec(),
+ encrypted_transport_key.to_vec(),
+ iv.to_vec(),
+ tag.to_vec(),
+ ))
+}
+
+/// Creates ASN.1 DER-encoded data corresponding to `KeyDescription` schema.
+/// See `IKeyMintDevice.aidl` for documentation of the `KeyDescription` schema.
+/// Below mentioned key parameters are used -
+/// Algorithm: AES-256
+/// Padding: PKCS7
+/// Blockmode: ECB
+/// Purpose: Encrypt, Decrypt
+pub fn create_wrapped_key_additional_auth_data() -> Result<Vec<u8>, Error> {
+ get_result(ffi::buildAsn1DerEncodedWrappedKeyDescription())
+}
diff --git a/keystore2/tests/keystore2_client_aes_key_tests.rs b/keystore2/tests/keystore2_client_aes_key_tests.rs
index 885cbf5..313f596 100644
--- a/keystore2/tests/keystore2_client_aes_key_tests.rs
+++ b/keystore2/tests/keystore2_client_aes_key_tests.rs
@@ -26,8 +26,7 @@
};
use crate::keystore2_client_test_utils::{
- has_trusty_keymint, perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op,
- SAMPLE_PLAIN_TEXT,
+ perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
};
/// Generate a AES key. Create encrypt and decrypt operations using the generated key.
@@ -393,11 +392,11 @@
));
assert!(result.is_err());
- if has_trusty_keymint() {
- assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::MISSING_MAC_LENGTH));
- } else {
- assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH));
- }
+ let e = result.unwrap_err();
+ assert!(
+ e == Error::Km(ErrorCode::MISSING_MAC_LENGTH)
+ || e == Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH)
+ );
}
/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index fc3148c..4febd9b 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -27,28 +27,13 @@
authorizations, get_keystore_service, key_generations, key_generations::Error,
};
+use crate::ffi_test_utils::validate_certchain;
+
use crate::{
keystore2_client_test_utils::app_attest_key_feature_exists,
skip_test_if_no_app_attest_key_feature,
};
-#[cxx::bridge]
-mod ffi {
- unsafe extern "C++" {
- include!("ffi_test_utils.hpp");
- fn validateCertChain(cert_buf: Vec<u8>, cert_len: u32, strict_issuer_check: bool) -> bool;
- }
-}
-
-/// Validate given certificate chain.
-pub fn validate_certchain(cert_buf: &[u8]) -> Result<bool, Error> {
- if ffi::validateCertChain(cert_buf.to_vec(), cert_buf.len().try_into().unwrap(), true) {
- return Ok(true);
- }
-
- Err(Error::ValidateCertChainFailed)
-}
-
/// Generate RSA and EC attestation keys and use them for signing RSA-signing keys.
/// Test should be able to generate attestation keys and use them successfully.
#[test]
@@ -58,13 +43,11 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
for algo in [Algorithm::RSA, Algorithm::EC] {
// Create attestation key.
let attestation_key_metadata =
- key_generations::generate_attestation_key(&sec_level, algo, att_challenge, att_app_id)
- .unwrap();
+ key_generations::generate_attestation_key(&sec_level, algo, att_challenge).unwrap();
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
@@ -86,7 +69,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: Some(att_challenge.to_vec()),
- att_app_id: Some(att_app_id.to_vec()),
},
Some(&attestation_key_metadata.key),
)
@@ -109,13 +91,11 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
for algo in [Algorithm::RSA, Algorithm::EC] {
// Create attestation key.
let attestation_key_metadata =
- key_generations::generate_attestation_key(&sec_level, algo, att_challenge, att_app_id)
- .unwrap();
+ key_generations::generate_attestation_key(&sec_level, algo, att_challenge).unwrap();
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
@@ -137,7 +117,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: Some(att_challenge.to_vec()),
- att_app_id: Some(att_app_id.to_vec()),
},
Some(&attestation_key_metadata.key),
)
@@ -161,13 +140,11 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
for algo in [Algorithm::RSA, Algorithm::EC] {
// Create attestation key.
let attestation_key_metadata =
- key_generations::generate_attestation_key(&sec_level, algo, att_challenge, att_app_id)
- .unwrap();
+ key_generations::generate_attestation_key(&sec_level, algo, att_challenge).unwrap();
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
@@ -180,7 +157,6 @@
&sec_level,
Some(ec_key_alias),
att_challenge,
- att_app_id,
&attestation_key_metadata.key,
)
.unwrap();
@@ -204,13 +180,11 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
// Create EcCurve::CURVE_25519 attestation key.
let attestation_key_metadata = key_generations::generate_ec_attestation_key(
&sec_level,
att_challenge,
- att_app_id,
Digest::NONE,
EcCurve::CURVE_25519,
)
@@ -236,7 +210,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: Some(att_challenge.to_vec()),
- att_app_id: Some(att_app_id.to_vec()),
},
Some(&attestation_key_metadata.key),
)
@@ -338,16 +311,11 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
// Create RSA attestation key.
- let attestation_key_metadata = key_generations::generate_attestation_key(
- &sec_level,
- Algorithm::RSA,
- att_challenge,
- att_app_id,
- )
- .unwrap();
+ let attestation_key_metadata =
+ key_generations::generate_attestation_key(&sec_level, Algorithm::RSA, att_challenge)
+ .unwrap();
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
@@ -369,7 +337,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: Some(att_app_id.to_vec()),
},
Some(&attestation_key_metadata.key),
));
@@ -387,7 +354,6 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
let alias = format!("non_attest_key_{}", getuid());
let non_attest_key_metadata = key_generations::generate_ec_p256_signing_key(
@@ -396,7 +362,6 @@
-1,
Some(alias),
None,
- None,
)
.unwrap();
@@ -415,7 +380,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: Some(att_challenge.to_vec()),
- att_app_id: Some(att_app_id.to_vec()),
},
Some(&non_attest_key_metadata.key),
));
@@ -432,7 +396,6 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
let alias = "aes_attest_key";
let sym_key_metadata = key_generations::generate_sym_key(
@@ -461,7 +424,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: Some(att_challenge.to_vec()),
- att_app_id: Some(att_app_id.to_vec()),
},
Some(&sym_key_metadata.key),
));
@@ -479,16 +441,11 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
// Create attestation key.
- let attestation_key_metadata = key_generations::generate_attestation_key(
- &sec_level,
- Algorithm::RSA,
- att_challenge,
- att_app_id,
- )
- .unwrap();
+ let attestation_key_metadata =
+ key_generations::generate_attestation_key(&sec_level, Algorithm::RSA, att_challenge)
+ .unwrap();
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(attestation_key_metadata.certificate.as_ref().unwrap());
@@ -504,8 +461,7 @@
.key_size(128)
.padding_mode(PaddingMode::NONE)
.block_mode(BlockMode::ECB)
- .attestation_challenge(att_challenge.to_vec())
- .attestation_app_id(att_app_id.to_vec());
+ .attestation_challenge(att_challenge.to_vec());
let alias = format!("ks_test_sym_key_attest_{}", getuid());
let aes_key_metadata = sec_level
diff --git a/keystore2/tests/keystore2_client_ec_key_tests.rs b/keystore2/tests/keystore2_client_ec_key_tests.rs
index 726d61c..c2034de 100644
--- a/keystore2/tests/keystore2_client_ec_key_tests.rs
+++ b/keystore2/tests/keystore2_client_ec_key_tests.rs
@@ -209,7 +209,6 @@
key_generations::SELINUX_SHELL_NAMESPACE,
None,
None,
- None,
)
.unwrap();
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 827a0de..7c75734 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -44,7 +44,6 @@
key_generations::SELINUX_SHELL_NAMESPACE,
Some(alias),
None,
- None,
)
.unwrap();
diff --git a/keystore2/tests/keystore2_client_import_keys_tests.rs b/keystore2/tests/keystore2_client_import_keys_tests.rs
index abf35b5..ecba402 100644
--- a/keystore2/tests/keystore2_client_import_keys_tests.rs
+++ b/keystore2/tests/keystore2_client_import_keys_tests.rs
@@ -14,21 +14,29 @@
use nix::unistd::getuid;
+use openssl::rand::rand_bytes;
+use openssl::x509::X509;
+
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
- ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
- SecurityLevel::SecurityLevel,
+ ErrorCode::ErrorCode, HardwareAuthenticatorType::HardwareAuthenticatorType,
+ KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
};
use android_system_keystore2::aidl::android::system::keystore2::{
- Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ AuthenticatorSpec::AuthenticatorSpec, Domain::Domain,
+ IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
};
use keystore2_test_utils::{
authorizations, get_keystore_service, key_generations, key_generations::Error,
};
+use crate::ffi_test_utils::{create_wrapped_key, create_wrapped_key_additional_auth_data};
+
use crate::keystore2_client_test_utils::{
- has_trusty_keymint, perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
+ encrypt_secure_key, encrypt_transport_key, has_default_keymint,
+ perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
};
@@ -51,6 +59,76 @@
);
}
+fn perform_sym_key_encrypt_decrypt_op(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ key_metadata: &KeyMetadata,
+) {
+ let cipher_text = perform_sample_sym_key_encrypt_op(
+ sec_level,
+ PaddingMode::PKCS7,
+ BlockMode::ECB,
+ &mut None,
+ None,
+ &key_metadata.key,
+ )
+ .unwrap();
+
+ assert!(cipher_text.is_some());
+
+ let plain_text = perform_sample_sym_key_decrypt_op(
+ sec_level,
+ &cipher_text.unwrap(),
+ PaddingMode::PKCS7,
+ BlockMode::ECB,
+ &mut None,
+ None,
+ &key_metadata.key,
+ )
+ .unwrap();
+
+ assert!(plain_text.is_some());
+ assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+}
+
+fn build_secure_key_wrapper(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ secure_key: &[u8],
+ transport_key: &[u8],
+ nonce: &[u8],
+ aad: &[u8],
+ wrapping_key_metadata: &KeyMetadata,
+) -> Result<Vec<u8>, Error> {
+ // Encrypt secure key with transport key.
+ let transport_key_alias = format!("ks_transport_key_aes_256_key_test_{}", getuid());
+ let transport_key_metadata =
+ key_generations::import_transport_key(sec_level, Some(transport_key_alias), transport_key)
+ .unwrap();
+ let encrypted_secure_key = encrypt_secure_key(
+ sec_level,
+ secure_key,
+ aad,
+ nonce.to_vec(),
+ 128,
+ &transport_key_metadata.key,
+ )
+ .unwrap();
+
+ // Extract GCM-tag and encrypted secure key data.
+ let encrypted_secure_key = encrypted_secure_key.unwrap();
+ let gcm_tag: Vec<u8> =
+ encrypted_secure_key[secure_key.len()..(encrypted_secure_key.len())].to_vec();
+ let encrypted_secure_key: Vec<u8> = encrypted_secure_key[0..secure_key.len()].to_vec();
+
+ // Get wrapping key puplic part and encrypt the transport key.
+ let cert_bytes = wrapping_key_metadata.certificate.as_ref().unwrap();
+ let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+ let public_key = cert.public_key().unwrap();
+ let encrypted_transport_key = encrypt_transport_key(transport_key, &public_key).unwrap();
+
+ // Create `SecureKeyWrapper` ASN.1 DER-encoded data.
+ create_wrapped_key(&encrypted_secure_key, &encrypted_transport_key, nonce, &gcm_tag)
+}
+
/// Import RSA key and verify imported key parameters. Try to create an operation using the
/// imported key. Test should be able to create an operation successfully.
#[test]
@@ -208,7 +286,7 @@
key_generations::RSA_2048_KEY,
));
- if has_trusty_keymint() {
+ if has_default_keymint() {
assert!(result.is_err());
assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
} else {
@@ -289,31 +367,7 @@
let key_metadata = key_generations::import_aes_key(&sec_level, Domain::APP, -1, Some(alias))
.expect("Failed to import AES key.");
- let cipher_text = perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(cipher_text.is_some());
-
- let plain_text = perform_sample_sym_key_decrypt_op(
- &sec_level,
- &cipher_text.unwrap(),
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(plain_text.is_some());
- assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &key_metadata);
}
/// Import 3DES key and verify key parameters. Try to create an operation using the imported key.
@@ -331,31 +385,7 @@
let key_metadata = key_generations::import_3des_key(&sec_level, Domain::APP, -1, Some(alias))
.expect("Failed to import 3DES key.");
- let cipher_text = perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(cipher_text.is_some());
-
- let plain_text = perform_sample_sym_key_decrypt_op(
- &sec_level,
- &cipher_text.unwrap(),
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- )
- .unwrap();
-
- assert!(plain_text.is_some());
- assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &key_metadata);
}
/// Import HMAC key and verify key parameters. Try to create an operation using the imported key.
@@ -372,3 +402,234 @@
perform_sample_hmac_sign_verify_op(&sec_level, &key_metadata.key);
}
+
+/// This test creates a wrapped key data and imports it. Validates the imported wrapped key.
+/// 1. Create a wrapped key material to import, as ASN.1 DER-encoded data corresponding to the
+/// `SecureKeyWrapper` schema defined in IKeyMintDevice.aidl.
+/// 2. Import wrapped key and use it for crypto operations.
+/// Test should successfully import the wrapped key and perform crypto operations.
+#[test]
+fn keystore2_create_wrapped_key_and_import_wrapped_key_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let mut secure_key = [0; 32];
+ rand_bytes(&mut secure_key).unwrap();
+
+ let mut transport_key = [0; 32];
+ rand_bytes(&mut transport_key).unwrap();
+
+ let mut nonce = [0; 12];
+ rand_bytes(&mut nonce).unwrap();
+
+ // Import wrapping key.
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_2_{}_2048", getuid());
+ let wrapping_key_metadata = key_generations::import_wrapping_key(
+ &sec_level,
+ key_generations::RSA_2048_KEY,
+ Some(wrapping_key_alias),
+ )
+ .unwrap();
+
+ // Create the DER-encoded representation of `KeyDescription` schema defined in
+ // `IKeyMintDevice.aidl` and use it as additional authenticated data.
+ let aad = create_wrapped_key_additional_auth_data().unwrap();
+
+ // Build ASN.1 DER-encoded wrapped key material as described in `SecureKeyWrapper` schema.
+ let wrapped_key_data = build_secure_key_wrapper(
+ &sec_level,
+ &secure_key,
+ &transport_key,
+ &nonce,
+ &aad,
+ &wrapping_key_metadata,
+ )
+ .unwrap();
+
+ // Unwrap the key. Import wrapped key.
+ let secured_key_alias = format!("ks_wrapped_aes_key_{}", getuid());
+ let secured_key_metadata = key_generations::import_wrapped_key(
+ &sec_level,
+ Some(secured_key_alias),
+ &wrapping_key_metadata,
+ Some(wrapped_key_data.to_vec()),
+ )
+ .unwrap();
+
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &secured_key_metadata);
+}
+
+/// Create a wrapped key data with invalid Additional Authenticated Data (AAD) and
+/// try to import wrapped key.
+/// 1. Create a wrapped key material with invalid AAD to import, as ASN.1 DER-encoded
+/// data corresponding to the `SecureKeyWrapper` schema defined in IKeyMintDevice.aidl.
+/// 2. Import wrapped key and use it for crypto operations.
+/// Test should fail to import the wrapped key with error code `VERIFICATION_FAILED`.
+#[test]
+fn keystore2_create_wrapped_key_with_invalid_aad_and_import_wrapped_key_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let mut secure_key = [0; 32];
+ rand_bytes(&mut secure_key).unwrap();
+
+ let mut transport_key = [0; 32];
+ rand_bytes(&mut transport_key).unwrap();
+
+ let mut nonce = [0; 12];
+ rand_bytes(&mut nonce).unwrap();
+
+ // Import wrapping key.
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_2_{}_2048", getuid());
+ let wrapping_key_metadata = key_generations::import_wrapping_key(
+ &sec_level,
+ key_generations::RSA_2048_KEY,
+ Some(wrapping_key_alias),
+ )
+ .unwrap();
+
+ // Use invalid value as the additional authenticated data.
+ let aad = b"foo";
+
+ // Build ASN.1 DER-encoded wrapped key material as described in `SecureKeyWrapper` schema.
+ let wrapped_key_data = build_secure_key_wrapper(
+ &sec_level,
+ &secure_key,
+ &transport_key,
+ &nonce,
+ aad,
+ &wrapping_key_metadata,
+ )
+ .unwrap();
+
+ // Unwrap the key. Import wrapped key.
+ let secured_key_alias = format!("ks_wrapped_aes_key_{}", getuid());
+ let result = key_generations::map_ks_error(key_generations::import_wrapped_key(
+ &sec_level,
+ Some(secured_key_alias),
+ &wrapping_key_metadata,
+ Some(wrapped_key_data.to_vec()),
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::VERIFICATION_FAILED), result.unwrap_err());
+}
+
+/// Import wrapped AES key and use it for crypto operations. Test should import wrapped key and
+/// perform crypto operations successfully.
+#[test]
+fn keystore2_import_wrapped_key_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = format!("ks_wrapped_key_test_import_1_{}_256", getuid());
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_1_{}_2048", getuid());
+
+ let wrapping_key_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .digest(Digest::SHA_2_256)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT)
+ .purpose(KeyPurpose::WRAP_KEY)
+ .padding_mode(PaddingMode::RSA_OAEP)
+ .key_size(2048)
+ .rsa_public_exponent(65537)
+ .cert_not_before(0)
+ .cert_not_after(253402300799000);
+
+ let key_metadata = key_generations::import_wrapping_key_and_wrapped_key(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ Some(wrapping_key_alias),
+ wrapping_key_params,
+ )
+ .expect("Failed to import wrapped key.");
+
+ // Try to perform operations using wrapped key.
+ perform_sym_key_encrypt_decrypt_op(&sec_level, &key_metadata);
+}
+
+/// Import wrapping-key without specifying KeyPurpose::WRAP_KEY in import key parameters. Try to
+/// use this as wrapping-key for importing wrapped-key. Test should fail with an error code
+/// `INCOMPATIBLE_PURPOSE` to import wrapped-key using a wrapping-key which doesn't possess
+/// `WRAP_KEY` purpose.
+#[test]
+fn keystore2_import_wrapped_key_fails_with_wrong_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let wrapping_key_alias = format!("ks_wrapping_key_test_import_2_{}_2048", getuid());
+ let alias = format!("ks_wrapped_key_test_import_2_{}_256", getuid());
+
+ // In this KeyPurpose::WRAP_KEY is missing.
+ let wrapping_key_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .digest(Digest::SHA_2_256)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .padding_mode(PaddingMode::RSA_OAEP)
+ .key_size(2048)
+ .rsa_public_exponent(65537)
+ .cert_not_before(0)
+ .cert_not_after(253402300799000);
+
+ let result =
+ key_generations::map_ks_error(key_generations::import_wrapping_key_and_wrapped_key(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ Some(wrapping_key_alias),
+ wrapping_key_params,
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Try to import wrapped key whose wrapping key is missing in Android Keystore.
+/// Test should fail to import wrapped key with `ResponseCode::KEY_NOT_FOUND`.
+#[test]
+fn keystore2_import_wrapped_key_fails_with_missing_wrapping_key() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let unwrap_params = authorizations::AuthSetBuilder::new()
+ .digest(Digest::SHA_2_256)
+ .padding_mode(PaddingMode::RSA_OAEP);
+
+ let authenticator_spec: &[AuthenticatorSpec] = &[AuthenticatorSpec {
+ authenticatorType: HardwareAuthenticatorType::NONE,
+ authenticatorId: 0,
+ }];
+
+ let alias = format!("ks_wrapped_key_test_import_3_{}_256", getuid());
+
+ // Wrapping key with this alias doesn't exist.
+ let wrapping_key_alias = format!("ks_wrapping_key_not_exist_{}_2048", getuid());
+
+ let result = key_generations::map_ks_error(sec_level.importWrappedKey(
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias),
+ blob: Some(key_generations::WRAPPED_KEY.to_vec()),
+ },
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(wrapping_key_alias),
+ blob: None,
+ },
+ None,
+ &unwrap_params,
+ authenticator_spec,
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
index def9d94..62e3dd0 100644
--- a/keystore2/tests/keystore2_client_list_entries_tests.rs
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -89,7 +89,6 @@
key_generations::SELINUX_SHELL_NAMESPACE,
Some(alias.to_string()),
None,
- None,
)
.unwrap();
@@ -128,7 +127,6 @@
-1,
Some(alias.to_string()),
None,
- None,
)
.unwrap();
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index e1102dd..9714900 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -307,7 +307,6 @@
key_generations::SELINUX_SHELL_NAMESPACE,
Some(alias),
None,
- None,
)
.unwrap();
diff --git a/keystore2/tests/keystore2_client_rsa_key_tests.rs b/keystore2/tests/keystore2_client_rsa_key_tests.rs
index 3139c2b..ad176a4 100644
--- a/keystore2/tests/keystore2_client_rsa_key_tests.rs
+++ b/keystore2/tests/keystore2_client_rsa_key_tests.rs
@@ -13,8 +13,8 @@
// limitations under the License.
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- BlockMode::BlockMode, Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
- PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
+ Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+ SecurityLevel::SecurityLevel,
};
use android_system_keystore2::aidl::android::system::keystore2::{
CreateOperationResponse::CreateOperationResponse, Domain::Domain,
@@ -25,9 +25,7 @@
authorizations, get_keystore_service, key_generations, key_generations::Error,
};
-use crate::keystore2_client_test_utils::{
- delete_app_key, has_trusty_keymint, perform_sample_sign_operation, ForcedOp,
-};
+use crate::keystore2_client_test_utils::{delete_app_key, perform_sample_sign_operation, ForcedOp};
/// This macro is used for creating signing key operation tests using digests and paddings
/// for various key sizes.
@@ -59,7 +57,6 @@
stringify!($test_name),
$padding,
None,
- None,
);
}
};
@@ -73,7 +70,6 @@
stringify!($test_name),
$padding,
$mgf_digest,
- Some(BlockMode::ECB),
);
}
};
@@ -133,7 +129,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::SIGN,
ForcedOp(false),
@@ -170,18 +165,16 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::SIGN,
ForcedOp(false),
));
assert!(result.is_err());
- if has_trusty_keymint() {
- assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::UNKNOWN_ERROR));
- } else {
- assert_eq!(result.unwrap_err(), Error::Km(ErrorCode::INCOMPATIBLE_DIGEST));
- }
+ let e = result.unwrap_err();
+ assert!(
+ e == Error::Km(ErrorCode::UNKNOWN_ERROR) || e == Error::Km(ErrorCode::INCOMPATIBLE_DIGEST)
+ );
delete_app_key(&keystore2, alias).unwrap();
}
@@ -193,7 +186,6 @@
alias: &str,
padding: PaddingMode,
mgf_digest: Option<Digest>,
- block_mode: Option<BlockMode>,
) {
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
@@ -209,9 +201,8 @@
padding: Some(padding),
digest,
mgf_digest,
- block_mode,
+ block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1559,7 +1550,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::SIGN,
ForcedOp(false),
@@ -1592,7 +1582,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1624,7 +1613,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1654,7 +1642,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::SIGN,
ForcedOp(false),
@@ -1684,7 +1671,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1714,7 +1700,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::AGREE_KEY,
ForcedOp(false),
@@ -1747,7 +1732,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1781,7 +1765,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::SIGN,
ForcedOp(false),
@@ -1813,7 +1796,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::ENCRYPT,
ForcedOp(false),
@@ -1845,7 +1827,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1876,7 +1857,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
KeyPurpose::DECRYPT,
ForcedOp(false),
@@ -1906,7 +1886,6 @@
mgf_digest: None,
block_mode: None,
att_challenge: None,
- att_app_id: None,
},
None,
));
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 758e88b..56995e4 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -15,7 +15,11 @@
use nix::unistd::{Gid, Uid};
use serde::{Deserialize, Serialize};
+use openssl::encrypt::Encrypter;
+use openssl::error::ErrorStack;
use openssl::hash::MessageDigest;
+use openssl::pkey::PKey;
+use openssl::pkey::Public;
use openssl::rsa::Padding;
use openssl::sign::Verifier;
use openssl::x509::X509;
@@ -80,7 +84,8 @@
};
}
-pub fn has_trusty_keymint() -> bool {
+/// Indicate whether the default device is KeyMint (rather than Keymaster).
+pub fn has_default_keymint() -> bool {
binder::is_declared("android.hardware.security.keymint.IKeyMintDevice/default")
.expect("Could not check for declared keymint interface")
}
@@ -98,10 +103,9 @@
let keystore2 = get_keystore_service();
let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sec_level, domain, nspace, alias, None, None,
- )
- .unwrap();
+ let key_metadata =
+ key_generations::generate_ec_p256_signing_key(&sec_level, domain, nspace, alias, None)
+ .unwrap();
sec_level.createOperation(
&key_metadata.key,
@@ -348,3 +352,45 @@
blob: None,
})
}
+
+/// Encrypt the secure key with given transport key.
+pub fn encrypt_secure_key(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ secure_key: &[u8],
+ aad: &[u8],
+ nonce: Vec<u8>,
+ mac_len: i32,
+ key: &KeyDescriptor,
+) -> binder::Result<Option<Vec<u8>>> {
+ let op_params = authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::ENCRYPT)
+ .padding_mode(PaddingMode::NONE)
+ .block_mode(BlockMode::GCM)
+ .nonce(nonce)
+ .mac_length(mac_len);
+
+ let op_response = sec_level.createOperation(key, &op_params, false)?;
+
+ let op = op_response.iOperation.unwrap();
+ op.updateAad(aad)?;
+ op.finish(Some(secure_key), None)
+}
+
+/// Encrypt the transport key with given RSA wrapping key.
+pub fn encrypt_transport_key(
+ transport_key: &[u8],
+ pkey: &PKey<Public>,
+) -> Result<Vec<u8>, ErrorStack> {
+ let mut encrypter = Encrypter::new(pkey).unwrap();
+ encrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap();
+ encrypter.set_rsa_oaep_md(MessageDigest::sha256()).unwrap();
+ encrypter.set_rsa_mgf1_md(MessageDigest::sha1()).unwrap();
+
+ let input = transport_key.to_vec();
+ let buffer_len = encrypter.encrypt_len(&input).unwrap();
+ let mut encoded = vec![0u8; buffer_len];
+ let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap();
+ let encoded = &encoded[..encoded_len];
+
+ Ok(encoded.to_vec())
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 41e3e36..d705aa4 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+pub mod ffi_test_utils;
pub mod keystore2_client_3des_key_tests;
pub mod keystore2_client_aes_key_tests;
pub mod keystore2_client_attest_key_tests;
diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
index 32ecd03..63122fe 100644
--- a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
+++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
@@ -165,14 +165,12 @@
.unwrap();
// Generate Key BLOB and prepare legacy keystore blob files.
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
let key_metadata = key_generations::generate_ec_p256_signing_key(
&sec_level,
Domain::BLOB,
SELINUX_SHELL_NAMESPACE,
None,
Some(att_challenge),
- Some(att_app_id),
)
.expect("Failed to generate key blob");
@@ -424,14 +422,12 @@
.unwrap();
// Generate Key BLOB and prepare legacy keystore blob files.
let att_challenge: &[u8] = b"foo";
- let att_app_id: &[u8] = b"bar";
let key_metadata = key_generations::generate_ec_p256_signing_key(
&sec_level,
Domain::BLOB,
SELINUX_SHELL_NAMESPACE,
None,
Some(att_challenge),
- Some(att_app_id),
)
.expect("Failed to generate key blob");