blob: aa434d68aabf94d2c2949b70a8a5bbbaed26d9ef [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::{
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
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,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700133 pw: &Password,
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,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700236 pw: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000237 ) -> 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,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700264 pw: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000265 ) -> 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,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700299 pw: &Password,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000300 ) -> 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
Paul Crowleyf61fee72021-03-17 14:38:44 -0700309 pub fn extract_super_key_from_key_entry(entry: KeyEntry, pw: &Password) -> Result<SuperKey> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000310 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)) => {
Paul Crowleyf61fee72021-03-17 14:38:44 -0700318 let key = pw.derive_key(Some(salt), AES_256_KEY_LENGTH).context(
319 "In extract_super_key_from_key_entry: Failed to generate key from password.",
320 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000321
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.
Paul Crowleyf61fee72021-03-17 14:38:44 -0700347 pub fn encrypt_with_password(
348 super_key: &[u8],
349 pw: &Password,
350 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000351 let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
Paul Crowleyf61fee72021-03-17 14:38:44 -0700352 let derived_key = pw
353 .derive_key(Some(&salt), AES_256_KEY_LENGTH)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000354 .context("In encrypt_with_password: Failed to derive password.")?;
355 let mut metadata = BlobMetaData::new();
356 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
357 metadata.add(BlobMetaEntry::Salt(salt));
358 let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
359 .context("In encrypt_with_password: Failed to encrypt new super key.")?;
360 metadata.add(BlobMetaEntry::Iv(iv));
361 metadata.add(BlobMetaEntry::AeadTag(tag));
362 Ok((encrypted_key, metadata))
363 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000364
365 // Encrypt the given key blob with the user's super key, if the super key exists and the device
366 // is unlocked. If the super key exists and the device is locked, or LSKF is not setup,
367 // return error. Note that it is out of the scope of this function to check if super encryption
368 // is required. Such check should be performed before calling this function.
369 fn super_encrypt_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000370 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000371 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000372 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000373 user_id: u32,
374 key_blob: &[u8],
375 ) -> Result<(Vec<u8>, BlobMetaData)> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000376 match UserState::get(db, legacy_migrator, self, user_id)
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000377 .context("In super_encrypt. Failed to get user state.")?
378 {
379 UserState::LskfUnlocked(super_key) => {
380 Self::encrypt_with_super_key(key_blob, &super_key)
381 .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
382 }
383 UserState::LskfLocked => {
384 Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
385 }
386 UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
387 .context("In super_encrypt. LSKF is not setup for the user."),
388 }
389 }
390
391 //Helper function to encrypt a key with the given super key. Callers should select which super
392 //key to be used. This is called when a key is super encrypted at its creation as well as at its
393 //upgrade.
394 fn encrypt_with_super_key(
395 key_blob: &[u8],
396 super_key: &SuperKey,
397 ) -> Result<(Vec<u8>, BlobMetaData)> {
398 let mut metadata = BlobMetaData::new();
399 let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
400 .context("In encrypt_with_super_key: Failed to encrypt new super key.")?;
401 metadata.add(BlobMetaEntry::Iv(iv));
402 metadata.add(BlobMetaEntry::AeadTag(tag));
403 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key.id)));
404 Ok((encrypted_key, metadata))
405 }
406
407 /// Check if super encryption is required and if so, super-encrypt the key to be stored in
408 /// the database.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000409 #[allow(clippy::clippy::too_many_arguments)]
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000410 pub fn handle_super_encryption_on_key_init(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000411 &self,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000412 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000413 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000414 domain: &Domain,
415 key_parameters: &[KeyParameter],
416 flags: Option<i32>,
417 user_id: u32,
418 key_blob: &[u8],
419 ) -> Result<(Vec<u8>, BlobMetaData)> {
420 match (*domain, Enforcements::super_encryption_required(key_parameters, flags)) {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000421 (Domain::APP, true) => {
422 self.super_encrypt_on_key_init(db, legacy_migrator, user_id, &key_blob).context(
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000423 "In handle_super_encryption_on_key_init.
424 Failed to super encrypt the key.",
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000425 )
426 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000427 _ => Ok((key_blob.to_vec(), BlobMetaData::new())),
428 }
429 }
430
431 /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using
432 /// the relevant super key.
433 pub fn unwrap_key_if_required<'a>(
434 &self,
435 metadata: &BlobMetaData,
436 key_blob: &'a [u8],
437 ) -> Result<KeyBlob<'a>> {
438 if Self::key_super_encrypted(&metadata) {
439 let unwrapped_key = self
440 .unwrap_key(key_blob, metadata)
441 .context("In unwrap_key_if_required. Error in unwrapping the key.")?;
442 Ok(unwrapped_key)
443 } else {
444 Ok(KeyBlob::Ref(key_blob))
445 }
446 }
447
448 /// Check if a given key needs re-super-encryption, from its KeyBlob type.
449 /// If so, re-super-encrypt the key and return a new set of metadata,
450 /// containing the new super encryption information.
451 pub fn reencrypt_on_upgrade_if_required<'a>(
452 key_blob_before_upgrade: &KeyBlob,
453 key_after_upgrade: &'a [u8],
454 ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)> {
455 match key_blob_before_upgrade {
456 KeyBlob::Sensitive(_, super_key) => {
457 let (key, metadata) = Self::encrypt_with_super_key(key_after_upgrade, super_key)
Janis Danisevskiseed69842021-02-18 20:04:10 -0800458 .context(concat!(
459 "In reencrypt_on_upgrade_if_required. ",
460 "Failed to re-super-encrypt key on key upgrade."
461 ))?;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000462 Ok((KeyBlob::NonSensitive(key), Some(metadata)))
463 }
464 _ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
465 }
466 }
467
468 // Helper function to decide if a key is super encrypted, given metadata.
469 fn key_super_encrypted(metadata: &BlobMetaData) -> bool {
470 if let Some(&EncryptedBy::KeyId(_)) = metadata.encrypted_by() {
471 return true;
472 }
473 false
474 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000475}
476
477/// This enum represents different states of the user's life cycle in the device.
478/// For now, only three states are defined. More states may be added later.
479pub enum UserState {
480 // The user has registered LSKF and has unlocked the device by entering PIN/Password,
481 // and hence the per-boot super key is available in the cache.
482 LskfUnlocked(SuperKey),
483 // The user has registered LSKF, but has not unlocked the device using password, after reboot.
484 // Hence the per-boot super-key(s) is not available in the cache.
485 // However, the encrypted super key is available in the database.
486 LskfLocked,
487 // There's no user in the device for the given user id, or the user with the user id has not
488 // setup LSKF.
489 Uninitialized,
490}
491
492impl UserState {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000493 pub fn get(
494 db: &mut KeystoreDB,
495 legacy_migrator: &LegacyMigrator,
496 skm: &SuperKeyManager,
497 user_id: u32,
498 ) -> Result<UserState> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000499 match skm.get_per_boot_key_by_user_id(user_id) {
500 Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
501 None => {
502 //Check if a super key exists in the database or legacy database.
503 //If so, return locked user state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000504 if SuperKeyManager::super_key_exists_in_db_for_user(db, legacy_migrator, user_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000505 .context("In get.")?
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000506 {
507 Ok(UserState::LskfLocked)
508 } else {
509 Ok(UserState::Uninitialized)
510 }
511 }
512 }
513 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000514
515 /// Queries user state when serving password change requests.
516 pub fn get_with_password_changed(
517 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000518 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000519 skm: &SuperKeyManager,
520 user_id: u32,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700521 password: Option<&Password>,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000522 ) -> Result<UserState> {
523 match skm.get_per_boot_key_by_user_id(user_id) {
524 Some(super_key) => {
525 if password.is_none() {
526 //transitioning to swiping, delete only the super key in database and cache, and
527 //super-encrypted keys in database (and in KM)
Janis Danisevskiseed69842021-02-18 20:04:10 -0800528 Self::reset_user(db, skm, legacy_migrator, user_id, true).context(
529 "In get_with_password_changed: Trying to delete keys from the db.",
530 )?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000531 //Lskf is now removed in Keystore
532 Ok(UserState::Uninitialized)
533 } else {
534 //Keystore won't be notified when changing to a new password when LSKF is
535 //already setup. Therefore, ideally this path wouldn't be reached.
536 Ok(UserState::LskfUnlocked(super_key))
537 }
538 }
539 None => {
540 //Check if a super key exists in the database or legacy database.
541 //If so, return LskfLocked state.
542 //Otherwise, i) if the password is provided, initialize the super key and return
543 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000544 skm.check_and_initialize_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000545 }
546 }
547 }
548
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000549 /// Queries user state when serving password unlock requests.
550 pub fn get_with_password_unlock(
551 db: &mut KeystoreDB,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000552 legacy_migrator: &LegacyMigrator,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000553 skm: &SuperKeyManager,
554 user_id: u32,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700555 password: &Password,
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000556 ) -> Result<UserState> {
557 match skm.get_per_boot_key_by_user_id(user_id) {
558 Some(super_key) => {
559 log::info!("In get_with_password_unlock. Trying to unlock when already unlocked.");
560 Ok(UserState::LskfUnlocked(super_key))
561 }
562 None => {
563 //Check if a super key exists in the database or legacy database.
564 //If not, return Uninitialized state.
565 //Otherwise, try to unlock the super key and if successful,
566 //return LskfUnlocked state
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000567 skm.check_and_unlock_super_key(db, legacy_migrator, user_id, password)
Hasini Gunasinghe731e3c82021-02-06 00:56:28 +0000568 .context("In get_with_password_unlock. Failed to unlock super key.")
569 }
570 }
571 }
572
Hasini Gunasingheda895552021-01-27 19:34:37 +0000573 /// Delete all the keys created on behalf of the user.
574 /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
575 /// encrypted keys.
576 pub fn reset_user(
577 db: &mut KeystoreDB,
578 skm: &SuperKeyManager,
Janis Danisevskiseed69842021-02-18 20:04:10 -0800579 legacy_migrator: &LegacyMigrator,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000580 user_id: u32,
581 keep_non_super_encrypted_keys: bool,
582 ) -> Result<()> {
583 // mark keys created on behalf of the user as unreferenced.
Janis Danisevskiseed69842021-02-18 20:04:10 -0800584 legacy_migrator
585 .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
586 .context("In reset_user: Trying to delete legacy keys.")?;
Hasini Gunasingheda895552021-01-27 19:34:37 +0000587 db.unbind_keys_for_user(user_id as u32, keep_non_super_encrypted_keys)
588 .context("In reset user. Error in unbinding keys.")?;
589
590 //delete super key in cache, if exists
591 skm.forget_all_keys_for_user(user_id as u32);
592 Ok(())
593 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800594}
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000595
Janis Danisevskiseed69842021-02-18 20:04:10 -0800596/// This enum represents three states a KeyMint Blob can be in, w.r.t super encryption.
597/// `Sensitive` holds the non encrypted key and a reference to its super key.
598/// `NonSensitive` holds a non encrypted key that is never supposed to be encrypted.
599/// `Ref` holds a reference to a key blob when it does not need to be modified if its
600/// life time allows it.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000601pub enum KeyBlob<'a> {
602 Sensitive(ZVec, SuperKey),
603 NonSensitive(Vec<u8>),
604 Ref(&'a [u8]),
605}
606
Janis Danisevskiseed69842021-02-18 20:04:10 -0800607/// Deref returns a reference to the key material in any variant.
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000608impl<'a> Deref for KeyBlob<'a> {
609 type Target = [u8];
610
611 fn deref(&self) -> &Self::Target {
612 match self {
613 Self::Sensitive(key, _) => &key,
614 Self::NonSensitive(key) => &key,
615 Self::Ref(key) => key,
616 }
617 }
618}