blob: ffd9d267156fe2026ea58076e89e67c5c171e773 [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
15#![allow(dead_code)]
16
17use crate::{
Hasini Gunasingheda895552021-01-27 19:34:37 +000018 database::BlobMetaData, database::BlobMetaEntry, database::EncryptedBy, database::KeyEntry,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000019 database::KeyType, database::KeystoreDB, enforcements::Enforcements, error::Error,
20 error::ResponseCode, key_parameter::KeyParameter, legacy_blob::LegacyBlobLoader,
Paul Crowley7a658392021-03-18 17:08:20 -070021 legacy_migrator::LegacyMigrator, try_insert::TryInsert,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080022};
23use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
24use anyhow::{Context, Result};
25use keystore2_crypto::{
Paul Crowleyf61fee72021-03-17 14:38:44 -070026 aes_gcm_decrypt, aes_gcm_encrypt, generate_aes256_key, generate_salt, Password, ZVec,
27 AES_256_KEY_LENGTH,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080028};
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000029use std::ops::Deref;
Janis Danisevskisb42fc182020-12-15 08:41:27 -080030use std::{
31 collections::HashMap,
32 sync::Arc,
33 sync::{Mutex, Weak},
34};
35
36type UserId = u32;
37
Paul Crowley7a658392021-03-18 17:08:20 -070038/// A particular user may have several superencryption keys in the database, each for a
39/// different purpose, distinguished by alias. Each is associated with a static
40/// constant of this type.
41pub struct SuperKeyType {
42 /// Alias used to look the key up in the `persistent.keyentry` table.
43 pub alias: &'static str,
44}
45
46/// Key used for LskfLocked keys; the corresponding superencryption key is loaded in memory
47/// when the user first unlocks, and remains in memory until the device reboots.
48pub const USER_SUPER_KEY: SuperKeyType = SuperKeyType { alias: "USER_SUPER_KEY" };
49/// Key used for ScreenLockBound keys; the corresponding superencryption key is loaded in memory
50/// each time the user enters their LSKF, and cleared from memory each time the device is locked.
51pub const USER_SCREEN_LOCK_BOUND_KEY: SuperKeyType =
52 SuperKeyType { alias: "USER_SCREEN_LOCK_BOUND_KEY" };
53
54/// Superencryption to apply to a new key.
55#[derive(Debug, Clone, Copy)]
56pub enum SuperEncryptionType {
57 /// Do not superencrypt this key.
58 None,
59 /// Superencrypt with a key that remains in memory from first unlock to reboot.
60 LskfBound,
61 /// Superencrypt with a key cleared from memory when the device is locked.
62 ScreenLockBound,
63}
64
Janis Danisevskisb42fc182020-12-15 08:41:27 -080065#[derive(Default)]
66struct UserSuperKeys {
67 /// The per boot key is used for LSKF binding of authentication bound keys. There is one
68 /// key per android user. The key is stored on flash encrypted with a key derived from a
69 /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF).
70 /// When the user unlocks the device for the first time, this key is unlocked, i.e., decrypted,
71 /// and stays memory resident until the device reboots.
Paul Crowley7a658392021-03-18 17:08:20 -070072 per_boot: Option<Arc<SuperKey>>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080073 /// The screen lock key works like the per boot key with the distinction that it is cleared
74 /// from memory when the screen lock is engaged.
Paul Crowley7a658392021-03-18 17:08:20 -070075 screen_lock_bound: Option<Arc<SuperKey>>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080076}
77
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000078pub struct SuperKey {
Paul Crowley7a658392021-03-18 17:08:20 -070079 key: ZVec,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000080 // id of the super key in the database.
81 id: i64,
82}
83
84impl SuperKey {
Paul Crowley7a658392021-03-18 17:08:20 -070085 /// For most purposes `unwrap_key` handles decryption,
86 /// but legacy handling and some tests need to assume AES and decrypt directly.
87 pub fn aes_gcm_decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
88 aes_gcm_decrypt(data, iv, tag, &self.key).context("In aes_gcm_decrypt: decryption failed")
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000089 }
90
91 pub fn get_id(&self) -> i64 {
92 self.id
93 }
94}
95
Janis Danisevskisb42fc182020-12-15 08:41:27 -080096#[derive(Default)]
97struct SkmState {
98 user_keys: HashMap<UserId, UserSuperKeys>,
Paul Crowley7a658392021-03-18 17:08:20 -070099 key_index: HashMap<i64, Weak<SuperKey>>,
100}
101
102impl SkmState {
103 fn add_key_to_key_index(&mut self, super_key: &Arc<SuperKey>) {
104 self.key_index.insert(super_key.id, Arc::downgrade(super_key));
105 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800106}
107
108#[derive(Default)]
109pub struct SuperKeyManager {
110 data: Mutex<SkmState>,
111}
112
113impl SuperKeyManager {
114 pub fn new() -> Self {
Paul Crowley7a658392021-03-18 17:08:20 -0700115 Default::default()
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800116 }
117
118 pub fn forget_all_keys_for_user(&self, user: UserId) {
119 let mut data = self.data.lock().unwrap();
120 data.user_keys.remove(&user);
121 }
122
Paul Crowley7a658392021-03-18 17:08:20 -0700123 fn install_per_boot_key_for_user(&self, user: UserId, super_key: Arc<SuperKey>) {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800124 let mut data = self.data.lock().unwrap();
Paul Crowley7a658392021-03-18 17:08:20 -0700125 data.add_key_to_key_index(&super_key);
Hasini Gunasingheda895552021-01-27 19:34:37 +0000126 data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800127 }
128
Paul Crowley7a658392021-03-18 17:08:20 -0700129 fn get_key(&self, key_id: &i64) -> Option<Arc<SuperKey>> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800130 self.data.lock().unwrap().key_index.get(key_id).and_then(|k| k.upgrade())
131 }
132
Paul Crowley7a658392021-03-18 17:08:20 -0700133 pub fn get_per_boot_key_by_user_id(&self, user_id: UserId) -> Option<Arc<SuperKey>> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800134 let data = self.data.lock().unwrap();
Paul Crowley7a658392021-03-18 17:08:20 -0700135 data.user_keys.get(&user_id).and_then(|e| e.per_boot.as_ref().cloned())
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800136 }
137
138 /// This function unlocks the super keys for a given user.
139 /// This means the key is loaded from the database, decrypted and placed in the
140 /// super key cache. If there is no such key a new key is created, encrypted with
141 /// a key derived from the given password and stored in the database.
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800142 pub fn unlock_user_key(
143 &self,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000144 db: &mut KeystoreDB,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800145 user: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700146 pw: &Password,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800147 legacy_blob_loader: &LegacyBlobLoader,
148 ) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800149 let (_, entry) = db
Max Bires8e93d2b2021-01-14 13:17:59 -0800150 .get_or_create_key_with(
151 Domain::APP,
152 user as u64 as i64,
Paul Crowley7a658392021-03-18 17:08:20 -0700153 &USER_SUPER_KEY.alias,
Max Bires8e93d2b2021-01-14 13:17:59 -0800154 crate::database::KEYSTORE_UUID,
155 || {
156 // For backward compatibility we need to check if there is a super key present.
157 let super_key = legacy_blob_loader
158 .load_super_key(user, pw)
159 .context("In create_new_key: Failed to load legacy key blob.")?;
160 let super_key = match super_key {
161 None => {
162 // No legacy file was found. So we generate a new key.
Hasini Gunasingheda895552021-01-27 19:34:37 +0000163 generate_aes256_key()
Max Bires8e93d2b2021-01-14 13:17:59 -0800164 .context("In create_new_key: Failed to generate AES 256 key.")?
165 }
166 Some(key) => key,
167 };
Hasini Gunasingheda895552021-01-27 19:34:37 +0000168 // Regardless of whether we loaded an old AES128 key or generated a new AES256
169 // key as the super key, we derive a AES256 key from the password and re-encrypt
170 // the super key before we insert it in the database. The length of the key is
171 // preserved by the encryption so we don't need any extra flags to inform us
172 // which algorithm to use it with.
173 Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
Max Bires8e93d2b2021-01-14 13:17:59 -0800174 },
175 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800176 .context("In unlock_user_key: Failed to get key id.")?;
177
Hasini Gunasingheda895552021-01-27 19:34:37 +0000178 self.populate_cache_from_super_key_blob(user, entry, pw).context("In unlock_user_key.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800179 Ok(())
180 }
181
182 /// Unwraps an encrypted key blob given metadata identifying the encryption key.
183 /// The function queries `metadata.encrypted_by()` to determine the encryption key.
184 /// It then check if the required key is memory resident, and if so decrypts the
185 /// blob.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000186 pub fn unwrap_key<'a>(&self, blob: &'a [u8], metadata: &BlobMetaData) -> Result<KeyBlob<'a>> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800187 match metadata.encrypted_by() {
188 Some(EncryptedBy::KeyId(key_id)) => match self.get_key(key_id) {
Paul Crowley7a658392021-03-18 17:08:20 -0700189 Some(super_key) => Ok(KeyBlob::Sensitive {
190 key: Self::unwrap_key_with_key(blob, metadata, &super_key)
191 .context("In unwrap_key: unwrap_key_with_key failed")?,
192 reencrypt_with: super_key.clone(),
193 }),
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800194 None => Err(Error::Rc(ResponseCode::LOCKED))
195 .context("In unwrap_key: Key is not usable until the user entered their LSKF."),
196 },
197 _ => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
198 .context("In unwrap_key: Cannot determined wrapping key."),
199 }
200 }
201
202 /// Unwraps an encrypted key blob given an encryption key.
Paul Crowley7a658392021-03-18 17:08:20 -0700203 fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800204 match (metadata.iv(), metadata.aead_tag()) {
Paul Crowley7a658392021-03-18 17:08:20 -0700205 (Some(iv), Some(tag)) => key
206 .aes_gcm_decrypt(blob, iv, tag)
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800207 .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
208 (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
209 concat!(
210 "In unwrap_key_with_key: Key has incomplete metadata.",
211 "Present: iv: {}, aead_tag: {}."
212 ),
213 iv.is_some(),
214 tag.is_some(),
215 )),
216 }
217 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000218
219 /// Checks if user has setup LSKF, even when super key cache is empty for the user.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000220 pub fn super_key_exists_in_db_for_user(
221 db: &mut KeystoreDB,
222 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700223 user_id: UserId,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000224 ) -> Result<bool> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000225 let key_in_db = db
Paul Crowley7a658392021-03-18 17:08:20 -0700226 .key_exists(Domain::APP, user_id as u64 as i64, &USER_SUPER_KEY.alias, KeyType::Super)
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000227 .context("In super_key_exists_in_db_for_user.")?;
228
229 if key_in_db {
230 Ok(key_in_db)
231 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000232 legacy_migrator
233 .has_super_key(user_id)
234 .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000235 }
236 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000237
238 /// 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 +0000239 /// legacy database). If not, return Uninitialized state.
240 /// Otherwise, decrypt the super key from the password and return LskfUnlocked state.
241 pub fn check_and_unlock_super_key(
242 &self,
243 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000244 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700245 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700246 pw: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000247 ) -> Result<UserState> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000248 let result = legacy_migrator
Paul Crowley7a658392021-03-18 17:08:20 -0700249 .with_try_migrate_super_key(user_id, pw, || db.load_super_key(&USER_SUPER_KEY, user_id))
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000250 .context("In check_and_unlock_super_key. Failed to load super key")?;
251
252 match result {
253 Some((_, entry)) => {
254 let super_key = self
255 .populate_cache_from_super_key_blob(user_id, entry, pw)
256 .context("In check_and_unlock_super_key.")?;
257 Ok(UserState::LskfUnlocked(super_key))
258 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000259 None => Ok(UserState::Uninitialized),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000260 }
261 }
262
263 /// 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 +0000264 /// legacy database). If so, return LskfLocked state.
265 /// If the password is provided, generate a new super key, encrypt with the password,
266 /// store in the database and populate the super key cache for the new user
267 /// and return LskfUnlocked state.
268 /// If the password is not provided, return Uninitialized state.
269 pub fn check_and_initialize_super_key(
270 &self,
271 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000272 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700273 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700274 pw: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000275 ) -> Result<UserState> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000276 let super_key_exists_in_db =
277 Self::super_key_exists_in_db_for_user(db, legacy_migrator, user_id).context(
278 "In check_and_initialize_super_key. Failed to check if super key exists.",
279 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000280 if super_key_exists_in_db {
281 Ok(UserState::LskfLocked)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000282 } else if let Some(pw) = pw {
283 //generate a new super key.
284 let super_key = generate_aes256_key()
285 .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
286 //derive an AES256 key from the password and re-encrypt the super key
287 //before we insert it in the database.
288 let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
289 .context("In check_and_initialize_super_key.")?;
290
291 let key_entry = db
Paul Crowley7a658392021-03-18 17:08:20 -0700292 .store_super_key(user_id, &USER_SUPER_KEY, &encrypted_super_key, &blob_metadata)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000293 .context("In check_and_initialize_super_key. Failed to store super key.")?;
294
295 let super_key = self
296 .populate_cache_from_super_key_blob(user_id, key_entry, pw)
297 .context("In check_and_initialize_super_key.")?;
298 Ok(UserState::LskfUnlocked(super_key))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000299 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000300 Ok(UserState::Uninitialized)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000301 }
302 }
303
304 //helper function to populate super key cache from the super key blob loaded from the database
305 fn populate_cache_from_super_key_blob(
306 &self,
Paul Crowley7a658392021-03-18 17:08:20 -0700307 user_id: UserId,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000308 entry: KeyEntry,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700309 pw: &Password,
Paul Crowley7a658392021-03-18 17:08:20 -0700310 ) -> Result<Arc<SuperKey>> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000311 let super_key = Self::extract_super_key_from_key_entry(entry, pw).context(
312 "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
313 )?;
314 self.install_per_boot_key_for_user(user_id, super_key.clone());
315 Ok(super_key)
316 }
317
318 /// Extracts super key from the entry loaded from the database
Paul Crowley7a658392021-03-18 17:08:20 -0700319 pub fn extract_super_key_from_key_entry(
320 entry: KeyEntry,
321 pw: &Password,
322 ) -> Result<Arc<SuperKey>> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000323 if let Some((blob, metadata)) = entry.key_blob_info() {
324 let key = match (
325 metadata.encrypted_by(),
326 metadata.salt(),
327 metadata.iv(),
328 metadata.aead_tag(),
329 ) {
330 (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
Paul Crowleyf61fee72021-03-17 14:38:44 -0700331 let key = pw.derive_key(Some(salt), AES_256_KEY_LENGTH).context(
332 "In extract_super_key_from_key_entry: Failed to generate key from password.",
333 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000334
335 aes_gcm_decrypt(blob, iv, tag, &key).context(
336 "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
337 )?
338 }
339 (enc_by, salt, iv, tag) => {
340 return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
341 concat!(
342 "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
343 "Present: encrypted_by: {}, salt: {}, iv: {}, aead_tag: {}."
344 ),
345 enc_by.is_some(),
346 salt.is_some(),
347 iv.is_some(),
348 tag.is_some()
349 ));
350 }
351 };
Paul Crowley7a658392021-03-18 17:08:20 -0700352 Ok(Arc::new(SuperKey { key, id: entry.id() }))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000353 } else {
354 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
355 .context("In extract_super_key_from_key_entry: No key blob info.")
356 }
357 }
358
359 /// Encrypts the super key from a key derived from the password, before storing in the database.
Paul Crowleyf61fee72021-03-17 14:38:44 -0700360 pub fn encrypt_with_password(
361 super_key: &[u8],
362 pw: &Password,
363 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000364 let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
Paul Crowleyf61fee72021-03-17 14:38:44 -0700365 let derived_key = pw
366 .derive_key(Some(&salt), AES_256_KEY_LENGTH)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000367 .context("In encrypt_with_password: Failed to derive password.")?;
368 let mut metadata = BlobMetaData::new();
369 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
370 metadata.add(BlobMetaEntry::Salt(salt));
371 let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
372 .context("In encrypt_with_password: Failed to encrypt new super key.")?;
373 metadata.add(BlobMetaEntry::Iv(iv));
374 metadata.add(BlobMetaEntry::AeadTag(tag));
375 Ok((encrypted_key, metadata))
376 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000377
378 // Encrypt the given key blob with the user's super key, if the super key exists and the device
379 // is unlocked. If the super key exists and the device is locked, or LSKF is not setup,
380 // return error. Note that it is out of the scope of this function to check if super encryption
381 // is required. Such check should be performed before calling this function.
382 fn super_encrypt_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000383 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000384 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000385 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700386 user_id: UserId,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000387 key_blob: &[u8],
388 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000389 match UserState::get(db, legacy_migrator, self, user_id)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000390 .context("In super_encrypt. Failed to get user state.")?
391 {
392 UserState::LskfUnlocked(super_key) => {
393 Self::encrypt_with_super_key(key_blob, &super_key)
394 .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
395 }
396 UserState::LskfLocked => {
397 Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
398 }
399 UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
400 .context("In super_encrypt. LSKF is not setup for the user."),
401 }
402 }
403
404 //Helper function to encrypt a key with the given super key. Callers should select which super
405 //key to be used. This is called when a key is super encrypted at its creation as well as at its
406 //upgrade.
407 fn encrypt_with_super_key(
408 key_blob: &[u8],
409 super_key: &SuperKey,
410 ) -> Result<(Vec<u8>, BlobMetaData)> {
411 let mut metadata = BlobMetaData::new();
412 let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
413 .context("In encrypt_with_super_key: Failed to encrypt new super key.")?;
414 metadata.add(BlobMetaEntry::Iv(iv));
415 metadata.add(BlobMetaEntry::AeadTag(tag));
416 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key.id)));
417 Ok((encrypted_key, metadata))
418 }
419
420 /// Check if super encryption is required and if so, super-encrypt the key to be stored in
421 /// the database.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000422 #[allow(clippy::clippy::too_many_arguments)]
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000423 pub fn handle_super_encryption_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000424 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000425 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000426 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000427 domain: &Domain,
428 key_parameters: &[KeyParameter],
429 flags: Option<i32>,
Paul Crowley7a658392021-03-18 17:08:20 -0700430 user_id: UserId,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000431 key_blob: &[u8],
432 ) -> Result<(Vec<u8>, BlobMetaData)> {
Paul Crowley7a658392021-03-18 17:08:20 -0700433 match Enforcements::super_encryption_required(domain, key_parameters, flags) {
434 SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
435 SuperEncryptionType::LskfBound => {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000436 self.super_encrypt_on_key_init(db, legacy_migrator, user_id, &key_blob).context(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000437 "In handle_super_encryption_on_key_init.
438 Failed to super encrypt the key.",
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000439 )
440 }
Paul Crowley7a658392021-03-18 17:08:20 -0700441 SuperEncryptionType::ScreenLockBound => {
442 let mut data = self.data.lock().unwrap();
443 let entry = data.user_keys.entry(user_id).or_default();
444 if let Some(super_key) = entry.screen_lock_bound.as_ref() {
445 Self::encrypt_with_super_key(key_blob, &super_key).context(concat!(
446 "In handle_super_encryption_on_key_init. ",
447 "Failed to encrypt the key with screen_lock_bound key."
448 ))
449 } else {
450 // FIXME: until ec encryption lands, we only superencrypt if the key
451 // happens to be present ie the device is unlocked.
452 Ok((key_blob.to_vec(), BlobMetaData::new()))
453 }
454 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000455 }
456 }
457
458 /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using
459 /// the relevant super key.
460 pub fn unwrap_key_if_required<'a>(
461 &self,
462 metadata: &BlobMetaData,
463 key_blob: &'a [u8],
464 ) -> Result<KeyBlob<'a>> {
465 if Self::key_super_encrypted(&metadata) {
466 let unwrapped_key = self
467 .unwrap_key(key_blob, metadata)
468 .context("In unwrap_key_if_required. Error in unwrapping the key.")?;
469 Ok(unwrapped_key)
470 } else {
471 Ok(KeyBlob::Ref(key_blob))
472 }
473 }
474
475 /// Check if a given key needs re-super-encryption, from its KeyBlob type.
476 /// If so, re-super-encrypt the key and return a new set of metadata,
477 /// containing the new super encryption information.
Paul Crowley7a658392021-03-18 17:08:20 -0700478 pub fn reencrypt_if_required<'a>(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000479 key_blob_before_upgrade: &KeyBlob,
480 key_after_upgrade: &'a [u8],
481 ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)> {
482 match key_blob_before_upgrade {
Paul Crowley7a658392021-03-18 17:08:20 -0700483 KeyBlob::Sensitive { reencrypt_with: super_key, .. } => {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000484 let (key, metadata) = Self::encrypt_with_super_key(key_after_upgrade, super_key)
Paul Crowley7a658392021-03-18 17:08:20 -0700485 .context("In reencrypt_if_required: Failed to re-super-encrypt key.")?;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000486 Ok((KeyBlob::NonSensitive(key), Some(metadata)))
487 }
488 _ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
489 }
490 }
491
492 // Helper function to decide if a key is super encrypted, given metadata.
493 fn key_super_encrypted(metadata: &BlobMetaData) -> bool {
494 if let Some(&EncryptedBy::KeyId(_)) = metadata.encrypted_by() {
495 return true;
496 }
497 false
498 }
Paul Crowley7a658392021-03-18 17:08:20 -0700499
500 /// Fetch a superencryption key from the database, or create it if it doesn't already exist.
501 /// When this is called, the caller must hold the lock on the SuperKeyManager.
502 /// So it's OK that the check and creation are different DB transactions.
503 fn get_or_create_super_key(
504 db: &mut KeystoreDB,
505 user_id: UserId,
506 key_type: &SuperKeyType,
507 password: &Password,
508 ) -> Result<Arc<SuperKey>> {
509 let loaded_key = db.load_super_key(key_type, user_id)?;
510 if let Some((_, key_entry)) = loaded_key {
511 Ok(Self::extract_super_key_from_key_entry(key_entry, password)?)
512 } else {
513 let super_key = generate_aes256_key()
514 .context("In get_or_create_super_key: Failed to generate AES 256 key.")?;
515 //derive an AES256 key from the password and re-encrypt the super key
516 //before we insert it in the database.
517 let (encrypted_super_key, blob_metadata) =
518 Self::encrypt_with_password(&super_key, password)
519 .context("In get_or_create_super_key.")?;
520 let key_entry = db
521 .store_super_key(user_id, key_type, &encrypted_super_key, &blob_metadata)
522 .context("In get_or_create_super_key. Failed to store super key.")?;
523 Ok(Arc::new(SuperKey { key: super_key, id: key_entry.id() }))
524 }
525 }
526
527 /// Create the screen-lock bound key for this user if it doesn't already exist
528 pub fn ensure_super_key_created(
529 &self,
530 db: &mut KeystoreDB,
531 user_id: UserId,
532 password: &Password,
533 ) -> Result<()> {
534 // Lock data to ensure no concurrent attempts to create the key.
535 let _data = self.data.lock().unwrap();
536 Self::get_or_create_super_key(db, user_id, &USER_SCREEN_LOCK_BOUND_KEY, password)?;
537 Ok(())
538 }
539
540 /// Decrypt the screen-lock bound key for this user using the password and store in memory.
541 pub fn unlock_screen_lock_bound_key(
542 &self,
543 db: &mut KeystoreDB,
544 user_id: UserId,
545 password: &Password,
546 ) -> Result<()> {
547 let mut data = self.data.lock().unwrap();
548 let entry = data.user_keys.entry(user_id).or_default();
549 let aes = entry
550 .screen_lock_bound
551 .get_or_try_to_insert_with(|| {
552 Self::get_or_create_super_key(db, user_id, &USER_SCREEN_LOCK_BOUND_KEY, password)
553 })?
554 .clone();
555 data.add_key_to_key_index(&aes);
556 Ok(())
557 }
558
559 /// Wipe the screen-lock bound key for this user from memory.
560 pub fn lock_screen_lock_bound_key(&self, user_id: UserId) {
561 let mut data = self.data.lock().unwrap();
562 let mut entry = data.user_keys.entry(user_id).or_default();
563 entry.screen_lock_bound = None;
564 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000565}
566
567/// This enum represents different states of the user's life cycle in the device.
568/// For now, only three states are defined. More states may be added later.
569pub enum UserState {
570 // The user has registered LSKF and has unlocked the device by entering PIN/Password,
571 // and hence the per-boot super key is available in the cache.
Paul Crowley7a658392021-03-18 17:08:20 -0700572 LskfUnlocked(Arc<SuperKey>),
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000573 // The user has registered LSKF, but has not unlocked the device using password, after reboot.
574 // Hence the per-boot super-key(s) is not available in the cache.
575 // However, the encrypted super key is available in the database.
576 LskfLocked,
577 // There's no user in the device for the given user id, or the user with the user id has not
578 // setup LSKF.
579 Uninitialized,
580}
581
582impl UserState {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000583 pub fn get(
584 db: &mut KeystoreDB,
585 legacy_migrator: &LegacyMigrator,
586 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -0700587 user_id: UserId,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000588 ) -> Result<UserState> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000589 match skm.get_per_boot_key_by_user_id(user_id) {
590 Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
591 None => {
592 //Check if a super key exists in the database or legacy database.
593 //If so, return locked user state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000594 if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000595 .context("In get.")?
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000596 {
597 Ok(UserState::LskfLocked)
598 } else {
599 Ok(UserState::Uninitialized)
600 }
601 }
602 }
603 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000604
605 /// Queries user state when serving password change requests.
606 pub fn get_with_password_changed(
607 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000608 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000609 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -0700610 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700611 password: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000612 ) -> Result<UserState> {
613 match skm.get_per_boot_key_by_user_id(user_id) {
614 Some(super_key) => {
615 if password.is_none() {
616 //transitioning to swiping, delete only the super key in database and cache, and
617 //super-encrypted keys in database (and in KM)
Janis Danisevskiseed69842021-02-18 20:04:10 -0800618 Self::reset_user(db, skm, legacy_migrator, user_id, true).context(
619 "In get_with_password_changed: Trying to delete keys from the db.",
620 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000621 //Lskf is now removed in Keystore
622 Ok(UserState::Uninitialized)
623 } else {
624 //Keystore won't be notified when changing to a new password when LSKF is
625 //already setup. Therefore, ideally this path wouldn't be reached.
626 Ok(UserState::LskfUnlocked(super_key))
627 }
628 }
629 None => {
630 //Check if a super key exists in the database or legacy database.
631 //If so, return LskfLocked state.
632 //Otherwise, i) if the password is provided, initialize the super key and return
633 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000634 skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000635 }
636 }
637 }
638
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000639 /// Queries user state when serving password unlock requests.
640 pub fn get_with_password_unlock(
641 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000642 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000643 skm: &SuperKeyManager,
Paul Crowley7a658392021-03-18 17:08:20 -0700644 user_id: UserId,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700645 password: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000646 ) -> Result<UserState> {
647 match skm.get_per_boot_key_by_user_id(user_id) {
648 Some(super_key) => {
649 log::info!("In get_with_password_unlock. Trying to unlock when already unlocked.");
650 Ok(UserState::LskfUnlocked(super_key))
651 }
652 None => {
653 //Check if a super key exists in the database or legacy database.
654 //If not, return Uninitialized state.
655 //Otherwise, try to unlock the super key and if successful,
656 //return LskfUnlocked state
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000657 skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000658 .context("In get_with_password_unlock. Failed to unlock super key.")
659 }
660 }
661 }
662
Hasini Gunasingheda895552021-01-27 19:34:37 +0000663 /// Delete all the keys created on behalf of the user.
664 /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
665 /// encrypted keys.
666 pub fn reset_user(
667 db: &mut KeystoreDB,
668 skm: &SuperKeyManager,
Janis Danisevskiseed69842021-02-18 20:04:10 -0800669 legacy_migrator: &LegacyMigrator,
Paul Crowley7a658392021-03-18 17:08:20 -0700670 user_id: UserId,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000671 keep_non_super_encrypted_keys: bool,
672 ) -> Result<()> {
673 // mark keys created on behalf of the user as unreferenced.
Janis Danisevskiseed69842021-02-18 20:04:10 -0800674 legacy_migrator
675 .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
676 .context("In reset_user: Trying to delete legacy keys.")?;
Paul Crowley7a658392021-03-18 17:08:20 -0700677 db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000678 .context("In reset user. Error in unbinding keys.")?;
679
680 //delete super key in cache, if exists
Paul Crowley7a658392021-03-18 17:08:20 -0700681 skm.forget_all_keys_for_user(user_id);
Hasini Gunasingheda895552021-01-27 19:34:37 +0000682 Ok(())
683 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800684}
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000685
Janis Danisevskiseed69842021-02-18 20:04:10 -0800686/// This enum represents three states a KeyMint Blob can be in, w.r.t super encryption.
687/// `Sensitive` holds the non encrypted key and a reference to its super key.
688/// `NonSensitive` holds a non encrypted key that is never supposed to be encrypted.
689/// `Ref` holds a reference to a key blob when it does not need to be modified if its
690/// life time allows it.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000691pub enum KeyBlob<'a> {
Paul Crowley7a658392021-03-18 17:08:20 -0700692 Sensitive { key: ZVec, reencrypt_with: Arc<SuperKey> },
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000693 NonSensitive(Vec<u8>),
694 Ref(&'a [u8]),
695}
696
Janis Danisevskiseed69842021-02-18 20:04:10 -0800697/// Deref returns a reference to the key material in any variant.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000698impl<'a> Deref for KeyBlob<'a> {
699 type Target = [u8];
700
701 fn deref(&self) -> &Self::Target {
702 match self {
Paul Crowley7a658392021-03-18 17:08:20 -0700703 Self::Sensitive { key, .. } => &key,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000704 Self::NonSensitive(key) => &key,
705 Self::Ref(key) => key,
706 }
707 }
708}