1 // Copyright 2021, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! Provide the [`KeyMintDevice`] wrapper for operating directly on a KeyMint device. 16 17 use crate::{ 18 database::{ 19 BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, KeyEntry, KeyEntryLoadBits, 20 KeyIdGuard, KeyMetaData, KeyMetaEntry, KeyType, KeystoreDB, SubComponentType, Uuid, 21 }, 22 error::{map_km_error, Error, ErrorCode}, 23 globals::get_keymint_device, 24 super_key::KeyBlob, 25 utils::{key_characteristics_to_internal, watchdog as wd, AID_KEYSTORE}, 26 }; 27 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ 28 HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice, 29 IKeyMintOperation::IKeyMintOperation, KeyCharacteristics::KeyCharacteristics, 30 KeyCreationResult::KeyCreationResult, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, 31 SecurityLevel::SecurityLevel, 32 }; 33 use android_system_keystore2::aidl::android::system::keystore2::{ 34 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode, 35 }; 36 use anyhow::{Context, Result}; 37 use binder::Strong; 38 39 /// Wrapper for operating directly on a KeyMint device. 40 /// These methods often mirror methods in [`crate::security_level`]. However 41 /// the functions in [`crate::security_level`] make assumptions that hold, and has side effects 42 /// that make sense, only if called by an external client through binder. 43 /// In addition we are trying to maintain a separation between interface services 44 /// so that the architecture is compatible with a future move to multiple thread pools. 45 /// So the simplest approach today is to write new implementations of them for internal use. 46 /// Because these methods run very early, we don't even try to cooperate with 47 /// the operation slot database; we assume there will be plenty of slots. 48 pub struct KeyMintDevice { 49 km_dev: Strong<dyn IKeyMintDevice>, 50 km_uuid: Uuid, 51 version: i32, 52 security_level: SecurityLevel, 53 } 54 55 impl KeyMintDevice { 56 /// Version number of KeyMasterDevice@V4_0 57 pub const KEY_MASTER_V4_0: i32 = 40; 58 /// Version number of KeyMasterDevice@V4_1 59 pub const KEY_MASTER_V4_1: i32 = 41; 60 /// Version number of KeyMintDevice@V1 61 pub const KEY_MINT_V1: i32 = 100; 62 63 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`] get(security_level: SecurityLevel) -> Result<KeyMintDevice>64 pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> { 65 let (asp, hw_info, km_uuid) = get_keymint_device(&security_level) 66 .context("In KeyMintDevice::get: get_keymint_device failed")?; 67 68 Ok(KeyMintDevice { 69 km_dev: asp.get_interface()?, 70 km_uuid, 71 version: hw_info.versionNumber, 72 security_level: hw_info.securityLevel, 73 }) 74 } 75 76 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`], return 77 /// [`None`] if the error `HARDWARE_TYPE_UNAVAILABLE` is returned get_or_none(security_level: SecurityLevel) -> Result<Option<KeyMintDevice>>78 pub fn get_or_none(security_level: SecurityLevel) -> Result<Option<KeyMintDevice>> { 79 KeyMintDevice::get(security_level).map(Some).or_else(|e| { 80 match e.root_cause().downcast_ref::<Error>() { 81 Some(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)) => Ok(None), 82 _ => Err(e), 83 } 84 }) 85 } 86 87 /// Returns the version of the underlying KeyMint/KeyMaster device. version(&self) -> i3288 pub fn version(&self) -> i32 { 89 self.version 90 } 91 92 /// Returns the self advertised security level of the KeyMint device. 93 /// This may differ from the requested security level if the best security level 94 /// on the device is Software. security_level(&self) -> SecurityLevel95 pub fn security_level(&self) -> SecurityLevel { 96 self.security_level 97 } 98 99 /// Create a KM key and store in the database. create_and_store_key<F>( &self, db: &mut KeystoreDB, key_desc: &KeyDescriptor, key_type: KeyType, creator: F, ) -> Result<()> where F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,100 pub fn create_and_store_key<F>( 101 &self, 102 db: &mut KeystoreDB, 103 key_desc: &KeyDescriptor, 104 key_type: KeyType, 105 creator: F, 106 ) -> Result<()> 107 where 108 F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>, 109 { 110 let creation_result = map_km_error(creator(&self.km_dev)) 111 .context("In create_and_store_key: creator failed")?; 112 let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics); 113 114 let creation_date = 115 DateTime::now().context("In create_and_store_key: DateTime::now() failed")?; 116 117 let mut key_metadata = KeyMetaData::new(); 118 key_metadata.add(KeyMetaEntry::CreationDate(creation_date)); 119 let mut blob_metadata = BlobMetaData::new(); 120 blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid)); 121 122 db.store_new_key( 123 &key_desc, 124 key_type, 125 &key_parameters, 126 &(&creation_result.keyBlob, &blob_metadata), 127 &CertificateInfo::new(None, None), 128 &key_metadata, 129 &self.km_uuid, 130 ) 131 .context("In create_and_store_key: store_new_key failed")?; 132 Ok(()) 133 } 134 135 /// Generate a KeyDescriptor for internal-use keys. internal_descriptor(alias: String) -> KeyDescriptor136 pub fn internal_descriptor(alias: String) -> KeyDescriptor { 137 KeyDescriptor { 138 domain: Domain::APP, 139 nspace: AID_KEYSTORE as i64, 140 alias: Some(alias), 141 blob: None, 142 } 143 } 144 145 /// Look up an internal-use key in the database given a key descriptor. lookup_from_desc( db: &mut KeystoreDB, key_desc: &KeyDescriptor, key_type: KeyType, ) -> Result<(KeyIdGuard, KeyEntry)>146 fn lookup_from_desc( 147 db: &mut KeystoreDB, 148 key_desc: &KeyDescriptor, 149 key_type: KeyType, 150 ) -> Result<(KeyIdGuard, KeyEntry)> { 151 db.load_key_entry(&key_desc, key_type, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| Ok(())) 152 .context("In lookup_from_desc: load_key_entry failed.") 153 } 154 155 /// Look up the key in the database, and return None if it is absent. not_found_is_none( lookup: Result<(KeyIdGuard, KeyEntry)>, ) -> Result<Option<(KeyIdGuard, KeyEntry)>>156 fn not_found_is_none( 157 lookup: Result<(KeyIdGuard, KeyEntry)>, 158 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> { 159 match lookup { 160 Ok(result) => Ok(Some(result)), 161 Err(e) => match e.root_cause().downcast_ref::<Error>() { 162 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None), 163 _ => Err(e), 164 }, 165 } 166 } 167 168 /// This does the lookup and store in separate transactions; caller must 169 /// hold a lock before calling. lookup_or_generate_key<F>( &self, db: &mut KeystoreDB, key_desc: &KeyDescriptor, key_type: KeyType, params: &[KeyParameter], validate_characteristics: F, ) -> Result<(KeyIdGuard, KeyBlob)> where F: FnOnce(&[KeyCharacteristics]) -> bool,170 pub fn lookup_or_generate_key<F>( 171 &self, 172 db: &mut KeystoreDB, 173 key_desc: &KeyDescriptor, 174 key_type: KeyType, 175 params: &[KeyParameter], 176 validate_characteristics: F, 177 ) -> Result<(KeyIdGuard, KeyBlob)> 178 where 179 F: FnOnce(&[KeyCharacteristics]) -> bool, 180 { 181 // We use a separate transaction for the lookup than for the store 182 // - to keep the code simple 183 // - because the caller needs to hold a lock in any case 184 // - because it avoids holding database locks during slow 185 // KeyMint operations 186 let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc, key_type)) 187 .context("In lookup_or_generate_key: first lookup failed")?; 188 189 if let Some((key_id_guard, mut key_entry)) = lookup { 190 // If the key is associated with a different km instance 191 // or if there is no blob metadata for some reason the key entry 192 // is considered corrupted and needs to be replaced with a new one. 193 let key_blob = key_entry.take_key_blob_info().and_then(|(key_blob, blob_metadata)| { 194 if Some(&self.km_uuid) == blob_metadata.km_uuid() { 195 Some(key_blob) 196 } else { 197 None 198 } 199 }); 200 201 if let Some(key_blob_vec) = key_blob { 202 let (key_characteristics, key_blob) = self 203 .upgrade_keyblob_if_required_with( 204 db, 205 &key_id_guard, 206 KeyBlob::NonSensitive(key_blob_vec), 207 |key_blob| { 208 map_km_error({ 209 let _wp = wd::watch_millis( 210 concat!( 211 "In KeyMintDevice::lookup_or_generate_key: ", 212 "calling getKeyCharacteristics." 213 ), 214 500, 215 ); 216 self.km_dev.getKeyCharacteristics(key_blob, &[], &[]) 217 }) 218 }, 219 ) 220 .context("In lookup_or_generate_key: calling getKeyCharacteristics")?; 221 222 if validate_characteristics(&key_characteristics) { 223 return Ok((key_id_guard, key_blob)); 224 } 225 226 // If this point is reached the existing key is considered outdated or corrupted 227 // in some way. It will be replaced with a new key below. 228 }; 229 } 230 231 self.create_and_store_key(db, &key_desc, key_type, |km_dev| { 232 km_dev.generateKey(¶ms, None) 233 }) 234 .context("In lookup_or_generate_key: generate_and_store_key failed")?; 235 Self::lookup_from_desc(db, key_desc, key_type) 236 .and_then(|(key_id_guard, mut key_entry)| { 237 Ok(( 238 key_id_guard, 239 key_entry 240 .take_key_blob_info() 241 .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND)) 242 .map(|(key_blob, _)| KeyBlob::NonSensitive(key_blob)) 243 .context("Missing key blob info.")?, 244 )) 245 }) 246 .context("In lookup_or_generate_key: second lookup failed") 247 } 248 249 /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and 250 /// write the upgraded key to the database. upgrade_keyblob_if_required_with<'a, T, F>( &self, db: &mut KeystoreDB, key_id_guard: &KeyIdGuard, key_blob: KeyBlob<'a>, f: F, ) -> Result<(T, KeyBlob<'a>)> where F: Fn(&[u8]) -> Result<T, Error>,251 fn upgrade_keyblob_if_required_with<'a, T, F>( 252 &self, 253 db: &mut KeystoreDB, 254 key_id_guard: &KeyIdGuard, 255 key_blob: KeyBlob<'a>, 256 f: F, 257 ) -> Result<(T, KeyBlob<'a>)> 258 where 259 F: Fn(&[u8]) -> Result<T, Error>, 260 { 261 match f(&key_blob) { 262 Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => { 263 let upgraded_blob = map_km_error({ 264 let _wp = wd::watch_millis( 265 "In KeyMintDevice::upgrade_keyblob_if_required_with: calling upgradeKey.", 266 500, 267 ); 268 self.km_dev.upgradeKey(&key_blob, &[]) 269 }) 270 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?; 271 272 let mut new_blob_metadata = BlobMetaData::new(); 273 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid)); 274 275 db.set_blob( 276 key_id_guard, 277 SubComponentType::KEY_BLOB, 278 Some(&upgraded_blob), 279 Some(&new_blob_metadata), 280 ) 281 .context(concat!( 282 "In upgrade_keyblob_if_required_with: ", 283 "Failed to insert upgraded blob into the database" 284 ))?; 285 286 Ok(( 287 f(&upgraded_blob).context( 288 "In upgrade_keyblob_if_required_with: Closure failed after upgrade", 289 )?, 290 KeyBlob::NonSensitive(upgraded_blob), 291 )) 292 } 293 result => Ok(( 294 result.context("In upgrade_keyblob_if_required_with: Closure failed")?, 295 key_blob, 296 )), 297 } 298 } 299 300 /// Use the created key in an operation that can be done with 301 /// a call to begin followed by a call to finish. 302 #[allow(clippy::too_many_arguments)] use_key_in_one_step( &self, db: &mut KeystoreDB, key_id_guard: &KeyIdGuard, key_blob: &[u8], purpose: KeyPurpose, operation_parameters: &[KeyParameter], auth_token: Option<&HardwareAuthToken>, input: &[u8], ) -> Result<Vec<u8>>303 pub fn use_key_in_one_step( 304 &self, 305 db: &mut KeystoreDB, 306 key_id_guard: &KeyIdGuard, 307 key_blob: &[u8], 308 purpose: KeyPurpose, 309 operation_parameters: &[KeyParameter], 310 auth_token: Option<&HardwareAuthToken>, 311 input: &[u8], 312 ) -> Result<Vec<u8>> { 313 let key_blob = KeyBlob::Ref(key_blob); 314 315 let (begin_result, _) = self 316 .upgrade_keyblob_if_required_with(db, key_id_guard, key_blob, |blob| { 317 map_km_error({ 318 let _wp = wd::watch_millis("In use_key_in_one_step: calling: begin", 500); 319 self.km_dev.begin(purpose, blob, operation_parameters, auth_token) 320 }) 321 }) 322 .context("In use_key_in_one_step: Failed to begin operation.")?; 323 let operation: Strong<dyn IKeyMintOperation> = begin_result 324 .operation 325 .ok_or_else(Error::sys) 326 .context("In use_key_in_one_step: Operation missing")?; 327 map_km_error({ 328 let _wp = wd::watch_millis("In use_key_in_one_step: calling: finish", 500); 329 operation.finish(Some(input), None, None, None, None) 330 }) 331 .context("In use_key_in_one_step: Failed to finish operation.") 332 } 333 } 334