blob: 156d20d9cddf1635147eeb4ca58e6f9b3e4f9c37 [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,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000021 legacy_migrator::LegacyMigrator,
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::{
Hasini Gunasingheda895552021-01-27 19:34:37 +000026 aes_gcm_decrypt, aes_gcm_encrypt, derive_key_from_password, generate_aes256_key, generate_salt,
27 ZVec, 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
38#[derive(Default)]
39struct UserSuperKeys {
40 /// The per boot key is used for LSKF binding of authentication bound keys. There is one
41 /// key per android user. The key is stored on flash encrypted with a key derived from a
42 /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF).
43 /// When the user unlocks the device for the first time, this key is unlocked, i.e., decrypted,
44 /// and stays memory resident until the device reboots.
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000045 per_boot: Option<SuperKey>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080046 /// The screen lock key works like the per boot key with the distinction that it is cleared
47 /// from memory when the screen lock is engaged.
48 /// TODO the life cycle is not fully implemented at this time.
49 screen_lock: Option<Arc<ZVec>>,
50}
51
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000052#[derive(Default, Clone)]
53pub struct SuperKey {
54 key: Arc<ZVec>,
55 // id of the super key in the database.
56 id: i64,
57}
58
59impl SuperKey {
60 pub fn get_key(&self) -> &Arc<ZVec> {
61 &self.key
62 }
63
64 pub fn get_id(&self) -> i64 {
65 self.id
66 }
67}
68
Janis Danisevskisb42fc182020-12-15 08:41:27 -080069#[derive(Default)]
70struct SkmState {
71 user_keys: HashMap<UserId, UserSuperKeys>,
72 key_index: HashMap<i64, Weak<ZVec>>,
73}
74
75#[derive(Default)]
76pub struct SuperKeyManager {
77 data: Mutex<SkmState>,
78}
79
80impl SuperKeyManager {
81 pub fn new() -> Self {
82 Self { data: Mutex::new(Default::default()) }
83 }
84
85 pub fn forget_screen_lock_key_for_user(&self, user: UserId) {
86 let mut data = self.data.lock().unwrap();
87 if let Some(usk) = data.user_keys.get_mut(&user) {
88 usk.screen_lock = None;
89 }
90 }
91
92 pub fn forget_screen_lock_keys(&self) {
93 let mut data = self.data.lock().unwrap();
94 for (_, usk) in data.user_keys.iter_mut() {
95 usk.screen_lock = None;
96 }
97 }
98
99 pub fn forget_all_keys_for_user(&self, user: UserId) {
100 let mut data = self.data.lock().unwrap();
101 data.user_keys.remove(&user);
102 }
103
104 pub fn forget_all_keys(&self) {
105 let mut data = self.data.lock().unwrap();
106 data.user_keys.clear();
107 data.key_index.clear();
108 }
109
Hasini Gunasingheda895552021-01-27 19:34:37 +0000110 fn install_per_boot_key_for_user(&self, user: UserId, super_key: SuperKey) {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800111 let mut data = self.data.lock().unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +0000112 data.key_index.insert(super_key.id, Arc::downgrade(&(super_key.key)));
113 data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800114 }
115
116 fn get_key(&self, key_id: &i64) -> Option<Arc<ZVec>> {
117 self.data.lock().unwrap().key_index.get(key_id).and_then(|k| k.upgrade())
118 }
119
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000120 pub fn get_per_boot_key_by_user_id(&self, user_id: u32) -> Option<SuperKey> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800121 let data = self.data.lock().unwrap();
122 data.user_keys.get(&user_id).map(|e| e.per_boot.clone()).flatten()
123 }
124
125 /// This function unlocks the super keys for a given user.
126 /// This means the key is loaded from the database, decrypted and placed in the
127 /// super key cache. If there is no such key a new key is created, encrypted with
128 /// a key derived from the given password and stored in the database.
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800129 pub fn unlock_user_key(
130 &self,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000131 db: &mut KeystoreDB,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800132 user: UserId,
133 pw: &[u8],
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800134 legacy_blob_loader: &LegacyBlobLoader,
135 ) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800136 let (_, entry) = db
Max Bires8e93d2b2021-01-14 13:17:59 -0800137 .get_or_create_key_with(
138 Domain::APP,
139 user as u64 as i64,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000140 KeystoreDB::USER_SUPER_KEY_ALIAS,
Max Bires8e93d2b2021-01-14 13:17:59 -0800141 crate::database::KEYSTORE_UUID,
142 || {
143 // For backward compatibility we need to check if there is a super key present.
144 let super_key = legacy_blob_loader
145 .load_super_key(user, pw)
146 .context("In create_new_key: Failed to load legacy key blob.")?;
147 let super_key = match super_key {
148 None => {
149 // No legacy file was found. So we generate a new key.
Hasini Gunasingheda895552021-01-27 19:34:37 +0000150 generate_aes256_key()
Max Bires8e93d2b2021-01-14 13:17:59 -0800151 .context("In create_new_key: Failed to generate AES 256 key.")?
152 }
153 Some(key) => key,
154 };
Hasini Gunasingheda895552021-01-27 19:34:37 +0000155 // Regardless of whether we loaded an old AES128 key or generated a new AES256
156 // key as the super key, we derive a AES256 key from the password and re-encrypt
157 // the super key before we insert it in the database. The length of the key is
158 // preserved by the encryption so we don't need any extra flags to inform us
159 // which algorithm to use it with.
160 Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
Max Bires8e93d2b2021-01-14 13:17:59 -0800161 },
162 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800163 .context("In unlock_user_key: Failed to get key id.")?;
164
Hasini Gunasingheda895552021-01-27 19:34:37 +0000165 self.populate_cache_from_super_key_blob(user, entry, pw).context("In unlock_user_key.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800166 Ok(())
167 }
168
169 /// Unwraps an encrypted key blob given metadata identifying the encryption key.
170 /// The function queries `metadata.encrypted_by()` to determine the encryption key.
171 /// It then check if the required key is memory resident, and if so decrypts the
172 /// blob.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000173 pub fn unwrap_key<'a>(&self, blob: &'a [u8], metadata: &BlobMetaData) -> Result<KeyBlob<'a>> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800174 match metadata.encrypted_by() {
175 Some(EncryptedBy::KeyId(key_id)) => match self.get_key(key_id) {
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000176 Some(key) => Ok(KeyBlob::Sensitive(
177 Self::unwrap_key_with_key(blob, metadata, &key).context("In unwrap_key.")?,
178 SuperKey { key: key.clone(), id: *key_id },
179 )),
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800180 None => Err(Error::Rc(ResponseCode::LOCKED))
181 .context("In unwrap_key: Key is not usable until the user entered their LSKF."),
182 },
183 _ => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
184 .context("In unwrap_key: Cannot determined wrapping key."),
185 }
186 }
187
188 /// Unwraps an encrypted key blob given an encryption key.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800189 fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &[u8]) -> Result<ZVec> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800190 match (metadata.iv(), metadata.aead_tag()) {
191 (Some(iv), Some(tag)) => aes_gcm_decrypt(blob, iv, tag, key)
192 .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
193 (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
194 concat!(
195 "In unwrap_key_with_key: Key has incomplete metadata.",
196 "Present: iv: {}, aead_tag: {}."
197 ),
198 iv.is_some(),
199 tag.is_some(),
200 )),
201 }
202 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000203
204 /// Checks if user has setup LSKF, even when super key cache is empty for the user.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000205 pub fn super_key_exists_in_db_for_user(
206 db: &mut KeystoreDB,
207 legacy_migrator: &LegacyMigrator,
208 user_id: u32,
209 ) -> Result<bool> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000210 let key_in_db = db
211 .key_exists(
212 Domain::APP,
213 user_id as u64 as i64,
214 KeystoreDB::USER_SUPER_KEY_ALIAS,
215 KeyType::Super,
216 )
217 .context("In super_key_exists_in_db_for_user.")?;
218
219 if key_in_db {
220 Ok(key_in_db)
221 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000222 legacy_migrator
223 .has_super_key(user_id)
224 .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000225 }
226 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000227
228 /// 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 +0000229 /// legacy database). If not, return Uninitialized state.
230 /// Otherwise, decrypt the super key from the password and return LskfUnlocked state.
231 pub fn check_and_unlock_super_key(
232 &self,
233 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000234 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000235 user_id: u32,
236 pw: &[u8],
237 ) -> Result<UserState> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000238 let result = legacy_migrator
239 .with_try_migrate_super_key(user_id, pw, || db.load_super_key(user_id))
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000240 .context("In check_and_unlock_super_key. Failed to load super key")?;
241
242 match result {
243 Some((_, entry)) => {
244 let super_key = self
245 .populate_cache_from_super_key_blob(user_id, entry, pw)
246 .context("In check_and_unlock_super_key.")?;
247 Ok(UserState::LskfUnlocked(super_key))
248 }
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000249 None => Ok(UserState::Uninitialized),
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000250 }
251 }
252
253 /// 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 +0000254 /// legacy database). If so, return LskfLocked state.
255 /// If the password is provided, generate a new super key, encrypt with the password,
256 /// store in the database and populate the super key cache for the new user
257 /// and return LskfUnlocked state.
258 /// If the password is not provided, return Uninitialized state.
259 pub fn check_and_initialize_super_key(
260 &self,
261 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000262 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000263 user_id: u32,
264 pw: Option<&[u8]>,
265 ) -> Result<UserState> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000266 let super_key_exists_in_db =
267 Self::super_key_exists_in_db_for_user(db, legacy_migrator, user_id).context(
268 "In check_and_initialize_super_key. Failed to check if super key exists.",
269 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000270 if super_key_exists_in_db {
271 Ok(UserState::LskfLocked)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000272 } else if let Some(pw) = pw {
273 //generate a new super key.
274 let super_key = generate_aes256_key()
275 .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
276 //derive an AES256 key from the password and re-encrypt the super key
277 //before we insert it in the database.
278 let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
279 .context("In check_and_initialize_super_key.")?;
280
281 let key_entry = db
282 .store_super_key(user_id, &(&encrypted_super_key, &blob_metadata))
283 .context("In check_and_initialize_super_key. Failed to store super key.")?;
284
285 let super_key = self
286 .populate_cache_from_super_key_blob(user_id, key_entry, pw)
287 .context("In check_and_initialize_super_key.")?;
288 Ok(UserState::LskfUnlocked(super_key))
Hasini Gunasingheda895552021-01-27 19:34:37 +0000289 } else {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000290 Ok(UserState::Uninitialized)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000291 }
292 }
293
294 //helper function to populate super key cache from the super key blob loaded from the database
295 fn populate_cache_from_super_key_blob(
296 &self,
297 user_id: u32,
298 entry: KeyEntry,
299 pw: &[u8],
300 ) -> Result<SuperKey> {
301 let super_key = Self::extract_super_key_from_key_entry(entry, pw).context(
302 "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
303 )?;
304 self.install_per_boot_key_for_user(user_id, super_key.clone());
305 Ok(super_key)
306 }
307
308 /// Extracts super key from the entry loaded from the database
309 pub fn extract_super_key_from_key_entry(entry: KeyEntry, pw: &[u8]) -> Result<SuperKey> {
310 if let Some((blob, metadata)) = entry.key_blob_info() {
311 let key = match (
312 metadata.encrypted_by(),
313 metadata.salt(),
314 metadata.iv(),
315 metadata.aead_tag(),
316 ) {
317 (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
318 let key = derive_key_from_password(pw, Some(salt), AES_256_KEY_LENGTH).context(
319 "In extract_super_key_from_key_entry: Failed to generate key from password.",
320 )?;
321
322 aes_gcm_decrypt(blob, iv, tag, &key).context(
323 "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
324 )?
325 }
326 (enc_by, salt, iv, tag) => {
327 return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
328 concat!(
329 "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
330 "Present: encrypted_by: {}, salt: {}, iv: {}, aead_tag: {}."
331 ),
332 enc_by.is_some(),
333 salt.is_some(),
334 iv.is_some(),
335 tag.is_some()
336 ));
337 }
338 };
339 Ok(SuperKey { key: Arc::new(key), id: entry.id() })
340 } else {
341 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
342 .context("In extract_super_key_from_key_entry: No key blob info.")
343 }
344 }
345
346 /// Encrypts the super key from a key derived from the password, before storing in the database.
347 pub fn encrypt_with_password(super_key: &[u8], pw: &[u8]) -> Result<(Vec<u8>, BlobMetaData)> {
348 let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
349 let derived_key = derive_key_from_password(pw, Some(&salt), AES_256_KEY_LENGTH)
350 .context("In encrypt_with_password: Failed to derive password.")?;
351 let mut metadata = BlobMetaData::new();
352 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
353 metadata.add(BlobMetaEntry::Salt(salt));
354 let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
355 .context("In encrypt_with_password: Failed to encrypt new super key.")?;
356 metadata.add(BlobMetaEntry::Iv(iv));
357 metadata.add(BlobMetaEntry::AeadTag(tag));
358 Ok((encrypted_key, metadata))
359 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000360
361 // Encrypt the given key blob with the user's super key, if the super key exists and the device
362 // is unlocked. If the super key exists and the device is locked, or LSKF is not setup,
363 // return error. Note that it is out of the scope of this function to check if super encryption
364 // is required. Such check should be performed before calling this function.
365 fn super_encrypt_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000366 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000367 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000368 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000369 user_id: u32,
370 key_blob: &[u8],
371 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000372 match UserState::get(db, legacy_migrator, self, user_id)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000373 .context("In super_encrypt. Failed to get user state.")?
374 {
375 UserState::LskfUnlocked(super_key) => {
376 Self::encrypt_with_super_key(key_blob, &super_key)
377 .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
378 }
379 UserState::LskfLocked => {
380 Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
381 }
382 UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
383 .context("In super_encrypt. LSKF is not setup for the user."),
384 }
385 }
386
387 //Helper function to encrypt a key with the given super key. Callers should select which super
388 //key to be used. This is called when a key is super encrypted at its creation as well as at its
389 //upgrade.
390 fn encrypt_with_super_key(
391 key_blob: &[u8],
392 super_key: &SuperKey,
393 ) -> Result<(Vec<u8>, BlobMetaData)> {
394 let mut metadata = BlobMetaData::new();
395 let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
396 .context("In encrypt_with_super_key: Failed to encrypt new super key.")?;
397 metadata.add(BlobMetaEntry::Iv(iv));
398 metadata.add(BlobMetaEntry::AeadTag(tag));
399 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key.id)));
400 Ok((encrypted_key, metadata))
401 }
402
403 /// Check if super encryption is required and if so, super-encrypt the key to be stored in
404 /// the database.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000405 #[allow(clippy::clippy::too_many_arguments)]
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000406 pub fn handle_super_encryption_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000407 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000408 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000409 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000410 domain: &Domain,
411 key_parameters: &[KeyParameter],
412 flags: Option<i32>,
413 user_id: u32,
414 key_blob: &[u8],
415 ) -> Result<(Vec<u8>, BlobMetaData)> {
416 match (*domain, Enforcements::super_encryption_required(key_parameters, flags)) {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000417 (Domain::APP, true) => {
418 self.super_encrypt_on_key_init(db, legacy_migrator, user_id, &key_blob).context(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000419 "In handle_super_encryption_on_key_init.
420 Failed to super encrypt the key.",
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000421 )
422 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000423 _ => Ok((key_blob.to_vec(), BlobMetaData::new())),
424 }
425 }
426
427 /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using
428 /// the relevant super key.
429 pub fn unwrap_key_if_required<'a>(
430 &self,
431 metadata: &BlobMetaData,
432 key_blob: &'a [u8],
433 ) -> Result<KeyBlob<'a>> {
434 if Self::key_super_encrypted(&metadata) {
435 let unwrapped_key = self
436 .unwrap_key(key_blob, metadata)
437 .context("In unwrap_key_if_required. Error in unwrapping the key.")?;
438 Ok(unwrapped_key)
439 } else {
440 Ok(KeyBlob::Ref(key_blob))
441 }
442 }
443
444 /// Check if a given key needs re-super-encryption, from its KeyBlob type.
445 /// If so, re-super-encrypt the key and return a new set of metadata,
446 /// containing the new super encryption information.
447 pub fn reencrypt_on_upgrade_if_required<'a>(
448 key_blob_before_upgrade: &KeyBlob,
449 key_after_upgrade: &'a [u8],
450 ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)> {
451 match key_blob_before_upgrade {
452 KeyBlob::Sensitive(_, super_key) => {
453 let (key, metadata) = Self::encrypt_with_super_key(key_after_upgrade, super_key)
454 .context(
455 "In reencrypt_on_upgrade_if_required. Failed to re-super-encrypt key on key upgrade.",
456 )?;
457 Ok((KeyBlob::NonSensitive(key), Some(metadata)))
458 }
459 _ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
460 }
461 }
462
463 // Helper function to decide if a key is super encrypted, given metadata.
464 fn key_super_encrypted(metadata: &BlobMetaData) -> bool {
465 if let Some(&EncryptedBy::KeyId(_)) = metadata.encrypted_by() {
466 return true;
467 }
468 false
469 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000470}
471
472/// This enum represents different states of the user's life cycle in the device.
473/// For now, only three states are defined. More states may be added later.
474pub enum UserState {
475 // The user has registered LSKF and has unlocked the device by entering PIN/Password,
476 // and hence the per-boot super key is available in the cache.
477 LskfUnlocked(SuperKey),
478 // The user has registered LSKF, but has not unlocked the device using password, after reboot.
479 // Hence the per-boot super-key(s) is not available in the cache.
480 // However, the encrypted super key is available in the database.
481 LskfLocked,
482 // There's no user in the device for the given user id, or the user with the user id has not
483 // setup LSKF.
484 Uninitialized,
485}
486
487impl UserState {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000488 pub fn get(
489 db: &mut KeystoreDB,
490 legacy_migrator: &LegacyMigrator,
491 skm: &SuperKeyManager,
492 user_id: u32,
493 ) -> Result<UserState> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000494 match skm.get_per_boot_key_by_user_id(user_id) {
495 Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
496 None => {
497 //Check if a super key exists in the database or legacy database.
498 //If so, return locked user state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000499 if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000500 .context("In get.")?
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000501 {
502 Ok(UserState::LskfLocked)
503 } else {
504 Ok(UserState::Uninitialized)
505 }
506 }
507 }
508 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000509
510 /// Queries user state when serving password change requests.
511 pub fn get_with_password_changed(
512 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000513 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000514 skm: &SuperKeyManager,
515 user_id: u32,
516 password: Option<&[u8]>,
517 ) -> Result<UserState> {
518 match skm.get_per_boot_key_by_user_id(user_id) {
519 Some(super_key) => {
520 if password.is_none() {
521 //transitioning to swiping, delete only the super key in database and cache, and
522 //super-encrypted keys in database (and in KM)
523 Self::reset_user(db, skm, user_id, true)
524 .context("In get_with_password_changed.")?;
525 //Lskf is now removed in Keystore
526 Ok(UserState::Uninitialized)
527 } else {
528 //Keystore won't be notified when changing to a new password when LSKF is
529 //already setup. Therefore, ideally this path wouldn't be reached.
530 Ok(UserState::LskfUnlocked(super_key))
531 }
532 }
533 None => {
534 //Check if a super key exists in the database or legacy database.
535 //If so, return LskfLocked state.
536 //Otherwise, i) if the password is provided, initialize the super key and return
537 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000538 skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000539 }
540 }
541 }
542
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000543 /// Queries user state when serving password unlock requests.
544 pub fn get_with_password_unlock(
545 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000546 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000547 skm: &SuperKeyManager,
548 user_id: u32,
549 password: &[u8],
550 ) -> Result<UserState> {
551 match skm.get_per_boot_key_by_user_id(user_id) {
552 Some(super_key) => {
553 log::info!("In get_with_password_unlock. Trying to unlock when already unlocked.");
554 Ok(UserState::LskfUnlocked(super_key))
555 }
556 None => {
557 //Check if a super key exists in the database or legacy database.
558 //If not, return Uninitialized state.
559 //Otherwise, try to unlock the super key and if successful,
560 //return LskfUnlocked state
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000561 skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000562 .context("In get_with_password_unlock. Failed to unlock super key.")
563 }
564 }
565 }
566
Hasini Gunasingheda895552021-01-27 19:34:37 +0000567 /// Delete all the keys created on behalf of the user.
568 /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
569 /// encrypted keys.
570 pub fn reset_user(
571 db: &mut KeystoreDB,
572 skm: &SuperKeyManager,
573 user_id: u32,
574 keep_non_super_encrypted_keys: bool,
575 ) -> Result<()> {
576 // mark keys created on behalf of the user as unreferenced.
577 db.unbind_keys_for_user(user_id as u32, keep_non_super_encrypted_keys)
578 .context("In reset user. Error in unbinding keys.")?;
579
580 //delete super key in cache, if exists
581 skm.forget_all_keys_for_user(user_id as u32);
582 Ok(())
583 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800584}
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000585
586/// This enum represents two states a Keymint Blob can be in, w.r.t super encryption.
587/// Sensitive variant represents a Keymint blob that is supposed to be super encrypted,
588/// but unwrapped during usage. Therefore, it has the super key along with the unwrapped key.
589/// Ref variant represents a Keymint blob that is not required to super encrypt or that is
590/// already super encrypted.
591pub enum KeyBlob<'a> {
592 Sensitive(ZVec, SuperKey),
593 NonSensitive(Vec<u8>),
594 Ref(&'a [u8]),
595}
596
597/// Deref returns a reference to the key material in both variants.
598impl<'a> Deref for KeyBlob<'a> {
599 type Target = [u8];
600
601 fn deref(&self) -> &Self::Target {
602 match self {
603 Self::Sensitive(key, _) => &key,
604 Self::NonSensitive(key) => &key,
605 Self::Ref(key) => key,
606 }
607 }
608}