Paul Crowley | 44c02da | 2021-04-08 17:04:43 +0000 | [diff] [blame] | 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 | //! Offer keys based on the "boot level" for superencryption. |
| 16 | |
| 17 | use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ |
| 18 | Algorithm::Algorithm, BeginResult::BeginResult, Digest::Digest, ErrorCode::ErrorCode, |
| 19 | IKeyMintDevice::IKeyMintDevice, IKeyMintOperation::IKeyMintOperation, |
| 20 | KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel, |
| 21 | }; |
| 22 | use android_system_keystore2::aidl::android::system::keystore2::{ |
| 23 | Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode, |
| 24 | }; |
| 25 | use anyhow::{Context, Result}; |
| 26 | use binder::Strong; |
| 27 | use keystore2_crypto::{hkdf_expand, ZVec, AES_256_KEY_LENGTH}; |
| 28 | use std::{collections::VecDeque, convert::TryFrom}; |
| 29 | |
| 30 | use crate::{ |
| 31 | database::{ |
| 32 | BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, KeyEntry, KeyEntryLoadBits, |
| 33 | KeyIdGuard, KeyMetaData, KeyMetaEntry, KeyType, KeystoreDB, SubComponentType, Uuid, |
| 34 | }, |
| 35 | error::{map_km_error, Error}, |
| 36 | globals::get_keymint_device, |
| 37 | key_parameter::KeyParameterValue, |
| 38 | super_key::KeyBlob, |
| 39 | utils::{key_characteristics_to_internal, Asp, AID_KEYSTORE}, |
| 40 | }; |
| 41 | |
| 42 | /// Wrapper for operating directly on a KeyMint device. |
| 43 | /// These methods often mirror methods in [`crate::security_level`]. However |
| 44 | /// the functions in [`crate::security_level`] make assumptions that hold, and has side effects |
| 45 | /// that make sense, only if called by an external client through binder. |
| 46 | /// In addition we are trying to maintain a separation between interface services |
| 47 | /// so that the architecture is compatible with a future move to multiple thread pools. |
| 48 | /// So the simplest approach today is to write new implementations of them for internal use. |
| 49 | /// Because these methods run very early, we don't even try to cooperate with |
| 50 | /// the operation slot database; we assume there will be plenty of slots. |
| 51 | struct KeyMintDevice { |
| 52 | asp: Asp, |
| 53 | km_uuid: Uuid, |
| 54 | } |
| 55 | |
| 56 | impl KeyMintDevice { |
| 57 | fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> { |
| 58 | let (asp, _hw_info, km_uuid) = get_keymint_device(&security_level) |
| 59 | .context("In KeyMintDevice::get: get_keymint_device failed")?; |
| 60 | Ok(KeyMintDevice { asp, km_uuid }) |
| 61 | } |
| 62 | |
| 63 | /// Generate a KM key and store in the database. |
| 64 | fn generate_and_store_key( |
| 65 | &self, |
| 66 | db: &mut KeystoreDB, |
| 67 | key_desc: &KeyDescriptor, |
| 68 | params: &[KeyParameter], |
| 69 | ) -> Result<()> { |
| 70 | let km_dev: Strong<dyn IKeyMintDevice> = self |
| 71 | .asp |
| 72 | .get_interface() |
| 73 | .context("In generate_and_store_key: Failed to get KeyMint device")?; |
| 74 | let creation_result = map_km_error(km_dev.generateKey(params, None)) |
| 75 | .context("In generate_and_store_key: generateKey failed")?; |
| 76 | let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics); |
| 77 | |
| 78 | let creation_date = |
| 79 | DateTime::now().context("In generate_and_store_key: DateTime::now() failed")?; |
| 80 | |
| 81 | let mut key_metadata = KeyMetaData::new(); |
| 82 | key_metadata.add(KeyMetaEntry::CreationDate(creation_date)); |
| 83 | let mut blob_metadata = BlobMetaData::new(); |
| 84 | blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid)); |
| 85 | |
| 86 | db.store_new_key( |
| 87 | &key_desc, |
| 88 | &key_parameters, |
| 89 | &(&creation_result.keyBlob, &blob_metadata), |
| 90 | &CertificateInfo::new(None, None), |
| 91 | &key_metadata, |
| 92 | &self.km_uuid, |
| 93 | ) |
| 94 | .context("In generate_and_store_key: store_new_key failed")?; |
| 95 | Ok(()) |
| 96 | } |
| 97 | |
| 98 | /// This does the lookup and store in separate transactions; caller must |
| 99 | /// hold a lock before calling. |
| 100 | fn lookup_or_generate_key( |
| 101 | &self, |
| 102 | db: &mut KeystoreDB, |
| 103 | key_desc: &KeyDescriptor, |
| 104 | params: &[KeyParameter], |
| 105 | ) -> Result<(KeyIdGuard, KeyEntry)> { |
| 106 | // We use a separate transaction for the lookup than for the store |
| 107 | // - to keep the code simple |
| 108 | // - because the caller needs to hold a lock in any case |
| 109 | // - because it avoids holding database locks during slow |
| 110 | // KeyMint operations |
| 111 | let lookup = db.load_key_entry( |
| 112 | &key_desc, |
| 113 | KeyType::Client, |
| 114 | KeyEntryLoadBits::KM, |
| 115 | AID_KEYSTORE, |
| 116 | |_, _| Ok(()), |
| 117 | ); |
| 118 | match lookup { |
| 119 | Ok(result) => return Ok(result), |
| 120 | Err(e) => match e.root_cause().downcast_ref::<Error>() { |
| 121 | Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => {} |
| 122 | _ => return Err(e), |
| 123 | }, |
| 124 | } |
| 125 | self.generate_and_store_key(db, &key_desc, ¶ms) |
| 126 | .context("In lookup_or_generate_key: generate_and_store_key failed")?; |
| 127 | db.load_key_entry(&key_desc, KeyType::Client, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| { |
| 128 | Ok(()) |
| 129 | }) |
| 130 | .context("In lookup_or_generate_key: load_key_entry failed") |
| 131 | } |
| 132 | |
| 133 | /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and |
| 134 | /// write the upgraded key to the database. |
| 135 | fn upgrade_keyblob_if_required_with<T, F>( |
| 136 | &self, |
| 137 | db: &mut KeystoreDB, |
| 138 | km_dev: &Strong<dyn IKeyMintDevice>, |
| 139 | key_id_guard: KeyIdGuard, |
| 140 | key_blob: &KeyBlob, |
| 141 | f: F, |
| 142 | ) -> Result<T> |
| 143 | where |
| 144 | F: Fn(&[u8]) -> Result<T, Error>, |
| 145 | { |
| 146 | match f(key_blob) { |
| 147 | Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => { |
| 148 | let upgraded_blob = map_km_error(km_dev.upgradeKey(key_blob, &[])) |
| 149 | .context("In upgrade_keyblob_if_required_with: Upgrade failed")?; |
| 150 | |
| 151 | let mut new_blob_metadata = BlobMetaData::new(); |
| 152 | new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid)); |
| 153 | |
| 154 | db.set_blob( |
| 155 | &key_id_guard, |
| 156 | SubComponentType::KEY_BLOB, |
| 157 | Some(&upgraded_blob), |
| 158 | Some(&new_blob_metadata), |
| 159 | ) |
| 160 | .context(concat!( |
| 161 | "In upgrade_keyblob_if_required_with: ", |
| 162 | "Failed to insert upgraded blob into the database" |
| 163 | ))?; |
| 164 | |
| 165 | Ok(f(&upgraded_blob).context(concat!( |
| 166 | "In upgrade_keyblob_if_required_with: ", |
| 167 | "Closure failed after upgrade" |
| 168 | ))?) |
| 169 | } |
| 170 | result => Ok(result.context("In upgrade_keyblob_if_required_with: Closure failed")?), |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | /// Use the created key in an operation that can be done with |
| 175 | /// a call to begin followed by a call to finish. |
| 176 | fn use_key_in_one_step( |
| 177 | &self, |
| 178 | db: &mut KeystoreDB, |
| 179 | key_id_guard: KeyIdGuard, |
| 180 | key_entry: &KeyEntry, |
| 181 | purpose: KeyPurpose, |
| 182 | operation_parameters: &[KeyParameter], |
| 183 | input: &[u8], |
| 184 | ) -> Result<Vec<u8>> { |
| 185 | let km_dev: Strong<dyn IKeyMintDevice> = self |
| 186 | .asp |
| 187 | .get_interface() |
| 188 | .context("In use_key_in_one_step: Failed to get KeyMint device")?; |
| 189 | |
| 190 | let (key_blob, _blob_metadata) = key_entry |
| 191 | .key_blob_info() |
| 192 | .as_ref() |
| 193 | .ok_or_else(Error::sys) |
| 194 | .context("use_key_in_one_step: Keyblob missing")?; |
| 195 | let key_blob = KeyBlob::Ref(&key_blob); |
| 196 | |
| 197 | let begin_result: BeginResult = self |
| 198 | .upgrade_keyblob_if_required_with(db, &km_dev, key_id_guard, &key_blob, |blob| { |
| 199 | map_km_error(km_dev.begin(purpose, blob, operation_parameters, &Default::default())) |
| 200 | }) |
| 201 | .context("In use_key_in_one_step: Failed to begin operation.")?; |
| 202 | let operation: Strong<dyn IKeyMintOperation> = begin_result |
| 203 | .operation |
| 204 | .ok_or_else(Error::sys) |
| 205 | .context("In use_key_in_one_step: Operation missing")?; |
| 206 | map_km_error(operation.finish(Some(input), None, None, None, None)) |
| 207 | .context("In use_key_in_one_step: Failed to finish operation.") |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | /// This is not thread safe; caller must hold a lock before calling. |
| 212 | /// In practice the caller is SuperKeyManager and the lock is the |
| 213 | /// Mutex on its internal state. |
| 214 | pub fn get_level_zero_key(db: &mut KeystoreDB) -> Result<ZVec> { |
| 215 | let key_desc = KeyDescriptor { |
| 216 | domain: Domain::APP, |
| 217 | nspace: AID_KEYSTORE as i64, |
| 218 | alias: Some("boot_level_key".to_string()), |
| 219 | blob: None, |
| 220 | }; |
| 221 | let params = [ |
| 222 | KeyParameterValue::Algorithm(Algorithm::HMAC).into(), |
| 223 | KeyParameterValue::Digest(Digest::SHA_2_256).into(), |
| 224 | KeyParameterValue::KeySize(256).into(), |
| 225 | KeyParameterValue::MinMacLength(256).into(), |
| 226 | KeyParameterValue::KeyPurpose(KeyPurpose::SIGN).into(), |
| 227 | KeyParameterValue::MaxUsesPerBoot(1).into(), |
| 228 | ]; |
| 229 | // We use TRUSTED_ENVIRONMENT here because it is the authority on when |
| 230 | // the device has rebooted. |
| 231 | let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT) |
| 232 | .context("In get_level_zero_key: KeyMintDevice::get failed")?; |
| 233 | let (key_id_guard, key_entry) = km_dev |
| 234 | .lookup_or_generate_key(db, &key_desc, ¶ms) |
| 235 | .context("In get_level_zero_key: lookup_or_generate_key failed")?; |
| 236 | |
| 237 | let params = [KeyParameterValue::MacLength(256).into()]; |
| 238 | let level_zero_key = km_dev |
| 239 | .use_key_in_one_step( |
| 240 | db, |
| 241 | key_id_guard, |
| 242 | &key_entry, |
| 243 | KeyPurpose::SIGN, |
| 244 | ¶ms, |
| 245 | b"Create boot level key", |
| 246 | ) |
| 247 | .context("In get_level_zero_key: use_key_in_one_step failed")?; |
| 248 | // TODO: this is rather unsatisfactory, we need a better way to handle |
| 249 | // sensitive binder returns. |
| 250 | let level_zero_key = ZVec::try_from(level_zero_key) |
| 251 | .context("In get_level_zero_key: conversion to ZVec failed")?; |
| 252 | Ok(level_zero_key) |
| 253 | } |
| 254 | |
| 255 | /// Holds the key for the current boot level, and a cache of future keys generated as required. |
| 256 | /// When the boot level advances, keys prior to the current boot level are securely dropped. |
| 257 | pub struct BootLevelKeyCache { |
| 258 | /// Least boot level currently accessible, if any is. |
| 259 | current: usize, |
| 260 | /// Invariant: cache entry *i*, if it exists, holds the HKDF key for boot level |
| 261 | /// *i* + `current`. If the cache is non-empty it can be grown forwards, but it cannot be |
| 262 | /// grown backwards, so keys below `current` are inaccessible. |
| 263 | /// `cache.clear()` makes all keys inaccessible. |
| 264 | cache: VecDeque<ZVec>, |
| 265 | } |
| 266 | |
| 267 | impl BootLevelKeyCache { |
| 268 | const HKDF_ADVANCE: &'static [u8] = b"Advance KDF one step"; |
| 269 | const HKDF_AES: &'static [u8] = b"Generate AES-256-GCM key"; |
| 270 | const HKDF_KEY_SIZE: usize = 32; |
| 271 | |
| 272 | /// Initialize the cache with the level zero key. |
| 273 | pub fn new(level_zero_key: ZVec) -> Self { |
| 274 | let mut cache: VecDeque<ZVec> = VecDeque::new(); |
| 275 | cache.push_back(level_zero_key); |
| 276 | Self { current: 0, cache } |
| 277 | } |
| 278 | |
| 279 | /// Report whether the key for the given level can be inferred. |
| 280 | pub fn level_accessible(&self, boot_level: usize) -> bool { |
| 281 | // If the requested boot level is lower than the current boot level |
| 282 | // or if we have reached the end (`cache.empty()`) we can't retrieve |
| 283 | // the boot key. |
| 284 | boot_level >= self.current && !self.cache.is_empty() |
| 285 | } |
| 286 | |
| 287 | /// Get the HKDF key for boot level `boot_level`. The key for level *i*+1 |
| 288 | /// is calculated from the level *i* key using `hkdf_expand`. |
| 289 | fn get_hkdf_key(&mut self, boot_level: usize) -> Result<Option<&ZVec>> { |
| 290 | if !self.level_accessible(boot_level) { |
| 291 | return Ok(None); |
| 292 | } |
| 293 | // `self.cache.len()` represents the first entry not in the cache, |
| 294 | // so `self.current + self.cache.len()` is the first boot level not in the cache. |
| 295 | let first_not_cached = self.current + self.cache.len(); |
| 296 | |
| 297 | // Grow the cache forwards until it contains the desired boot level. |
| 298 | for _level in first_not_cached..=boot_level { |
| 299 | // We check at the start that cache is non-empty and future iterations only push, |
| 300 | // so this must unwrap. |
| 301 | let highest_key = self.cache.back().unwrap(); |
| 302 | let next_key = hkdf_expand(Self::HKDF_KEY_SIZE, highest_key, Self::HKDF_ADVANCE) |
| 303 | .context("In BootLevelKeyCache::get_hkdf_key: Advancing key one step")?; |
| 304 | self.cache.push_back(next_key); |
| 305 | } |
| 306 | |
| 307 | // If we reach this point, we should have a key at index boot_level - current. |
| 308 | Ok(Some(self.cache.get(boot_level - self.current).unwrap())) |
| 309 | } |
| 310 | |
| 311 | /// Drop keys prior to the given boot level, while retaining the ability to generate keys for |
| 312 | /// that level and later. |
| 313 | pub fn advance_boot_level(&mut self, new_boot_level: usize) -> Result<()> { |
| 314 | if !self.level_accessible(new_boot_level) { |
| 315 | log::error!( |
| 316 | concat!( |
| 317 | "In BootLevelKeyCache::advance_boot_level: ", |
| 318 | "Failed to advance boot level to {}, current is {}, cache size {}" |
| 319 | ), |
| 320 | new_boot_level, |
| 321 | self.current, |
| 322 | self.cache.len() |
| 323 | ); |
| 324 | return Ok(()); |
| 325 | } |
| 326 | |
| 327 | // We `get` the new boot level for the side effect of advancing the cache to a point |
| 328 | // where the new boot level is present. |
| 329 | self.get_hkdf_key(new_boot_level) |
| 330 | .context("In BootLevelKeyCache::advance_boot_level: Advancing cache")?; |
| 331 | |
| 332 | // Then we split the queue at the index of the new boot level and discard the front, |
| 333 | // keeping only the keys with the current boot level or higher. |
| 334 | self.cache = self.cache.split_off(new_boot_level - self.current); |
| 335 | |
| 336 | // The new cache has the new boot level at index 0, so we set `current` to |
| 337 | // `new_boot_level`. |
| 338 | self.current = new_boot_level; |
| 339 | |
| 340 | Ok(()) |
| 341 | } |
| 342 | |
| 343 | /// Drop all keys, effectively raising the current boot level to infinity; no keys can |
| 344 | /// be inferred from this point on. |
| 345 | pub fn finish(&mut self) { |
| 346 | self.cache.clear(); |
| 347 | } |
| 348 | |
| 349 | fn expand_key( |
| 350 | &mut self, |
| 351 | boot_level: usize, |
| 352 | out_len: usize, |
| 353 | info: &[u8], |
| 354 | ) -> Result<Option<ZVec>> { |
| 355 | self.get_hkdf_key(boot_level) |
| 356 | .context("In BootLevelKeyCache::expand_key: Looking up HKDF key")? |
| 357 | .map(|k| hkdf_expand(out_len, k, info)) |
| 358 | .transpose() |
| 359 | .context("In BootLevelKeyCache::expand_key: Calling hkdf_expand") |
| 360 | } |
| 361 | |
| 362 | /// Return the AES-256-GCM key for the current boot level. |
| 363 | pub fn aes_key(&mut self, boot_level: usize) -> Result<Option<ZVec>> { |
| 364 | self.expand_key(boot_level, AES_256_KEY_LENGTH, BootLevelKeyCache::HKDF_AES) |
| 365 | .context("In BootLevelKeyCache::aes_key: expand_key failed") |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | #[cfg(test)] |
| 370 | mod test { |
| 371 | use super::*; |
| 372 | |
| 373 | #[test] |
| 374 | fn test_output_is_consistent() -> Result<()> { |
| 375 | let initial_key = b"initial key"; |
| 376 | let mut blkc = BootLevelKeyCache::new(ZVec::try_from(initial_key as &[u8])?); |
| 377 | assert_eq!(true, blkc.level_accessible(0)); |
| 378 | assert_eq!(true, blkc.level_accessible(9)); |
| 379 | assert_eq!(true, blkc.level_accessible(10)); |
| 380 | assert_eq!(true, blkc.level_accessible(100)); |
| 381 | let v0 = blkc.aes_key(0).unwrap().unwrap(); |
| 382 | let v10 = blkc.aes_key(10).unwrap().unwrap(); |
| 383 | assert_eq!(Some(&v0), blkc.aes_key(0)?.as_ref()); |
| 384 | assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref()); |
| 385 | blkc.advance_boot_level(5)?; |
| 386 | assert_eq!(false, blkc.level_accessible(0)); |
| 387 | assert_eq!(true, blkc.level_accessible(9)); |
| 388 | assert_eq!(true, blkc.level_accessible(10)); |
| 389 | assert_eq!(true, blkc.level_accessible(100)); |
| 390 | assert_eq!(None, blkc.aes_key(0)?); |
| 391 | assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref()); |
| 392 | blkc.advance_boot_level(10)?; |
| 393 | assert_eq!(false, blkc.level_accessible(0)); |
| 394 | assert_eq!(false, blkc.level_accessible(9)); |
| 395 | assert_eq!(true, blkc.level_accessible(10)); |
| 396 | assert_eq!(true, blkc.level_accessible(100)); |
| 397 | assert_eq!(None, blkc.aes_key(0)?); |
| 398 | assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref()); |
| 399 | blkc.advance_boot_level(0)?; |
| 400 | assert_eq!(false, blkc.level_accessible(0)); |
| 401 | assert_eq!(false, blkc.level_accessible(9)); |
| 402 | assert_eq!(true, blkc.level_accessible(10)); |
| 403 | assert_eq!(true, blkc.level_accessible(100)); |
| 404 | assert_eq!(None, blkc.aes_key(0)?); |
| 405 | assert_eq!(Some(v10), blkc.aes_key(10)?); |
| 406 | blkc.finish(); |
| 407 | assert_eq!(false, blkc.level_accessible(0)); |
| 408 | assert_eq!(false, blkc.level_accessible(9)); |
| 409 | assert_eq!(false, blkc.level_accessible(10)); |
| 410 | assert_eq!(false, blkc.level_accessible(100)); |
| 411 | assert_eq!(None, blkc.aes_key(0)?); |
| 412 | assert_eq!(None, blkc.aes_key(10)?); |
| 413 | Ok(()) |
| 414 | } |
| 415 | } |