Merge "Make librkpd_client available to com.android.virt" into main
diff --git a/keystore/tests/fuzzer/Android.bp b/keystore/tests/fuzzer/Android.bp
index 5df5c7a..d459f75 100644
--- a/keystore/tests/fuzzer/Android.bp
+++ b/keystore/tests/fuzzer/Android.bp
@@ -40,9 +40,17 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-hardware-security@google.com",
],
- componentid: 155276,
+ componentid: 1084732,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libkeystore-wifi-hidl",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
@@ -62,9 +70,17 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-hardware-security@google.com",
],
- componentid: 155276,
+ componentid: 1084732,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libkeystore-attestation-application-id",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/keystore2/aconfig/flags.aconfig b/keystore2/aconfig/flags.aconfig
index 5d2a422..6a65f11 100644
--- a/keystore2/aconfig/flags.aconfig
+++ b/keystore2/aconfig/flags.aconfig
@@ -9,9 +9,9 @@
}
flag {
- name: "deprecate_legacy_keystore"
+ name: "disable_legacy_keystore_put"
namespace: "hardware_backed_security"
- description: "This flag rolls out legacy keystore deprecation and makes it so that the put command returns a deprecation error"
+ description: "This flag disables legacy keystore put and makes it so that command returns an error"
bug: "307460850"
is_fixed_read_only: true
}
diff --git a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
index 86d38d7..8275e8c 100644
--- a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
+++ b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
@@ -39,6 +39,20 @@
void onUserAdded(in int userId);
/**
+ * Allows LockSettingsService to tell Keystore to create a user's superencryption keys and store
+ * them encrypted by the given secret. Requires 'ChangeUser' permission.
+ *
+ * ## Error conditions:
+ * `ResponseCode::PERMISSION_DENIED` - if caller does not have the 'ChangeUser' permission
+ * `ResponseCode::SYSTEM_ERROR` - if failed to initialize the user's super keys
+ *
+ * @param userId - Android user id
+ * @param password - a secret derived from the synthetic password of the user
+ * @param allowExisting - if true, then the keys already existing is not considered an error
+ */
+ void initUserSuperKeys(in int userId, in byte[] password, in boolean allowExisting);
+
+ /**
* Allows LockSettingsService to inform keystore about removing a user.
* Callers require 'ChangeUser' permission.
*
@@ -51,6 +65,18 @@
void onUserRemoved(in int userId);
/**
+ * Allows LockSettingsService to tell Keystore that a user's LSKF is being removed, ie the
+ * user's lock screen is changing to Swipe or None. Requires 'ChangePassword' permission.
+ *
+ * ## Error conditions:
+ * `ResponseCode::PERMISSION_DENIED` - if caller does not have the 'ChangePassword' permission
+ * `ResponseCode::SYSTEM_ERROR` - if failed to delete the user's auth-bound keys
+ *
+ * @param userId - Android user id
+ */
+ void onUserLskfRemoved(in int userId);
+
+ /**
* Allows LockSettingsService to inform keystore about password change of a user.
* Callers require 'ChangePassword' permission.
*
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 83963f9..63dbf7f 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -47,7 +47,7 @@
use crate::gc::Gc;
use crate::impl_metadata; // This is in db_utils.rs
-use crate::key_parameter::{KeyParameter, Tag};
+use crate::key_parameter::{KeyParameter, KeyParameterValue, Tag};
use crate::ks_err;
use crate::permission::KeyPermSet;
use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, AID_USER_OFFSET};
@@ -2544,6 +2544,70 @@
.context(ks_err!())
}
+ /// Deletes all auth-bound keys, i.e. keys that require user authentication, for the given user.
+ /// This runs when the user's lock screen is being changed to Swipe or None.
+ ///
+ /// This intentionally does *not* delete keys that require that the device be unlocked, unless
+ /// such keys also require user authentication. Keystore's concept of user authentication is
+ /// fairly strong, and it requires that keys that require authentication be deleted as soon as
+ /// authentication is no longer possible. In contrast, keys that just require that the device
+ /// be unlocked should remain usable when the lock screen is set to Swipe or None, as the device
+ /// is always considered "unlocked" in that case.
+ pub fn unbind_auth_bound_keys_for_user(&mut self, user_id: u32) -> Result<()> {
+ let _wp = wd::watch_millis("KeystoreDB::unbind_auth_bound_keys_for_user", 500);
+
+ self.with_transaction(TransactionBehavior::Immediate, |tx| {
+ let mut stmt = tx
+ .prepare(&format!(
+ "SELECT id from persistent.keyentry
+ WHERE key_type = ?
+ AND domain = ?
+ AND cast ( (namespace/{aid_user_offset}) as int) = ?
+ AND state = ?;",
+ aid_user_offset = AID_USER_OFFSET
+ ))
+ .context(concat!(
+ "In unbind_auth_bound_keys_for_user. ",
+ "Failed to prepare the query to find the keys created by apps."
+ ))?;
+
+ let mut rows = stmt
+ .query(params![KeyType::Client, Domain::APP.0 as u32, user_id, KeyLifeCycle::Live,])
+ .context(ks_err!("Failed to query the keys created by apps."))?;
+
+ let mut key_ids: Vec<i64> = Vec::new();
+ db_utils::with_rows_extract_all(&mut rows, |row| {
+ key_ids
+ .push(row.get(0).context("Failed to read key id of a key created by an app.")?);
+ Ok(())
+ })
+ .context(ks_err!())?;
+
+ let mut notify_gc = false;
+ let mut num_unbound = 0;
+ for key_id in key_ids {
+ // Load the key parameters and filter out non-auth-bound keys. To identify
+ // auth-bound keys, use the presence of UserSecureID. The absence of NoAuthRequired
+ // could also be used, but UserSecureID is what Keystore treats as authoritative
+ // when actually enforcing the key parameters (it might not matter, though).
+ let params = Self::load_key_parameters(key_id, tx)
+ .context("Failed to load key parameters.")?;
+ let is_auth_bound_key = params.iter().any(|kp| {
+ matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_))
+ });
+ if is_auth_bound_key {
+ notify_gc = Self::mark_unreferenced(tx, key_id)
+ .context("In unbind_auth_bound_keys_for_user.")?
+ || notify_gc;
+ num_unbound += 1;
+ }
+ }
+ log::info!("Deleting {num_unbound} auth-bound keys for user {user_id}");
+ Ok(()).do_gc(notify_gc)
+ })
+ .context(ks_err!())
+ }
+
fn load_key_components(
tx: &Transaction,
load_bits: KeyEntryLoadBits,
@@ -4752,6 +4816,53 @@
Ok(key_id)
}
+ // Creates an app key that is marked as being superencrypted by the given
+ // super key ID and that has the given authentication and unlocked device
+ // parameters. This does not actually superencrypt the key blob.
+ fn make_superencrypted_key_entry(
+ db: &mut KeystoreDB,
+ namespace: i64,
+ alias: &str,
+ requires_authentication: bool,
+ requires_unlocked_device: bool,
+ super_key_id: i64,
+ ) -> Result<KeyIdGuard> {
+ let domain = Domain::APP;
+ let key_id = db.create_key_entry(&domain, &namespace, KeyType::Client, &KEYSTORE_UUID)?;
+
+ let mut blob_metadata = BlobMetaData::new();
+ blob_metadata.add(BlobMetaEntry::KmUuid(KEYSTORE_UUID));
+ blob_metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
+ db.set_blob(
+ &key_id,
+ SubComponentType::KEY_BLOB,
+ Some(TEST_KEY_BLOB),
+ Some(&blob_metadata),
+ )?;
+
+ let mut params = vec![];
+ if requires_unlocked_device {
+ params.push(KeyParameter::new(
+ KeyParameterValue::UnlockedDeviceRequired,
+ SecurityLevel::TRUSTED_ENVIRONMENT,
+ ));
+ }
+ if requires_authentication {
+ params.push(KeyParameter::new(
+ KeyParameterValue::UserSecureID(42),
+ SecurityLevel::TRUSTED_ENVIRONMENT,
+ ));
+ }
+ db.insert_keyparameter(&key_id, ¶ms)?;
+
+ let mut metadata = KeyMetaData::new();
+ metadata.add(KeyMetaEntry::CreationDate(DateTime::from_millis_epoch(123456789)));
+ db.insert_key_metadata(&key_id, &metadata)?;
+
+ rebind_alias(db, &key_id, alias, domain, namespace)?;
+ Ok(key_id)
+ }
+
fn make_bootlevel_test_key_entry_test_vector(key_id: i64, logical_only: bool) -> KeyEntry {
let mut params = make_test_params(None);
params.push(KeyParameter::new(KeyParameterValue::MaxBootLevel(3), SecurityLevel::KEYSTORE));
@@ -4955,6 +5066,71 @@
Ok(())
}
+ fn app_key_exists(db: &mut KeystoreDB, nspace: i64, alias: &str) -> Result<bool> {
+ db.key_exists(Domain::APP, nspace, alias, KeyType::Client)
+ }
+
+ // Tests the unbind_auth_bound_keys_for_user() function.
+ #[test]
+ fn test_unbind_auth_bound_keys_for_user() -> Result<()> {
+ let mut db = new_test_db()?;
+ let user_id = 1;
+ let nspace: i64 = (user_id * AID_USER_OFFSET).into();
+ let other_user_id = 2;
+ let other_user_nspace: i64 = (other_user_id * AID_USER_OFFSET).into();
+ let super_key_type = &USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
+
+ // Create a superencryption key.
+ let super_key = keystore2_crypto::generate_aes256_key()?;
+ let pw: keystore2_crypto::Password = (&b"xyzabc"[..]).into();
+ let (encrypted_super_key, blob_metadata) =
+ SuperKeyManager::encrypt_with_password(&super_key, &pw)?;
+ db.store_super_key(
+ user_id,
+ super_key_type,
+ &encrypted_super_key,
+ &blob_metadata,
+ &KeyMetaData::new(),
+ )?;
+ let super_key_id = db.load_super_key(super_key_type, user_id)?.unwrap().0 .0;
+
+ // Store 4 superencrypted app keys, one for each possible combination of
+ // (authentication required, unlocked device required).
+ make_superencrypted_key_entry(&mut db, nspace, "noauth_noud", false, false, super_key_id)?;
+ make_superencrypted_key_entry(&mut db, nspace, "noauth_ud", false, true, super_key_id)?;
+ make_superencrypted_key_entry(&mut db, nspace, "auth_noud", true, false, super_key_id)?;
+ make_superencrypted_key_entry(&mut db, nspace, "auth_ud", true, true, super_key_id)?;
+ assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
+ assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
+ assert!(app_key_exists(&mut db, nspace, "auth_noud")?);
+ assert!(app_key_exists(&mut db, nspace, "auth_ud")?);
+
+ // Also store a key for a different user that requires authentication.
+ make_superencrypted_key_entry(
+ &mut db,
+ other_user_nspace,
+ "auth_ud",
+ true,
+ true,
+ super_key_id,
+ )?;
+
+ db.unbind_auth_bound_keys_for_user(user_id)?;
+
+ // Verify that only the user's app keys that require authentication were
+ // deleted. Keys that require an unlocked device but not authentication
+ // should *not* have been deleted, nor should the super key have been
+ // deleted, nor should other users' keys have been deleted.
+ assert!(db.load_super_key(super_key_type, user_id)?.is_some());
+ assert!(app_key_exists(&mut db, nspace, "noauth_noud")?);
+ assert!(app_key_exists(&mut db, nspace, "noauth_ud")?);
+ assert!(!app_key_exists(&mut db, nspace, "auth_noud")?);
+ assert!(!app_key_exists(&mut db, nspace, "auth_ud")?);
+ assert!(app_key_exists(&mut db, other_user_nspace, "auth_ud")?);
+
+ Ok(())
+ }
+
#[test]
fn test_store_super_key() -> Result<()> {
let mut db = new_test_db()?;
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 95e8837..43147e8 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -603,6 +603,44 @@
}
}
+ if android_security_flags::fix_unlocked_device_required_keys() {
+ let (hat, state) = if user_secure_ids.is_empty() {
+ (None, DeferredAuthState::NoAuthRequired)
+ } else if let Some(key_time_out) = key_time_out {
+ let (hat, last_off_body) =
+ Self::find_auth_token(|hat: &AuthTokenEntry| match user_auth_type {
+ Some(auth_type) => hat.satisfies(&user_secure_ids, auth_type),
+ None => false, // not reachable due to earlier check
+ })
+ .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
+ .context(ks_err!("No suitable auth token found."))?;
+ let now = MonotonicRawTime::now();
+ let token_age = now
+ .checked_sub(&hat.time_received())
+ .ok_or_else(Error::sys)
+ .context(ks_err!(
+ "Overflow while computing Auth token validity. \
+ Validity cannot be established."
+ ))?;
+
+ let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
+
+ if token_age.seconds() > key_time_out && !on_body_extended {
+ return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
+ .context(ks_err!("matching auth token is expired."));
+ }
+ let state = if requires_timestamp {
+ DeferredAuthState::TimeStampRequired(hat.auth_token().clone())
+ } else {
+ DeferredAuthState::NoAuthRequired
+ };
+ (Some(hat.take_auth_token()), state)
+ } else {
+ (None, DeferredAuthState::OpAuthRequired)
+ };
+ return Ok((hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver }));
+ }
+
if !unlocked_device_required && no_auth_required {
return Ok((
None,
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index ea48f4d..74858de 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -120,6 +120,41 @@
.context(ks_err!("While invoking the delete listener."))
}
+ fn init_user_super_keys(
+ &self,
+ user_id: i32,
+ password: Password,
+ allow_existing: bool,
+ ) -> Result<()> {
+ // Permission check. Must return on error. Do not touch the '?'.
+ check_keystore_permission(KeystorePerm::ChangeUser).context(ks_err!())?;
+
+ let mut skm = SUPER_KEY.write().unwrap();
+ DB.with(|db| {
+ skm.initialize_user(
+ &mut db.borrow_mut(),
+ &LEGACY_IMPORTER,
+ user_id as u32,
+ &password,
+ allow_existing,
+ )
+ })
+ .context(ks_err!("Failed to initialize user super keys"))
+ }
+
+ // Deletes all auth-bound keys when the user's LSKF is removed.
+ fn on_user_lskf_removed(user_id: i32) -> Result<()> {
+ // Permission check. Must return on error. Do not touch the '?'.
+ check_keystore_permission(KeystorePerm::ChangePassword).context(ks_err!())?;
+
+ LEGACY_IMPORTER
+ .bulk_delete_user(user_id as u32, true)
+ .context(ks_err!("Failed to delete legacy keys."))?;
+
+ DB.with(|db| db.borrow_mut().unbind_auth_bound_keys_for_user(user_id as u32))
+ .context(ks_err!("Failed to delete auth-bound keys."))
+ }
+
fn clear_namespace(&self, domain: Domain, nspace: i64) -> Result<()> {
// Permission check. Must return on error. Do not touch the '?'.
check_keystore_permission(KeystorePerm::ClearUID).context("In clear_namespace.")?;
@@ -272,12 +307,29 @@
map_or_log_err(self.add_or_remove_user(user_id), Ok)
}
+ fn initUserSuperKeys(
+ &self,
+ user_id: i32,
+ password: &[u8],
+ allow_existing: bool,
+ ) -> BinderResult<()> {
+ log::info!("initUserSuperKeys(user={user_id}, allow_existing={allow_existing})");
+ let _wp = wd::watch_millis("IKeystoreMaintenance::initUserSuperKeys", 500);
+ map_or_log_err(self.init_user_super_keys(user_id, password.into(), allow_existing), Ok)
+ }
+
fn onUserRemoved(&self, user_id: i32) -> BinderResult<()> {
log::info!("onUserRemoved(user={user_id})");
let _wp = wd::watch_millis("IKeystoreMaintenance::onUserRemoved", 500);
map_or_log_err(self.add_or_remove_user(user_id), Ok)
}
+ fn onUserLskfRemoved(&self, user_id: i32) -> BinderResult<()> {
+ log::info!("onUserLskfRemoved(user={user_id})");
+ let _wp = wd::watch_millis("IKeystoreMaintenance::onUserLskfRemoved", 500);
+ map_or_log_err(Self::on_user_lskf_removed(user_id), Ok)
+ }
+
fn clearNamespace(&self, domain: Domain, nspace: i64) -> BinderResult<()> {
log::info!("clearNamespace({domain:?}, nspace={nspace})");
let _wp = wd::watch_millis("IKeystoreMaintenance::clearNamespace", 500);
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index 898a8c2..3992eb2 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -248,11 +248,12 @@
#[derive(Default)]
struct UserSuperKeys {
- /// The AfterFirstUnlock super key is used for LSKF binding of authentication bound keys. There
- /// is one key per android user. The key is stored on flash encrypted with a key derived from a
- /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF). When the
- /// user unlocks the device for the first time, this key is unlocked, i.e., decrypted, and stays
- /// memory resident until the device reboots.
+ /// The AfterFirstUnlock super key is used for synthetic password binding of authentication
+ /// bound keys. There is one key per android user. The key is stored on flash encrypted with a
+ /// key derived from a secret, that is itself derived from the user's synthetic password. (In
+ /// most cases, the user's synthetic password can, in turn, only be decrypted using the user's
+ /// Lock Screen Knowledge Factor or LSKF.) When the user unlocks the device for the first time,
+ /// this key is unlocked, i.e., decrypted, and stays memory resident until the device reboots.
after_first_unlock: Option<Arc<SuperKey>>,
/// The UnlockedDeviceRequired symmetric super key works like the AfterFirstUnlock super key
/// with the distinction that it is cleared from memory when the device is locked.
@@ -474,7 +475,7 @@
}
}
- /// Checks if user has setup LSKF, even when super key cache is empty for the user.
+ /// Checks if the user's AfterFirstUnlock super key exists in the database (or legacy database).
/// The reference to self is unused but it is required to prevent calling this function
/// concurrently with skm state database changes.
fn super_key_exists_in_db_for_user(
@@ -662,7 +663,8 @@
SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
SuperEncryptionType::AfterFirstUnlock => {
// Encrypt the given key blob with the user's AfterFirstUnlock super key. If the
- // user has not unlocked the device since boot or has no LSKF, an error is returned.
+ // user has not unlocked the device since boot or the super keys were never
+ // initialized for the user for some reason, an error is returned.
match self
.get_user_state(db, legacy_importer, user_id)
.context(ks_err!("Failed to get user state for user {user_id}"))?
@@ -676,7 +678,7 @@
Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked."))
}
UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
- .context(ks_err!("LSKF is not setup for user {user_id}")),
+ .context(ks_err!("User {user_id} does not have super keys")),
}
}
SuperEncryptionType::UnlockedDeviceRequired => {
@@ -1131,6 +1133,37 @@
}
}
+ /// Initializes the given user by creating their super keys, both AfterFirstUnlock and
+ /// UnlockedDeviceRequired. If allow_existing is true, then the user already being initialized
+ /// is not considered an error.
+ pub fn initialize_user(
+ &mut self,
+ db: &mut KeystoreDB,
+ legacy_importer: &LegacyImporter,
+ user_id: UserId,
+ password: &Password,
+ allow_existing: bool,
+ ) -> Result<()> {
+ // Create the AfterFirstUnlock super key.
+ if self.super_key_exists_in_db_for_user(db, legacy_importer, user_id)? {
+ log::info!("AfterFirstUnlock super key already exists");
+ if !allow_existing {
+ return Err(Error::sys()).context(ks_err!("Tried to re-init an initialized user!"));
+ }
+ } else {
+ let super_key = self
+ .create_super_key(db, user_id, &USER_AFTER_FIRST_UNLOCK_SUPER_KEY, password, None)
+ .context(ks_err!("Failed to create AfterFirstUnlock super key"))?;
+
+ self.install_after_first_unlock_key_for_user(user_id, super_key)
+ .context(ks_err!("Failed to install AfterFirstUnlock super key for user"))?;
+ }
+
+ // Create the UnlockedDeviceRequired super keys.
+ self.unlock_unlocked_device_required_keys(db, user_id, password)
+ .context(ks_err!("Failed to create UnlockedDeviceRequired super keys"))
+ }
+
/// Unlocks the given user with the given password.
///
/// If the user state is BeforeFirstUnlock:
@@ -1186,15 +1219,15 @@
/// This enum represents different states of the user's life cycle in the device.
/// For now, only three states are defined. More states may be added later.
pub enum UserState {
- // The user has registered LSKF and has unlocked the device by entering PIN/Password,
- // and hence the AfterFirstUnlock super key is available in the cache.
+ // The user's super keys exist, and the user has unlocked the device at least once since boot.
+ // Hence, the AfterFirstUnlock super key is available in the cache.
AfterFirstUnlock(Arc<SuperKey>),
- // The user has registered LSKF, but has not unlocked the device using password, after reboot.
- // Hence the AfterFirstUnlock and UnlockedDeviceRequired super keys are not available in the
- // cache. However, they exist in the database in encrypted form.
+ // The user's super keys exist, but the user hasn't unlocked the device at least once since
+ // boot. Hence, the AfterFirstUnlock and UnlockedDeviceRequired super keys are not available in
+ // the cache. However, they exist in the database in encrypted form.
BeforeFirstUnlock,
- // There's no user in the device for the given user id, or the user with the user id has not
- // setup LSKF.
+ // The user's super keys don't exist. I.e., there's no user with the given user ID, or the user
+ // is in the process of being created or destroyed.
Uninitialized,
}
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
index 02ceb83..2cb2aaf 100644
--- a/keystore2/test_utils/authorizations.rs
+++ b/keystore2/test_utils/authorizations.rs
@@ -335,6 +335,31 @@
self.0.push(KeyParameter { tag: Tag::APPLICATION_ID, value: KeyParameterValue::Blob(b) });
self
}
+
+ /// Set device-unique-attestation.
+ pub fn device_unique_attestation(mut self) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::DEVICE_UNIQUE_ATTESTATION,
+ value: KeyParameterValue::BoolValue(true),
+ });
+ self
+ }
+
+ /// Add certificate serial number.
+ pub fn cert_serial(mut self, b: Vec<u8>) -> Self {
+ self.0
+ .push(KeyParameter { tag: Tag::CERTIFICATE_SERIAL, value: KeyParameterValue::Blob(b) });
+ self
+ }
+
+ /// Add certificate subject name.
+ pub fn cert_subject_name(mut self, b: Vec<u8>) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::CERTIFICATE_SUBJECT,
+ value: KeyParameterValue::Blob(b),
+ });
+ self
+ }
}
impl Deref for AuthSetBuilder {
diff --git a/keystore2/test_utils/ffi_test_utils.rs b/keystore2/test_utils/ffi_test_utils.rs
index 5d6bf46..1ccdcc8 100644
--- a/keystore2/test_utils/ffi_test_utils.rs
+++ b/keystore2/test_utils/ffi_test_utils.rs
@@ -50,7 +50,19 @@
/// 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) {
+ validate_certchain_with_strict_issuer_check(cert_buf, true)
+}
+
+/// Validate given certificate chain with an option to validate the issuer.
+pub fn validate_certchain_with_strict_issuer_check(
+ cert_buf: &[u8],
+ strict_issuer_check: bool,
+) -> Result<bool, Error> {
+ if ffi::validateCertChain(
+ cert_buf.to_vec(),
+ cert_buf.len().try_into().unwrap(),
+ strict_issuer_check,
+ ) {
return Ok(true);
}
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index badc480..9ddc87a 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -40,7 +40,7 @@
use crate::ffi_test_utils::{
get_os_patchlevel, get_os_version, get_value_from_attest_record, get_vendor_patchlevel,
- validate_certchain,
+ validate_certchain_with_strict_issuer_check,
};
/// Shell namespace.
@@ -1426,7 +1426,10 @@
let mut cert_chain: Vec<u8> = Vec::new();
cert_chain.extend(key_metadata.certificate.as_ref().unwrap());
cert_chain.extend(key_metadata.certificateChain.as_ref().unwrap());
- validate_certchain(&cert_chain).expect("Error while validating cert chain");
+ let strict_issuer_check =
+ !(gen_params.iter().any(|kp| kp.tag == Tag::DEVICE_UNIQUE_ATTESTATION));
+ validate_certchain_with_strict_issuer_check(&cert_chain, strict_issuer_check)
+ .expect("Error while validating cert chain");
}
if let Some(challenge_param) =
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index c9ef298..3532a35 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -488,12 +488,12 @@
fn get_attestation_ids(keystore2: &binder::Strong<dyn IKeystoreService>) -> Vec<(Tag, Vec<u8>)> {
let attest_ids = vec![
- (Tag::ATTESTATION_ID_BRAND, "ro.product.brand_for_attestation"),
- (Tag::ATTESTATION_ID_DEVICE, "ro.product.device"),
- (Tag::ATTESTATION_ID_PRODUCT, "ro.product.name_for_attestation"),
- (Tag::ATTESTATION_ID_SERIAL, "ro.serialno"),
- (Tag::ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer"),
- (Tag::ATTESTATION_ID_MODEL, "ro.product.model_for_attestation"),
+ (Tag::ATTESTATION_ID_BRAND, "brand"),
+ (Tag::ATTESTATION_ID_DEVICE, "device"),
+ (Tag::ATTESTATION_ID_PRODUCT, "name"),
+ (Tag::ATTESTATION_ID_SERIAL, "serialno"),
+ (Tag::ATTESTATION_ID_MANUFACTURER, "manufacturer"),
+ (Tag::ATTESTATION_ID_MODEL, "model"),
(Tag::ATTESTATION_ID_IMEI, ""), //Get this value from Telephony service.
(Tag::ATTESTATION_ID_SECOND_IMEI, ""), //Get this value from Telephony service.
];
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
index 279ecd7..2291a08 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -14,6 +14,9 @@
use std::time::SystemTime;
+use openssl::bn::{BigNum, MsbOption};
+use openssl::x509::X509NameBuilder;
+
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
@@ -39,7 +42,8 @@
use crate::keystore2_client_test_utils::{
delete_app_key, 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,
+ perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op,
+ verify_certificate_serial_num, verify_certificate_subject_name, SAMPLE_PLAIN_TEXT,
};
use keystore2_test_utils::ffi_test_utils::get_value_from_attest_record;
@@ -964,3 +968,39 @@
keystore_auth.getLastAuthTime(0, &[HardwareAuthenticatorType::FINGERPRINT]).unwrap() > 0
);
}
+
+/// Generate a key with specifying `CERTIFICATE_SUBJECT and CERTIFICATE_SERIAL`. Test should
+/// generate a key successfully and verify the specified key parameters.
+#[test]
+fn keystore2_gen_key_auth_serial_number_subject_test_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let cert_subject = "test cert subject";
+ let mut x509_name = X509NameBuilder::new().unwrap();
+ x509_name.append_entry_by_text("CN", cert_subject).unwrap();
+ let x509_name = x509_name.build().to_der().unwrap();
+
+ let mut serial = BigNum::new().unwrap();
+ serial.rand(159, MsbOption::MAYBE_ZERO, false).unwrap();
+
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .cert_subject_name(x509_name)
+ .cert_serial(serial.to_vec());
+
+ let alias = "ks_test_auth_tags_test";
+ let key_metadata = key_generations::generate_key(&sec_level, &gen_params, alias).unwrap();
+ verify_certificate_subject_name(
+ key_metadata.certificate.as_ref().unwrap(),
+ cert_subject.as_bytes(),
+ );
+ verify_certificate_serial_num(key_metadata.certificate.as_ref().unwrap(), &serial);
+ delete_app_key(&keystore2, alias).unwrap();
+}
diff --git a/keystore2/tests/keystore2_client_device_unique_attestation_tests.rs b/keystore2/tests/keystore2_client_device_unique_attestation_tests.rs
new file mode 100644
index 0000000..cf88fc5
--- /dev/null
+++ b/keystore2/tests/keystore2_client_device_unique_attestation_tests.rs
@@ -0,0 +1,406 @@
+// Copyright 2023, 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 android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
+ KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, SecurityLevel::SecurityLevel, Tag::Tag,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use keystore2_test_utils::ffi_test_utils::get_value_from_attest_record;
+
+use crate::keystore2_client_test_utils::{
+ delete_app_key, get_attest_id_value, is_second_imei_id_attestation_required,
+ perform_sample_asym_sign_verify_op,
+};
+
+/// This macro is used for generating device unique attested EC key with device id attestation.
+macro_rules! test_ec_key_device_unique_attestation_id {
+ ( $test_name:ident, $tag:expr, $prop_name:expr ) => {
+ #[test]
+ fn $test_name() {
+ generate_ec_key_device_unique_attested_with_id_attest($tag, $prop_name);
+ }
+ };
+}
+
+/// This macro is used for generating device unique attested RSA key with device id attestation.
+macro_rules! test_rsa_key_device_unique_attestation_id {
+ ( $test_name:ident, $tag:expr, $prop_name:expr ) => {
+ #[test]
+ fn $test_name() {
+ generate_rsa_key_device_unique_attested_with_id_attest($tag, $prop_name);
+ }
+ };
+}
+
+fn generate_ec_key_device_unique_attested_with_id_attest(attest_id_tag: Tag, prop_name: &str) {
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+ generate_device_unique_attested_key_with_device_attest_ids(
+ gen_params,
+ attest_id_tag,
+ prop_name,
+ );
+}
+
+fn generate_rsa_key_device_unique_attested_with_id_attest(attest_id_tag: Tag, prop_name: &str) {
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .rsa_public_exponent(65537)
+ .key_size(2048)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .padding_mode(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+ generate_device_unique_attested_key_with_device_attest_ids(
+ gen_params,
+ attest_id_tag,
+ prop_name,
+ );
+}
+
+fn add_attest_id_auth(
+ gen_params: authorizations::AuthSetBuilder,
+ attest_id_tag: Tag,
+ value: Vec<u8>,
+) -> authorizations::AuthSetBuilder {
+ match attest_id_tag {
+ Tag::ATTESTATION_ID_BRAND => gen_params.attestation_device_brand(value),
+ Tag::ATTESTATION_ID_DEVICE => gen_params.attestation_device_name(value),
+ Tag::ATTESTATION_ID_PRODUCT => gen_params.attestation_device_product_name(value),
+ Tag::ATTESTATION_ID_SERIAL => gen_params.attestation_device_serial(value),
+ Tag::ATTESTATION_ID_MANUFACTURER => gen_params.attestation_device_manufacturer(value),
+ Tag::ATTESTATION_ID_MODEL => gen_params.attestation_device_model(value),
+ Tag::ATTESTATION_ID_IMEI => gen_params.attestation_device_imei(value),
+ Tag::ATTESTATION_ID_SECOND_IMEI => gen_params.attestation_device_second_imei(value),
+ _ => {
+ panic!("Unknown attestation id");
+ }
+ }
+}
+
+/// Generate a device unique attested key with attestation of the device's identifiers. Test should
+/// succeed in generating a attested key with attestation of device identifiers. Test might fail on
+/// devices which don't support device id attestation with error response code `CANNOT_ATTEST_IDS`.
+fn generate_device_unique_attested_key_with_device_attest_ids(
+ gen_params: authorizations::AuthSetBuilder,
+ attest_id: Tag,
+ prop_name: &str,
+) {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+ let sec_level = result.unwrap();
+
+ if attest_id == Tag::ATTESTATION_ID_SECOND_IMEI
+ && !is_second_imei_id_attestation_required(&keystore2)
+ {
+ return;
+ }
+
+ if let Some(value) = get_attest_id_value(attest_id, prop_name) {
+ if value.is_empty() {
+ return;
+ }
+ let gen_params = add_attest_id_auth(gen_params, attest_id, value.clone());
+ let alias = "ks_test_device_unique_attest_id_test";
+ match key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ )) {
+ Ok(key_metadata) => {
+ let attest_id_value = get_value_from_attest_record(
+ key_metadata.certificate.as_ref().unwrap(),
+ attest_id,
+ key_metadata.keySecurityLevel,
+ )
+ .expect("Attest id verification failed.");
+ assert_eq!(attest_id_value, value);
+ delete_app_key(&keystore2, alias).unwrap();
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+ }
+ }
+ }
+}
+
+/// Try generate a key with `DEVICE_UNIQUE_ATTESTATION` using `TRUSTED_ENVIRONMENT` security level.
+/// Test should fail to generate a key with error code `INVALID_ARGUMENT`
+#[test]
+fn keystore2_gen_key_device_unique_attest_with_default_sec_level_unimplemented() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+
+ let alias = "ks_test_auth_tags_test";
+ let result = key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Generate a EC key with `DEVICE_UNIQUE_ATTESTATION` using `STRONGBOX` security level.
+/// Test should create a key successfully, verify key characteristics, cert-chain signatures and
+/// use it for performing an operation.
+#[test]
+fn keystore2_gen_ec_key_device_unique_attest_with_strongbox_sec_level_test_success() {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+
+ let sec_level = result.unwrap();
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+
+ let alias = "ks_device_unique_ec_key_attest_test";
+ match key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ )) {
+ Ok(key_metadata) => {
+ perform_sample_asym_sign_verify_op(
+ &sec_level,
+ &key_metadata,
+ None,
+ Some(Digest::SHA_2_256),
+ );
+ delete_app_key(&keystore2, alias).unwrap();
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+ }
+ }
+}
+
+/// Generate a RSA key with `DEVICE_UNIQUE_ATTESTATION` using `STRONGBOX` security level.
+/// Test should create a key successfully, verify key characteristics, cert-chain signatures and
+/// use it for performing an operation.
+#[test]
+fn keystore2_gen_rsa_key_device_unique_attest_with_strongbox_sec_level_test_success() {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+
+ let sec_level = result.unwrap();
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::RSA)
+ .rsa_public_exponent(65537)
+ .key_size(2048)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .padding_mode(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+
+ let alias = "ks_device_unique_rsa_key_attest_test";
+ match key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ )) {
+ Ok(key_metadata) => {
+ perform_sample_asym_sign_verify_op(
+ &sec_level,
+ &key_metadata,
+ Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+ Some(Digest::SHA_2_256),
+ );
+ delete_app_key(&keystore2, alias).unwrap();
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::CANNOT_ATTEST_IDS));
+ }
+ }
+}
+
+/// Try to generate a device unique attested key with attestation of invalid device's identifiers.
+/// Test should fail with error response code `CANNOT_ATTEST_IDS`.
+#[test]
+fn keystore2_device_unique_attest_key_fails_with_invalid_attestation_id() {
+ let keystore2 = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::STRONGBOX));
+ if result.is_err() {
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+ return;
+ }
+
+ let sec_level = result.unwrap();
+ let attest_id_params = vec![
+ (Tag::ATTESTATION_ID_BRAND, b"invalid-brand".to_vec()),
+ (Tag::ATTESTATION_ID_DEVICE, b"invalid-device-name".to_vec()),
+ (Tag::ATTESTATION_ID_PRODUCT, b"invalid-product-name".to_vec()),
+ (Tag::ATTESTATION_ID_SERIAL, b"invalid-ro-serial".to_vec()),
+ (Tag::ATTESTATION_ID_MANUFACTURER, b"invalid-ro-product-manufacturer".to_vec()),
+ (Tag::ATTESTATION_ID_MODEL, b"invalid-ro-product-model".to_vec()),
+ (Tag::ATTESTATION_ID_IMEI, b"invalid-imei".to_vec()),
+ ];
+
+ for (attest_id, value) in attest_id_params {
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(b"foo".to_vec())
+ .device_unique_attestation();
+ let alias = "ks_ec_device_unique_attested_test_key_fail";
+ let gen_params = add_attest_id_auth(gen_params, attest_id, value.clone());
+
+ let result = key_generations::map_ks_error(key_generations::generate_key(
+ &sec_level,
+ &gen_params,
+ alias,
+ ));
+ assert!(result.is_err());
+ assert!(matches!(result.unwrap_err(), Error::Km(ErrorCode::CANNOT_ATTEST_IDS)));
+ }
+}
+
+// Below macros generate tests for generating device unique attested EC keys with attestation
+// of the device's identifiers.
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_brand,
+ Tag::ATTESTATION_ID_BRAND,
+ "ro.product.brand_for_attestation"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_device,
+ Tag::ATTESTATION_ID_DEVICE,
+ "ro.product.device"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_product,
+ Tag::ATTESTATION_ID_PRODUCT,
+ "ro.product.name_for_attestation"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_serial,
+ Tag::ATTESTATION_ID_SERIAL,
+ "ro.serialno"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_manufacturer,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_model,
+ Tag::ATTESTATION_ID_MODEL,
+ "ro.product.model_for_attestation"
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_imei,
+ Tag::ATTESTATION_ID_IMEI,
+ ""
+);
+test_ec_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_ecdsa_attest_id_second_imei,
+ Tag::ATTESTATION_ID_SECOND_IMEI,
+ ""
+);
+
+// Below macros generate tests for generating device unique attested RSA keys with attestation
+// of the device's identifiers.
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_brand,
+ Tag::ATTESTATION_ID_BRAND,
+ "ro.product.brand_for_attestation"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_device,
+ Tag::ATTESTATION_ID_DEVICE,
+ "ro.product.device"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_product,
+ Tag::ATTESTATION_ID_PRODUCT,
+ "ro.product.name_for_attestation"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_serial,
+ Tag::ATTESTATION_ID_SERIAL,
+ "ro.serialno"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_manufacturer,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_model,
+ Tag::ATTESTATION_ID_MODEL,
+ "ro.product.model_for_attestation"
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_imei,
+ Tag::ATTESTATION_ID_IMEI,
+ ""
+);
+test_rsa_key_device_unique_attestation_id!(
+ keystore2_device_unique_attest_rsa_attest_id_second_imei,
+ Tag::ATTESTATION_ID_SECOND_IMEI,
+ ""
+);
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index e76c64b..037482a 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -17,9 +17,11 @@
use std::process::{Command, Output};
+use openssl::bn::BigNum;
use openssl::encrypt::Encrypter;
use openssl::error::ErrorStack;
use openssl::hash::MessageDigest;
+use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::pkey::Public;
use openssl::rsa::Padding;
@@ -517,30 +519,33 @@
match attest_id {
Tag::ATTESTATION_ID_IMEI => get_imei(0),
Tag::ATTESTATION_ID_SECOND_IMEI => get_imei(1),
- Tag::ATTESTATION_ID_BRAND => {
- let prop_val = get_system_prop(prop_name);
- if prop_val.is_empty() {
- Some(get_system_prop("ro.product.brand"))
- } else {
+ Tag::ATTESTATION_ID_SERIAL => Some(get_system_prop(format!("ro.{}", prop_name).as_str())),
+ _ => {
+ let prop_val =
+ get_system_prop(format!("ro.product.{}_for_attestation", prop_name).as_str());
+ if !prop_val.is_empty() {
Some(prop_val)
+ } else {
+ let prop_val = get_system_prop(format!("ro.product.vendor.{}", prop_name).as_str());
+ if !prop_val.is_empty() {
+ Some(prop_val)
+ } else {
+ Some(get_system_prop(format!("ro.product.{}", prop_name).as_str()))
+ }
}
}
- Tag::ATTESTATION_ID_PRODUCT => {
- let prop_val = get_system_prop(prop_name);
- if prop_val.is_empty() {
- Some(get_system_prop("ro.product.name"))
- } else {
- Some(prop_val)
- }
- }
- Tag::ATTESTATION_ID_MODEL => {
- let prop_val = get_system_prop(prop_name);
- if prop_val.is_empty() {
- Some(get_system_prop("ro.product.model"))
- } else {
- Some(prop_val)
- }
- }
- _ => Some(get_system_prop(prop_name)),
}
}
+
+pub fn verify_certificate_subject_name(cert_bytes: &[u8], expected_subject: &[u8]) {
+ let cert = X509::from_der(cert_bytes).unwrap();
+ let subject = cert.subject_name();
+ let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap();
+ assert_eq!(cn.data().as_slice(), expected_subject);
+}
+
+pub fn verify_certificate_serial_num(cert_bytes: &[u8], expected_serial_num: &BigNum) {
+ let cert = X509::from_der(cert_bytes).unwrap();
+ let serial_num = cert.serial_number();
+ assert_eq!(serial_num.to_bn().as_ref().unwrap(), expected_serial_num);
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index ac7f19f..a0c140a 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -17,6 +17,7 @@
pub mod keystore2_client_attest_key_tests;
pub mod keystore2_client_authorizations_tests;
pub mod keystore2_client_delete_key_tests;
+pub mod keystore2_client_device_unique_attestation_tests;
pub mod keystore2_client_ec_key_tests;
pub mod keystore2_client_grant_key_tests;
pub mod keystore2_client_hmac_key_tests;
diff --git a/provisioner/support/test.cpp b/provisioner/support/test.cpp
index 418eab9..0e6e2f4 100644
--- a/provisioner/support/test.cpp
+++ b/provisioner/support/test.cpp
@@ -34,6 +34,10 @@
public:
virtual void SetUp() override {
auto rpcName = String16(GetParam().c_str());
+ String16 avfName = String16(IRemotelyProvisionedComponent::descriptor) + String16("/avf");
+ if (avfName == rpcName) {
+ GTEST_SKIP() << "Skipping test for avf";
+ }
rpc_ = android::waitForService<IRemotelyProvisionedComponent>(rpcName);
ASSERT_NE(rpc_, nullptr);
}