diff options
author | Hasini Gunasinghe <hasinitg@google.com> | 2021-07-01 21:36:23 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-07-01 21:36:23 +0000 |
commit | 691d4d4dfb8fb174c336761b66c6b79fb08dbac4 (patch) | |
tree | dd74432bc61e66a887b659de939223d26e2addf9 | |
parent | 664ea465c24f19118fb9deedb24d2cf2675885b8 (diff) | |
parent | a3444f867b8ee07dcbc911de22fc3804bb83cf87 (diff) | |
download | security-691d4d4dfb8fb174c336761b66c6b79fb08dbac4.tar.gz |
Merge "Log metrics related to Remote Key Provisioning (RKP)." into sc-dev
-rw-r--r-- | keystore2/aidl/android/security/metrics/RkpPoolStats.aidl | 11 | ||||
-rw-r--r-- | keystore2/src/database.rs | 3 | ||||
-rw-r--r-- | keystore2/src/metrics_store.rs | 52 | ||||
-rw-r--r-- | keystore2/src/remote_provisioning.rs | 38 |
4 files changed, 77 insertions, 27 deletions
diff --git a/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl b/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl index b2338423..016b6ff3 100644 --- a/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl +++ b/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl @@ -16,14 +16,17 @@ package android.security.metrics; -import android.security.metrics.PoolStatus; +import android.security.metrics.SecurityLevel; /** - * Count of keys in the key pool related to Remote Key Provisioning (RKP). + * Count of keys in the attestation key pool related to Remote Key Provisioning (RKP). * @hide */ @RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true) parcelable RkpPoolStats { - PoolStatus pool_status; - int count_of_keys; + SecurityLevel security_level; + int expiring; + int unassigned; + int attested; + int total; }
\ No newline at end of file diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs index ca346e0a..c7887200 100644 --- a/keystore2/src/database.rs +++ b/keystore2/src/database.rs @@ -47,6 +47,7 @@ mod versioning; use crate::impl_metadata; // This is in db_utils.rs use crate::key_parameter::{KeyParameter, Tag}; +use crate::metrics_store::log_rkp_error_stats; use crate::permission::KeyPermSet; use crate::utils::{get_current_time_in_milliseconds, watchdog as wd, AID_USER_OFFSET}; use crate::{ @@ -72,6 +73,7 @@ use android_security_remoteprovisioning::aidl::android::security::remoteprovisio use android_security_metrics::aidl::android::security::metrics::{ StorageStats::StorageStats, Storage::Storage as MetricsStorage, + RkpError::RkpError as MetricsRkpError, }; use keystore2_crypto::ZVec; @@ -1829,6 +1831,7 @@ impl KeystoreDB { ) .context("Failed to assign attestation key")?; if result == 0 { + log_rkp_error_stats(MetricsRkpError::OUT_OF_KEYS); return Err(KsError::Rc(ResponseCode::OUT_OF_KEYS)).context("Out of keys."); } else if result > 1 { return Err(KsError::sys()) diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs index e3de0352..32fe353e 100644 --- a/keystore2/src/metrics_store.rs +++ b/keystore2/src/metrics_store.rs @@ -21,6 +21,7 @@ use crate::error::get_error_code; use crate::globals::DB; use crate::key_parameter::KeyParameterValue as KsKeyParamValue; use crate::operation::Outcome; +use crate::remote_provisioning::get_pool_status; use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve, HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin, @@ -38,12 +39,15 @@ use android_security_metrics::aidl::android::security::metrics::{ KeyOrigin::KeyOrigin as MetricsKeyOrigin, Keystore2AtomWithOverflow::Keystore2AtomWithOverflow, KeystoreAtom::KeystoreAtom, KeystoreAtomPayload::KeystoreAtomPayload, Outcome::Outcome as MetricsOutcome, Purpose::Purpose as MetricsPurpose, - SecurityLevel::SecurityLevel as MetricsSecurityLevel, Storage::Storage as MetricsStorage, + RkpError::RkpError as MetricsRkpError, RkpErrorStats::RkpErrorStats, + RkpPoolStats::RkpPoolStats, SecurityLevel::SecurityLevel as MetricsSecurityLevel, + Storage::Storage as MetricsStorage, }; use anyhow::Result; use lazy_static::lazy_static; use std::collections::HashMap; use std::sync::Mutex; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; lazy_static! { /// Singleton for MetricsStore. @@ -83,7 +87,10 @@ impl MetricsStore { return pull_storage_stats(); } - // TODO (b/184301651): process and return RKP pool stats. + // Process and return RKP pool stats. + if AtomID::RKP_POOL_STATS == atom_id { + return pull_attestation_pool_stats(); + } // 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. @@ -534,6 +541,47 @@ fn pull_storage_stats() -> Result<Vec<KeystoreAtom>> { Ok(atom_vec) } +fn pull_attestation_pool_stats() -> Result<Vec<KeystoreAtom>> { + let mut atoms = Vec::<KeystoreAtom>::new(); + for sec_level in &[SecurityLevel::TRUSTED_ENVIRONMENT, SecurityLevel::STRONGBOX] { + let expired_by = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_else(|_| Duration::new(0, 0)) + .as_secs() as i64; + + let result = get_pool_status(expired_by, *sec_level); + + if let Ok(pool_status) = result { + let rkp_pool_stats = RkpPoolStats { + security_level: process_security_level(*sec_level), + expiring: pool_status.expiring, + unassigned: pool_status.unassigned, + attested: pool_status.attested, + total: pool_status.total, + }; + atoms.push(KeystoreAtom { + payload: KeystoreAtomPayload::RkpPoolStats(rkp_pool_stats), + ..Default::default() + }); + } else { + log::error!( + concat!( + "In pull_attestation_pool_stats: Failed to retrieve pool status", + " for security level: {:?}" + ), + sec_level + ); + } + } + Ok(atoms) +} + +/// Log error events related to Remote Key Provisioning (RKP). +pub fn log_rkp_error_stats(rkp_error: MetricsRkpError) { + let rkp_error_stats = KeystoreAtomPayload::RkpErrorStats(RkpErrorStats { rkpError: rkp_error }); + METRICS_STORE.insert_atom(AtomID::RKP_ERROR_STATS, rkp_error_stats); +} + /// Enum defining the bit position for each padding mode. Since padding mode can be repeatable, it /// is represented using a bitmap. #[allow(non_camel_case_types)] diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs index 40ffd0ca..6666f416 100644 --- a/keystore2/src/remote_provisioning.rs +++ b/keystore2/src/remote_provisioning.rs @@ -234,26 +234,6 @@ impl RemoteProvisioningService { Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default())) } - /// Populates the AttestationPoolStatus parcelable with information about how many - /// certs will be expiring by the date provided in `expired_by` along with how many - /// keys have not yet been assigned. - pub fn get_pool_status( - &self, - expired_by: i64, - sec_level: SecurityLevel, - ) -> Result<AttestationPoolStatus> { - let (_, _, uuid) = get_keymint_device(&sec_level)?; - DB.with::<_, Result<AttestationPoolStatus>>(|db| { - let mut db = db.borrow_mut(); - // delete_expired_attestation_keys is always safe to call, and will remove anything - // older than the date at the time of calling. No work should be done on the - // attestation keys unless the pool status is checked first, so this call should be - // enough to routinely clean out expired keys. - db.delete_expired_attestation_keys()?; - db.get_attestation_pool_status(expired_by, &uuid) - }) - } - /// Generates a CBOR blob which will be assembled by the calling code into a larger /// CBOR blob intended for delivery to a provisioning serever. This blob will contain /// `num_csr` certificate signing requests for attestation keys generated in the TEE, @@ -389,6 +369,22 @@ impl RemoteProvisioningService { } } +/// Populates the AttestationPoolStatus parcelable with information about how many +/// certs will be expiring by the date provided in `expired_by` along with how many +/// keys have not yet been assigned. +pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> { + let (_, _, uuid) = get_keymint_device(&sec_level)?; + DB.with::<_, Result<AttestationPoolStatus>>(|db| { + let mut db = db.borrow_mut(); + // delete_expired_attestation_keys is always safe to call, and will remove anything + // older than the date at the time of calling. No work should be done on the + // attestation keys unless the pool status is checked first, so this call should be + // enough to routinely clean out expired keys. + db.delete_expired_attestation_keys()?; + db.get_attestation_pool_status(expired_by, &uuid) + }) +} + impl binder::Interface for RemoteProvisioningService {} // Implementation of IRemoteProvisioning. See AIDL spec at @@ -400,7 +396,7 @@ impl IRemoteProvisioning for RemoteProvisioningService { sec_level: SecurityLevel, ) -> binder::public_api::Result<AttestationPoolStatus> { let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500); - map_or_log_err(self.get_pool_status(expired_by, sec_level), Ok) + map_or_log_err(get_pool_status(expired_by, sec_level), Ok) } fn generateCsr( |