blob: 0aae232dcdfe57e44aa0a2d99f1d5264eabf9c7b [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,
19 database::KeyType, database::KeystoreDB, error::Error, error::ResponseCode,
20 legacy_blob::LegacyBlobLoader,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080021};
22use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
23use anyhow::{Context, Result};
24use keystore2_crypto::{
Hasini Gunasingheda895552021-01-27 19:34:37 +000025 aes_gcm_decrypt, aes_gcm_encrypt, derive_key_from_password, generate_aes256_key, generate_salt,
26 ZVec, AES_256_KEY_LENGTH,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080027};
28use std::{
29 collections::HashMap,
30 sync::Arc,
31 sync::{Mutex, Weak},
32};
33
34type UserId = u32;
35
36#[derive(Default)]
37struct UserSuperKeys {
38 /// The per boot key is used for LSKF binding of authentication bound keys. There is one
39 /// key per android user. The key is stored on flash encrypted with a key derived from a
40 /// secret, that is itself derived from the user's lock screen knowledge factor (LSKF).
41 /// When the user unlocks the device for the first time, this key is unlocked, i.e., decrypted,
42 /// and stays memory resident until the device reboots.
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000043 per_boot: Option<SuperKey>,
Janis Danisevskisb42fc182020-12-15 08:41:27 -080044 /// The screen lock key works like the per boot key with the distinction that it is cleared
45 /// from memory when the screen lock is engaged.
46 /// TODO the life cycle is not fully implemented at this time.
47 screen_lock: Option<Arc<ZVec>>,
48}
49
Hasini Gunasinghe0e161452021-01-27 19:34:37 +000050#[derive(Default, Clone)]
51pub struct SuperKey {
52 key: Arc<ZVec>,
53 // id of the super key in the database.
54 id: i64,
55}
56
57impl SuperKey {
58 pub fn get_key(&self) -> &Arc<ZVec> {
59 &self.key
60 }
61
62 pub fn get_id(&self) -> i64 {
63 self.id
64 }
65}
66
Janis Danisevskisb42fc182020-12-15 08:41:27 -080067#[derive(Default)]
68struct SkmState {
69 user_keys: HashMap<UserId, UserSuperKeys>,
70 key_index: HashMap<i64, Weak<ZVec>>,
71}
72
73#[derive(Default)]
74pub struct SuperKeyManager {
75 data: Mutex<SkmState>,
76}
77
78impl SuperKeyManager {
79 pub fn new() -> Self {
80 Self { data: Mutex::new(Default::default()) }
81 }
82
83 pub fn forget_screen_lock_key_for_user(&self, user: UserId) {
84 let mut data = self.data.lock().unwrap();
85 if let Some(usk) = data.user_keys.get_mut(&user) {
86 usk.screen_lock = None;
87 }
88 }
89
90 pub fn forget_screen_lock_keys(&self) {
91 let mut data = self.data.lock().unwrap();
92 for (_, usk) in data.user_keys.iter_mut() {
93 usk.screen_lock = None;
94 }
95 }
96
97 pub fn forget_all_keys_for_user(&self, user: UserId) {
98 let mut data = self.data.lock().unwrap();
99 data.user_keys.remove(&user);
100 }
101
102 pub fn forget_all_keys(&self) {
103 let mut data = self.data.lock().unwrap();
104 data.user_keys.clear();
105 data.key_index.clear();
106 }
107
Hasini Gunasingheda895552021-01-27 19:34:37 +0000108 fn install_per_boot_key_for_user(&self, user: UserId, super_key: SuperKey) {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800109 let mut data = self.data.lock().unwrap();
Hasini Gunasingheda895552021-01-27 19:34:37 +0000110 data.key_index.insert(super_key.id, Arc::downgrade(&(super_key.key)));
111 data.user_keys.entry(user).or_default().per_boot = Some(super_key);
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800112 }
113
114 fn get_key(&self, key_id: &i64) -> Option<Arc<ZVec>> {
115 self.data.lock().unwrap().key_index.get(key_id).and_then(|k| k.upgrade())
116 }
117
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000118 pub fn get_per_boot_key_by_user_id(&self, user_id: u32) -> Option<SuperKey> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800119 let data = self.data.lock().unwrap();
120 data.user_keys.get(&user_id).map(|e| e.per_boot.clone()).flatten()
121 }
122
123 /// This function unlocks the super keys for a given user.
124 /// This means the key is loaded from the database, decrypted and placed in the
125 /// super key cache. If there is no such key a new key is created, encrypted with
126 /// a key derived from the given password and stored in the database.
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800127 pub fn unlock_user_key(
128 &self,
Hasini Gunasingheda895552021-01-27 19:34:37 +0000129 db: &mut KeystoreDB,
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800130 user: UserId,
131 pw: &[u8],
Janis Danisevskisa51ccbc2020-11-25 21:04:24 -0800132 legacy_blob_loader: &LegacyBlobLoader,
133 ) -> Result<()> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800134 let (_, entry) = db
Max Bires8e93d2b2021-01-14 13:17:59 -0800135 .get_or_create_key_with(
136 Domain::APP,
137 user as u64 as i64,
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000138 KeystoreDB::USER_SUPER_KEY_ALIAS,
Max Bires8e93d2b2021-01-14 13:17:59 -0800139 crate::database::KEYSTORE_UUID,
140 || {
141 // For backward compatibility we need to check if there is a super key present.
142 let super_key = legacy_blob_loader
143 .load_super_key(user, pw)
144 .context("In create_new_key: Failed to load legacy key blob.")?;
145 let super_key = match super_key {
146 None => {
147 // No legacy file was found. So we generate a new key.
Hasini Gunasingheda895552021-01-27 19:34:37 +0000148 generate_aes256_key()
Max Bires8e93d2b2021-01-14 13:17:59 -0800149 .context("In create_new_key: Failed to generate AES 256 key.")?
150 }
151 Some(key) => key,
152 };
Hasini Gunasingheda895552021-01-27 19:34:37 +0000153 // Regardless of whether we loaded an old AES128 key or generated a new AES256
154 // key as the super key, we derive a AES256 key from the password and re-encrypt
155 // the super key before we insert it in the database. The length of the key is
156 // preserved by the encryption so we don't need any extra flags to inform us
157 // which algorithm to use it with.
158 Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
Max Bires8e93d2b2021-01-14 13:17:59 -0800159 },
160 )
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800161 .context("In unlock_user_key: Failed to get key id.")?;
162
Hasini Gunasingheda895552021-01-27 19:34:37 +0000163 self.populate_cache_from_super_key_blob(user, entry, pw).context("In unlock_user_key.")?;
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800164 Ok(())
165 }
166
167 /// Unwraps an encrypted key blob given metadata identifying the encryption key.
168 /// The function queries `metadata.encrypted_by()` to determine the encryption key.
169 /// It then check if the required key is memory resident, and if so decrypts the
170 /// blob.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800171 pub fn unwrap_key(&self, blob: &[u8], metadata: &BlobMetaData) -> Result<ZVec> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800172 match metadata.encrypted_by() {
173 Some(EncryptedBy::KeyId(key_id)) => match self.get_key(key_id) {
174 Some(key) => {
175 Self::unwrap_key_with_key(blob, metadata, &key).context("In unwrap_key.")
176 }
177 None => Err(Error::Rc(ResponseCode::LOCKED))
178 .context("In unwrap_key: Key is not usable until the user entered their LSKF."),
179 },
180 _ => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
181 .context("In unwrap_key: Cannot determined wrapping key."),
182 }
183 }
184
185 /// Unwraps an encrypted key blob given an encryption key.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800186 fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &[u8]) -> Result<ZVec> {
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800187 match (metadata.iv(), metadata.aead_tag()) {
188 (Some(iv), Some(tag)) => aes_gcm_decrypt(blob, iv, tag, key)
189 .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
190 (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
191 concat!(
192 "In unwrap_key_with_key: Key has incomplete metadata.",
193 "Present: iv: {}, aead_tag: {}."
194 ),
195 iv.is_some(),
196 tag.is_some(),
197 )),
198 }
199 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000200
201 /// Checks if user has setup LSKF, even when super key cache is empty for the user.
202 pub fn super_key_exists_in_db_for_user(db: &mut KeystoreDB, user_id: u32) -> Result<bool> {
203 let key_in_db = db
204 .key_exists(
205 Domain::APP,
206 user_id as u64 as i64,
207 KeystoreDB::USER_SUPER_KEY_ALIAS,
208 KeyType::Super,
209 )
210 .context("In super_key_exists_in_db_for_user.")?;
211
212 if key_in_db {
213 Ok(key_in_db)
214 } else {
215 //TODO (b/159371296): add a function to legacy blob loader to check if super key exists
216 //given user id
217 Ok(false)
218 }
219 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000220
221 /// Checks if user has already setup LSKF (i.e. a super key is persisted in the database or the
222 /// legacy database). If so, return LskfLocked state.
223 /// If the password is provided, generate a new super key, encrypt with the password,
224 /// store in the database and populate the super key cache for the new user
225 /// and return LskfUnlocked state.
226 /// If the password is not provided, return Uninitialized state.
227 pub fn check_and_initialize_super_key(
228 &self,
229 db: &mut KeystoreDB,
230 user_id: u32,
231 pw: Option<&[u8]>,
232 ) -> Result<UserState> {
233 let super_key_exists_in_db = Self::super_key_exists_in_db_for_user(db, user_id)
234 .context("In check_and_initialize_super_key. Failed to check if super key exists.")?;
235
236 if super_key_exists_in_db {
237 Ok(UserState::LskfLocked)
238 } else {
239 //TODO: 159371296. check if super key exists in legacy key database. If so, return
240 //LskfLocked. Otherwise, if pw is provided, initialize the super key.
241 if let Some(pw) = pw {
242 //generate a new super key.
243 let super_key = generate_aes256_key().context(
244 "In check_and_initialize_super_key: Failed to generate AES 256 key.",
245 )?;
246 //derive an AES256 key from the password and re-encrypt the super key
247 //before we insert it in the database.
248 let (encrypted_super_key, blob_metadata) =
249 Self::encrypt_with_password(&super_key, pw)
250 .context("In check_and_initialize_super_key.")?;
251
252 let key_entry = db
253 .store_super_key(user_id as u64 as i64, &(&encrypted_super_key, &blob_metadata))
254 .context("In check_and_initialize_super_key. Failed to store super key.")?;
255
256 let super_key = self
257 .populate_cache_from_super_key_blob(user_id, key_entry, pw)
258 .context("In check_and_initialize_super_key.")?;
259 Ok(UserState::LskfUnlocked(super_key))
260 } else {
261 Ok(UserState::Uninitialized)
262 }
263 }
264 }
265
266 //helper function to populate super key cache from the super key blob loaded from the database
267 fn populate_cache_from_super_key_blob(
268 &self,
269 user_id: u32,
270 entry: KeyEntry,
271 pw: &[u8],
272 ) -> Result<SuperKey> {
273 let super_key = Self::extract_super_key_from_key_entry(entry, pw).context(
274 "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
275 )?;
276 self.install_per_boot_key_for_user(user_id, super_key.clone());
277 Ok(super_key)
278 }
279
280 /// Extracts super key from the entry loaded from the database
281 pub fn extract_super_key_from_key_entry(entry: KeyEntry, pw: &[u8]) -> Result<SuperKey> {
282 if let Some((blob, metadata)) = entry.key_blob_info() {
283 let key = match (
284 metadata.encrypted_by(),
285 metadata.salt(),
286 metadata.iv(),
287 metadata.aead_tag(),
288 ) {
289 (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
290 let key = derive_key_from_password(pw, Some(salt), AES_256_KEY_LENGTH).context(
291 "In extract_super_key_from_key_entry: Failed to generate key from password.",
292 )?;
293
294 aes_gcm_decrypt(blob, iv, tag, &key).context(
295 "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
296 )?
297 }
298 (enc_by, salt, iv, tag) => {
299 return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
300 concat!(
301 "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
302 "Present: encrypted_by: {}, salt: {}, iv: {}, aead_tag: {}."
303 ),
304 enc_by.is_some(),
305 salt.is_some(),
306 iv.is_some(),
307 tag.is_some()
308 ));
309 }
310 };
311 Ok(SuperKey { key: Arc::new(key), id: entry.id() })
312 } else {
313 Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
314 .context("In extract_super_key_from_key_entry: No key blob info.")
315 }
316 }
317
318 /// Encrypts the super key from a key derived from the password, before storing in the database.
319 pub fn encrypt_with_password(super_key: &[u8], pw: &[u8]) -> Result<(Vec<u8>, BlobMetaData)> {
320 let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
321 let derived_key = derive_key_from_password(pw, Some(&salt), AES_256_KEY_LENGTH)
322 .context("In encrypt_with_password: Failed to derive password.")?;
323 let mut metadata = BlobMetaData::new();
324 metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
325 metadata.add(BlobMetaEntry::Salt(salt));
326 let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
327 .context("In encrypt_with_password: Failed to encrypt new super key.")?;
328 metadata.add(BlobMetaEntry::Iv(iv));
329 metadata.add(BlobMetaEntry::AeadTag(tag));
330 Ok((encrypted_key, metadata))
331 }
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000332}
333
334/// This enum represents different states of the user's life cycle in the device.
335/// For now, only three states are defined. More states may be added later.
336pub enum UserState {
337 // The user has registered LSKF and has unlocked the device by entering PIN/Password,
338 // and hence the per-boot super key is available in the cache.
339 LskfUnlocked(SuperKey),
340 // The user has registered LSKF, but has not unlocked the device using password, after reboot.
341 // Hence the per-boot super-key(s) is not available in the cache.
342 // However, the encrypted super key is available in the database.
343 LskfLocked,
344 // There's no user in the device for the given user id, or the user with the user id has not
345 // setup LSKF.
346 Uninitialized,
347}
348
349impl UserState {
Hasini Gunasingheda895552021-01-27 19:34:37 +0000350 pub fn get(db: &mut KeystoreDB, skm: &SuperKeyManager, user_id: u32) -> Result<UserState> {
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000351 match skm.get_per_boot_key_by_user_id(user_id) {
352 Some(super_key) => Ok(UserState::LskfUnlocked(super_key)),
353 None => {
354 //Check if a super key exists in the database or legacy database.
355 //If so, return locked user state.
356 if SuperKeyManager::super_key_exists_in_db_for_user(db, user_id)
Hasini Gunasingheda895552021-01-27 19:34:37 +0000357 .context("In get.")?
Hasini Gunasinghe0e161452021-01-27 19:34:37 +0000358 {
359 Ok(UserState::LskfLocked)
360 } else {
361 Ok(UserState::Uninitialized)
362 }
363 }
364 }
365 }
Hasini Gunasingheda895552021-01-27 19:34:37 +0000366
367 /// Queries user state when serving password change requests.
368 pub fn get_with_password_changed(
369 db: &mut KeystoreDB,
370 skm: &SuperKeyManager,
371 user_id: u32,
372 password: Option<&[u8]>,
373 ) -> Result<UserState> {
374 match skm.get_per_boot_key_by_user_id(user_id) {
375 Some(super_key) => {
376 if password.is_none() {
377 //transitioning to swiping, delete only the super key in database and cache, and
378 //super-encrypted keys in database (and in KM)
379 Self::reset_user(db, skm, user_id, true)
380 .context("In get_with_password_changed.")?;
381 //Lskf is now removed in Keystore
382 Ok(UserState::Uninitialized)
383 } else {
384 //Keystore won't be notified when changing to a new password when LSKF is
385 //already setup. Therefore, ideally this path wouldn't be reached.
386 Ok(UserState::LskfUnlocked(super_key))
387 }
388 }
389 None => {
390 //Check if a super key exists in the database or legacy database.
391 //If so, return LskfLocked state.
392 //Otherwise, i) if the password is provided, initialize the super key and return
393 //LskfUnlocked state ii) if password is not provided, return Uninitialized state.
394 skm.check_and_initialize_super_key(db, user_id, password)
395 }
396 }
397 }
398
399 /// Delete all the keys created on behalf of the user.
400 /// If 'keep_non_super_encrypted_keys' is set to true, delete only the super key and super
401 /// encrypted keys.
402 pub fn reset_user(
403 db: &mut KeystoreDB,
404 skm: &SuperKeyManager,
405 user_id: u32,
406 keep_non_super_encrypted_keys: bool,
407 ) -> Result<()> {
408 // mark keys created on behalf of the user as unreferenced.
409 db.unbind_keys_for_user(user_id as u32, keep_non_super_encrypted_keys)
410 .context("In reset user. Error in unbinding keys.")?;
411
412 //delete super key in cache, if exists
413 skm.forget_all_keys_for_user(user_id as u32);
414 Ok(())
415 }
Janis Danisevskisb42fc182020-12-15 08:41:27 -0800416}