blob: 50a5f31bdecc8033575de16cb6a2ae69405d567a [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,
Paul Crowley618869e2021-04-08 20:30:54 -070022 database::{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 Danisevskisb42fc182020-12-15 08:41:27 -080032};
Paul Crowley618869e2021-04-08 20:30:54 -070033use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
34 Algorithm::Algorithm, BlockMode::BlockMode, HardwareAuthToken::HardwareAuthToken,
35 HardwareAuthenticatorType::HardwareAuthenticatorType, KeyFormat::KeyFormat,
36 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
37 SecurityLevel::SecurityLevel,
38};
39use android_system_keystore2::aidl::android::system::keystore2::{
40 Domain::Domain, KeyDescriptor::KeyDescriptor,
41};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080042use anyhow::{Context, Result};
43use keystore2_crypto::{
Paul Crowleyf61fee72021-03-17 14:38:44 -070044 aes_gcm_decrypt, aes_gcm_encrypt, generate_aes256_key, generate_salt, Password, ZVec,
45 AES_256_KEY_LENGTH,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080046};
Paul Crowley44c02da2021-04-08 17:04:43 +000047use keystore2_system_property::PropertyWatcher;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080048use std::{
49 collections::HashMap,
50 sync::Arc,
51 sync::{Mutex, Weak},
52};
Paul Crowley618869e2021-04-08 20:30:54 -070053use std::{convert::TryFrom, ops::Deref};
Janis Danisevskisb42fc182020-12-15 08:41:27 -080054
Paul Crowley44c02da2021-04-08 17:04:43 +000055const MAX_MAX_BOOT_LEVEL: usize = 1_000_000_000;
Paul Crowley618869e2021-04-08 20:30:54 -070056/// Allow up to 15 seconds between the user unlocking using a biometric, and the auth
57/// token being used to unlock in [`SuperKeyManager::try_unlock_user_with_biometric`].
58/// This seems short enough for security purposes, while long enough that even the
59/// very slowest device will present the auth token in time.
60const BIOMETRIC_AUTH_TIMEOUT_S: i32 = 15; // seconds
Paul Crowley44c02da2021-04-08 17:04:43 +000061
Janis Danisevskisb42fc182020-12-15 08:41:27 -080062type UserId = u32;
63
Paul Crowley8d5b2532021-03-19 10:53:07 -070064/// Encryption algorithm used by a particular type of superencryption key
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum SuperEncryptionAlgorithm {
67 /// Symmetric encryption with AES-256-GCM
68 Aes256Gcm,
69 /// Public-key encryption with ECDH P-256
70 EcdhP256,
71}
72
Paul Crowley7a658392021-03-18 17:08:20 -070073/// A particular user may have several superencryption keys in the database, each for a
74/// different purpose, distinguished by alias. Each is associated with a static
75/// constant of this type.
76pub struct SuperKeyType {
77 /// Alias used to look the key up in the `persistent.keyentry` table.
78 pub alias: &'static str,
Paul Crowley8d5b2532021-03-19 10:53:07 -070079 /// Encryption algorithm
80 pub algorithm: SuperEncryptionAlgorithm,
Paul Crowley7a658392021-03-18 17:08:20 -070081}
82
83/// Key used for LskfLocked keys; the corresponding superencryption key is loaded in memory
84/// when the user first unlocks, and remains in memory until the device reboots.
Paul Crowley8d5b2532021-03-19 10:53:07 -070085pub const USER_SUPER_KEY: SuperKeyType =
86 SuperKeyType { alias: "USER_SUPER_KEY", algorithm: SuperEncryptionAlgorithm::Aes256Gcm };
Paul Crowley7a658392021-03-18 17:08:20 -070087/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
88/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
Paul Crowley8d5b2532021-03-19 10:53:07 -070089/// Symmetric.
90pub const USER_SCREEN_LOCK_BOUND_KEY: SuperKeyType = SuperKeyType {
91 alias: "USER_SCREEN_LOCK_BOUND_KEY",
92 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
93};
94/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
95/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
96/// Asymmetric, so keys can be encrypted when the device is locked.
97pub const USER_SCREEN_LOCK_BOUND_ECDH_KEY: SuperKeyType = SuperKeyType {
98 alias: "USER_SCREEN_LOCK_BOUND_ECDH_KEY",
99 algorithm: SuperEncryptionAlgorithm::EcdhP256,
100};
Paul Crowley7a658392021-03-18 17:08:20 -0700101
102/// Superencryption to apply to a new key.
103#[derive(Debug, Clone, Copy)]
104pub enum SuperEncryptionType {
105 /// Do not superencrypt this key.
106 None,
107 /// Superencrypt with a key that remains in memory from first unlock to reboot.
108 LskfBound,
109 /// Superencrypt with a key cleared from memory when the device is locked.
110 ScreenLockBound,
Paul Crowley44c02da2021-04-08 17:04:43 +0000111 /// Superencrypt with a key based on the desired boot level
112 BootLevel(i32),
113}
114
115#[derive(Debug, Clone, Copy)]
116pub enum SuperKeyIdentifier {
117 /// id of the super key in the database.
118 DatabaseId(i64),
119 /// Boot level of the encrypting boot level key
120 BootLevel(i32),
121}
122
123impl SuperKeyIdentifier {
124 fn from_metadata(metadata: &BlobMetaData) -> Option<Self> {
125 if let Some(EncryptedBy::KeyId(key_id)) = metadata.encrypted_by() {
126 Some(SuperKeyIdentifier::DatabaseId(*key_id))
127 } else if let Some(boot_level) = metadata.max_boot_level() {
128 Some(SuperKeyIdentifier::BootLevel(*boot_level))
129 } else {
130 None
131 }
132 }
133
134 fn add_to_metadata(&self, metadata: &mut BlobMetaData) {
135 match self {
136 SuperKeyIdentifier::DatabaseId(id) => {
137 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(*id)));
138 }
139 SuperKeyIdentifier::BootLevel(level) => {
140 metadata.add(BlobMetaEntry::MaxBootLevel(*level));
141 }
142 }
143 }
Paul Crowley7a658392021-03-18 17:08:20 -0700144}
145
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000146pub struct SuperKey {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700147 algorithm: SuperEncryptionAlgorithm,
Paul Crowley7a658392021-03-18 17:08:20 -0700148 key: ZVec,
Paul Crowley44c02da2021-04-08 17:04:43 +0000149 /// Identifier of the encrypting key, used to write an encrypted blob
150 /// back to the database after re-encryption eg on a key update.
151 id: SuperKeyIdentifier,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700152 /// ECDH is more expensive than AES. So on ECDH private keys we set the
153 /// reencrypt_with field to point at the corresponding AES key, and the
154 /// keys will be re-encrypted with AES on first use.
155 reencrypt_with: Option<Arc<SuperKey>>,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000156}
157
158impl SuperKey {
Paul Crowley7a658392021-03-18 17:08:20 -0700159 /// For most purposes `unwrap_key` handles decryption,
160 /// but legacy handling and some tests need to assume AES and decrypt directly.
161 pub fn aes_gcm_decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700162 if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm {
163 aes_gcm_decrypt(data, iv, tag, &self.key)
164 .context("In aes_gcm_decrypt: decryption failed")
165 } else {
166 Err(Error::sys()).context("In aes_gcm_decrypt: Key is not an AES key")
167 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000168 }
Paul Crowleye8826e52021-03-31 08:33:53 -0700169}
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000170
Paul Crowley618869e2021-04-08 20:30:54 -0700171/// A SuperKey that has been encrypted with an AES-GCM key. For
172/// encryption the key is in memory, and for decryption it is in KM.
173struct LockedKey {
174 algorithm: SuperEncryptionAlgorithm,
175 id: SuperKeyIdentifier,
176 nonce: Vec<u8>,
177 ciphertext: Vec<u8>, // with tag appended
178}
179
180impl LockedKey {
181 fn new(key: &[u8], to_encrypt: &Arc<SuperKey>) -> Result<Self> {
182 let (mut ciphertext, nonce, mut tag) = aes_gcm_encrypt(&to_encrypt.key, key)?;
183 ciphertext.append(&mut tag);
184 Ok(LockedKey { algorithm: to_encrypt.algorithm, id: to_encrypt.id, nonce, ciphertext })
185 }
186
187 fn decrypt(
188 &self,
189 db: &mut KeystoreDB,
190 km_dev: &KeyMintDevice,
191 key_id_guard: &KeyIdGuard,
192 key_entry: &KeyEntry,
193 auth_token: &HardwareAuthToken,
194 reencrypt_with: Option<Arc<SuperKey>>,
195 ) -> Result<Arc<SuperKey>> {
196 let key_params = vec![
197 KeyParameterValue::Algorithm(Algorithm::AES),
198 KeyParameterValue::KeySize(256),
199 KeyParameterValue::BlockMode(BlockMode::GCM),
200 KeyParameterValue::PaddingMode(PaddingMode::NONE),
201 KeyParameterValue::Nonce(self.nonce.clone()),
202 KeyParameterValue::MacLength(128),
203 ];
204 let key_params: Vec<KmKeyParameter> = key_params.into_iter().map(|x| x.into()).collect();
205 let key = ZVec::try_from(km_dev.use_key_in_one_step(
206 db,
207 key_id_guard,
208 key_entry,
209 KeyPurpose::DECRYPT,
210 &key_params,
211 Some(auth_token),
212 &self.ciphertext,
213 )?)?;
214 Ok(Arc::new(SuperKey { algorithm: self.algorithm, key, id: self.id, reencrypt_with }))
215 }
216}
217
218/// Keys for unlocking UNLOCKED_DEVICE_REQUIRED keys, as LockedKeys, complete with
219/// a database descriptor for the encrypting key and the sids for the auth tokens
220/// that can be used to decrypt it.
221struct BiometricUnlock {
222 /// List of auth token SIDs that can be used to unlock these keys.
223 sids: Vec<i64>,
224 /// Database descriptor of key to use to unlock.
225 key_desc: KeyDescriptor,
226 /// Locked versions of the matching UserSuperKeys fields
227 screen_lock_bound: LockedKey,
228 screen_lock_bound_private: LockedKey,
229}
230
Paul Crowleye8826e52021-03-31 08:33:53 -0700231#[derive(Default)]
232struct UserSuperKeys {
233 /// The per boot key is used for LSKF binding of authentication bound keys. There is one
234 /// key per android user. The key is stored on flash encrypted with a key derived from a
235 /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF).
236 /// When the user unlocks the device for the first time, this key is unlocked, i.e., decrypted,
237 /// and stays memory resident until the device reboots.
238 per_boot: Option<Arc<SuperKey>>,
239 /// The screen lock key works like the per boot key with the distinction that it is cleared
240 /// from memory when the screen lock is engaged.
241 screen_lock_bound: Option<Arc<SuperKey>>,
242 /// When the device is locked, screen-lock-bound keys can still be encrypted, using
243 /// ECDH public-key encryption. This field holds the decryption private key.
244 screen_lock_bound_private: Option<Arc<SuperKey>>,
Paul Crowley618869e2021-04-08 20:30:54 -0700245 /// Versions of the above two keys, locked behind a biometric.
246 biometric_unlock: Option<BiometricUnlock>,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000247}
248
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800249#[derive(Default)]
250struct SkmState {
251 user_keys: HashMap<UserId, UserSuperKeys>,
Paul Crowley7a658392021-03-18 17:08:20 -0700252 key_index: HashMap<i64, Weak<SuperKey>>,
Paul Crowley44c02da2021-04-08 17:04:43 +0000253 boot_level_key_cache: Option<BootLevelKeyCache>,
Paul Crowley7a658392021-03-18 17:08:20 -0700254}
255
256impl SkmState {
Paul Crowley44c02da2021-04-08 17:04:43 +0000257 fn add_key_to_key_index(&mut self, super_key: &Arc<SuperKey>) -> Result<()> {
258 if let SuperKeyIdentifier::DatabaseId(id) = super_key.id {
259 self.key_index.insert(id, Arc::downgrade(super_key));
260 Ok(())
261 } else {
262 Err(Error::sys()).context(format!(
263 "In add_key_to_key_index: cannot add key with ID {:?}",
264 super_key.id
265 ))
266 }
Paul Crowley7a658392021-03-18 17:08:20 -0700267 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800268}
269
270#[derive(Default)]
271pub struct SuperKeyManager {
272 data: Mutex<SkmState>,
273}
274
275impl SuperKeyManager {
Paul Crowley44c02da2021-04-08 17:04:43 +0000276 pub fn set_up_boot_level_cache(self: &Arc<Self>, db: &mut KeystoreDB) -> Result<()> {
277 let mut data = self.data.lock().unwrap();
278 if data.boot_level_key_cache.is_some() {
279 log::info!("In set_up_boot_level_cache: called for a second time");
280 return Ok(());
281 }
282 let level_zero_key = get_level_zero_key(db)
283 .context("In set_up_boot_level_cache: get_level_zero_key failed")?;
284 data.boot_level_key_cache = Some(BootLevelKeyCache::new(level_zero_key));
285 log::info!("Starting boot level watcher.");
286 let clone = self.clone();
287 std::thread::spawn(move || {
288 clone
289 .watch_boot_level()
290 .unwrap_or_else(|e| log::error!("watch_boot_level failed:\n{:?}", e));
291 });
292 Ok(())
293 }
294
295 /// Watch the `keystore.boot_level` system property, and keep boot level up to date.
296 /// Blocks waiting for system property changes, so must be run in its own thread.
297 fn watch_boot_level(&self) -> Result<()> {
298 let mut w = PropertyWatcher::new("keystore.boot_level")
299 .context("In watch_boot_level: PropertyWatcher::new failed")?;
300 loop {
301 let level = w
302 .read(|_n, v| v.parse::<usize>().map_err(std::convert::Into::into))
303 .context("In watch_boot_level: read of property failed")?;
304 // watch_boot_level should only be called once data.boot_level_key_cache is Some,
305 // so it's safe to unwrap in the branches below.
306 if level < MAX_MAX_BOOT_LEVEL {
307 log::info!("Read keystore.boot_level value {}", level);
308 let mut data = self.data.lock().unwrap();
309 data.boot_level_key_cache
310 .as_mut()
311 .unwrap()
312 .advance_boot_level(level)
313 .context("In watch_boot_level: advance_boot_level failed")?;
314 } else {
315 log::info!(
316 "keystore.boot_level {} hits maximum {}, finishing.",
317 level,
318 MAX_MAX_BOOT_LEVEL
319 );
320 let mut data = self.data.lock().unwrap();
321 data.boot_level_key_cache.as_mut().unwrap().finish();
322 break;
323 }
324 w.wait().context("In watch_boot_level: property wait failed")?;
325 }
326 Ok(())
327 }
328
329 pub fn level_accessible(&self, boot_level: i32) -> bool {
330 self.data
331 .lock()
332 .unwrap()
333 .boot_level_key_cache
334 .as_ref()
335 .map_or(false, |c| c.level_accessible(boot_level as usize))
336 }
337
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800338 pub fn forget_all_keys_for_user(&self, user: UserId) {
339 let mut data = self.data.lock().unwrap();
340 data.user_keys.remove(&user);
341 }
342
Paul Crowley44c02da2021-04-08 17:04:43 +0000343 fn install_per_boot_key_for_user(&self, user: UserId, super_key: Arc<SuperKey>) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800344 let mut data = self.data.lock().unwrap();
Paul Crowley44c02da2021-04-08 17:04:43 +0000345 data.add_key_to_key_index(&super_key)
346 .context("In install_per_boot_key_for_user: add_key_to_key_index failed")?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000347 data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Paul Crowley44c02da2021-04-08 17:04:43 +0000348 Ok(())
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800349 }
350
Paul Crowley44c02da2021-04-08 17:04:43 +0000351 fn lookup_key(&self, key_id: &SuperKeyIdentifier) -> Result<Option<Arc<SuperKey>>> {
352 let mut data = self.data.lock().unwrap();
353 Ok(match key_id {
354 SuperKeyIdentifier::DatabaseId(id) => data.key_index.get(id).and_then(|k| k.upgrade()),
355 SuperKeyIdentifier::BootLevel(level) => data
356 .boot_level_key_cache
357 .as_mut()
358 .map(|b| b.aes_key(*level as usize))
359 .transpose()
360 .context("In lookup_key: aes_key failed")?
361 .flatten()
362 .map(|key| {
363 Arc::new(SuperKey {
364 algorithm: SuperEncryptionAlgorithm::Aes256Gcm,
365 key,
366 id: *key_id,
367 reencrypt_with: None,
368 })
369 }),
370 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800371 }
372
Paul Crowley7a658392021-03-18 17:08:20 -0700373 pub fn get_per_boot_key_by_user_id(&self, user_id: UserId) -> Option<Arc<SuperKey>> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800374 let data = self.data.lock().unwrap();
Paul Crowley7a658392021-03-18 17:08:20 -0700375 data.user_keys.get(&user_id).and_then(|e| e.per_boot.as_ref().cloned())
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800376 }
377
378 /// This function unlocks the super keys for a given user.
379 /// This means the key is loaded from the database, decrypted and placed in the
380 /// super key cache. If there is no such key a new key is created, encrypted with
381 /// a key derived from the given password and stored in the database.
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800382 pub fn unlock_user_key(
383 &self,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000384 db: &mut KeystoreDB,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800385 user: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700386 pw: &Password,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800387 legacy_blob_loader: &LegacyBlobLoader,
388 ) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800389 let (_, entry) = db
Max Bires8e93d2b2021-01-14 13:17:59 -0800390 .get_or_create_key_with(
391 Domain::APP,
392 user as u64 as i64,
Paul Crowley7a658392021-03-18 17:08:20 -0700393 &USER_SUPER_KEY.alias,
Max Bires8e93d2b2021-01-14 13:17:59 -0800394 crate::database::KEYSTORE_UUID,
395 || {
396 // For backward compatibility we need to check if there is a super key present.
397 let super_key = legacy_blob_loader
398 .load_super_key(user, pw)
399 .context("In create_new_key: Failed to load legacy key blob.")?;
400 let super_key = match super_key {
401 None => {
402 // No legacy file was found. So we generate a new key.
Hasini Gunasingheda895552021-01-27 19:34:37 +0000403 generate_aes256_key()
Max Bires8e93d2b2021-01-14 13:17:59 -0800404 .context("In create_new_key: Failed to generate AES 256 key.")?
405 }
406 Some(key) => key,
407 };
Hasini Gunasingheda895552021-01-27 19:34:37 +0000408 // Regardless of whether we loaded an old AES128 key or generated a new AES256
409 // key as the super key, we derive a AES256 key from the password and re-encrypt
410 // the super key before we insert it in the database. The length of the key is
411 // preserved by the encryption so we don't need any extra flags to inform us
412 // which algorithm to use it with.
413 Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
Max Bires8e93d2b2021-01-14 13:17:59 -0800414 },
415 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800416 .context("In unlock_user_key: Failed to get key id.")?;
417
Paul Crowley8d5b2532021-03-19 10:53:07 -0700418 self.populate_cache_from_super_key_blob(user, USER_SUPER_KEY.algorithm, entry, pw)
419 .context("In unlock_user_key.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800420 Ok(())
421 }
422
Paul Crowley44c02da2021-04-08 17:04:43 +0000423 /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using
424 /// the relevant super key.
425 pub fn unwrap_key_if_required<'a>(
426 &self,
427 metadata: &BlobMetaData,
428 blob: &'a [u8],
429 ) -> Result<KeyBlob<'a>> {
430 Ok(if let Some(key_id) = SuperKeyIdentifier::from_metadata(metadata) {
431 let super_key = self
432 .lookup_key(&key_id)
433 .context("In unwrap_key: lookup_key failed")?
434 .ok_or(Error::Rc(ResponseCode::LOCKED))
435 .context("In unwrap_key: Required super decryption key is not in memory.")?;
436 KeyBlob::Sensitive {
437 key: Self::unwrap_key_with_key(blob, metadata, &super_key)
438 .context("In unwrap_key: unwrap_key_with_key failed")?,
439 reencrypt_with: super_key.reencrypt_with.as_ref().unwrap_or(&super_key).clone(),
440 force_reencrypt: super_key.reencrypt_with.is_some(),
441 }
Paul Crowleye8826e52021-03-31 08:33:53 -0700442 } else {
Paul Crowley44c02da2021-04-08 17:04:43 +0000443 KeyBlob::Ref(blob)
Paul Crowleye8826e52021-03-31 08:33:53 -0700444 })
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800445 }
446
447 /// Unwraps an encrypted key blob given an encryption key.
Paul Crowley7a658392021-03-18 17:08:20 -0700448 fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700449 match key.algorithm {
450 SuperEncryptionAlgorithm::Aes256Gcm => match (metadata.iv(), metadata.aead_tag()) {
451 (Some(iv), Some(tag)) => key
452 .aes_gcm_decrypt(blob, iv, tag)
453 .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
454 (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
455 concat!(
456 "In unwrap_key_with_key: Key has incomplete metadata.",
457 "Present: iv: {}, aead_tag: {}."
458 ),
459 iv.is_some(),
460 tag.is_some(),
461 )),
462 },
463 SuperEncryptionAlgorithm::EcdhP256 => {
464 match (metadata.public_key(), metadata.salt(), metadata.iv(), metadata.aead_tag()) {
465 (Some(public_key), Some(salt), Some(iv), Some(aead_tag)) => {
466 ECDHPrivateKey::from_private_key(&key.key)
467 .and_then(|k| k.decrypt_message(public_key, salt, iv, blob, aead_tag))
468 .context(
469 "In unwrap_key_with_key: Failed to decrypt the key blob with ECDH.",
470 )
471 }
472 (public_key, salt, iv, aead_tag) => {
473 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
474 concat!(
475 "In unwrap_key_with_key: Key has incomplete metadata.",
476 "Present: public_key: {}, salt: {}, iv: {}, aead_tag: {}."
477 ),
478 public_key.is_some(),
479 salt.is_some(),
480 iv.is_some(),
481 aead_tag.is_some(),
482 ))
483 }
484 }
485 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800486 }
487 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000488
489 /// Checks if user has setup LSKF, even when super key cache is empty for the user.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000490 pub fn super_key_exists_in_db_for_user(
491 db: &mut KeystoreDB,
492 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700493 user_id: UserId,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000494 ) -> Result<bool> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000495 let key_in_db = db
Paul Crowley7a658392021-03-18 17:08:20 -0700496 .key_exists(Domain::APP, user_id as u64 as i64, &USER_SUPER_KEY.alias, KeyType::Super)
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000497 .context("In super_key_exists_in_db_for_user.")?;
498
499 if key_in_db {
500 Ok(key_in_db)
501 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000502 legacy_migrator
503 .has_super_key(user_id)
504 .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000505 }
506 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000507
508 /// 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 +0000509 /// legacy database). If not, return Uninitialized state.
510 /// Otherwise, decrypt the super key from the password and return LskfUnlocked state.
511 pub fn check_and_unlock_super_key(
512 &self,
513 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000514 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700515 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700516 pw: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000517 ) -> Result<UserState> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700518 let alias = &USER_SUPER_KEY;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000519 let result = legacy_migrator
Paul Crowley8d5b2532021-03-19 10:53:07 -0700520 .with_try_migrate_super_key(user_id, pw, || db.load_super_key(alias, user_id))
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000521 .context("In check_and_unlock_super_key. Failed to load super key")?;
522
523 match result {
524 Some((_, entry)) => {
525 let super_key = self
Paul Crowley8d5b2532021-03-19 10:53:07 -0700526 .populate_cache_from_super_key_blob(user_id, alias.algorithm, entry, pw)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000527 .context("In check_and_unlock_super_key.")?;
528 Ok(UserState::LskfUnlocked(super_key))
529 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000530 None => Ok(UserState::Uninitialized),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000531 }
532 }
533
534 /// 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 +0000535 /// legacy database). If so, return LskfLocked state.
536 /// If the password is provided, generate a new super key, encrypt with the password,
537 /// store in the database and populate the super key cache for the new user
538 /// and return LskfUnlocked state.
539 /// If the password is not provided, return Uninitialized state.
540 pub fn check_and_initialize_super_key(
541 &self,
542 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000543 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700544 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700545 pw: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000546 ) -> Result<UserState> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000547 let super_key_exists_in_db =
548 Self::super_key_exists_in_db_for_user(db, legacy_migrator, user_id).context(
549 "In check_and_initialize_super_key. Failed to check if super key exists.",
550 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000551 if super_key_exists_in_db {
552 Ok(UserState::LskfLocked)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000553 } else if let Some(pw) = pw {
554 //generate a new super key.
555 let super_key = generate_aes256_key()
556 .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
557 //derive an AES256 key from the password and re-encrypt the super key
558 //before we insert it in the database.
559 let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
560 .context("In check_and_initialize_super_key.")?;
561
562 let key_entry = db
Paul Crowley8d5b2532021-03-19 10:53:07 -0700563 .store_super_key(
564 user_id,
565 &USER_SUPER_KEY,
566 &encrypted_super_key,
567 &blob_metadata,
568 &KeyMetaData::new(),
569 )
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000570 .context("In check_and_initialize_super_key. Failed to store super key.")?;
571
572 let super_key = self
Paul Crowley8d5b2532021-03-19 10:53:07 -0700573 .populate_cache_from_super_key_blob(
574 user_id,
575 USER_SUPER_KEY.algorithm,
576 key_entry,
577 pw,
578 )
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000579 .context("In check_and_initialize_super_key.")?;
580 Ok(UserState::LskfUnlocked(super_key))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000581 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000582 Ok(UserState::Uninitialized)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000583 }
584 }
585
586 //helper function to populate super key cache from the super key blob loaded from the database
587 fn populate_cache_from_super_key_blob(
588 &self,
Paul Crowley7a658392021-03-18 17:08:20 -0700589 user_id: UserId,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700590 algorithm: SuperEncryptionAlgorithm,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000591 entry: KeyEntry,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700592 pw: &Password,
Paul Crowley7a658392021-03-18 17:08:20 -0700593 ) -> Result<Arc<SuperKey>> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700594 let super_key = Self::extract_super_key_from_key_entry(algorithm, entry, pw, None)
595 .context(
596 "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
597 )?;
Paul Crowley44c02da2021-04-08 17:04:43 +0000598 self.install_per_boot_key_for_user(user_id, super_key.clone())?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000599 Ok(super_key)
600 }
601
602 /// Extracts super key from the entry loaded from the database
Paul Crowley7a658392021-03-18 17:08:20 -0700603 pub fn extract_super_key_from_key_entry(
Paul Crowley8d5b2532021-03-19 10:53:07 -0700604 algorithm: SuperEncryptionAlgorithm,
Paul Crowley7a658392021-03-18 17:08:20 -0700605 entry: KeyEntry,
606 pw: &Password,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700607 reencrypt_with: Option<Arc<SuperKey>>,
Paul Crowley7a658392021-03-18 17:08:20 -0700608 ) -> Result<Arc<SuperKey>> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000609 if let Some((blob, metadata)) = entry.key_blob_info() {
610 let key = match (
611 metadata.encrypted_by(),
612 metadata.salt(),
613 metadata.iv(),
614 metadata.aead_tag(),
615 ) {
616 (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700617 // Note that password encryption is AES no matter the value of algorithm
Paul Crowleyf61fee72021-03-17 14:38:44 -0700618 let key = pw.derive_key(Some(salt), AES_256_KEY_LENGTH).context(
619 "In extract_super_key_from_key_entry: Failed to generate key from password.",
620 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000621
622 aes_gcm_decrypt(blob, iv, tag, &key).context(
623 "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
624 )?
625 }
626 (enc_by, salt, iv, tag) => {
627 return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
628 concat!(
629 "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
Paul Crowleye8826e52021-03-31 08:33:53 -0700630 "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}."
Hasini Gunasingheda895552021-01-27 19:34:37 +0000631 ),
Paul Crowleye8826e52021-03-31 08:33:53 -0700632 enc_by,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000633 salt.is_some(),
634 iv.is_some(),
635 tag.is_some()
636 ));
637 }
638 };
Paul Crowley44c02da2021-04-08 17:04:43 +0000639 Ok(Arc::new(SuperKey {
640 algorithm,
641 key,
642 id: SuperKeyIdentifier::DatabaseId(entry.id()),
643 reencrypt_with,
644 }))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000645 } else {
646 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
647 .context("In extract_super_key_from_key_entry: No key blob info.")
648 }
649 }
650
651 /// Encrypts the super key from a key derived from the password, before storing in the database.
Paul Crowleyf61fee72021-03-17 14:38:44 -0700652 pub fn encrypt_with_password(
653 super_key: &[u8],
654 pw: &Password,
655 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000656 let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
Paul Crowleyf61fee72021-03-17 14:38:44 -0700657 let derived_key = pw
658 .derive_key(Some(&salt), AES_256_KEY_LENGTH)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000659 .context("In encrypt_with_password: Failed to derive password.")?;
660 let mut metadata = BlobMetaData::new();
661 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
662 metadata.add(BlobMetaEntry::Salt(salt));
663 let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
664 .context("In encrypt_with_password: Failed to encrypt new super key.")?;
665 metadata.add(BlobMetaEntry::Iv(iv));
666 metadata.add(BlobMetaEntry::AeadTag(tag));
667 Ok((encrypted_key, metadata))
668 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000669
670 // Encrypt the given key blob with the user's super key, if the super key exists and the device
671 // is unlocked. If the super key exists and the device is locked, or LSKF is not setup,
672 // return error. Note that it is out of the scope of this function to check if super encryption
673 // is required. Such check should be performed before calling this function.
674 fn super_encrypt_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000675 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000676 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000677 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700678 user_id: UserId,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000679 key_blob: &[u8],
680 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000681 match UserState::get(db, legacy_migrator, self, user_id)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000682 .context("In super_encrypt. Failed to get user state.")?
683 {
684 UserState::LskfUnlocked(super_key) => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700685 Self::encrypt_with_aes_super_key(key_blob, &super_key)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000686 .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
687 }
688 UserState::LskfLocked => {
689 Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
690 }
691 UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
692 .context("In super_encrypt. LSKF is not setup for the user."),
693 }
694 }
695
696 //Helper function to encrypt a key with the given super key. Callers should select which super
697 //key to be used. This is called when a key is super encrypted at its creation as well as at its
698 //upgrade.
Paul Crowley8d5b2532021-03-19 10:53:07 -0700699 fn encrypt_with_aes_super_key(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000700 key_blob: &[u8],
701 super_key: &SuperKey,
702 ) -> Result<(Vec<u8>, BlobMetaData)> {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700703 if super_key.algorithm != SuperEncryptionAlgorithm::Aes256Gcm {
704 return Err(Error::sys())
705 .context("In encrypt_with_aes_super_key: unexpected algorithm");
706 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000707 let mut metadata = BlobMetaData::new();
708 let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
Paul Crowley8d5b2532021-03-19 10:53:07 -0700709 .context("In encrypt_with_aes_super_key: Failed to encrypt new super key.")?;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000710 metadata.add(BlobMetaEntry::Iv(iv));
711 metadata.add(BlobMetaEntry::AeadTag(tag));
Paul Crowley44c02da2021-04-08 17:04:43 +0000712 super_key.id.add_to_metadata(&mut metadata);
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000713 Ok((encrypted_key, metadata))
714 }
715
716 /// Check if super encryption is required and if so, super-encrypt the key to be stored in
717 /// the database.
Paul Crowley618869e2021-04-08 20:30:54 -0700718 #[allow(clippy::too_many_arguments)]
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000719 pub fn handle_super_encryption_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000720 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000721 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000722 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000723 domain: &Domain,
724 key_parameters: &[KeyParameter],
725 flags: Option<i32>,
Paul Crowley7a658392021-03-18 17:08:20 -0700726 user_id: UserId,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000727 key_blob: &[u8],
728 ) -> Result<(Vec<u8>, BlobMetaData)> {
Paul Crowley7a658392021-03-18 17:08:20 -0700729 match Enforcements::super_encryption_required(domain, key_parameters, flags) {
730 SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
Paul Crowleye8826e52021-03-31 08:33:53 -0700731 SuperEncryptionType::LskfBound => self
732 .super_encrypt_on_key_init(db, legacy_migrator, user_id, &key_blob)
733 .context(concat!(
734 "In handle_super_encryption_on_key_init. ",
735 "Failed to super encrypt with LskfBound key."
736 )),
Paul Crowley7a658392021-03-18 17:08:20 -0700737 SuperEncryptionType::ScreenLockBound => {
738 let mut data = self.data.lock().unwrap();
739 let entry = data.user_keys.entry(user_id).or_default();
740 if let Some(super_key) = entry.screen_lock_bound.as_ref() {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700741 Self::encrypt_with_aes_super_key(key_blob, &super_key).context(concat!(
Paul Crowley7a658392021-03-18 17:08:20 -0700742 "In handle_super_encryption_on_key_init. ",
Paul Crowleye8826e52021-03-31 08:33:53 -0700743 "Failed to encrypt with ScreenLockBound key."
Paul Crowley7a658392021-03-18 17:08:20 -0700744 ))
745 } else {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700746 // Symmetric key is not available, use public key encryption
747 let loaded =
748 db.load_super_key(&USER_SCREEN_LOCK_BOUND_ECDH_KEY, user_id).context(
749 "In handle_super_encryption_on_key_init: load_super_key failed.",
750 )?;
751 let (key_id_guard, key_entry) = loaded.ok_or_else(Error::sys).context(
752 "In handle_super_encryption_on_key_init: User ECDH key missing.",
753 )?;
754 let public_key =
755 key_entry.metadata().sec1_public_key().ok_or_else(Error::sys).context(
756 "In handle_super_encryption_on_key_init: sec1_public_key missing.",
757 )?;
758 let mut metadata = BlobMetaData::new();
759 let (ephem_key, salt, iv, encrypted_key, aead_tag) =
760 ECDHPrivateKey::encrypt_message(public_key, key_blob).context(concat!(
761 "In handle_super_encryption_on_key_init: ",
762 "ECDHPrivateKey::encrypt_message failed."
763 ))?;
764 metadata.add(BlobMetaEntry::PublicKey(ephem_key));
765 metadata.add(BlobMetaEntry::Salt(salt));
766 metadata.add(BlobMetaEntry::Iv(iv));
767 metadata.add(BlobMetaEntry::AeadTag(aead_tag));
Paul Crowley44c02da2021-04-08 17:04:43 +0000768 SuperKeyIdentifier::DatabaseId(key_id_guard.id())
769 .add_to_metadata(&mut metadata);
Paul Crowley8d5b2532021-03-19 10:53:07 -0700770 Ok((encrypted_key, metadata))
Paul Crowley7a658392021-03-18 17:08:20 -0700771 }
772 }
Paul Crowley44c02da2021-04-08 17:04:43 +0000773 SuperEncryptionType::BootLevel(level) => {
774 let key_id = SuperKeyIdentifier::BootLevel(level);
775 let super_key = self
776 .lookup_key(&key_id)
777 .context("In handle_super_encryption_on_key_init: lookup_key failed")?
778 .ok_or(Error::Rc(ResponseCode::LOCKED))
779 .context("In handle_super_encryption_on_key_init: Boot stage key absent")?;
780 Self::encrypt_with_aes_super_key(key_blob, &super_key).context(concat!(
781 "In handle_super_encryption_on_key_init: ",
782 "Failed to encrypt with BootLevel key."
783 ))
784 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000785 }
786 }
787
788 /// Check if a given key needs re-super-encryption, from its KeyBlob type.
789 /// If so, re-super-encrypt the key and return a new set of metadata,
790 /// containing the new super encryption information.
Paul Crowley7a658392021-03-18 17:08:20 -0700791 pub fn reencrypt_if_required<'a>(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000792 key_blob_before_upgrade: &KeyBlob,
793 key_after_upgrade: &'a [u8],
794 ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)> {
795 match key_blob_before_upgrade {
Paul Crowley7a658392021-03-18 17:08:20 -0700796 KeyBlob::Sensitive { reencrypt_with: super_key, .. } => {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700797 let (key, metadata) =
798 Self::encrypt_with_aes_super_key(key_after_upgrade, super_key)
799 .context("In reencrypt_if_required: Failed to re-super-encrypt key.")?;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000800 Ok((KeyBlob::NonSensitive(key), Some(metadata)))
801 }
802 _ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
803 }
804 }
805
Paul Crowley7a658392021-03-18 17:08:20 -0700806 /// Fetch a superencryption key from the database, or create it if it doesn't already exist.
807 /// When this is called, the caller must hold the lock on the SuperKeyManager.
808 /// So it's OK that the check and creation are different DB transactions.
809 fn get_or_create_super_key(
810 db: &mut KeystoreDB,
811 user_id: UserId,
812 key_type: &SuperKeyType,
813 password: &Password,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700814 reencrypt_with: Option<Arc<SuperKey>>,
Paul Crowley7a658392021-03-18 17:08:20 -0700815 ) -> Result<Arc<SuperKey>> {
816 let loaded_key = db.load_super_key(key_type, user_id)?;
817 if let Some((_, key_entry)) = loaded_key {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700818 Ok(Self::extract_super_key_from_key_entry(
819 key_type.algorithm,
820 key_entry,
821 password,
822 reencrypt_with,
823 )?)
Paul Crowley7a658392021-03-18 17:08:20 -0700824 } else {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700825 let (super_key, public_key) = match key_type.algorithm {
826 SuperEncryptionAlgorithm::Aes256Gcm => (
827 generate_aes256_key()
828 .context("In get_or_create_super_key: Failed to generate AES 256 key.")?,
829 None,
830 ),
831 SuperEncryptionAlgorithm::EcdhP256 => {
832 let key = ECDHPrivateKey::generate()
833 .context("In get_or_create_super_key: Failed to generate ECDH key")?;
834 (
835 key.private_key()
836 .context("In get_or_create_super_key: private_key failed")?,
837 Some(
838 key.public_key()
839 .context("In get_or_create_super_key: public_key failed")?,
840 ),
841 )
842 }
843 };
Paul Crowley7a658392021-03-18 17:08:20 -0700844 //derive an AES256 key from the password and re-encrypt the super key
845 //before we insert it in the database.
846 let (encrypted_super_key, blob_metadata) =
847 Self::encrypt_with_password(&super_key, password)
848 .context("In get_or_create_super_key.")?;
Paul Crowley8d5b2532021-03-19 10:53:07 -0700849 let mut key_metadata = KeyMetaData::new();
850 if let Some(pk) = public_key {
851 key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk));
852 }
Paul Crowley7a658392021-03-18 17:08:20 -0700853 let key_entry = db
Paul Crowley8d5b2532021-03-19 10:53:07 -0700854 .store_super_key(
855 user_id,
856 key_type,
857 &encrypted_super_key,
858 &blob_metadata,
859 &key_metadata,
860 )
Paul Crowley7a658392021-03-18 17:08:20 -0700861 .context("In get_or_create_super_key. Failed to store super key.")?;
Paul Crowley8d5b2532021-03-19 10:53:07 -0700862 Ok(Arc::new(SuperKey {
863 algorithm: key_type.algorithm,
864 key: super_key,
Paul Crowley44c02da2021-04-08 17:04:43 +0000865 id: SuperKeyIdentifier::DatabaseId(key_entry.id()),
Paul Crowley8d5b2532021-03-19 10:53:07 -0700866 reencrypt_with,
867 }))
Paul Crowley7a658392021-03-18 17:08:20 -0700868 }
869 }
870
Paul Crowley8d5b2532021-03-19 10:53:07 -0700871 /// Decrypt the screen-lock bound keys for this user using the password and store in memory.
Paul Crowley7a658392021-03-18 17:08:20 -0700872 pub fn unlock_screen_lock_bound_key(
873 &self,
874 db: &mut KeystoreDB,
875 user_id: UserId,
876 password: &Password,
877 ) -> Result<()> {
878 let mut data = self.data.lock().unwrap();
879 let entry = data.user_keys.entry(user_id).or_default();
880 let aes = entry
881 .screen_lock_bound
882 .get_or_try_to_insert_with(|| {
Paul Crowley8d5b2532021-03-19 10:53:07 -0700883 Self::get_or_create_super_key(
884 db,
885 user_id,
886 &USER_SCREEN_LOCK_BOUND_KEY,
887 password,
888 None,
889 )
890 })?
891 .clone();
892 let ecdh = entry
893 .screen_lock_bound_private
894 .get_or_try_to_insert_with(|| {
895 Self::get_or_create_super_key(
896 db,
897 user_id,
898 &USER_SCREEN_LOCK_BOUND_ECDH_KEY,
899 password,
900 Some(aes.clone()),
901 )
Paul Crowley7a658392021-03-18 17:08:20 -0700902 })?
903 .clone();
Paul Crowley44c02da2021-04-08 17:04:43 +0000904 data.add_key_to_key_index(&aes)?;
905 data.add_key_to_key_index(&ecdh)?;
Paul Crowley7a658392021-03-18 17:08:20 -0700906 Ok(())
907 }
908
Paul Crowley8d5b2532021-03-19 10:53:07 -0700909 /// Wipe the screen-lock bound keys for this user from memory.
Paul Crowley618869e2021-04-08 20:30:54 -0700910 pub fn lock_screen_lock_bound_key(
911 &self,
912 db: &mut KeystoreDB,
913 user_id: UserId,
914 unlocking_sids: &[i64],
915 ) {
916 log::info!("Locking screen bound for user {} sids {:?}", user_id, unlocking_sids);
Paul Crowley7a658392021-03-18 17:08:20 -0700917 let mut data = self.data.lock().unwrap();
918 let mut entry = data.user_keys.entry(user_id).or_default();
Paul Crowley618869e2021-04-08 20:30:54 -0700919 if !unlocking_sids.is_empty() {
920 if let (Some(aes), Some(ecdh)) = (
921 entry.screen_lock_bound.as_ref().cloned(),
922 entry.screen_lock_bound_private.as_ref().cloned(),
923 ) {
924 let res = (|| -> Result<()> {
925 let key_desc = KeyMintDevice::internal_descriptor(format!(
926 "biometric_unlock_key_{}",
927 user_id
928 ));
929 let encrypting_key = generate_aes256_key()?;
930 let km_dev: KeyMintDevice =
931 KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
932 .context("In lock_screen_lock_bound_key: KeyMintDevice::get failed")?;
933 let mut key_params = vec![
934 KeyParameterValue::Algorithm(Algorithm::AES),
935 KeyParameterValue::KeySize(256),
936 KeyParameterValue::BlockMode(BlockMode::GCM),
937 KeyParameterValue::PaddingMode(PaddingMode::NONE),
938 KeyParameterValue::CallerNonce,
939 KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT),
940 KeyParameterValue::MinMacLength(128),
941 KeyParameterValue::AuthTimeout(BIOMETRIC_AUTH_TIMEOUT_S),
942 KeyParameterValue::HardwareAuthenticatorType(
943 HardwareAuthenticatorType::FINGERPRINT,
944 ),
945 ];
946 for sid in unlocking_sids {
947 key_params.push(KeyParameterValue::UserSecureID(*sid));
948 }
949 let key_params: Vec<KmKeyParameter> =
950 key_params.into_iter().map(|x| x.into()).collect();
951 km_dev.create_and_store_key(db, &key_desc, |dev| {
952 dev.importKey(key_params.as_slice(), KeyFormat::RAW, &encrypting_key, None)
953 })?;
954 entry.biometric_unlock = Some(BiometricUnlock {
955 sids: unlocking_sids.into(),
956 key_desc,
957 screen_lock_bound: LockedKey::new(&encrypting_key, &aes)?,
958 screen_lock_bound_private: LockedKey::new(&encrypting_key, &ecdh)?,
959 });
960 Ok(())
961 })();
962 // There is no reason to propagate an error here upwards. We must discard
963 // entry.screen_lock_bound* in any case.
964 if let Err(e) = res {
965 log::error!("Error setting up biometric unlock: {:#?}", e);
966 }
967 }
968 }
Paul Crowley7a658392021-03-18 17:08:20 -0700969 entry.screen_lock_bound = None;
Paul Crowley8d5b2532021-03-19 10:53:07 -0700970 entry.screen_lock_bound_private = None;
Paul Crowley7a658392021-03-18 17:08:20 -0700971 }
Paul Crowley618869e2021-04-08 20:30:54 -0700972
973 /// User has unlocked, not using a password. See if any of our stored auth tokens can be used
974 /// to unlock the keys protecting UNLOCKED_DEVICE_REQUIRED keys.
975 pub fn try_unlock_user_with_biometric(
976 &self,
977 db: &mut KeystoreDB,
978 user_id: UserId,
979 ) -> Result<()> {
980 let mut data = self.data.lock().unwrap();
981 let mut entry = data.user_keys.entry(user_id).or_default();
982 if let Some(biometric) = entry.biometric_unlock.as_ref() {
983 let (key_id_guard, key_entry) =
984 KeyMintDevice::lookup_from_desc(db, &biometric.key_desc)?;
985 let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
986 .context("In try_unlock_user_with_biometric: KeyMintDevice::get failed")?;
987 for sid in &biometric.sids {
988 if let Some((auth_token_entry, _)) = db.find_auth_token_entry(|entry| {
989 entry.auth_token().userId == *sid || entry.auth_token().authenticatorId == *sid
990 })? {
991 let res: Result<(Arc<SuperKey>, Arc<SuperKey>)> = (|| {
992 let slb = biometric.screen_lock_bound.decrypt(
993 db,
994 &km_dev,
995 &key_id_guard,
996 &key_entry,
997 auth_token_entry.auth_token(),
998 None,
999 )?;
1000 let slbp = biometric.screen_lock_bound_private.decrypt(
1001 db,
1002 &km_dev,
1003 &key_id_guard,
1004 &key_entry,
1005 auth_token_entry.auth_token(),
1006 Some(slb.clone()),
1007 )?;
1008 Ok((slb, slbp))
1009 })();
1010 match res {
1011 Ok((slb, slbp)) => {
1012 entry.screen_lock_bound = Some(slb.clone());
1013 entry.screen_lock_bound_private = Some(slbp.clone());
1014 data.add_key_to_key_index(&slb)?;
1015 data.add_key_to_key_index(&slbp)?;
1016 log::info!(concat!(
1017 "In try_unlock_user_with_biometric: ",
1018 "Successfully unlocked with biometric"
1019 ));
1020 return Ok(());
1021 }
1022 Err(e) => {
1023 log::warn!("In try_unlock_user_with_biometric: attempt failed: {:?}", e)
1024 }
1025 }
1026 }
1027 }
1028 }
1029 Ok(())
1030 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001031}
1032
1033/// This enum represents different states of the user's life cycle in the device.
1034/// For now, only three states are defined. More states may be added later.
1035pub enum UserState {
1036 // The user has registered LSKF and has unlocked the device by entering PIN/Password,
1037 // and hence the per-boot super key is available in the cache.
Paul Crowley7a658392021-03-18 17:08:20 -07001038 LskfUnlocked(Arc<SuperKey>),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001039 // The user has registered LSKF, but has not unlocked the device using password, after reboot.
1040 // Hence the per-boot super-key(s) is not available in the cache.
1041 // However, the encrypted super key is available in the database.
1042 LskfLocked,
1043 // There's no user in the device for the given user id, or the user with the user id has not
1044 // setup LSKF.
1045 Uninitialized,
1046}
1047
1048impl UserState {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001049 pub fn get(
1050 db: &mut KeystoreDB,
1051 legacy_migrator: &LegacyMigrator,
1052 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -07001053 user_id: UserId,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001054 ) -> Result<UserState> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001055 match skm.get_per_boot_key_by_user_id(user_id) {
1056 Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
1057 None => {
1058 //Check if a super key exists in the database or legacy database.
1059 //If so, return locked user state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001060 if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +00001061 .context("In get.")?
Hasini Gunasinghe0e161452021-01-27 19:34:37 +00001062 {
1063 Ok(UserState::LskfLocked)
1064 } else {
1065 Ok(UserState::Uninitialized)
1066 }
1067 }
1068 }
1069 }
Hasini Gunasingheda895552021-01-27 19:34:37 +00001070
1071 /// Queries user state when serving password change requests.
1072 pub fn get_with_password_changed(
1073 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001074 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001075 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -07001076 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -07001077 password: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001078 ) -> Result<UserState> {
1079 match skm.get_per_boot_key_by_user_id(user_id) {
1080 Some(super_key) => {
1081 if password.is_none() {
1082 //transitioning to swiping, delete only the super key in database and cache, and
1083 //super-encrypted keys in database (and in KM)
Janis Danisevskiseed69842021-02-18 20:04:10 -08001084 Self::reset_user(db, skm, legacy_migrator, user_id, true).context(
1085 "In get_with_password_changed: Trying to delete keys from the db.",
1086 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +00001087 //Lskf is now removed in Keystore
1088 Ok(UserState::Uninitialized)
1089 } else {
1090 //Keystore won't be notified when changing to a new password when LSKF is
1091 //already setup. Therefore, ideally this path wouldn't be reached.
1092 Ok(UserState::LskfUnlocked(super_key))
1093 }
1094 }
1095 None => {
1096 //Check if a super key exists in the database or legacy database.
1097 //If so, return LskfLocked state.
1098 //Otherwise, i) if the password is provided, initialize the super key and return
1099 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001100 skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasingheda895552021-01-27 19:34:37 +00001101 }
1102 }
1103 }
1104
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001105 /// Queries user state when serving password unlock requests.
1106 pub fn get_with_password_unlock(
1107 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001108 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001109 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -07001110 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -07001111 password: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001112 ) -> Result<UserState> {
1113 match skm.get_per_boot_key_by_user_id(user_id) {
1114 Some(super_key) => {
1115 log::info!("In get_with_password_unlock. Trying to unlock when already unlocked.");
1116 Ok(UserState::LskfUnlocked(super_key))
1117 }
1118 None => {
1119 //Check if a super key exists in the database or legacy database.
1120 //If not, return Uninitialized state.
1121 //Otherwise, try to unlock the super key and if successful,
1122 //return LskfUnlocked state
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001123 skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +00001124 .context("In get_with_password_unlock. Failed to unlock super key.")
1125 }
1126 }
1127 }
1128
Hasini Gunasingheda895552021-01-27 19:34:37 +00001129 /// Delete all the keys created on behalf of the user.
1130 /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
1131 /// encrypted keys.
1132 pub fn reset_user(
1133 db: &mut KeystoreDB,
1134 skm: &SuperKeyManager,
Janis Danisevskiseed69842021-02-18 20:04:10 -08001135 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -07001136 user_id: UserId,
Hasini Gunasingheda895552021-01-27 19:34:37 +00001137 keep_non_super_encrypted_keys: bool,
1138 ) -> Result<()> {
1139 // mark keys created on behalf of the user as unreferenced.
Janis Danisevskiseed69842021-02-18 20:04:10 -08001140 legacy_migrator
1141 .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
1142 .context("In reset_user: Trying to delete legacy keys.")?;
Paul Crowley7a658392021-03-18 17:08:20 -07001143 db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
Hasini Gunasingheda895552021-01-27 19:34:37 +00001144 .context("In reset user. Error in unbinding keys.")?;
1145
1146 //delete super key in cache, if exists
Paul Crowley7a658392021-03-18 17:08:20 -07001147 skm.forget_all_keys_for_user(user_id);
Hasini Gunasingheda895552021-01-27 19:34:37 +00001148 Ok(())
1149 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -08001150}
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001151
Janis Danisevskiseed69842021-02-18 20:04:10 -08001152/// This enum represents three states a KeyMint Blob can be in, w.r.t super encryption.
1153/// `Sensitive` holds the non encrypted key and a reference to its super key.
1154/// `NonSensitive` holds a non encrypted key that is never supposed to be encrypted.
1155/// `Ref` holds a reference to a key blob when it does not need to be modified if its
1156/// life time allows it.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001157pub enum KeyBlob<'a> {
Paul Crowley8d5b2532021-03-19 10:53:07 -07001158 Sensitive {
1159 key: ZVec,
1160 /// If KeyMint reports that the key must be upgraded, we must
1161 /// re-encrypt the key before writing to the database; we use
1162 /// this key.
1163 reencrypt_with: Arc<SuperKey>,
1164 /// If this key was decrypted with an ECDH key, we want to
1165 /// re-encrypt it on first use whether it was upgraded or not;
1166 /// this field indicates that that's necessary.
1167 force_reencrypt: bool,
1168 },
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001169 NonSensitive(Vec<u8>),
1170 Ref(&'a [u8]),
1171}
1172
Paul Crowley8d5b2532021-03-19 10:53:07 -07001173impl<'a> KeyBlob<'a> {
1174 pub fn force_reencrypt(&self) -> bool {
1175 if let KeyBlob::Sensitive { force_reencrypt, .. } = self {
1176 *force_reencrypt
1177 } else {
1178 false
1179 }
1180 }
1181}
1182
Janis Danisevskiseed69842021-02-18 20:04:10 -08001183/// Deref returns a reference to the key material in any variant.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001184impl<'a> Deref for KeyBlob<'a> {
1185 type Target = [u8];
1186
1187 fn deref(&self) -> &Self::Target {
1188 match self {
Paul Crowley7a658392021-03-18 17:08:20 -07001189 Self::Sensitive { key, .. } => &key,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +00001190 Self::NonSensitive(key) => &key,
1191 Self::Ref(key) => key,
1192 }
1193 }
1194}