diff options
author | Janis Danisevskis <jdanis@google.com> | 2021-05-25 10:56:10 -0700 |
---|---|---|
committer | Janis Danisevskis <jdanis@google.com> | 2021-06-01 14:30:27 -0700 |
commit | acebfa2471594c8971513064deacfec2efaad7bf (patch) | |
tree | 46ac088e7df0374ea33dfabb9a11425234c76ad4 /keystore2/src/raw_device.rs | |
parent | 5c7482104f61d43b15f8421c3a5c546d16d0cd45 (diff) | |
download | security-acebfa2471594c8971513064deacfec2efaad7bf.tar.gz |
Keystore 2.0: Boot level keys: Check key characteristics.
Check the key characteristics of the level zero key to verify its
integrity.
Ignore-AOSP-First: No automerge path from AOSP.
Bug: 187862706
Test: N/A
Change-Id: Id83e581781507e499790e77729b0e2d96795f908
Merged-In: Id83e581781507e499790e77729b0e2d96795f908
Diffstat (limited to 'keystore2/src/raw_device.rs')
-rw-r--r-- | keystore2/src/raw_device.rs | 151 |
1 files changed, 99 insertions, 52 deletions
diff --git a/keystore2/src/raw_device.rs b/keystore2/src/raw_device.rs index 9cc69ef6..4e86d394 100644 --- a/keystore2/src/raw_device.rs +++ b/keystore2/src/raw_device.rs @@ -22,12 +22,13 @@ use crate::{ error::{map_km_error, Error, ErrorCode}, globals::get_keymint_device, super_key::KeyBlob, - utils::{key_characteristics_to_internal, watchdog as wd, Asp, AID_KEYSTORE}, + utils::{key_characteristics_to_internal, watchdog as wd, AID_KEYSTORE}, }; use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ - BeginResult::BeginResult, HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice, - IKeyMintOperation::IKeyMintOperation, KeyCreationResult::KeyCreationResult, - KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel, + HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice, + IKeyMintOperation::IKeyMintOperation, KeyCharacteristics::KeyCharacteristics, + KeyCreationResult::KeyCreationResult, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, + SecurityLevel::SecurityLevel, }; use android_system_keystore2::aidl::android::system::keystore2::{ Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode, @@ -45,9 +46,10 @@ use binder::Strong; /// Because these methods run very early, we don't even try to cooperate with /// the operation slot database; we assume there will be plenty of slots. pub struct KeyMintDevice { - asp: Asp, + km_dev: Strong<dyn IKeyMintDevice>, km_uuid: Uuid, version: i32, + security_level: SecurityLevel, } impl KeyMintDevice { @@ -63,7 +65,12 @@ impl KeyMintDevice { let (asp, hw_info, km_uuid) = get_keymint_device(&security_level) .context("In KeyMintDevice::get: get_keymint_device failed")?; - Ok(KeyMintDevice { asp, km_uuid, version: hw_info.versionNumber }) + Ok(KeyMintDevice { + km_dev: asp.get_interface()?, + km_uuid, + version: hw_info.versionNumber, + security_level: hw_info.securityLevel, + }) } /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`], return @@ -82,6 +89,13 @@ impl KeyMintDevice { self.version } + /// Returns the self advertised security level of the KeyMint device. + /// This may differ from the requested security level if the best security level + /// on the device is Software. + pub fn security_level(&self) -> SecurityLevel { + self.security_level + } + /// Create a KM key and store in the database. pub fn create_and_store_key<F>( &self, @@ -90,14 +104,10 @@ impl KeyMintDevice { creator: F, ) -> Result<()> where - F: FnOnce(Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>, + F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>, { - let km_dev: Strong<dyn IKeyMintDevice> = self - .asp - .get_interface() - .context("In create_and_store_key: Failed to get KeyMint device")?; - let creation_result = - map_km_error(creator(km_dev)).context("In create_and_store_key: creator failed")?; + let creation_result = map_km_error(creator(&self.km_dev)) + .context("In create_and_store_key: creator failed")?; let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics); let creation_date = @@ -131,7 +141,7 @@ impl KeyMintDevice { } /// Look up an internal-use key in the database given a key descriptor. - pub fn lookup_from_desc( + fn lookup_from_desc( db: &mut KeystoreDB, key_desc: &KeyDescriptor, ) -> Result<(KeyIdGuard, KeyEntry)> { @@ -142,7 +152,7 @@ impl KeyMintDevice { } /// Look up the key in the database, and return None if it is absent. - pub fn not_found_is_none( + fn not_found_is_none( lookup: Result<(KeyIdGuard, KeyEntry)>, ) -> Result<Option<(KeyIdGuard, KeyEntry)>> { match lookup { @@ -156,12 +166,16 @@ impl KeyMintDevice { /// This does the lookup and store in separate transactions; caller must /// hold a lock before calling. - pub fn lookup_or_generate_key( + pub fn lookup_or_generate_key<F>( &self, db: &mut KeystoreDB, key_desc: &KeyDescriptor, params: &[KeyParameter], - ) -> Result<(KeyIdGuard, KeyEntry)> { + validate_characteristics: F, + ) -> Result<(KeyIdGuard, KeyBlob)> + where + F: FnOnce(&[KeyCharacteristics]) -> bool, + { // We use a separate transaction for the lookup than for the store // - to keep the code simple // - because the caller needs to hold a lock in any case @@ -170,46 +184,84 @@ impl KeyMintDevice { let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc)) .context("In lookup_or_generate_key: first lookup failed")?; - if let Some((key_id_guard, key_entry)) = lookup { + if let Some((key_id_guard, mut key_entry)) = lookup { // If the key is associated with a different km instance // or if there is no blob metadata for some reason the key entry // is considered corrupted and needs to be replaced with a new one. - if key_entry - .key_blob_info() - .as_ref() - .map(|(_, blob_metadata)| Some(&self.km_uuid) == blob_metadata.km_uuid()) - .unwrap_or(false) - { - return Ok((key_id_guard, key_entry)); - } + let key_blob = key_entry.take_key_blob_info().and_then(|(key_blob, blob_metadata)| { + if Some(&self.km_uuid) == blob_metadata.km_uuid() { + Some(key_blob) + } else { + None + } + }); + + if let Some(key_blob_vec) = key_blob { + let (key_characteristics, key_blob) = self + .upgrade_keyblob_if_required_with( + db, + &key_id_guard, + KeyBlob::NonSensitive(key_blob_vec), + |key_blob| { + map_km_error({ + let _wp = wd::watch_millis( + concat!( + "In KeyMintDevice::lookup_or_generate_key: ", + "calling getKeyCharacteristics." + ), + 500, + ); + self.km_dev.getKeyCharacteristics(key_blob, &[], &[]) + }) + }, + ) + .context("In lookup_or_generate_key: calling getKeyCharacteristics")?; + + if validate_characteristics(&key_characteristics) { + return Ok((key_id_guard, key_blob)); + } + + // If this point is reached the existing key is considered outdated or corrupted + // in some way. It will be replaced with a new key below. + }; } + self.create_and_store_key(db, &key_desc, |km_dev| km_dev.generateKey(¶ms, None)) .context("In lookup_or_generate_key: generate_and_store_key failed")?; Self::lookup_from_desc(db, key_desc) + .and_then(|(key_id_guard, mut key_entry)| { + Ok(( + key_id_guard, + key_entry + .take_key_blob_info() + .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND)) + .map(|(key_blob, _)| KeyBlob::NonSensitive(key_blob)) + .context("Missing key blob info.")?, + )) + }) .context("In lookup_or_generate_key: second lookup failed") } /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and /// write the upgraded key to the database. - fn upgrade_keyblob_if_required_with<T, F>( + fn upgrade_keyblob_if_required_with<'a, T, F>( &self, db: &mut KeystoreDB, - km_dev: &Strong<dyn IKeyMintDevice>, key_id_guard: &KeyIdGuard, - key_blob: &KeyBlob, + key_blob: KeyBlob<'a>, f: F, - ) -> Result<T> + ) -> Result<(T, KeyBlob<'a>)> where F: Fn(&[u8]) -> Result<T, Error>, { - match f(key_blob) { + match f(&key_blob) { Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => { let upgraded_blob = map_km_error({ let _wp = wd::watch_millis( "In KeyMintDevice::upgrade_keyblob_if_required_with: calling upgradeKey.", 500, ); - km_dev.upgradeKey(key_blob, &[]) + self.km_dev.upgradeKey(&key_blob, &[]) }) .context("In upgrade_keyblob_if_required_with: Upgrade failed")?; @@ -227,12 +279,17 @@ impl KeyMintDevice { "Failed to insert upgraded blob into the database" ))?; - Ok(f(&upgraded_blob).context(concat!( - "In upgrade_keyblob_if_required_with: ", - "Closure failed after upgrade" - ))?) + Ok(( + f(&upgraded_blob).context( + "In upgrade_keyblob_if_required_with: Closure failed after upgrade", + )?, + KeyBlob::NonSensitive(upgraded_blob), + )) } - result => Ok(result.context("In upgrade_keyblob_if_required_with: Closure failed")?), + result => Ok(( + result.context("In upgrade_keyblob_if_required_with: Closure failed")?, + key_blob, + )), } } @@ -243,29 +300,19 @@ impl KeyMintDevice { &self, db: &mut KeystoreDB, key_id_guard: &KeyIdGuard, - key_entry: &KeyEntry, + key_blob: &[u8], purpose: KeyPurpose, operation_parameters: &[KeyParameter], auth_token: Option<&HardwareAuthToken>, input: &[u8], ) -> Result<Vec<u8>> { - let km_dev: Strong<dyn IKeyMintDevice> = self - .asp - .get_interface() - .context("In use_key_in_one_step: Failed to get KeyMint device")?; - - let (key_blob, _blob_metadata) = key_entry - .key_blob_info() - .as_ref() - .ok_or_else(Error::sys) - .context("use_key_in_one_step: Keyblob missing")?; - let key_blob = KeyBlob::Ref(&key_blob); + let key_blob = KeyBlob::Ref(key_blob); - let begin_result: BeginResult = self - .upgrade_keyblob_if_required_with(db, &km_dev, key_id_guard, &key_blob, |blob| { + let (begin_result, _) = self + .upgrade_keyblob_if_required_with(db, key_id_guard, key_blob, |blob| { map_km_error({ let _wp = wd::watch_millis("In use_key_in_one_step: calling: begin", 500); - km_dev.begin(purpose, blob, operation_parameters, auth_token) + self.km_dev.begin(purpose, blob, operation_parameters, auth_token) }) }) .context("In use_key_in_one_step: Failed to begin operation.")?; |