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