blob: e02d9bcfe6c6ad9c1b9eba9e4041eb87e1e15563 [file] [log] [blame]
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001// Copyright 2020, 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
Janis Danisevskisb42fc182020-12-15 08:41:27 -080015use crate::{
Paul Crowley44c02da2021-04-08 17:04:43 +000016 boot_level_keys::{get_level_zero_key, BootLevelKeyCache},
Paul Crowley8d5b2532021-03-19 10:53:07 -070017 database::BlobMetaData,
18 database::BlobMetaEntry,
19 database::EncryptedBy,
20 database::KeyEntry,
21 database::KeyType,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070022 database::{KeyEntryLoadBits, KeyIdGuard, KeyMetaData, KeyMetaEntry, KeystoreDB},
Paul Crowley8d5b2532021-03-19 10:53:07 -070023 ec_crypto::ECDHPrivateKey,
24 enforcements::Enforcements,
25 error::Error,
26 error::ResponseCode,
Paul Crowley618869e2021-04-08 20:30:54 -070027 key_parameter::{KeyParameter, KeyParameterValue},
Paul Crowley8d5b2532021-03-19 10:53:07 -070028 legacy_blob::LegacyBlobLoader,
29 legacy_migrator::LegacyMigrator,
Paul Crowley618869e2021-04-08 20:30:54 -070030 raw_device::KeyMintDevice,
Paul Crowley8d5b2532021-03-19 10:53:07 -070031 try_insert::TryInsert,
Janis Danisevskis2ee014b2021-05-05 14:29:08 -070032 utils::watchdog as wd,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070033 utils::AID_KEYSTORE,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080034};
Paul Crowley618869e2021-04-08 20:30:54 -070035use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
36 Algorithm::Algorithm, BlockMode::BlockMode, HardwareAuthToken::HardwareAuthToken,
37 HardwareAuthenticatorType::HardwareAuthenticatorType, KeyFormat::KeyFormat,
38 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
39 SecurityLevel::SecurityLevel,
40};
41use android_system_keystore2::aidl::android::system::keystore2::{
42 Domain::Domain, KeyDescriptor::KeyDescriptor,
43};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080044use anyhow::{Context, Result};
45use keystore2_crypto::{
Paul Crowleyf61fee72021-03-17 14:38:44 -070046 aes_gcm_decrypt, aes_gcm_encrypt, generate_aes256_key, generate_salt, Password, ZVec,
47 AES_256_KEY_LENGTH,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080048};
Paul Crowley44c02da2021-04-08 17:04:43 +000049use keystore2_system_property::PropertyWatcher;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080050use std::{
51 collections::HashMap,
52 sync::Arc,
53 sync::{Mutex, Weak},
54};
Paul Crowley618869e2021-04-08 20:30:54 -070055use std::{convert::TryFrom, ops::Deref};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080056
Paul Crowley44c02da2021-04-08 17:04:43 +000057const MAX_MAX_BOOT_LEVEL: usize = 1_000_000_000;
Paul Crowley618869e2021-04-08 20:30:54 -070058/// Allow up to 15 seconds between the user unlocking using a biometric, and the auth
59/// token being used to unlock in [`SuperKeyManager::try_unlock_user_with_biometric`].
60/// This seems short enough for security purposes, while long enough that even the
61/// very slowest device will present the auth token in time.
62const BIOMETRIC_AUTH_TIMEOUT_S: i32 = 15; // seconds
Paul Crowley44c02da2021-04-08 17:04:43 +000063
Janis Danisevskisb42fc182020-12-15 08:41:27 -080064type UserId = u32;
65
Paul Crowley8d5b2532021-03-19 10:53:07 -070066/// Encryption algorithm used by a particular type of superencryption key
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum SuperEncryptionAlgorithm {
69 /// Symmetric encryption with AES-256-GCM
70 Aes256Gcm,
Paul Crowley52f017f2021-06-22 08:16:01 -070071 /// Public-key encryption with ECDH P-521
72 EcdhP521,
Paul Crowley8d5b2532021-03-19 10:53:07 -070073}
74
Paul Crowley7a658392021-03-18 17:08:20 -070075/// A particular user may have several superencryption keys in the database, each for a
76/// different purpose, distinguished by alias. Each is associated with a static
77/// constant of this type.
78pub struct SuperKeyType {
79 /// Alias used to look the key up in the `persistent.keyentry` table.
80 pub alias: &'static str,
Paul Crowley8d5b2532021-03-19 10:53:07 -070081 /// Encryption algorithm
82 pub algorithm: SuperEncryptionAlgorithm,
Paul Crowley7a658392021-03-18 17:08:20 -070083}
84
85/// Key used for LskfLocked keys; the corresponding superencryption key is loaded in memory
86/// when the user first unlocks, and remains in memory until the device reboots.
Paul Crowley8d5b2532021-03-19 10:53:07 -070087pub const USER_SUPER_KEY: SuperKeyType =
88 SuperKeyType { alias: "USER_SUPER_KEY", algorithm: SuperEncryptionAlgorithm::Aes256Gcm };
Paul Crowley7a658392021-03-18 17:08:20 -070089/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
90/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
Paul Crowley8d5b2532021-03-19 10:53:07 -070091/// Symmetric.
92pub const USER_SCREEN_LOCK_BOUND_KEY: SuperKeyType = SuperKeyType {
93 alias: "USER_SCREEN_LOCK_BOUND_KEY",
94 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
95};
96/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
97/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
98/// Asymmetric, so keys can be encrypted when the device is locked.
Paul Crowley52f017f2021-06-22 08:16:01 -070099pub const USER_SCREEN_LOCK_BOUND_P521_KEY: SuperKeyType = SuperKeyType {
100 alias: "USER_SCREEN_LOCK_BOUND_P521_KEY",
101 algorithm: SuperEncryptionAlgorithm::EcdhP521,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700102};
Paul Crowley7a658392021-03-18 17:08:20 -0700103
104/// Superencryption to apply to a new key.
105#[derive(Debug, Clone, Copy)]
106pub enum SuperEncryptionType {
107 /// Do not superencrypt this key.
108 None,
109 /// Superencrypt with a key that remains in memory from first unlock to reboot.
110 LskfBound,
111 /// Superencrypt with a key cleared from memory when the device is locked.
112 ScreenLockBound,
Paul Crowley44c02da2021-04-08 17:04:43 +0000113 /// Superencrypt with a key based on the desired boot level
114 BootLevel(i32),
115}
116
117#[derive(Debug, Clone, Copy)]
118pub enum SuperKeyIdentifier {
119 /// id of the super key in the database.
120 DatabaseId(i64),
121 /// Boot level of the encrypting boot level key
122 BootLevel(i32),
123}
124
125impl SuperKeyIdentifier {
126 fn from_metadata(metadata: &BlobMetaData) -> Option<Self> {
127 if let Some(EncryptedBy::KeyId(key_id)) = metadata.encrypted_by() {
128 Some(SuperKeyIdentifier::DatabaseId(*key_id))
129 } else if let Some(boot_level) = metadata.max_boot_level() {
130 Some(SuperKeyIdentifier::BootLevel(*boot_level))
131 } else {
132 None
133 }
134 }
135
136 fn add_to_metadata(&self, metadata: &mut BlobMetaData) {
137 match self {
138 SuperKeyIdentifier::DatabaseId(id) => {
139 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(*id)));
140 }
141 SuperKeyIdentifier::BootLevel(level) => {
142 metadata.add(BlobMetaEntry::MaxBootLevel(*level));
143 }
144 }
145 }
Paul Crowley7a658392021-03-18 17:08:20 -0700146}
147
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000148pub struct SuperKey {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700149 algorithm: SuperEncryptionAlgorithm,
Paul Crowley7a658392021-03-18 17:08:20 -0700150 key: ZVec,
Paul Crowley44c02da2021-04-08 17:04:43 +0000151 /// Identifier of the encrypting key, used to write an encrypted blob
152 /// back to the database after re-encryption eg on a key update.
153 id: SuperKeyIdentifier,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700154 /// ECDH is more expensive than AES. So on ECDH private keys we set the
155 /// reencrypt_with field to point at the corresponding AES key, and the
156 /// keys will be re-encrypted with AES on first use.
157 reencrypt_with: Option<Arc<SuperKey>>,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000158}
159
160impl SuperKey {
Paul Crowley7a658392021-03-18 17:08:20 -0700161 /// For most purposes `unwrap_key` handles decryption,
162 /// but legacy handling and some tests need to assume AES and decrypt directly.
163 pub fn aes_gcm_decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700164 if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm {
165 aes_gcm_decrypt(data, iv, tag, &self.key)
166 .context("In aes_gcm_decrypt: decryption failed")
167 } else {
168 Err(Error::sys()).context("In aes_gcm_decrypt: Key is not an AES key")
169 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000170 }
Paul Crowleye8826e52021-03-31 08:33:53 -0700171}
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000172
Paul Crowley618869e2021-04-08 20:30:54 -0700173/// A SuperKey that has been encrypted with an AES-GCM key. For
174/// encryption the key is in memory, and for decryption it is in KM.
175struct LockedKey {
176 algorithm: SuperEncryptionAlgorithm,
177 id: SuperKeyIdentifier,
178 nonce: Vec<u8>,
179 ciphertext: Vec<u8>, // with tag appended
180}
181
182impl LockedKey {
183 fn new(key: &[u8], to_encrypt: &Arc<SuperKey>) -> Result<Self> {
184 let (mut ciphertext, nonce, mut tag) = aes_gcm_encrypt(&to_encrypt.key, key)?;
185 ciphertext.append(&mut tag);
186 Ok(LockedKey { algorithm: to_encrypt.algorithm, id: to_encrypt.id, nonce, ciphertext })
187 }
188
189 fn decrypt(
190 &self,
191 db: &mut KeystoreDB,
192 km_dev: &KeyMintDevice,
193 key_id_guard: &KeyIdGuard,
194 key_entry: &KeyEntry,
195 auth_token: &HardwareAuthToken,
196 reencrypt_with: Option<Arc<SuperKey>>,
197 ) -> Result<Arc<SuperKey>> {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700198 let key_blob = key_entry
199 .key_blob_info()
200 .as_ref()
201 .map(|(key_blob, _)| KeyBlob::Ref(key_blob))
202 .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
203 .context("In LockedKey::decrypt: Missing key blob info.")?;
Paul Crowley618869e2021-04-08 20:30:54 -0700204 let key_params = vec![
205 KeyParameterValue::Algorithm(Algorithm::AES),
206 KeyParameterValue::KeySize(256),
207 KeyParameterValue::BlockMode(BlockMode::GCM),
208 KeyParameterValue::PaddingMode(PaddingMode::NONE),
209 KeyParameterValue::Nonce(self.nonce.clone()),
210 KeyParameterValue::MacLength(128),
211 ];
212 let key_params: Vec<KmKeyParameter> = key_params.into_iter().map(|x| x.into()).collect();
213 let key = ZVec::try_from(km_dev.use_key_in_one_step(
214 db,
215 key_id_guard,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700216 &key_blob,
Paul Crowley618869e2021-04-08 20:30:54 -0700217 KeyPurpose::DECRYPT,
218 &key_params,
219 Some(auth_token),
220 &self.ciphertext,
221 )?)?;
222 Ok(Arc::new(SuperKey { algorithm: self.algorithm, key, id: self.id, reencrypt_with }))
223 }
224}
225
226/// Keys for unlocking UNLOCKED_DEVICE_REQUIRED keys, as LockedKeys, complete with
227/// a database descriptor for the encrypting key and the sids for the auth tokens
228/// that can be used to decrypt it.
229struct BiometricUnlock {
230 /// List of auth token SIDs that can be used to unlock these keys.
231 sids: Vec<i64>,
232 /// Database descriptor of key to use to unlock.
233 key_desc: KeyDescriptor,
234 /// Locked versions of the matching UserSuperKeys fields
235 screen_lock_bound: LockedKey,
236 screen_lock_bound_private: LockedKey,
237}
238
Paul Crowleye8826e52021-03-31 08:33:53 -0700239#[derive(Default)]
240struct UserSuperKeys {
241 /// The per boot key is used for LSKF binding of authentication bound keys. There is one
242 /// key per android user. The key is stored on flash encrypted with a key derived from a
243 /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF).
244 /// When the user unlocks the device for the first time, this key is unlocked, i.e., decrypted,
245 /// and stays memory resident until the device reboots.
246 per_boot: Option<Arc<SuperKey>>,
247 /// The screen lock key works like the per boot key with the distinction that it is cleared
248 /// from memory when the screen lock is engaged.
249 screen_lock_bound: Option<Arc<SuperKey>>,
250 /// When the device is locked, screen-lock-bound keys can still be encrypted, using
251 /// ECDH public-key encryption. This field holds the decryption private key.
252 screen_lock_bound_private: Option<Arc<SuperKey>>,
Paul Crowley618869e2021-04-08 20:30:54 -0700253 /// Versions of the above two keys, locked behind a biometric.
254 biometric_unlock: Option<BiometricUnlock>,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000255}
256
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800257#[derive(Default)]
258struct SkmState {
259 user_keys: HashMap<UserId, UserSuperKeys>,
Paul Crowley7a658392021-03-18 17:08:20 -0700260 key_index: HashMap<i64, Weak<SuperKey>>,
Paul Crowley44c02da2021-04-08 17:04:43 +0000261 boot_level_key_cache: Option<BootLevelKeyCache>,
Paul Crowley7a658392021-03-18 17:08:20 -0700262}
263
264impl SkmState {
Paul Crowley44c02da2021-04-08 17:04:43 +0000265 fn add_key_to_key_index(&mut self, super_key: &Arc<SuperKey>) -> Result<()> {
266 if let SuperKeyIdentifier::DatabaseId(id) = super_key.id {
267 self.key_index.insert(id, Arc::downgrade(super_key));
268 Ok(())
269 } else {
270 Err(Error::sys()).context(format!(
271 "In add_key_to_key_index: cannot add key with ID {:?}",
272 super_key.id
273 ))
274 }
Paul Crowley7a658392021-03-18 17:08:20 -0700275 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800276}
277
278#[derive(Default)]
279pub struct SuperKeyManager {
280 data: Mutex<SkmState>,
281}
282
283impl SuperKeyManager {
Paul Crowley44c02da2021-04-08 17:04:43 +0000284 pub fn set_up_boot_level_cache(self: &Arc<Self>, db: &mut KeystoreDB) -> Result<()> {
285 let mut data = self.data.lock().unwrap();
286 if data.boot_level_key_cache.is_some() {
287 log::info!("In set_up_boot_level_cache: called for a second time");
288 return Ok(());
289 }
290 let level_zero_key = get_level_zero_key(db)
291 .context("In set_up_boot_level_cache: get_level_zero_key failed")?;
292 data.boot_level_key_cache = Some(BootLevelKeyCache::new(level_zero_key));
293 log::info!("Starting boot level watcher.");
294 let clone = self.clone();
295 std::thread::spawn(move || {
296 clone
297 .watch_boot_level()
298 .unwrap_or_else(|e| log::error!("watch_boot_level failed:\n{:?}", e));
299 });
300 Ok(())
301 }
302
303 /// Watch the `keystore.boot_level` system property, and keep boot level up to date.
304 /// Blocks waiting for system property changes, so must be run in its own thread.
305 fn watch_boot_level(&self) -> Result<()> {
306 let mut w = PropertyWatcher::new("keystore.boot_level")
307 .context("In watch_boot_level: PropertyWatcher::new failed")?;
308 loop {
309 let level = w
310 .read(|_n, v| v.parse::<usize>().map_err(std::convert::Into::into))
311 .context("In watch_boot_level: read of property failed")?;
312 // watch_boot_level should only be called once data.boot_level_key_cache is Some,
313 // so it's safe to unwrap in the branches below.
314 if level < MAX_MAX_BOOT_LEVEL {
315 log::info!("Read keystore.boot_level value {}", level);
316 let mut data = self.data.lock().unwrap();
317 data.boot_level_key_cache
318 .as_mut()
319 .unwrap()
320 .advance_boot_level(level)
321 .context("In watch_boot_level: advance_boot_level failed")?;
322 } else {
323 log::info!(
324 "keystore.boot_level {} hits maximum {}, finishing.",
325 level,
326 MAX_MAX_BOOT_LEVEL
327 );
328 let mut data = self.data.lock().unwrap();
329 data.boot_level_key_cache.as_mut().unwrap().finish();
330 break;
331 }
332 w.wait().context("In watch_boot_level: property wait failed")?;
333 }
334 Ok(())
335 }
336
337 pub fn level_accessible(&self, boot_level: i32) -> bool {
338 self.data
339 .lock()
340 .unwrap()
341 .boot_level_key_cache
342 .as_ref()
343 .map_or(false, |c| c.level_accessible(boot_level as usize))
344 }
345
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800346 pub fn forget_all_keys_for_user(&self, user: UserId) {
347 let mut data = self.data.lock().unwrap();
348 data.user_keys.remove(&user);
349 }
350
Paul Crowley44c02da2021-04-08 17:04:43 +0000351 fn install_per_boot_key_for_user(&self, user: UserId, super_key: Arc<SuperKey>) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800352 let mut data = self.data.lock().unwrap();
Paul Crowley44c02da2021-04-08 17:04:43 +0000353 data.add_key_to_key_index(&super_key)
354 .context("In install_per_boot_key_for_user: add_key_to_key_index failed")?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000355 data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Paul Crowley44c02da2021-04-08 17:04:43 +0000356 Ok(())
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800357 }
358
Paul Crowley44c02da2021-04-08 17:04:43 +0000359 fn lookup_key(&self, key_id: &SuperKeyIdentifier) -> Result<Option<Arc<SuperKey>>> {
360 let mut data = self.data.lock().unwrap();
361 Ok(match key_id {
362 SuperKeyIdentifier::DatabaseId(id) => data.key_index.get(id).and_then(|k| k.upgrade()),
363 SuperKeyIdentifier::BootLevel(level) => data
364 .boot_level_key_cache
365 .as_mut()
366 .map(|b| b.aes_key(*level as usize))
367 .transpose()
368 .context("In lookup_key: aes_key failed")?
369 .flatten()
370 .map(|key| {
371 Arc::new(SuperKey {
372 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
373 key,
374 id: *key_id,
375 reencrypt_with: None,
376 })
377 }),
378 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800379 }
380
Paul Crowley7a658392021-03-18 17:08:20 -0700381 pub fn get_per_boot_key_by_user_id(&self, user_id: UserId) -> Option<Arc<SuperKey>> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800382 let data = self.data.lock().unwrap();
Paul Crowley7a658392021-03-18 17:08:20 -0700383 data.user_keys.get(&user_id).and_then(|e| e.per_boot.as_ref().cloned())
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800384 }
385
386 /// This function unlocks the super keys for a given user.
387 /// This means the key is loaded from the database, decrypted and placed in the
388 /// super key cache. If there is no such key a new key is created, encrypted with
389 /// a key derived from the given password and stored in the database.
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800390 pub fn unlock_user_key(
391 &self,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000392 db: &mut KeystoreDB,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800393 user: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700394 pw: &Password,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800395 legacy_blob_loader: &LegacyBlobLoader,
396 ) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800397 let (_, entry) = db
Max Bires8e93d2b2021-01-14 13:17:59 -0800398 .get_or_create_key_with(
399 Domain::APP,
400 user as u64 as i64,
Paul Crowley7a658392021-03-18 17:08:20 -0700401 &USER_SUPER_KEY.alias,
Max Bires8e93d2b2021-01-14 13:17:59 -0800402 crate::database::KEYSTORE_UUID,
403 || {
404 // For backward compatibility we need to check if there is a super key present.
405 let super_key = legacy_blob_loader
406 .load_super_key(user, pw)
407 .context("In create_new_key: Failed to load legacy key blob.")?;
408 let super_key = match super_key {
409 None => {
410 // No legacy file was found. So we generate a new key.
Hasini Gunasingheda895552021-01-27 19:34:37 +0000411 generate_aes256_key()
Max Bires8e93d2b2021-01-14 13:17:59 -0800412 .context("In create_new_key: Failed to generate AES 256 key.")?
413 }
414 Some(key) => key,
415 };
Hasini Gunasingheda895552021-01-27 19:34:37 +0000416 // Regardless of whether we loaded an old AES128 key or generated a new AES256
417 // key as the super key, we derive a AES256 key from the password and re-encrypt
418 // the super key before we insert it in the database. The length of the key is
419 // preserved by the encryption so we don't need any extra flags to inform us
420 // which algorithm to use it with.
421 Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
Max Bires8e93d2b2021-01-14 13:17:59 -0800422 },
423 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800424 .context("In unlock_user_key: Failed to get key id.")?;
425
Paul Crowley8d5b2532021-03-19 10:53:07 -0700426 self.populate_cache_from_super_key_blob(user, USER_SUPER_KEY.algorithm, entry, pw)
427 .context("In unlock_user_key.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800428 Ok(())
429 }
430
Paul Crowley44c02da2021-04-08 17:04:43 +0000431 /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using
432 /// the relevant super key.
433 pub fn unwrap_key_if_required<'a>(
434 &self,
435 metadata: &BlobMetaData,
436 blob: &'a [u8],
437 ) -> Result<KeyBlob<'a>> {
438 Ok(if let Some(key_id) = SuperKeyIdentifier::from_metadata(metadata) {
439 let super_key = self
440 .lookup_key(&key_id)
441 .context("In unwrap_key: lookup_key failed")?
442 .ok_or(Error::Rc(ResponseCode::LOCKED))
443 .context("In unwrap_key: Required super decryption key is not in memory.")?;
444 KeyBlob::Sensitive {
445 key: Self::unwrap_key_with_key(blob, metadata, &super_key)
446 .context("In unwrap_key: unwrap_key_with_key failed")?,
447 reencrypt_with: super_key.reencrypt_with.as_ref().unwrap_or(&super_key).clone(),
448 force_reencrypt: super_key.reencrypt_with.is_some(),
449 }
Paul Crowleye8826e52021-03-31 08:33:53 -0700450 } else {
Paul Crowley44c02da2021-04-08 17:04:43 +0000451 KeyBlob::Ref(blob)
Paul Crowleye8826e52021-03-31 08:33:53 -0700452 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800453 }
454
455 /// Unwraps an encrypted key blob given an encryption key.
Paul Crowley7a658392021-03-18 17:08:20 -0700456 fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700457 match key.algorithm {
458 SuperEncryptionAlgorithm::Aes256Gcm => match (metadata.iv(), metadata.aead_tag()) {
459 (Some(iv), Some(tag)) => key
460 .aes_gcm_decrypt(blob, iv, tag)
461 .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
462 (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
463 concat!(
464 "In unwrap_key_with_key: Key has incomplete metadata.",
465 "Present: iv: {}, aead_tag: {}."
466 ),
467 iv.is_some(),
468 tag.is_some(),
469 )),
470 },
Paul Crowley52f017f2021-06-22 08:16:01 -0700471 SuperEncryptionAlgorithm::EcdhP521 => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700472 match (metadata.public_key(), metadata.salt(), metadata.iv(), metadata.aead_tag()) {
473 (Some(public_key), Some(salt), Some(iv), Some(aead_tag)) => {
474 ECDHPrivateKey::from_private_key(&key.key)
475 .and_then(|k| k.decrypt_message(public_key, salt, iv, blob, aead_tag))
476 .context(
477 "In unwrap_key_with_key: Failed to decrypt the key blob with ECDH.",
478 )
479 }
480 (public_key, salt, iv, aead_tag) => {
481 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
482 concat!(
483 "In unwrap_key_with_key: Key has incomplete metadata.",
484 "Present: public_key: {}, salt: {}, iv: {}, aead_tag: {}."
485 ),
486 public_key.is_some(),
487 salt.is_some(),
488 iv.is_some(),
489 aead_tag.is_some(),
490 ))
491 }
492 }
493 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800494 }
495 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000496
497 /// Checks if user has setup LSKF, even when super key cache is empty for the user.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000498 pub fn super_key_exists_in_db_for_user(
499 db: &mut KeystoreDB,
500 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700501 user_id: UserId,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000502 ) -> Result<bool> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000503 let key_in_db = db
Paul Crowley7a658392021-03-18 17:08:20 -0700504 .key_exists(Domain::APP, user_id as u64 as i64, &USER_SUPER_KEY.alias, KeyType::Super)
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000505 .context("In super_key_exists_in_db_for_user.")?;
506
507 if key_in_db {
508 Ok(key_in_db)
509 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000510 legacy_migrator
511 .has_super_key(user_id)
512 .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000513 }
514 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000515
516 /// Checks if user has already setup LSKF (i.e. a super key is persisted in the database or the
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000517 /// legacy database). If not, return Uninitialized state.
518 /// Otherwise, decrypt the super key from the password and return LskfUnlocked state.
519 pub fn check_and_unlock_super_key(
520 &self,
521 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000522 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700523 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700524 pw: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000525 ) -> Result<UserState> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700526 let alias = &USER_SUPER_KEY;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000527 let result = legacy_migrator
Paul Crowley8d5b2532021-03-19 10:53:07 -0700528 .with_try_migrate_super_key(user_id, pw, || db.load_super_key(alias, user_id))
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000529 .context("In check_and_unlock_super_key. Failed to load super key")?;
530
531 match result {
532 Some((_, entry)) => {
533 let super_key = self
Paul Crowley8d5b2532021-03-19 10:53:07 -0700534 .populate_cache_from_super_key_blob(user_id, alias.algorithm, entry, pw)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000535 .context("In check_and_unlock_super_key.")?;
536 Ok(UserState::LskfUnlocked(super_key))
537 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000538 None => Ok(UserState::Uninitialized),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000539 }
540 }
541
542 /// Checks if user has already setup LSKF (i.e. a super key is persisted in the database or the
Hasini Gunasingheda895552021-01-27 19:34:37 +0000543 /// legacy database). If so, return LskfLocked state.
544 /// If the password is provided, generate a new super key, encrypt with the password,
545 /// store in the database and populate the super key cache for the new user
546 /// and return LskfUnlocked state.
547 /// If the password is not provided, return Uninitialized state.
548 pub fn check_and_initialize_super_key(
549 &self,
550 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000551 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700552 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700553 pw: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000554 ) -> Result<UserState> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000555 let super_key_exists_in_db =
556 Self::super_key_exists_in_db_for_user(db, legacy_migrator, user_id).context(
557 "In check_and_initialize_super_key. Failed to check if super key exists.",
558 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000559 if super_key_exists_in_db {
560 Ok(UserState::LskfLocked)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000561 } else if let Some(pw) = pw {
562 //generate a new super key.
563 let super_key = generate_aes256_key()
564 .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
565 //derive an AES256 key from the password and re-encrypt the super key
566 //before we insert it in the database.
567 let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
568 .context("In check_and_initialize_super_key.")?;
569
570 let key_entry = db
Paul Crowley8d5b2532021-03-19 10:53:07 -0700571 .store_super_key(
572 user_id,
573 &USER_SUPER_KEY,
574 &encrypted_super_key,
575 &blob_metadata,
576 &KeyMetaData::new(),
577 )
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000578 .context("In check_and_initialize_super_key. Failed to store super key.")?;
579
580 let super_key = self
Paul Crowley8d5b2532021-03-19 10:53:07 -0700581 .populate_cache_from_super_key_blob(
582 user_id,
583 USER_SUPER_KEY.algorithm,
584 key_entry,
585 pw,
586 )
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000587 .context("In check_and_initialize_super_key.")?;
588 Ok(UserState::LskfUnlocked(super_key))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000589 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000590 Ok(UserState::Uninitialized)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000591 }
592 }
593
594 //helper function to populate super key cache from the super key blob loaded from the database
595 fn populate_cache_from_super_key_blob(
596 &self,
Paul Crowley7a658392021-03-18 17:08:20 -0700597 user_id: UserId,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700598 algorithm: SuperEncryptionAlgorithm,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000599 entry: KeyEntry,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700600 pw: &Password,
Paul Crowley7a658392021-03-18 17:08:20 -0700601 ) -> Result<Arc<SuperKey>> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700602 let super_key = Self::extract_super_key_from_key_entry(algorithm, entry, pw, None)
603 .context(
604 "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
605 )?;
Paul Crowley44c02da2021-04-08 17:04:43 +0000606 self.install_per_boot_key_for_user(user_id, super_key.clone())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000607 Ok(super_key)
608 }
609
610 /// Extracts super key from the entry loaded from the database
Paul Crowley7a658392021-03-18 17:08:20 -0700611 pub fn extract_super_key_from_key_entry(
Paul Crowley8d5b2532021-03-19 10:53:07 -0700612 algorithm: SuperEncryptionAlgorithm,
Paul Crowley7a658392021-03-18 17:08:20 -0700613 entry: KeyEntry,
614 pw: &Password,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700615 reencrypt_with: Option<Arc<SuperKey>>,
Paul Crowley7a658392021-03-18 17:08:20 -0700616 ) -> Result<Arc<SuperKey>> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000617 if let Some((blob, metadata)) = entry.key_blob_info() {
618 let key = match (
619 metadata.encrypted_by(),
620 metadata.salt(),
621 metadata.iv(),
622 metadata.aead_tag(),
623 ) {
624 (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700625 // Note that password encryption is AES no matter the value of algorithm
Paul Crowleyf61fee72021-03-17 14:38:44 -0700626 let key = pw.derive_key(Some(salt), AES_256_KEY_LENGTH).context(
627 "In extract_super_key_from_key_entry: Failed to generate key from password.",
628 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000629
630 aes_gcm_decrypt(blob, iv, tag, &key).context(
631 "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
632 )?
633 }
634 (enc_by, salt, iv, tag) => {
635 return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
636 concat!(
637 "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
Paul Crowleye8826e52021-03-31 08:33:53 -0700638 "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}."
Hasini Gunasingheda895552021-01-27 19:34:37 +0000639 ),
Paul Crowleye8826e52021-03-31 08:33:53 -0700640 enc_by,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000641 salt.is_some(),
642 iv.is_some(),
643 tag.is_some()
644 ));
645 }
646 };
Paul Crowley44c02da2021-04-08 17:04:43 +0000647 Ok(Arc::new(SuperKey {
648 algorithm,
649 key,
650 id: SuperKeyIdentifier::DatabaseId(entry.id()),
651 reencrypt_with,
652 }))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000653 } else {
654 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
655 .context("In extract_super_key_from_key_entry: No key blob info.")
656 }
657 }
658
659 /// Encrypts the super key from a key derived from the password, before storing in the database.
Paul Crowleyf61fee72021-03-17 14:38:44 -0700660 pub fn encrypt_with_password(
661 super_key: &[u8],
662 pw: &Password,
663 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000664 let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
Paul Crowleyf61fee72021-03-17 14:38:44 -0700665 let derived_key = pw
666 .derive_key(Some(&salt), AES_256_KEY_LENGTH)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000667 .context("In encrypt_with_password: Failed to derive password.")?;
668 let mut metadata = BlobMetaData::new();
669 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
670 metadata.add(BlobMetaEntry::Salt(salt));
671 let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
672 .context("In encrypt_with_password: Failed to encrypt new super key.")?;
673 metadata.add(BlobMetaEntry::Iv(iv));
674 metadata.add(BlobMetaEntry::AeadTag(tag));
675 Ok((encrypted_key, metadata))
676 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000677
678 // Encrypt the given key blob with the user's super key, if the super key exists and the device
679 // is unlocked. If the super key exists and the device is locked, or LSKF is not setup,
680 // return error. Note that it is out of the scope of this function to check if super encryption
681 // is required. Such check should be performed before calling this function.
682 fn super_encrypt_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000683 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000684 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000685 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700686 user_id: UserId,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000687 key_blob: &[u8],
688 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000689 match UserState::get(db, legacy_migrator, self, user_id)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000690 .context("In super_encrypt. Failed to get user state.")?
691 {
692 UserState::LskfUnlocked(super_key) => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700693 Self::encrypt_with_aes_super_key(key_blob, &super_key)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000694 .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
695 }
696 UserState::LskfLocked => {
697 Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
698 }
699 UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
700 .context("In super_encrypt. LSKF is not setup for the user."),
701 }
702 }
703
704 //Helper function to encrypt a key with the given super key. Callers should select which super
705 //key to be used. This is called when a key is super encrypted at its creation as well as at its
706 //upgrade.
Paul Crowley8d5b2532021-03-19 10:53:07 -0700707 fn encrypt_with_aes_super_key(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000708 key_blob: &[u8],
709 super_key: &SuperKey,
710 ) -> Result<(Vec<u8>, BlobMetaData)> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700711 if super_key.algorithm != SuperEncryptionAlgorithm::Aes256Gcm {
712 return Err(Error::sys())
713 .context("In encrypt_with_aes_super_key: unexpected algorithm");
714 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000715 let mut metadata = BlobMetaData::new();
716 let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
Paul Crowley8d5b2532021-03-19 10:53:07 -0700717 .context("In encrypt_with_aes_super_key: Failed to encrypt new super key.")?;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000718 metadata.add(BlobMetaEntry::Iv(iv));
719 metadata.add(BlobMetaEntry::AeadTag(tag));
Paul Crowley44c02da2021-04-08 17:04:43 +0000720 super_key.id.add_to_metadata(&mut metadata);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000721 Ok((encrypted_key, metadata))
722 }
723
724 /// Check if super encryption is required and if so, super-encrypt the key to be stored in
725 /// the database.
Paul Crowley618869e2021-04-08 20:30:54 -0700726 #[allow(clippy::too_many_arguments)]
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000727 pub fn handle_super_encryption_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000728 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000729 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000730 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000731 domain: &Domain,
732 key_parameters: &[KeyParameter],
733 flags: Option<i32>,
Paul Crowley7a658392021-03-18 17:08:20 -0700734 user_id: UserId,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000735 key_blob: &[u8],
736 ) -> Result<(Vec<u8>, BlobMetaData)> {
Paul Crowley7a658392021-03-18 17:08:20 -0700737 match Enforcements::super_encryption_required(domain, key_parameters, flags) {
738 SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
Paul Crowleye8826e52021-03-31 08:33:53 -0700739 SuperEncryptionType::LskfBound => self
740 .super_encrypt_on_key_init(db, legacy_migrator, user_id, &key_blob)
741 .context(concat!(
742 "In handle_super_encryption_on_key_init. ",
743 "Failed to super encrypt with LskfBound key."
744 )),
Paul Crowley7a658392021-03-18 17:08:20 -0700745 SuperEncryptionType::ScreenLockBound => {
746 let mut data = self.data.lock().unwrap();
747 let entry = data.user_keys.entry(user_id).or_default();
748 if let Some(super_key) = entry.screen_lock_bound.as_ref() {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700749 Self::encrypt_with_aes_super_key(key_blob, &super_key).context(concat!(
Paul Crowley7a658392021-03-18 17:08:20 -0700750 "In handle_super_encryption_on_key_init. ",
Paul Crowleye8826e52021-03-31 08:33:53 -0700751 "Failed to encrypt with ScreenLockBound key."
Paul Crowley7a658392021-03-18 17:08:20 -0700752 ))
753 } else {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700754 // Symmetric key is not available, use public key encryption
755 let loaded =
Paul Crowley52f017f2021-06-22 08:16:01 -0700756 db.load_super_key(&USER_SCREEN_LOCK_BOUND_P521_KEY, user_id).context(
Paul Crowley8d5b2532021-03-19 10:53:07 -0700757 "In handle_super_encryption_on_key_init: load_super_key failed.",
758 )?;
759 let (key_id_guard, key_entry) = loaded.ok_or_else(Error::sys).context(
760 "In handle_super_encryption_on_key_init: User ECDH key missing.",
761 )?;
762 let public_key =
763 key_entry.metadata().sec1_public_key().ok_or_else(Error::sys).context(
764 "In handle_super_encryption_on_key_init: sec1_public_key missing.",
765 )?;
766 let mut metadata = BlobMetaData::new();
767 let (ephem_key, salt, iv, encrypted_key, aead_tag) =
768 ECDHPrivateKey::encrypt_message(public_key, key_blob).context(concat!(
769 "In handle_super_encryption_on_key_init: ",
770 "ECDHPrivateKey::encrypt_message failed."
771 ))?;
772 metadata.add(BlobMetaEntry::PublicKey(ephem_key));
773 metadata.add(BlobMetaEntry::Salt(salt));
774 metadata.add(BlobMetaEntry::Iv(iv));
775 metadata.add(BlobMetaEntry::AeadTag(aead_tag));
Paul Crowley44c02da2021-04-08 17:04:43 +0000776 SuperKeyIdentifier::DatabaseId(key_id_guard.id())
777 .add_to_metadata(&mut metadata);
Paul Crowley8d5b2532021-03-19 10:53:07 -0700778 Ok((encrypted_key, metadata))
Paul Crowley7a658392021-03-18 17:08:20 -0700779 }
780 }
Paul Crowley44c02da2021-04-08 17:04:43 +0000781 SuperEncryptionType::BootLevel(level) => {
782 let key_id = SuperKeyIdentifier::BootLevel(level);
783 let super_key = self
784 .lookup_key(&key_id)
785 .context("In handle_super_encryption_on_key_init: lookup_key failed")?
786 .ok_or(Error::Rc(ResponseCode::LOCKED))
787 .context("In handle_super_encryption_on_key_init: Boot stage key absent")?;
788 Self::encrypt_with_aes_super_key(key_blob, &super_key).context(concat!(
789 "In handle_super_encryption_on_key_init: ",
790 "Failed to encrypt with BootLevel key."
791 ))
792 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000793 }
794 }
795
796 /// Check if a given key needs re-super-encryption, from its KeyBlob type.
797 /// If so, re-super-encrypt the key and return a new set of metadata,
798 /// containing the new super encryption information.
Paul Crowley7a658392021-03-18 17:08:20 -0700799 pub fn reencrypt_if_required<'a>(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000800 key_blob_before_upgrade: &KeyBlob,
801 key_after_upgrade: &'a [u8],
802 ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)> {
803 match key_blob_before_upgrade {
Paul Crowley7a658392021-03-18 17:08:20 -0700804 KeyBlob::Sensitive { reencrypt_with: super_key, .. } => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700805 let (key, metadata) =
806 Self::encrypt_with_aes_super_key(key_after_upgrade, super_key)
807 .context("In reencrypt_if_required: Failed to re-super-encrypt key.")?;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000808 Ok((KeyBlob::NonSensitive(key), Some(metadata)))
809 }
810 _ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
811 }
812 }
813
Paul Crowley7a658392021-03-18 17:08:20 -0700814 /// Fetch a superencryption key from the database, or create it if it doesn't already exist.
815 /// When this is called, the caller must hold the lock on the SuperKeyManager.
816 /// So it's OK that the check and creation are different DB transactions.
817 fn get_or_create_super_key(
818 db: &mut KeystoreDB,
819 user_id: UserId,
820 key_type: &SuperKeyType,
821 password: &Password,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700822 reencrypt_with: Option<Arc<SuperKey>>,
Paul Crowley7a658392021-03-18 17:08:20 -0700823 ) -> Result<Arc<SuperKey>> {
824 let loaded_key = db.load_super_key(key_type, user_id)?;
825 if let Some((_, key_entry)) = loaded_key {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700826 Ok(Self::extract_super_key_from_key_entry(
827 key_type.algorithm,
828 key_entry,
829 password,
830 reencrypt_with,
831 )?)
Paul Crowley7a658392021-03-18 17:08:20 -0700832 } else {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700833 let (super_key, public_key) = match key_type.algorithm {
834 SuperEncryptionAlgorithm::Aes256Gcm => (
835 generate_aes256_key()
836 .context("In get_or_create_super_key: Failed to generate AES 256 key.")?,
837 None,
838 ),
Paul Crowley52f017f2021-06-22 08:16:01 -0700839 SuperEncryptionAlgorithm::EcdhP521 => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700840 let key = ECDHPrivateKey::generate()
841 .context("In get_or_create_super_key: Failed to generate ECDH key")?;
842 (
843 key.private_key()
844 .context("In get_or_create_super_key: private_key failed")?,
845 Some(
846 key.public_key()
847 .context("In get_or_create_super_key: public_key failed")?,
848 ),
849 )
850 }
851 };
Paul Crowley7a658392021-03-18 17:08:20 -0700852 //derive an AES256 key from the password and re-encrypt the super key
853 //before we insert it in the database.
854 let (encrypted_super_key, blob_metadata) =
855 Self::encrypt_with_password(&super_key, password)
856 .context("In get_or_create_super_key.")?;
Paul Crowley8d5b2532021-03-19 10:53:07 -0700857 let mut key_metadata = KeyMetaData::new();
858 if let Some(pk) = public_key {
859 key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk));
860 }
Paul Crowley7a658392021-03-18 17:08:20 -0700861 let key_entry = db
Paul Crowley8d5b2532021-03-19 10:53:07 -0700862 .store_super_key(
863 user_id,
864 key_type,
865 &encrypted_super_key,
866 &blob_metadata,
867 &key_metadata,
868 )
Paul Crowley7a658392021-03-18 17:08:20 -0700869 .context("In get_or_create_super_key. Failed to store super key.")?;
Paul Crowley8d5b2532021-03-19 10:53:07 -0700870 Ok(Arc::new(SuperKey {
871 algorithm: key_type.algorithm,
872 key: super_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000873 id: SuperKeyIdentifier::DatabaseId(key_entry.id()),
Paul Crowley8d5b2532021-03-19 10:53:07 -0700874 reencrypt_with,
875 }))
Paul Crowley7a658392021-03-18 17:08:20 -0700876 }
877 }
878
Paul Crowley8d5b2532021-03-19 10:53:07 -0700879 /// Decrypt the screen-lock bound keys for this user using the password and store in memory.
Paul Crowley7a658392021-03-18 17:08:20 -0700880 pub fn unlock_screen_lock_bound_key(
881 &self,
882 db: &mut KeystoreDB,
883 user_id: UserId,
884 password: &Password,
885 ) -> Result<()> {
886 let mut data = self.data.lock().unwrap();
887 let entry = data.user_keys.entry(user_id).or_default();
888 let aes = entry
889 .screen_lock_bound
890 .get_or_try_to_insert_with(|| {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700891 Self::get_or_create_super_key(
892 db,
893 user_id,
894 &USER_SCREEN_LOCK_BOUND_KEY,
895 password,
896 None,
897 )
898 })?
899 .clone();
900 let ecdh = entry
901 .screen_lock_bound_private
902 .get_or_try_to_insert_with(|| {
903 Self::get_or_create_super_key(
904 db,
905 user_id,
Paul Crowley52f017f2021-06-22 08:16:01 -0700906 &USER_SCREEN_LOCK_BOUND_P521_KEY,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700907 password,
908 Some(aes.clone()),
909 )
Paul Crowley7a658392021-03-18 17:08:20 -0700910 })?
911 .clone();
Paul Crowley44c02da2021-04-08 17:04:43 +0000912 data.add_key_to_key_index(&aes)?;
913 data.add_key_to_key_index(&ecdh)?;
Paul Crowley7a658392021-03-18 17:08:20 -0700914 Ok(())
915 }
916
Paul Crowley8d5b2532021-03-19 10:53:07 -0700917 /// Wipe the screen-lock bound keys for this user from memory.
Paul Crowley618869e2021-04-08 20:30:54 -0700918 pub fn lock_screen_lock_bound_key(
919 &self,
920 db: &mut KeystoreDB,
921 user_id: UserId,
922 unlocking_sids: &[i64],
923 ) {
924 log::info!("Locking screen bound for user {} sids {:?}", user_id, unlocking_sids);
Paul Crowley7a658392021-03-18 17:08:20 -0700925 let mut data = self.data.lock().unwrap();
926 let mut entry = data.user_keys.entry(user_id).or_default();
Paul Crowley618869e2021-04-08 20:30:54 -0700927 if !unlocking_sids.is_empty() {
928 if let (Some(aes), Some(ecdh)) = (
929 entry.screen_lock_bound.as_ref().cloned(),
930 entry.screen_lock_bound_private.as_ref().cloned(),
931 ) {
932 let res = (|| -> Result<()> {
933 let key_desc = KeyMintDevice::internal_descriptor(format!(
934 "biometric_unlock_key_{}",
935 user_id
936 ));
937 let encrypting_key = generate_aes256_key()?;
938 let km_dev: KeyMintDevice =
939 KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
940 .context("In lock_screen_lock_bound_key: KeyMintDevice::get failed")?;
941 let mut key_params = vec![
942 KeyParameterValue::Algorithm(Algorithm::AES),
943 KeyParameterValue::KeySize(256),
944 KeyParameterValue::BlockMode(BlockMode::GCM),
945 KeyParameterValue::PaddingMode(PaddingMode::NONE),
946 KeyParameterValue::CallerNonce,
947 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
948 KeyParameterValue::MinMacLength(128),
949 KeyParameterValue::AuthTimeout(BIOMETRIC_AUTH_TIMEOUT_S),
950 KeyParameterValue::HardwareAuthenticatorType(
951 HardwareAuthenticatorType::FINGERPRINT,
952 ),
953 ];
954 for sid in unlocking_sids {
955 key_params.push(KeyParameterValue::UserSecureID(*sid));
956 }
957 let key_params: Vec<KmKeyParameter> =
958 key_params.into_iter().map(|x| x.into()).collect();
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700959 km_dev.create_and_store_key(
960 db,
961 &key_desc,
962 KeyType::Client, /* TODO Should be Super b/189470584 */
963 |dev| {
964 let _wp = wd::watch_millis(
965 "In lock_screen_lock_bound_key: calling importKey.",
966 500,
967 );
968 dev.importKey(
969 key_params.as_slice(),
970 KeyFormat::RAW,
971 &encrypting_key,
972 None,
973 )
974 },
975 )?;
Paul Crowley618869e2021-04-08 20:30:54 -0700976 entry.biometric_unlock = Some(BiometricUnlock {
977 sids: unlocking_sids.into(),
978 key_desc,
979 screen_lock_bound: LockedKey::new(&encrypting_key, &aes)?,
980 screen_lock_bound_private: LockedKey::new(&encrypting_key, &ecdh)?,
981 });
982 Ok(())
983 })();
984 // There is no reason to propagate an error here upwards. We must discard
985 // entry.screen_lock_bound* in any case.
986 if let Err(e) = res {
987 log::error!("Error setting up biometric unlock: {:#?}", e);
988 }
989 }
990 }
Paul Crowley7a658392021-03-18 17:08:20 -0700991 entry.screen_lock_bound = None;
Paul Crowley8d5b2532021-03-19 10:53:07 -0700992 entry.screen_lock_bound_private = None;
Paul Crowley7a658392021-03-18 17:08:20 -0700993 }
Paul Crowley618869e2021-04-08 20:30:54 -0700994
995 /// User has unlocked, not using a password. See if any of our stored auth tokens can be used
996 /// to unlock the keys protecting UNLOCKED_DEVICE_REQUIRED keys.
997 pub fn try_unlock_user_with_biometric(
998 &self,
999 db: &mut KeystoreDB,
1000 user_id: UserId,
1001 ) -> Result<()> {
1002 let mut data = self.data.lock().unwrap();
1003 let mut entry = data.user_keys.entry(user_id).or_default();
1004 if let Some(biometric) = entry.biometric_unlock.as_ref() {
Janis Danisevskisacebfa22021-05-25 10:56:10 -07001005 let (key_id_guard, key_entry) = db
1006 .load_key_entry(
1007 &biometric.key_desc,
1008 KeyType::Client, // This should not be a Client key.
1009 KeyEntryLoadBits::KM,
1010 AID_KEYSTORE,
1011 |_, _| Ok(()),
1012 )
1013 .context("In try_unlock_user_with_biometric: load_key_entry failed")?;
Paul Crowley618869e2021-04-08 20:30:54 -07001014 let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
1015 .context("In try_unlock_user_with_biometric: KeyMintDevice::get failed")?;
1016 for sid in &biometric.sids {
1017 if let Some((auth_token_entry, _)) = db.find_auth_token_entry(|entry| {
1018 entry.auth_token().userId == *sid || entry.auth_token().authenticatorId == *sid
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001019 }) {
Paul Crowley618869e2021-04-08 20:30:54 -07001020 let res: Result<(Arc<SuperKey>, Arc<SuperKey>)> = (|| {
1021 let slb = biometric.screen_lock_bound.decrypt(
1022 db,
1023 &km_dev,
1024 &key_id_guard,
1025 &key_entry,
1026 auth_token_entry.auth_token(),
1027 None,
1028 )?;
1029 let slbp = biometric.screen_lock_bound_private.decrypt(
1030 db,
1031 &km_dev,
1032 &key_id_guard,
1033 &key_entry,
1034 auth_token_entry.auth_token(),
1035 Some(slb.clone()),
1036 )?;
1037 Ok((slb, slbp))
1038 })();
1039 match res {
1040 Ok((slb, slbp)) => {
1041 entry.screen_lock_bound = Some(slb.clone());
1042 entry.screen_lock_bound_private = Some(slbp.clone());
1043 data.add_key_to_key_index(&slb)?;
1044 data.add_key_to_key_index(&slbp)?;
1045 log::info!(concat!(
1046 "In try_unlock_user_with_biometric: ",
1047 "Successfully unlocked with biometric"
1048 ));
1049 return Ok(());
1050 }
1051 Err(e) => {
1052 log::warn!("In try_unlock_user_with_biometric: attempt failed: {:?}", e)
1053 }
1054 }
1055 }
1056 }
1057 }
1058 Ok(())
1059 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001060}
1061
1062/// This enum represents different states of the user's life cycle in the device.
1063/// For now, only three states are defined. More states may be added later.
1064pub enum UserState {
1065 // The user has registered LSKF and has unlocked the device by entering PIN/Password,
1066 // and hence the per-boot super key is available in the cache.
Paul Crowley7a658392021-03-18 17:08:20 -07001067 LskfUnlocked(Arc<SuperKey>),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001068 // The user has registered LSKF, but has not unlocked the device using password, after reboot.
1069 // Hence the per-boot super-key(s) is not available in the cache.
1070 // However, the encrypted super key is available in the database.
1071 LskfLocked,
1072 // There's no user in the device for the given user id, or the user with the user id has not
1073 // setup LSKF.
1074 Uninitialized,
1075}
1076
1077impl UserState {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001078 pub fn get(
1079 db: &mut KeystoreDB,
1080 legacy_migrator: &LegacyMigrator,
1081 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -07001082 user_id: UserId,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001083 ) -> Result<UserState> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001084 match skm.get_per_boot_key_by_user_id(user_id) {
1085 Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
1086 None => {
1087 //Check if a super key exists in the database or legacy database.
1088 //If so, return locked user state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001089 if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00001090 .context("In get.")?
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001091 {
1092 Ok(UserState::LskfLocked)
1093 } else {
1094 Ok(UserState::Uninitialized)
1095 }
1096 }
1097 }
1098 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00001099
1100 /// Queries user state when serving password change requests.
1101 pub fn get_with_password_changed(
1102 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001103 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001104 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -07001105 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -07001106 password: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001107 ) -> Result<UserState> {
1108 match skm.get_per_boot_key_by_user_id(user_id) {
1109 Some(super_key) => {
1110 if password.is_none() {
1111 //transitioning to swiping, delete only the super key in database and cache, and
1112 //super-encrypted keys in database (and in KM)
Janis Danisevskiseed69842021-02-18 20:04:10 -08001113 Self::reset_user(db, skm, legacy_migrator, user_id, true).context(
1114 "In get_with_password_changed: Trying to delete keys from the db.",
1115 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00001116 //Lskf is now removed in Keystore
1117 Ok(UserState::Uninitialized)
1118 } else {
1119 //Keystore won't be notified when changing to a new password when LSKF is
1120 //already setup. Therefore, ideally this path wouldn't be reached.
1121 Ok(UserState::LskfUnlocked(super_key))
1122 }
1123 }
1124 None => {
1125 //Check if a super key exists in the database or legacy database.
1126 //If so, return LskfLocked state.
1127 //Otherwise, i) if the password is provided, initialize the super key and return
1128 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001129 skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasingheda895552021-01-27 19:34:37 +00001130 }
1131 }
1132 }
1133
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001134 /// Queries user state when serving password unlock requests.
1135 pub fn get_with_password_unlock(
1136 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001137 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001138 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -07001139 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -07001140 password: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001141 ) -> Result<UserState> {
1142 match skm.get_per_boot_key_by_user_id(user_id) {
1143 Some(super_key) => {
1144 log::info!("In get_with_password_unlock. Trying to unlock when already unlocked.");
1145 Ok(UserState::LskfUnlocked(super_key))
1146 }
1147 None => {
1148 //Check if a super key exists in the database or legacy database.
1149 //If not, return Uninitialized state.
1150 //Otherwise, try to unlock the super key and if successful,
1151 //return LskfUnlocked state
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001152 skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001153 .context("In get_with_password_unlock. Failed to unlock super key.")
1154 }
1155 }
1156 }
1157
Hasini Gunasingheda895552021-01-27 19:34:37 +00001158 /// Delete all the keys created on behalf of the user.
1159 /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
1160 /// encrypted keys.
1161 pub fn reset_user(
1162 db: &mut KeystoreDB,
1163 skm: &SuperKeyManager,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001164 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -07001165 user_id: UserId,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001166 keep_non_super_encrypted_keys: bool,
1167 ) -> Result<()> {
1168 // mark keys created on behalf of the user as unreferenced.
Janis Danisevskiseed69842021-02-18 20:04:10 -08001169 legacy_migrator
1170 .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
1171 .context("In reset_user: Trying to delete legacy keys.")?;
Paul Crowley7a658392021-03-18 17:08:20 -07001172 db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
Hasini Gunasingheda895552021-01-27 19:34:37 +00001173 .context("In reset user. Error in unbinding keys.")?;
1174
1175 //delete super key in cache, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001176 skm.forget_all_keys_for_user(user_id);
Hasini Gunasingheda895552021-01-27 19:34:37 +00001177 Ok(())
1178 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001179}
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001180
Janis Danisevskiseed69842021-02-18 20:04:10 -08001181/// This enum represents three states a KeyMint Blob can be in, w.r.t super encryption.
1182/// `Sensitive` holds the non encrypted key and a reference to its super key.
1183/// `NonSensitive` holds a non encrypted key that is never supposed to be encrypted.
1184/// `Ref` holds a reference to a key blob when it does not need to be modified if its
1185/// life time allows it.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001186pub enum KeyBlob<'a> {
Paul Crowley8d5b2532021-03-19 10:53:07 -07001187 Sensitive {
1188 key: ZVec,
1189 /// If KeyMint reports that the key must be upgraded, we must
1190 /// re-encrypt the key before writing to the database; we use
1191 /// this key.
1192 reencrypt_with: Arc<SuperKey>,
1193 /// If this key was decrypted with an ECDH key, we want to
1194 /// re-encrypt it on first use whether it was upgraded or not;
1195 /// this field indicates that that's necessary.
1196 force_reencrypt: bool,
1197 },
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001198 NonSensitive(Vec<u8>),
1199 Ref(&'a [u8]),
1200}
1201
Paul Crowley8d5b2532021-03-19 10:53:07 -07001202impl<'a> KeyBlob<'a> {
1203 pub fn force_reencrypt(&self) -> bool {
1204 if let KeyBlob::Sensitive { force_reencrypt, .. } = self {
1205 *force_reencrypt
1206 } else {
1207 false
1208 }
1209 }
1210}
1211
Janis Danisevskiseed69842021-02-18 20:04:10 -08001212/// Deref returns a reference to the key material in any variant.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001213impl<'a> Deref for KeyBlob<'a> {
1214 type Target = [u8];
1215
1216 fn deref(&self) -> &Self::Target {
1217 match self {
Paul Crowley7a658392021-03-18 17:08:20 -07001218 Self::Sensitive { key, .. } => &key,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001219 Self::NonSensitive(key) => &key,
1220 Self::Ref(key) => key,
1221 }
1222 }
1223}