Merge "Handling `UNIMPLEMENTED` error code from deleteKey API in Keystore VTS Tests." into main
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index be2f812..ef5111f 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -50,6 +50,8 @@
"libandroid_security_flags_rust",
"libanyhow",
"libbinder_rs",
+ "libbssl_crypto",
+ "libder",
"libkeystore2_aaid-rust",
"libkeystore2_apc_compat-rust",
"libkeystore2_crypto_rust",
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index c815622..66b123e 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -1245,7 +1245,7 @@
/// types that map to a table, information about the table's storage is
/// returned. Requests for storage types that are not DB tables return None.
pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
- let _wp = wd::watch("KeystoreDB::get_storage_stat");
+ let _wp = wd::watch_millis_with("KeystoreDB::get_storage_stat", 500, storage_type);
match storage_type {
MetricsStorage::DATABASE => self.get_total_size(),
@@ -3049,4 +3049,11 @@
let app_uids_vec: Vec<i64> = app_uids_affected_by_sid.into_iter().collect();
Ok(app_uids_vec)
}
+
+ /// Retrieve a database PRAGMA config value.
+ pub fn pragma<T: FromSql>(&mut self, name: &str) -> Result<T> {
+ self.conn
+ .query_row(&format!("PRAGMA persistent.{name}"), (), |row| row.get(0))
+ .context(format!("failed to read pragma {name}"))
+ }
}
diff --git a/keystore2/src/database/tests.rs b/keystore2/src/database/tests.rs
index 381a45a..4ada694 100644
--- a/keystore2/src/database/tests.rs
+++ b/keystore2/src/database/tests.rs
@@ -2832,6 +2832,7 @@
let batch_size = crate::utils::estimate_safe_amount_to_return(
domain,
namespace,
+ None,
&keys,
crate::utils::RESPONSE_SIZE_LIMIT,
);
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 4c895ae..7b44ad7 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -19,7 +19,7 @@
use crate::error::map_km_error;
use crate::error::Error;
use crate::globals::get_keymint_device;
-use crate::globals::{DB, LEGACY_IMPORTER, SUPER_KEY};
+use crate::globals::{DB, LEGACY_IMPORTER, SUPER_KEY, ENCODED_MODULE_INFO};
use crate::ks_err;
use crate::permission::{KeyPerm, KeystorePerm};
use crate::super_key::SuperKeyManager;
@@ -28,7 +28,7 @@
check_keystore_permission, uid_to_android_user, watchdog as wd,
};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- ErrorCode::ErrorCode, IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
+ ErrorCode::ErrorCode, IKeyMintDevice::IKeyMintDevice, KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel, Tag::Tag,
};
use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::{
BnKeystoreMaintenance, IKeystoreMaintenance,
@@ -41,12 +41,37 @@
};
use android_system_keystore2::aidl::android::system::keystore2::KeyDescriptor::KeyDescriptor;
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
-use anyhow::{Context, Result};
+use anyhow::{anyhow, Context, Result};
+use bssl_crypto::digest;
+use der::{DerOrd, Encode, asn1::OctetString, asn1::SetOfVec, Sequence};
use keystore2_crypto::Password;
+use std::cmp::Ordering;
/// Reexport Domain for the benefit of DeleteListener
pub use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
+/// Version number of KeyMint V4.
+pub const KEYMINT_V4: i32 = 400;
+
+/// Module information structure for DER-encoding.
+#[derive(Sequence, Debug)]
+struct ModuleInfo {
+ name: OctetString,
+ version: i32,
+}
+
+impl DerOrd for ModuleInfo {
+ // DER mandates "encodings of the component values of a set-of value shall appear in ascending
+ // order". `der_cmp` serves as a proxy for determining that ordering (though why the `der` crate
+ // requires this is unclear). Essentially, we just need to compare the `name` lengths, and then
+ // if those are equal, the `name`s themselves. (No need to consider `version`s since there can't
+ // be more than one `ModuleInfo` with the same `name` in the set-of `ModuleInfo`s.) We rely on
+ // `OctetString`'s `der_cmp` to do the aforementioned comparison.
+ fn der_cmp(&self, other: &Self) -> std::result::Result<Ordering, der::Error> {
+ self.name.der_cmp(&other.name)
+ }
+}
+
/// The Maintenance module takes a delete listener argument which observes user and namespace
/// deletion events.
pub trait DeleteListener {
@@ -139,19 +164,35 @@
.context(ks_err!("While invoking the delete listener."))
}
- fn call_with_watchdog<F>(sec_level: SecurityLevel, name: &'static str, op: &F) -> Result<()>
+ fn call_with_watchdog<F>(
+ sec_level: SecurityLevel,
+ name: &'static str,
+ op: &F,
+ min_version: Option<i32>,
+ ) -> Result<()>
where
F: Fn(Strong<dyn IKeyMintDevice>) -> binder::Result<()>,
{
- let (km_dev, _, _) =
+ let (km_dev, hw_info, _) =
get_keymint_device(&sec_level).context(ks_err!("getting keymint device"))?;
+ if let Some(min_version) = min_version {
+ if hw_info.versionNumber < min_version {
+ log::info!("skipping {name} for {sec_level:?} since its keymint version {} is less than the minimum required version {min_version}", hw_info.versionNumber);
+ return Ok(());
+ }
+ }
+
let _wp = wd::watch_millis_with("Maintenance::call_with_watchdog", 500, (sec_level, name));
map_km_error(op(km_dev)).with_context(|| ks_err!("calling {}", name))?;
Ok(())
}
- fn call_on_all_security_levels<F>(name: &'static str, op: F) -> Result<()>
+ fn call_on_all_security_levels<F>(
+ name: &'static str,
+ op: F,
+ min_version: Option<i32>,
+ ) -> Result<()>
where
F: Fn(Strong<dyn IKeyMintDevice>) -> binder::Result<()>,
{
@@ -160,7 +201,7 @@
(SecurityLevel::STRONGBOX, "STRONGBOX"),
];
sec_levels.iter().try_fold((), |_result, (sec_level, sec_level_string)| {
- let curr_result = Maintenance::call_with_watchdog(*sec_level, name, &op);
+ let curr_result = Maintenance::call_with_watchdog(*sec_level, name, &op, min_version);
match curr_result {
Ok(()) => log::info!(
"Call to {} succeeded for security level {}.",
@@ -197,7 +238,8 @@
{
log::error!("SUPER_KEY.set_up_boot_level_cache failed:\n{:?}\n:(", e);
}
- Maintenance::call_on_all_security_levels("earlyBootEnded", |dev| dev.earlyBootEnded())
+
+ Maintenance::call_on_all_security_levels("earlyBootEnded", |dev| dev.earlyBootEnded(), None)
}
fn migrate_key_namespace(source: &KeyDescriptor, destination: &KeyDescriptor) -> Result<()> {
@@ -253,7 +295,7 @@
.context(ks_err!("Checking permission"))?;
log::info!("In delete_all_keys.");
- Maintenance::call_on_all_security_levels("deleteAllKeys", |dev| dev.deleteAllKeys())
+ Maintenance::call_on_all_security_levels("deleteAllKeys", |dev| dev.deleteAllKeys(), None)
}
fn get_app_uids_affected_by_sid(
@@ -309,6 +351,34 @@
}
writeln!(f)?;
+ // Display database config information.
+ writeln!(f, "Database configuration:")?;
+ DB.with(|db| -> std::io::Result<()> {
+ let pragma_str = |f: &mut dyn std::io::Write, name| -> std::io::Result<()> {
+ let mut db = db.borrow_mut();
+ let value: String = db
+ .pragma(name)
+ .unwrap_or_else(|e| format!("unknown value for '{name}', failed: {e:?}"));
+ writeln!(f, " {name} = {value}")
+ };
+ let pragma_i32 = |f: &mut dyn std::io::Write, name| -> std::io::Result<()> {
+ let mut db = db.borrow_mut();
+ let value: i32 = db.pragma(name).unwrap_or_else(|e| {
+ log::error!("unknown value for '{name}', failed: {e:?}");
+ -1
+ });
+ writeln!(f, " {name} = {value}")
+ };
+ pragma_i32(f, "auto_vacuum")?;
+ pragma_str(f, "journal_mode")?;
+ pragma_i32(f, "journal_size_limit")?;
+ pragma_i32(f, "synchronous")?;
+ pragma_i32(f, "schema_version")?;
+ pragma_i32(f, "user_version")?;
+ Ok(())
+ })?;
+ writeln!(f)?;
+
// Display accumulated metrics.
writeln!(f, "Metrics information:")?;
writeln!(f)?;
@@ -320,6 +390,44 @@
Ok(())
}
+
+ #[allow(dead_code)]
+ fn set_module_info(module_info: Vec<ModuleInfo>) -> Result<()> {
+ let encoding = Self::encode_module_info(module_info)
+ .map_err(|e| anyhow!({ e }))
+ .context(ks_err!("Failed to encode module_info"))?;
+ let hash = digest::Sha256::hash(&encoding).to_vec();
+
+ {
+ let mut saved = ENCODED_MODULE_INFO.write().unwrap();
+ if let Some(saved_encoding) = &*saved {
+ if *saved_encoding == encoding {
+ log::warn!(
+ "Module info already set, ignoring repeated attempt to set same info."
+ );
+ return Ok(());
+ }
+ return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(ks_err!(
+ "Failed to set module info as it is already set to a different value."
+ ));
+ }
+ *saved = Some(encoding);
+ }
+
+ let kps =
+ vec![KeyParameter { tag: Tag::MODULE_HASH, value: KeyParameterValue::Blob(hash) }];
+
+ Maintenance::call_on_all_security_levels(
+ "setAdditionalAttestationInfo",
+ |dev| dev.setAdditionalAttestationInfo(&kps),
+ Some(KEYMINT_V4),
+ )
+ }
+
+ #[allow(dead_code)]
+ fn encode_module_info(module_info: Vec<ModuleInfo>) -> Result<Vec<u8>, der::Error> {
+ SetOfVec::<ModuleInfo>::from_iter(module_info.into_iter())?.to_der()
+ }
}
impl Interface for Maintenance {
diff --git a/keystore2/src/metrics.rs b/keystore2/src/metrics.rs
index 4757739..b884809 100644
--- a/keystore2/src/metrics.rs
+++ b/keystore2/src/metrics.rs
@@ -51,7 +51,7 @@
impl IKeystoreMetrics for Metrics {
fn pullMetrics(&self, atom_id: AtomID) -> BinderResult<Vec<KeystoreAtom>> {
- let _wp = wd::watch("IKeystoreMetrics::pullMetrics");
+ let _wp = wd::watch_millis_with("IKeystoreMetrics::pullMetrics", 500, atom_id);
self.pull_metrics(atom_id).map_err(into_logged_binder)
}
}
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
index 7149d12..fd1f9b5 100644
--- a/keystore2/src/metrics_store.rs
+++ b/keystore2/src/metrics_store.rs
@@ -22,6 +22,7 @@
use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
use crate::ks_err;
use crate::operation::Outcome;
+use crate::utils::watchdog as wd;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
@@ -104,11 +105,13 @@
// StorageStats is an original pulled atom (i.e. not a pushed atom converted to a
// pulled atom). Therefore, it is handled separately.
if AtomID::STORAGE_STATS == atom_id {
+ let _wp = wd::watch("MetricsStore::get_atoms calling pull_storage_stats");
return pull_storage_stats();
}
// Process keystore crash stats.
if AtomID::CRASH_STATS == atom_id {
+ let _wp = wd::watch("MetricsStore::get_atoms calling read_keystore_crash_count");
return match read_keystore_crash_count()? {
Some(count) => Ok(vec![KeystoreAtom {
payload: KeystoreAtomPayload::CrashStats(CrashStats {
@@ -120,8 +123,6 @@
};
}
- // It is safe to call unwrap here since the lock can not be poisoned based on its usage
- // in this module and the lock is not acquired in the same thread before.
let metrics_store_guard = self.metrics_store.lock().unwrap();
metrics_store_guard.get(&atom_id).map_or(Ok(Vec::<KeystoreAtom>::new()), |atom_count_map| {
Ok(atom_count_map
@@ -133,8 +134,6 @@
/// Insert an atom object to the metrics_store indexed by the atom ID.
fn insert_atom(&self, atom_id: AtomID, atom: KeystoreAtomPayload) {
- // It is ok to unwrap here since the mutex cannot be poisoned according to the way it is
- // used in this module. And the lock is not acquired by this thread before.
let mut metrics_store_guard = self.metrics_store.lock().unwrap();
let atom_count_map = metrics_store_guard.entry(atom_id).or_default();
if atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 9ae8ccf..c11c1f4 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -308,9 +308,8 @@
locked_outcome: &mut Outcome,
err: Result<T, Error>,
) -> Result<T, Error> {
- match &err {
- Err(e) => *locked_outcome = Outcome::ErrorCode(error_to_serialized_error(e)),
- Ok(_) => (),
+ if let Err(e) = &err {
+ *locked_outcome = Outcome::ErrorCode(error_to_serialized_error(e))
}
err
}
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index c6dc11e..35290df 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -541,39 +541,40 @@
pub(crate) fn estimate_safe_amount_to_return(
domain: Domain,
namespace: i64,
+ start_past_alias: Option<&str>,
key_descriptors: &[KeyDescriptor],
response_size_limit: usize,
) -> usize {
- let mut items_to_return = 0;
- let mut returned_bytes: usize = 0;
+ let mut count = 0;
+ let mut bytes: usize = 0;
// Estimate the transaction size to avoid returning more items than what
// could fit in a binder transaction.
for kd in key_descriptors.iter() {
// 4 bytes for the Domain enum
// 8 bytes for the Namespace long.
- returned_bytes += 4 + 8;
+ bytes += 4 + 8;
// Size of the alias string. Includes 4 bytes for length encoding.
if let Some(alias) = &kd.alias {
- returned_bytes += 4 + alias.len();
+ bytes += 4 + alias.len();
}
// Size of the blob. Includes 4 bytes for length encoding.
if let Some(blob) = &kd.blob {
- returned_bytes += 4 + blob.len();
+ bytes += 4 + blob.len();
}
// The binder transaction size limit is 1M. Empirical measurements show
// that the binder overhead is 60% (to be confirmed). So break after
// 350KB and return a partial list.
- if returned_bytes > response_size_limit {
+ if bytes > response_size_limit {
log::warn!(
- "{domain:?}:{namespace}: Key descriptors list ({} items) may exceed binder \
- size, returning {items_to_return} items est {returned_bytes} bytes.",
+ "{domain:?}:{namespace}: Key descriptors list ({} items after {start_past_alias:?}) \
+ may exceed binder size, returning {count} items est. {bytes} bytes",
key_descriptors.len(),
);
break;
}
- items_to_return += 1;
+ count += 1;
}
- items_to_return
+ count
}
/// Estimate for maximum size of a Binder response in bytes.
@@ -602,8 +603,13 @@
start_past_alias,
);
- let safe_amount_to_return =
- estimate_safe_amount_to_return(domain, namespace, &merged_key_entries, RESPONSE_SIZE_LIMIT);
+ let safe_amount_to_return = estimate_safe_amount_to_return(
+ domain,
+ namespace,
+ start_past_alias,
+ &merged_key_entries,
+ RESPONSE_SIZE_LIMIT,
+ );
Ok(merged_key_entries[..safe_amount_to_return].to_vec())
}
diff --git a/keystore2/src/utils/tests.rs b/keystore2/src/utils/tests.rs
index 618ea47..e514b2a 100644
--- a/keystore2/src/utils/tests.rs
+++ b/keystore2/src/utils/tests.rs
@@ -53,9 +53,9 @@
let key_aliases = vec!["key1", "key2", "key3"];
let key_descriptors = create_key_descriptors_from_aliases(&key_aliases);
- assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 20), 1);
- assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 50), 2);
- assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, &key_descriptors, 100), 3);
+ assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, None, &key_descriptors, 20), 1);
+ assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, None, &key_descriptors, 50), 2);
+ assert_eq!(estimate_safe_amount_to_return(Domain::APP, 1017, None, &key_descriptors, 100), 3);
Ok(())
}
diff --git a/keystore2/tests/user_auth.rs b/keystore2/tests/user_auth.rs
index 187256b..789f54b 100644
--- a/keystore2/tests/user_auth.rs
+++ b/keystore2/tests/user_auth.rs
@@ -14,7 +14,9 @@
//! Tests for user authentication interactions (via `IKeystoreAuthorization`).
-use crate::keystore2_client_test_utils::{BarrierReached, BarrierReachedWithData};
+use crate::keystore2_client_test_utils::{
+ BarrierReached, BarrierReachedWithData, get_vsr_api_level
+};
use android_security_authorization::aidl::android::security::authorization::{
IKeystoreAuthorization::IKeystoreAuthorization
};
@@ -59,12 +61,13 @@
];
/// Gatekeeper password.
static GK_PASSWORD: &[u8] = b"correcthorsebatterystaple";
-/// Fake SID value corresponding to Gatekeeper.
-static GK_FAKE_SID: i64 = 123456;
-/// Fake SID value corresponding to a biometric authenticator.
-static BIO_FAKE_SID1: i64 = 345678;
-/// Fake SID value corresponding to a biometric authenticator.
-static BIO_FAKE_SID2: i64 = 456789;
+/// Fake SID base value corresponding to Gatekeeper. Individual tests use different SIDs to reduce
+/// the chances of cross-contamination, calculated statically (because each test is forked into a
+/// separate process).
+static GK_FAKE_SID_BASE: i64 = 123400;
+/// Fake SID base value corresponding to a biometric authenticator. Individual tests use different
+/// SIDs to reduce the chances of cross-contamination.
+static BIO_FAKE_SID_BASE: i64 = 345600;
const WEAK_UNLOCK_ENABLED: bool = true;
const WEAK_UNLOCK_DISABLED: bool = false;
@@ -171,6 +174,8 @@
#[test]
fn test_auth_bound_timeout_with_gk() {
+ let bio_fake_sid1 = BIO_FAKE_SID_BASE + 1;
+ let bio_fake_sid2 = BIO_FAKE_SID_BASE + 2;
type Barrier = BarrierReachedWithData<Option<i64>>;
android_logger::init_once(
android_logger::Config::default()
@@ -199,8 +204,8 @@
ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
let params = AuthSetBuilder::new()
.user_secure_id(gk_sid)
- .user_secure_id(BIO_FAKE_SID1)
- .user_secure_id(BIO_FAKE_SID2)
+ .user_secure_id(bio_fake_sid1)
+ .user_secure_id(bio_fake_sid2)
.user_auth_type(HardwareAuthenticatorType::ANY)
.auth_timeout(3)
.algorithm(Algorithm::EC)
@@ -214,7 +219,7 @@
&KeyDescriptor {
domain: Domain::APP,
nspace: -1,
- alias: Some("auth-bound-timeout".to_string()),
+ alias: Some("auth-bound-timeout-1".to_string()),
blob: None,
},
None,
@@ -223,7 +228,7 @@
b"entropy",
)
.context("key generation failed")?;
- info!("A: created auth-timeout key {key:?}");
+ info!("A: created auth-timeout key {key:?} bound to sids {gk_sid}, {bio_fake_sid1}, {bio_fake_sid2}");
// No HATs so cannot create an operation using the key.
let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
@@ -279,7 +284,7 @@
// Lock and unlock to ensure super keys are already created.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_DISABLED)
.unwrap();
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
@@ -304,6 +309,9 @@
#[test]
fn test_auth_bound_timeout_failure() {
+ let gk_fake_sid = GK_FAKE_SID_BASE + 1;
+ let bio_fake_sid1 = BIO_FAKE_SID_BASE + 3;
+ let bio_fake_sid2 = BIO_FAKE_SID_BASE + 4;
android_logger::init_once(
android_logger::Config::default()
.with_tag("keystore2_client_tests")
@@ -323,8 +331,8 @@
let sec_level =
ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
let params = AuthSetBuilder::new()
- .user_secure_id(BIO_FAKE_SID1)
- .user_secure_id(BIO_FAKE_SID2)
+ .user_secure_id(bio_fake_sid1)
+ .user_secure_id(bio_fake_sid2)
.user_auth_type(HardwareAuthenticatorType::ANY)
.auth_timeout(3)
.algorithm(Algorithm::EC)
@@ -338,7 +346,7 @@
&KeyDescriptor {
domain: Domain::APP,
nspace: -1,
- alias: Some("auth-bound-timeout".to_string()),
+ alias: Some("auth-bound-timeout-2".to_string()),
blob: None,
},
None,
@@ -347,7 +355,7 @@
b"entropy",
)
.context("key generation failed")?;
- info!("A: created auth-timeout key {key:?}");
+ info!("A: created auth-timeout key {key:?} bound to sids {bio_fake_sid1}, {bio_fake_sid2}");
// No HATs so cannot create an operation using the key.
let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
@@ -361,7 +369,12 @@
reader.recv();
let result = sec_level.createOperation(&key, ¶ms, UNFORCED);
- expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
+ expect!(result.is_err());
+ if get_vsr_api_level() >= 35 {
+ // Older devices may report an incorrect error code when presented with an invalid auth
+ // token.
+ expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
+ }
info!("B: failed auth-bound operation (HAT is invalid) as expected {result:?}");
writer.send(&BarrierReached {}); // B done.
@@ -395,10 +408,10 @@
// Lock and unlock to ensure super keys are already created.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_DISABLED)
.unwrap();
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
- auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
+ auth_service.addAuthToken(&fake_lskf_token(gk_fake_sid)).unwrap();
info!("trigger child process action A and wait for completion");
child_handle.send(&BarrierReached {});
@@ -406,7 +419,7 @@
// Unlock with password and a fake auth token that matches the key
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
- auth_service.addAuthToken(&fake_bio_lskf_token(GK_FAKE_SID, BIO_FAKE_SID1)).unwrap();
+ auth_service.addAuthToken(&fake_bio_lskf_token(gk_fake_sid, bio_fake_sid1)).unwrap();
info!("trigger child process action B and wait for completion");
child_handle.send(&BarrierReached {});
@@ -421,6 +434,8 @@
#[test]
fn test_auth_bound_per_op_with_gk() {
+ let bio_fake_sid1 = BIO_FAKE_SID_BASE + 5;
+ let bio_fake_sid2 = BIO_FAKE_SID_BASE + 6;
type Barrier = BarrierReachedWithData<Option<i64>>;
android_logger::init_once(
android_logger::Config::default()
@@ -449,7 +464,7 @@
ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
let params = AuthSetBuilder::new()
.user_secure_id(gk_sid)
- .user_secure_id(BIO_FAKE_SID1)
+ .user_secure_id(bio_fake_sid1)
.user_auth_type(HardwareAuthenticatorType::ANY)
.algorithm(Algorithm::EC)
.purpose(KeyPurpose::SIGN)
@@ -462,7 +477,7 @@
&KeyDescriptor {
domain: Domain::APP,
nspace: -1,
- alias: Some("auth-per-op".to_string()),
+ alias: Some("auth-per-op-1".to_string()),
blob: None,
},
None,
@@ -471,7 +486,7 @@
b"entropy",
)
.context("key generation failed")?;
- info!("A: created auth-per-op key {key:?}");
+ info!("A: created auth-per-op key {key:?} bound to sids {gk_sid}, {bio_fake_sid1}");
// We can create an operation using the key...
let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
@@ -530,7 +545,7 @@
// Lock and unlock to ensure super keys are already created.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_DISABLED)
.unwrap();
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
@@ -554,8 +569,10 @@
}
#[test]
-fn test_auth_bound_per_op_failure() {
- type Barrier = BarrierReachedWithData<i64>;
+fn test_auth_bound_per_op_with_gk_failure() {
+ let bio_fake_sid1 = BIO_FAKE_SID_BASE + 7;
+ let bio_fake_sid2 = BIO_FAKE_SID_BASE + 8;
+ type Barrier = BarrierReachedWithData<Option<i64>>;
android_logger::init_once(
android_logger::Config::default()
.with_tag("keystore2_client_tests")
@@ -566,17 +583,24 @@
writer: &mut ChannelWriter<Barrier>|
-> Result<(), run_as::Error> {
// Now we're in a new process, wait to be notified before starting.
- reader.recv();
+ let gk_sid: i64 = match reader.recv().0 {
+ Some(sid) => sid,
+ None => {
+ // There is no AIDL Gatekeeper available, so abandon the test. It would be nice to
+ // know this before starting the child process, but finding it out requires Binder,
+ // which can't be used until after the child has forked.
+ return Ok(());
+ }
+ };
// Action A: create a new auth-bound key which requires auth-per-operation (because
// AUTH_TIMEOUT is not specified), and fail to finish an operation using it.
let ks2 = get_keystore_service();
-
let sec_level =
ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
let params = AuthSetBuilder::new()
- .user_secure_id(GK_FAKE_SID)
- .user_secure_id(BIO_FAKE_SID1)
+ .user_secure_id(gk_sid)
+ .user_secure_id(bio_fake_sid1)
.user_auth_type(HardwareAuthenticatorType::ANY)
.algorithm(Algorithm::EC)
.purpose(KeyPurpose::SIGN)
@@ -589,7 +613,7 @@
&KeyDescriptor {
domain: Domain::APP,
nspace: -1,
- alias: Some("auth-per-op".to_string()),
+ alias: Some("auth-per-op-2".to_string()),
blob: None,
},
None,
@@ -598,7 +622,7 @@
b"entropy",
)
.context("key generation failed")?;
- info!("A: created auth-per-op key {key:?}");
+ info!("A: created auth-per-op key {key:?} bound to sids {gk_sid}, {bio_fake_sid1}");
// We can create an operation using the key...
let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
@@ -613,7 +637,7 @@
expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
info!("A: failed auth-per-op op (no HAT) as expected {result:?}");
- writer.send(&Barrier::new(0)); // A done.
+ writer.send(&Barrier::new(None)); // A done.
// Action B: fail again when an irrelevant HAT is available.
reader.recv();
@@ -629,7 +653,7 @@
expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
info!("B: failed auth-per-op op (HAT is not per-op) as expected {result:?}");
- writer.send(&Barrier::new(0)); // B done.
+ writer.send(&Barrier::new(None)); // B done.
// Action C: start an operation and pass out the challenge
reader.recv();
@@ -638,7 +662,7 @@
.expect("failed to create auth-per-op operation");
let op = result.iOperation.context("no operation in result")?;
info!("C: created auth-per-op operation, got challenge {:?}", result.operationChallenge);
- writer.send(&Barrier::new(result.operationChallenge.unwrap().challenge)); // C done.
+ writer.send(&Barrier::new(Some(result.operationChallenge.unwrap().challenge))); // C done.
// Action D: finishing the operation still fails because the per-op HAT
// is invalid (the HMAC signature is faked and so the secure world
@@ -647,7 +671,7 @@
let result = op.finish(Some(b"data"), None);
expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
info!("D: failed auth-per-op op (HAT is per-op but invalid) as expected {result:?}");
- writer.send(&Barrier::new(0)); // D done.
+ writer.send(&Barrier::new(None)); // D done.
Ok(())
};
@@ -664,37 +688,43 @@
// user.
let _ks2 = get_keystore_service();
let user = TestUser::new();
+ if user.gk.is_none() {
+ // Can't run this test if there's no AIDL Gatekeeper.
+ child_handle.send(&Barrier::new(None));
+ assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
+ return;
+ }
let user_id = user.id;
let auth_service = get_authorization();
// Lock and unlock to ensure super keys are already created.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_DISABLED)
.unwrap();
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
- auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
info!("trigger child process action A and wait for completion");
- child_handle.send(&Barrier::new(0));
+ let gk_sid = user.gk_sid.unwrap();
+ child_handle.send(&Barrier::new(Some(gk_sid)));
child_handle.recv_or_die();
// Unlock with password and a fake auth token.
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
- auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
+ auth_service.addAuthToken(&fake_lskf_token(gk_sid)).unwrap();
info!("trigger child process action B and wait for completion");
- child_handle.send(&Barrier::new(0));
+ child_handle.send(&Barrier::new(None));
child_handle.recv_or_die();
info!("trigger child process action C and wait for completion");
- child_handle.send(&Barrier::new(0));
- let challenge = child_handle.recv_or_die().0;
+ child_handle.send(&Barrier::new(None));
+ let challenge = child_handle.recv_or_die().0.expect("no challenge");
// Add a fake auth token with the challenge value.
- auth_service.addAuthToken(&fake_lskf_token_with_challenge(GK_FAKE_SID, challenge)).unwrap();
+ auth_service.addAuthToken(&fake_lskf_token_with_challenge(gk_sid, challenge)).unwrap();
info!("trigger child process action D and wait for completion");
- child_handle.send(&Barrier::new(0));
+ child_handle.send(&Barrier::new(None));
child_handle.recv_or_die();
assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
@@ -702,6 +732,9 @@
#[test]
fn test_unlocked_device_required() {
+ let gk_fake_sid = GK_FAKE_SID_BASE + 3;
+ let bio_fake_sid1 = BIO_FAKE_SID_BASE + 9;
+ let bio_fake_sid2 = BIO_FAKE_SID_BASE + 10;
android_logger::init_once(
android_logger::Config::default()
.with_tag("keystore2_client_tests")
@@ -804,10 +837,10 @@
// Lock and unlock to ensure super keys are already created.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_DISABLED)
.unwrap();
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
- auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
+ auth_service.addAuthToken(&fake_lskf_token(gk_fake_sid)).unwrap();
info!("trigger child process action A while unlocked and wait for completion");
child_handle.send(&BarrierReached {});
@@ -815,7 +848,7 @@
// Move to locked and don't allow weak unlock, so super keys are wiped.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_DISABLED)
.unwrap();
info!("trigger child process action B while locked and wait for completion");
@@ -824,7 +857,7 @@
// Unlock with password => loads super key from database.
auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
- auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
+ auth_service.addAuthToken(&fake_lskf_token(gk_fake_sid)).unwrap();
info!("trigger child process action C while lskf-unlocked and wait for completion");
child_handle.send(&BarrierReached {});
@@ -832,7 +865,7 @@
// Move to locked and allow weak unlock, then do a weak unlock.
auth_service
- .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_ENABLED)
+ .onDeviceLocked(user_id, &[bio_fake_sid1, bio_fake_sid2], WEAK_UNLOCK_ENABLED)
.unwrap();
auth_service.onDeviceUnlocked(user_id, None).unwrap();
@@ -866,7 +899,7 @@
challenge: 0,
userId: gk_sid,
authenticatorId: bio_sid,
- authenticatorType: HardwareAuthenticatorType::PASSWORD,
+ authenticatorType: HardwareAuthenticatorType::FINGERPRINT,
timestamp: Timestamp { milliSeconds: 123 },
mac: vec![1, 2, 3],
}
diff --git a/provisioner/rkp_factory_extraction_lib_test.cpp b/provisioner/rkp_factory_extraction_lib_test.cpp
index 9bfb25e..e21ef93 100644
--- a/provisioner/rkp_factory_extraction_lib_test.cpp
+++ b/provisioner/rkp_factory_extraction_lib_test.cpp
@@ -61,6 +61,77 @@
} // namespace cppbor
+inline const std::vector<uint8_t> kCsrWithoutUdsCerts{
+ 0x85, 0x01, 0xa0, 0x82, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xb8, 0x36,
+ 0xbb, 0x1e, 0x07, 0x85, 0x02, 0xde, 0xdb, 0x91, 0x38, 0x5d, 0xc7, 0xf8, 0x59, 0xa9, 0x4f, 0x50,
+ 0xee, 0x2a, 0x3f, 0xa5, 0x5f, 0xaa, 0xa1, 0x8e, 0x46, 0x84, 0xb8, 0x3b, 0x4b, 0x6d, 0x22, 0x58,
+ 0x20, 0xa1, 0xc1, 0xd8, 0xa5, 0x9d, 0x1b, 0xce, 0x8c, 0x65, 0x10, 0x8d, 0xcf, 0xa1, 0xf4, 0x91,
+ 0x10, 0x09, 0xfb, 0xb0, 0xc5, 0xb4, 0x01, 0x75, 0x72, 0xb4, 0x44, 0xaa, 0x23, 0x13, 0xe1, 0xe9,
+ 0xe5, 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x01, 0x04, 0xa9, 0x01, 0x66, 0x69, 0x73, 0x73,
+ 0x75, 0x65, 0x72, 0x02, 0x67, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x00, 0x47, 0x44,
+ 0x50, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20, 0xb8, 0x96, 0x54, 0xe2, 0x2c, 0xa4,
+ 0xd2, 0x4a, 0x9c, 0x0e, 0x45, 0x11, 0xc8, 0xf2, 0x63, 0xf0, 0x66, 0x0d, 0x2e, 0x20, 0x48, 0x96,
+ 0x90, 0x14, 0xf4, 0x54, 0x63, 0xc4, 0xf4, 0x39, 0x30, 0x38, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x55,
+ 0xa1, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
+ 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x3a, 0x00, 0x47, 0x44,
+ 0x56, 0x41, 0x01, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20,
+ 0x01, 0x21, 0x58, 0x20, 0x91, 0xdc, 0x49, 0x60, 0x0d, 0x22, 0xf6, 0x28, 0x14, 0xaf, 0xab, 0xa5,
+ 0x9d, 0x4f, 0x26, 0xac, 0xf9, 0x99, 0xe7, 0xe1, 0xc9, 0xb7, 0x5d, 0x36, 0x21, 0x9d, 0x00, 0x47,
+ 0x63, 0x28, 0x79, 0xa7, 0x22, 0x58, 0x20, 0x13, 0x77, 0x51, 0x7f, 0x6a, 0xca, 0xa0, 0x50, 0x79,
+ 0x52, 0xb4, 0x6b, 0xd9, 0xb1, 0x3a, 0x1c, 0x9f, 0x91, 0x97, 0x60, 0xc1, 0x4b, 0x43, 0x5e, 0x45,
+ 0xd3, 0x0b, 0xa4, 0xbb, 0xc7, 0x27, 0x39, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40,
+ 0x88, 0xbd, 0xf9, 0x82, 0x04, 0xfe, 0xa6, 0xfe, 0x82, 0x94, 0xa3, 0xe9, 0x10, 0x91, 0xb5, 0x2e,
+ 0xa1, 0x62, 0x68, 0xa5, 0x3d, 0xab, 0xdb, 0xa5, 0x87, 0x2a, 0x97, 0x26, 0xb8, 0xd4, 0x60, 0x1a,
+ 0xf1, 0x3a, 0x45, 0x72, 0x77, 0xd4, 0xeb, 0x2b, 0xa4, 0x48, 0x93, 0xba, 0xae, 0x79, 0x35, 0x57,
+ 0x66, 0x54, 0x9d, 0x8e, 0xbd, 0xb0, 0x87, 0x5f, 0x8c, 0xf9, 0x04, 0xa3, 0xa7, 0x00, 0xf1, 0x21,
+ 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x59, 0x02, 0x0f, 0x82, 0x58, 0x20, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x59, 0x01, 0xe9, 0x84,
+ 0x03, 0x67, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0xae, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64,
+ 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x01, 0x65, 0x6d,
+ 0x6f, 0x64, 0x65, 0x6c, 0x65, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63,
+ 0x65, 0x66, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x67, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74,
+ 0x65, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x68, 0x76, 0x62, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x65,
+ 0x67, 0x72, 0x65, 0x65, 0x6e, 0x6a, 0x6f, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x62, 0x31, 0x32, 0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72,
+ 0x66, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x6d, 0x76, 0x62, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x64,
+ 0x69, 0x67, 0x65, 0x73, 0x74, 0x4f, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+ 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6c,
+ 0x65, 0x76, 0x65, 0x6c, 0x63, 0x74, 0x65, 0x65, 0x70, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x61,
+ 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x62, 0x70, 0x62,
+ 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x66,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x72, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x70, 0x61,
+ 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x61, 0x72, 0x76,
+ 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6c, 0x65, 0x76, 0x65,
+ 0x6c, 0x1a, 0x01, 0x34, 0x8c, 0x63, 0x82, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58,
+ 0x20, 0x85, 0xcd, 0xd8, 0x8c, 0x35, 0x50, 0x11, 0x9c, 0x44, 0x24, 0xa7, 0xf1, 0xbf, 0x75, 0x6e,
+ 0x7c, 0xab, 0x8c, 0x86, 0xfa, 0x23, 0x95, 0x2c, 0x11, 0xaf, 0xf9, 0x52, 0x80, 0x8f, 0x45, 0x43,
+ 0x40, 0x22, 0x58, 0x20, 0xec, 0x4e, 0x0d, 0x5a, 0x81, 0xe8, 0x06, 0x12, 0x18, 0xa8, 0x10, 0x74,
+ 0x6e, 0x56, 0x33, 0x11, 0x7d, 0x74, 0xff, 0x49, 0xf7, 0x38, 0x32, 0xda, 0xf4, 0x60, 0xaa, 0x19,
+ 0x64, 0x29, 0x58, 0xbe, 0x23, 0x58, 0x21, 0x00, 0xa6, 0xd1, 0x85, 0xdb, 0x8b, 0x15, 0x84, 0xde,
+ 0x34, 0xf2, 0xe3, 0xee, 0x73, 0x8b, 0x85, 0x57, 0xc1, 0xa3, 0x5d, 0x3f, 0x95, 0x14, 0xd3, 0x74,
+ 0xfc, 0x73, 0x51, 0x7f, 0xe7, 0x1b, 0x30, 0xbb, 0xa6, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
+ 0x58, 0x20, 0x96, 0x6c, 0x16, 0x6c, 0x4c, 0xa7, 0x73, 0x64, 0x9a, 0x34, 0x88, 0x75, 0xf4, 0xdc,
+ 0xf3, 0x93, 0xb2, 0xf1, 0xd7, 0xfd, 0xe3, 0x11, 0xcf, 0x6b, 0xee, 0x26, 0xa4, 0xc5, 0xeb, 0xa5,
+ 0x33, 0x24, 0x22, 0x58, 0x20, 0xe0, 0x33, 0xe8, 0x53, 0xb2, 0x65, 0x1e, 0x33, 0x2a, 0x61, 0x9a,
+ 0x7a, 0xf4, 0x5f, 0x40, 0x0f, 0x80, 0x4a, 0x38, 0xff, 0x5d, 0x3c, 0xa3, 0x82, 0x36, 0x1e, 0x9d,
+ 0x93, 0xd9, 0x48, 0xaa, 0x0a, 0x23, 0x58, 0x20, 0x5e, 0xe5, 0x8f, 0x9a, 0x8c, 0xd3, 0xf4, 0xc0,
+ 0xf7, 0x08, 0x27, 0x5f, 0x8f, 0x77, 0x12, 0x36, 0x7b, 0x6d, 0xf7, 0x65, 0xd4, 0xcc, 0x63, 0xdc,
+ 0x28, 0x35, 0x33, 0x27, 0x5d, 0x28, 0xc9, 0x9d, 0x58, 0x40, 0x6c, 0xfa, 0xc9, 0xc0, 0xdf, 0x0e,
+ 0xe4, 0x17, 0x58, 0x06, 0xea, 0xf9, 0x88, 0x9e, 0x27, 0xa0, 0x89, 0x17, 0xa8, 0x1a, 0xe6, 0x0c,
+ 0x5e, 0x85, 0xa1, 0x13, 0x20, 0x86, 0x14, 0x2e, 0xd6, 0xae, 0xfb, 0xc1, 0xb6, 0x59, 0x66, 0x83,
+ 0xd2, 0xf4, 0xc8, 0x7a, 0x30, 0x0c, 0x6b, 0x53, 0x8b, 0x76, 0x06, 0xcb, 0x1b, 0x0f, 0xc3, 0x51,
+ 0x71, 0x52, 0xd1, 0xe3, 0x2a, 0xbc, 0x53, 0x16, 0x46, 0x49, 0xa1, 0x6b, 0x66, 0x69, 0x6e, 0x67,
+ 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x78, 0x3b, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x31, 0x2f,
+ 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x31, 0x2f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x31,
+ 0x3a, 0x31, 0x31, 0x2f, 0x69, 0x64, 0x2f, 0x32, 0x30, 0x32, 0x31, 0x30, 0x38, 0x30, 0x35, 0x2e,
+ 0x34, 0x32, 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2d,
+ 0x6b, 0x65, 0x79, 0x73};
+
std::string toBase64(const std::vector<uint8_t>& buffer) {
size_t base64Length;
int rc = EVP_EncodedLength(&base64Length, buffer.size());
@@ -184,7 +255,7 @@
std::vector<uint8_t> eekChain;
std::vector<uint8_t> challenge;
- // Set up mock, then call getSCsr
+ // Set up mock, then call getCsr
auto mockRpc = SharedRefBase::make<MockIRemotelyProvisionedComponent>();
EXPECT_CALL(*mockRpc, getHardwareInfo(NotNull())).WillRepeatedly([](RpcHardwareInfo* hwInfo) {
hwInfo->versionNumber = 2;
@@ -295,12 +366,7 @@
}
TEST(LibRkpFactoryExtractionTests, requireUdsCerts) {
- const std::vector<uint8_t> kCsr = Array()
- .add(1 /* version */)
- .add(Map() /* UdsCerts */)
- .add(Array() /* DiceCertChain */)
- .add(Array() /* SignedData */)
- .encode();
+ const std::vector<uint8_t> csrEncoded = kCsrWithoutUdsCerts;
std::vector<uint8_t> challenge;
// Set up mock, then call getCsr
@@ -313,23 +379,18 @@
generateCertificateRequestV2(IsEmpty(), // keysToSign
_, // challenge
NotNull())) // _aidl_return
- .WillOnce(DoAll(SaveArg<1>(&challenge), SetArgPointee<2>(kCsr),
+ .WillOnce(DoAll(SaveArg<1>(&challenge), SetArgPointee<2>(csrEncoded),
Return(ByMove(ScopedAStatus::ok()))));
auto [csr, csrErrMsg] =
- getCsr("mock component name", mockRpc.get(),
+ getCsr("default", mockRpc.get(),
/*selfTest=*/true, /*allowDegenerate=*/false, /*requireUdsCerts=*/true);
ASSERT_EQ(csr, nullptr);
- ASSERT_THAT(csrErrMsg, testing::HasSubstr("UdsCerts must not be empty"));
+ ASSERT_THAT(csrErrMsg, testing::HasSubstr("UdsCerts are required"));
}
TEST(LibRkpFactoryExtractionTests, dontRequireUdsCerts) {
- const std::vector<uint8_t> kCsr = Array()
- .add(1 /* version */)
- .add(Map() /* UdsCerts */)
- .add(Array() /* DiceCertChain */)
- .add(Array() /* SignedData */)
- .encode();
+ const std::vector<uint8_t> csrEncoded = kCsrWithoutUdsCerts;
std::vector<uint8_t> challenge;
// Set up mock, then call getCsr
@@ -342,14 +403,14 @@
generateCertificateRequestV2(IsEmpty(), // keysToSign
_, // challenge
NotNull())) // _aidl_return
- .WillOnce(DoAll(SaveArg<1>(&challenge), SetArgPointee<2>(kCsr),
+ .WillOnce(DoAll(SaveArg<1>(&challenge), SetArgPointee<2>(csrEncoded),
Return(ByMove(ScopedAStatus::ok()))));
auto [csr, csrErrMsg] =
- getCsr("mock component name", mockRpc.get(),
+ getCsr("default", mockRpc.get(),
/*selfTest=*/true, /*allowDegenerate=*/false, /*requireUdsCerts=*/false);
ASSERT_EQ(csr, nullptr);
- ASSERT_THAT(csrErrMsg, testing::Not(testing::HasSubstr("UdsCerts must not be empty")));
+ ASSERT_THAT(csrErrMsg, testing::HasSubstr("challenges do not match"));
}
TEST(LibRkpFactoryExtractionTests, parseCommaDelimitedString) {
@@ -362,4 +423,4 @@
ASSERT_TRUE(rpcSet.count("avf") == 1);
ASSERT_TRUE(rpcSet.count("strongbox") == 1);
ASSERT_TRUE(rpcSet.count("Strongbox") == 1);
-}
\ No newline at end of file
+}