1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2020, The Android Open Source Project 2*e1997b9aSAndroid Build Coastguard Worker // 3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*e1997b9aSAndroid Build Coastguard Worker // 7*e1997b9aSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 8*e1997b9aSAndroid Build Coastguard Worker // 9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License. 14*e1997b9aSAndroid Build Coastguard Worker 15*e1997b9aSAndroid Build Coastguard Worker use crate::{ 16*e1997b9aSAndroid Build Coastguard Worker boot_level_keys::{get_level_zero_key, BootLevelKeyCache}, 17*e1997b9aSAndroid Build Coastguard Worker database::BlobMetaData, 18*e1997b9aSAndroid Build Coastguard Worker database::BlobMetaEntry, 19*e1997b9aSAndroid Build Coastguard Worker database::EncryptedBy, 20*e1997b9aSAndroid Build Coastguard Worker database::KeyEntry, 21*e1997b9aSAndroid Build Coastguard Worker database::KeyType, 22*e1997b9aSAndroid Build Coastguard Worker database::{KeyEntryLoadBits, KeyIdGuard, KeyMetaData, KeyMetaEntry, KeystoreDB}, 23*e1997b9aSAndroid Build Coastguard Worker ec_crypto::ECDHPrivateKey, 24*e1997b9aSAndroid Build Coastguard Worker enforcements::Enforcements, 25*e1997b9aSAndroid Build Coastguard Worker error::Error, 26*e1997b9aSAndroid Build Coastguard Worker error::ResponseCode, 27*e1997b9aSAndroid Build Coastguard Worker key_parameter::{KeyParameter, KeyParameterValue}, 28*e1997b9aSAndroid Build Coastguard Worker ks_err, 29*e1997b9aSAndroid Build Coastguard Worker legacy_importer::LegacyImporter, 30*e1997b9aSAndroid Build Coastguard Worker raw_device::KeyMintDevice, 31*e1997b9aSAndroid Build Coastguard Worker utils::{watchdog as wd, AesGcm, AID_KEYSTORE}, 32*e1997b9aSAndroid Build Coastguard Worker }; 33*e1997b9aSAndroid Build Coastguard Worker use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ 34*e1997b9aSAndroid Build Coastguard Worker Algorithm::Algorithm, BlockMode::BlockMode, HardwareAuthToken::HardwareAuthToken, 35*e1997b9aSAndroid Build Coastguard Worker HardwareAuthenticatorType::HardwareAuthenticatorType, KeyFormat::KeyFormat, 36*e1997b9aSAndroid Build Coastguard Worker KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode, 37*e1997b9aSAndroid Build Coastguard Worker SecurityLevel::SecurityLevel, 38*e1997b9aSAndroid Build Coastguard Worker }; 39*e1997b9aSAndroid Build Coastguard Worker use android_system_keystore2::aidl::android::system::keystore2::{ 40*e1997b9aSAndroid Build Coastguard Worker Domain::Domain, KeyDescriptor::KeyDescriptor, 41*e1997b9aSAndroid Build Coastguard Worker }; 42*e1997b9aSAndroid Build Coastguard Worker use anyhow::{Context, Result}; 43*e1997b9aSAndroid Build Coastguard Worker use keystore2_crypto::{ 44*e1997b9aSAndroid Build Coastguard Worker aes_gcm_decrypt, aes_gcm_encrypt, generate_aes256_key, generate_salt, Password, ZVec, 45*e1997b9aSAndroid Build Coastguard Worker AES_256_KEY_LENGTH, 46*e1997b9aSAndroid Build Coastguard Worker }; 47*e1997b9aSAndroid Build Coastguard Worker use rustutils::system_properties::PropertyWatcher; 48*e1997b9aSAndroid Build Coastguard Worker use std::{ 49*e1997b9aSAndroid Build Coastguard Worker collections::HashMap, 50*e1997b9aSAndroid Build Coastguard Worker sync::Arc, 51*e1997b9aSAndroid Build Coastguard Worker sync::{Mutex, RwLock, Weak}, 52*e1997b9aSAndroid Build Coastguard Worker }; 53*e1997b9aSAndroid Build Coastguard Worker use std::{convert::TryFrom, ops::Deref}; 54*e1997b9aSAndroid Build Coastguard Worker 55*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)] 56*e1997b9aSAndroid Build Coastguard Worker mod tests; 57*e1997b9aSAndroid Build Coastguard Worker 58*e1997b9aSAndroid Build Coastguard Worker const MAX_MAX_BOOT_LEVEL: usize = 1_000_000_000; 59*e1997b9aSAndroid Build Coastguard Worker /// Allow up to 15 seconds between the user unlocking using a biometric, and the auth 60*e1997b9aSAndroid Build Coastguard Worker /// token being used to unlock in [`SuperKeyManager::try_unlock_user_with_biometric`]. 61*e1997b9aSAndroid Build Coastguard Worker /// This seems short enough for security purposes, while long enough that even the 62*e1997b9aSAndroid Build Coastguard Worker /// very slowest device will present the auth token in time. 63*e1997b9aSAndroid Build Coastguard Worker const BIOMETRIC_AUTH_TIMEOUT_S: i32 = 15; // seconds 64*e1997b9aSAndroid Build Coastguard Worker 65*e1997b9aSAndroid Build Coastguard Worker type UserId = u32; 66*e1997b9aSAndroid Build Coastguard Worker 67*e1997b9aSAndroid Build Coastguard Worker /// Encryption algorithm used by a particular type of superencryption key 68*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)] 69*e1997b9aSAndroid Build Coastguard Worker pub enum SuperEncryptionAlgorithm { 70*e1997b9aSAndroid Build Coastguard Worker /// Symmetric encryption with AES-256-GCM 71*e1997b9aSAndroid Build Coastguard Worker Aes256Gcm, 72*e1997b9aSAndroid Build Coastguard Worker /// Public-key encryption with ECDH P-521 73*e1997b9aSAndroid Build Coastguard Worker EcdhP521, 74*e1997b9aSAndroid Build Coastguard Worker } 75*e1997b9aSAndroid Build Coastguard Worker 76*e1997b9aSAndroid Build Coastguard Worker /// A particular user may have several superencryption keys in the database, each for a 77*e1997b9aSAndroid Build Coastguard Worker /// different purpose, distinguished by alias. Each is associated with a static 78*e1997b9aSAndroid Build Coastguard Worker /// constant of this type. 79*e1997b9aSAndroid Build Coastguard Worker pub struct SuperKeyType<'a> { 80*e1997b9aSAndroid Build Coastguard Worker /// Alias used to look up the key in the `persistent.keyentry` table. 81*e1997b9aSAndroid Build Coastguard Worker pub alias: &'a str, 82*e1997b9aSAndroid Build Coastguard Worker /// Encryption algorithm 83*e1997b9aSAndroid Build Coastguard Worker pub algorithm: SuperEncryptionAlgorithm, 84*e1997b9aSAndroid Build Coastguard Worker /// What to call this key in log messages. Not used for anything else. 85*e1997b9aSAndroid Build Coastguard Worker pub name: &'a str, 86*e1997b9aSAndroid Build Coastguard Worker } 87*e1997b9aSAndroid Build Coastguard Worker 88*e1997b9aSAndroid Build Coastguard Worker /// The user's AfterFirstUnlock super key. This super key is loaded into memory when the user first 89*e1997b9aSAndroid Build Coastguard Worker /// unlocks the device, and it remains in memory until the device reboots. This is used to encrypt 90*e1997b9aSAndroid Build Coastguard Worker /// keys that require user authentication but not an unlocked device. 91*e1997b9aSAndroid Build Coastguard Worker pub const USER_AFTER_FIRST_UNLOCK_SUPER_KEY: SuperKeyType = SuperKeyType { 92*e1997b9aSAndroid Build Coastguard Worker alias: "USER_SUPER_KEY", 93*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm::Aes256Gcm, 94*e1997b9aSAndroid Build Coastguard Worker name: "AfterFirstUnlock super key", 95*e1997b9aSAndroid Build Coastguard Worker }; 96*e1997b9aSAndroid Build Coastguard Worker 97*e1997b9aSAndroid Build Coastguard Worker /// The user's UnlockedDeviceRequired symmetric super key. This super key is loaded into memory each 98*e1997b9aSAndroid Build Coastguard Worker /// time the user unlocks the device, and it is cleared from memory each time the user locks the 99*e1997b9aSAndroid Build Coastguard Worker /// device. This is used to encrypt keys that use the UnlockedDeviceRequired key parameter. 100*e1997b9aSAndroid Build Coastguard Worker pub const USER_UNLOCKED_DEVICE_REQUIRED_SYMMETRIC_SUPER_KEY: SuperKeyType = SuperKeyType { 101*e1997b9aSAndroid Build Coastguard Worker alias: "USER_SCREEN_LOCK_BOUND_KEY", 102*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm::Aes256Gcm, 103*e1997b9aSAndroid Build Coastguard Worker name: "UnlockedDeviceRequired symmetric super key", 104*e1997b9aSAndroid Build Coastguard Worker }; 105*e1997b9aSAndroid Build Coastguard Worker 106*e1997b9aSAndroid Build Coastguard Worker /// The user's UnlockedDeviceRequired asymmetric super key. This is used to allow, while the device 107*e1997b9aSAndroid Build Coastguard Worker /// is locked, the creation of keys that use the UnlockedDeviceRequired key parameter. The private 108*e1997b9aSAndroid Build Coastguard Worker /// part of this key is loaded and cleared when the symmetric key is loaded and cleared. 109*e1997b9aSAndroid Build Coastguard Worker pub const USER_UNLOCKED_DEVICE_REQUIRED_P521_SUPER_KEY: SuperKeyType = SuperKeyType { 110*e1997b9aSAndroid Build Coastguard Worker alias: "USER_SCREEN_LOCK_BOUND_P521_KEY", 111*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm::EcdhP521, 112*e1997b9aSAndroid Build Coastguard Worker name: "UnlockedDeviceRequired asymmetric super key", 113*e1997b9aSAndroid Build Coastguard Worker }; 114*e1997b9aSAndroid Build Coastguard Worker 115*e1997b9aSAndroid Build Coastguard Worker /// Superencryption to apply to a new key. 116*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy)] 117*e1997b9aSAndroid Build Coastguard Worker pub enum SuperEncryptionType { 118*e1997b9aSAndroid Build Coastguard Worker /// Do not superencrypt this key. 119*e1997b9aSAndroid Build Coastguard Worker None, 120*e1997b9aSAndroid Build Coastguard Worker /// Superencrypt with the AfterFirstUnlock super key. 121*e1997b9aSAndroid Build Coastguard Worker AfterFirstUnlock, 122*e1997b9aSAndroid Build Coastguard Worker /// Superencrypt with an UnlockedDeviceRequired super key. 123*e1997b9aSAndroid Build Coastguard Worker UnlockedDeviceRequired, 124*e1997b9aSAndroid Build Coastguard Worker /// Superencrypt with a key based on the desired boot level 125*e1997b9aSAndroid Build Coastguard Worker BootLevel(i32), 126*e1997b9aSAndroid Build Coastguard Worker } 127*e1997b9aSAndroid Build Coastguard Worker 128*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy)] 129*e1997b9aSAndroid Build Coastguard Worker pub enum SuperKeyIdentifier { 130*e1997b9aSAndroid Build Coastguard Worker /// id of the super key in the database. 131*e1997b9aSAndroid Build Coastguard Worker DatabaseId(i64), 132*e1997b9aSAndroid Build Coastguard Worker /// Boot level of the encrypting boot level key 133*e1997b9aSAndroid Build Coastguard Worker BootLevel(i32), 134*e1997b9aSAndroid Build Coastguard Worker } 135*e1997b9aSAndroid Build Coastguard Worker 136*e1997b9aSAndroid Build Coastguard Worker impl SuperKeyIdentifier { from_metadata(metadata: &BlobMetaData) -> Option<Self>137*e1997b9aSAndroid Build Coastguard Worker fn from_metadata(metadata: &BlobMetaData) -> Option<Self> { 138*e1997b9aSAndroid Build Coastguard Worker if let Some(EncryptedBy::KeyId(key_id)) = metadata.encrypted_by() { 139*e1997b9aSAndroid Build Coastguard Worker Some(SuperKeyIdentifier::DatabaseId(*key_id)) 140*e1997b9aSAndroid Build Coastguard Worker } else { 141*e1997b9aSAndroid Build Coastguard Worker metadata.max_boot_level().map(|boot_level| SuperKeyIdentifier::BootLevel(*boot_level)) 142*e1997b9aSAndroid Build Coastguard Worker } 143*e1997b9aSAndroid Build Coastguard Worker } 144*e1997b9aSAndroid Build Coastguard Worker add_to_metadata(&self, metadata: &mut BlobMetaData)145*e1997b9aSAndroid Build Coastguard Worker fn add_to_metadata(&self, metadata: &mut BlobMetaData) { 146*e1997b9aSAndroid Build Coastguard Worker match self { 147*e1997b9aSAndroid Build Coastguard Worker SuperKeyIdentifier::DatabaseId(id) => { 148*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(*id))); 149*e1997b9aSAndroid Build Coastguard Worker } 150*e1997b9aSAndroid Build Coastguard Worker SuperKeyIdentifier::BootLevel(level) => { 151*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::MaxBootLevel(*level)); 152*e1997b9aSAndroid Build Coastguard Worker } 153*e1997b9aSAndroid Build Coastguard Worker } 154*e1997b9aSAndroid Build Coastguard Worker } 155*e1997b9aSAndroid Build Coastguard Worker } 156*e1997b9aSAndroid Build Coastguard Worker 157*e1997b9aSAndroid Build Coastguard Worker pub struct SuperKey { 158*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm, 159*e1997b9aSAndroid Build Coastguard Worker key: ZVec, 160*e1997b9aSAndroid Build Coastguard Worker /// Identifier of the encrypting key, used to write an encrypted blob 161*e1997b9aSAndroid Build Coastguard Worker /// back to the database after re-encryption eg on a key update. 162*e1997b9aSAndroid Build Coastguard Worker id: SuperKeyIdentifier, 163*e1997b9aSAndroid Build Coastguard Worker /// ECDH is more expensive than AES. So on ECDH private keys we set the 164*e1997b9aSAndroid Build Coastguard Worker /// reencrypt_with field to point at the corresponding AES key, and the 165*e1997b9aSAndroid Build Coastguard Worker /// keys will be re-encrypted with AES on first use. 166*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: Option<Arc<SuperKey>>, 167*e1997b9aSAndroid Build Coastguard Worker } 168*e1997b9aSAndroid Build Coastguard Worker 169*e1997b9aSAndroid Build Coastguard Worker impl AesGcm for SuperKey { decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec>170*e1997b9aSAndroid Build Coastguard Worker fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> { 171*e1997b9aSAndroid Build Coastguard Worker if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm { 172*e1997b9aSAndroid Build Coastguard Worker aes_gcm_decrypt(data, iv, tag, &self.key).context(ks_err!("Decryption failed.")) 173*e1997b9aSAndroid Build Coastguard Worker } else { 174*e1997b9aSAndroid Build Coastguard Worker Err(Error::sys()).context(ks_err!("Key is not an AES key.")) 175*e1997b9aSAndroid Build Coastguard Worker } 176*e1997b9aSAndroid Build Coastguard Worker } 177*e1997b9aSAndroid Build Coastguard Worker encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)>178*e1997b9aSAndroid Build Coastguard Worker fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> { 179*e1997b9aSAndroid Build Coastguard Worker if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm { 180*e1997b9aSAndroid Build Coastguard Worker aes_gcm_encrypt(plaintext, &self.key).context(ks_err!("Encryption failed.")) 181*e1997b9aSAndroid Build Coastguard Worker } else { 182*e1997b9aSAndroid Build Coastguard Worker Err(Error::sys()).context(ks_err!("Key is not an AES key.")) 183*e1997b9aSAndroid Build Coastguard Worker } 184*e1997b9aSAndroid Build Coastguard Worker } 185*e1997b9aSAndroid Build Coastguard Worker } 186*e1997b9aSAndroid Build Coastguard Worker 187*e1997b9aSAndroid Build Coastguard Worker /// A SuperKey that has been encrypted with an AES-GCM key. For 188*e1997b9aSAndroid Build Coastguard Worker /// encryption the key is in memory, and for decryption it is in KM. 189*e1997b9aSAndroid Build Coastguard Worker struct LockedKey { 190*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm, 191*e1997b9aSAndroid Build Coastguard Worker id: SuperKeyIdentifier, 192*e1997b9aSAndroid Build Coastguard Worker nonce: Vec<u8>, 193*e1997b9aSAndroid Build Coastguard Worker ciphertext: Vec<u8>, // with tag appended 194*e1997b9aSAndroid Build Coastguard Worker } 195*e1997b9aSAndroid Build Coastguard Worker 196*e1997b9aSAndroid Build Coastguard Worker impl LockedKey { new(key: &[u8], to_encrypt: &Arc<SuperKey>) -> Result<Self>197*e1997b9aSAndroid Build Coastguard Worker fn new(key: &[u8], to_encrypt: &Arc<SuperKey>) -> Result<Self> { 198*e1997b9aSAndroid Build Coastguard Worker let (mut ciphertext, nonce, mut tag) = aes_gcm_encrypt(&to_encrypt.key, key)?; 199*e1997b9aSAndroid Build Coastguard Worker ciphertext.append(&mut tag); 200*e1997b9aSAndroid Build Coastguard Worker Ok(LockedKey { algorithm: to_encrypt.algorithm, id: to_encrypt.id, nonce, ciphertext }) 201*e1997b9aSAndroid Build Coastguard Worker } 202*e1997b9aSAndroid Build Coastguard Worker decrypt( &self, db: &mut KeystoreDB, km_dev: &KeyMintDevice, key_id_guard: &KeyIdGuard, key_entry: &KeyEntry, auth_token: &HardwareAuthToken, reencrypt_with: Option<Arc<SuperKey>>, ) -> Result<Arc<SuperKey>>203*e1997b9aSAndroid Build Coastguard Worker fn decrypt( 204*e1997b9aSAndroid Build Coastguard Worker &self, 205*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 206*e1997b9aSAndroid Build Coastguard Worker km_dev: &KeyMintDevice, 207*e1997b9aSAndroid Build Coastguard Worker key_id_guard: &KeyIdGuard, 208*e1997b9aSAndroid Build Coastguard Worker key_entry: &KeyEntry, 209*e1997b9aSAndroid Build Coastguard Worker auth_token: &HardwareAuthToken, 210*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: Option<Arc<SuperKey>>, 211*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Arc<SuperKey>> { 212*e1997b9aSAndroid Build Coastguard Worker let key_blob = key_entry 213*e1997b9aSAndroid Build Coastguard Worker .key_blob_info() 214*e1997b9aSAndroid Build Coastguard Worker .as_ref() 215*e1997b9aSAndroid Build Coastguard Worker .map(|(key_blob, _)| KeyBlob::Ref(key_blob)) 216*e1997b9aSAndroid Build Coastguard Worker .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND)) 217*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Missing key blob info."))?; 218*e1997b9aSAndroid Build Coastguard Worker let key_params = vec![ 219*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::Algorithm(Algorithm::AES), 220*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::KeySize(256), 221*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::BlockMode(BlockMode::GCM), 222*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::PaddingMode(PaddingMode::NONE), 223*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::Nonce(self.nonce.clone()), 224*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::MacLength(128), 225*e1997b9aSAndroid Build Coastguard Worker ]; 226*e1997b9aSAndroid Build Coastguard Worker let key_params: Vec<KmKeyParameter> = key_params.into_iter().map(|x| x.into()).collect(); 227*e1997b9aSAndroid Build Coastguard Worker let key = ZVec::try_from(km_dev.use_key_in_one_step( 228*e1997b9aSAndroid Build Coastguard Worker db, 229*e1997b9aSAndroid Build Coastguard Worker key_id_guard, 230*e1997b9aSAndroid Build Coastguard Worker &key_blob, 231*e1997b9aSAndroid Build Coastguard Worker KeyPurpose::DECRYPT, 232*e1997b9aSAndroid Build Coastguard Worker &key_params, 233*e1997b9aSAndroid Build Coastguard Worker Some(auth_token), 234*e1997b9aSAndroid Build Coastguard Worker &self.ciphertext, 235*e1997b9aSAndroid Build Coastguard Worker )?)?; 236*e1997b9aSAndroid Build Coastguard Worker Ok(Arc::new(SuperKey { algorithm: self.algorithm, key, id: self.id, reencrypt_with })) 237*e1997b9aSAndroid Build Coastguard Worker } 238*e1997b9aSAndroid Build Coastguard Worker } 239*e1997b9aSAndroid Build Coastguard Worker 240*e1997b9aSAndroid Build Coastguard Worker /// A user's UnlockedDeviceRequired super keys, encrypted with a biometric-bound key, and 241*e1997b9aSAndroid Build Coastguard Worker /// information about that biometric-bound key. 242*e1997b9aSAndroid Build Coastguard Worker struct BiometricUnlock { 243*e1997b9aSAndroid Build Coastguard Worker /// List of auth token SIDs that are accepted by the encrypting biometric-bound key. 244*e1997b9aSAndroid Build Coastguard Worker sids: Vec<i64>, 245*e1997b9aSAndroid Build Coastguard Worker /// Key descriptor of the encrypting biometric-bound key. 246*e1997b9aSAndroid Build Coastguard Worker key_desc: KeyDescriptor, 247*e1997b9aSAndroid Build Coastguard Worker /// The UnlockedDeviceRequired super keys, encrypted with a biometric-bound key. 248*e1997b9aSAndroid Build Coastguard Worker symmetric: LockedKey, 249*e1997b9aSAndroid Build Coastguard Worker private: LockedKey, 250*e1997b9aSAndroid Build Coastguard Worker } 251*e1997b9aSAndroid Build Coastguard Worker 252*e1997b9aSAndroid Build Coastguard Worker #[derive(Default)] 253*e1997b9aSAndroid Build Coastguard Worker struct UserSuperKeys { 254*e1997b9aSAndroid Build Coastguard Worker /// The AfterFirstUnlock super key is used for synthetic password binding of authentication 255*e1997b9aSAndroid Build Coastguard Worker /// bound keys. There is one key per android user. The key is stored on flash encrypted with a 256*e1997b9aSAndroid Build Coastguard Worker /// key derived from a secret, that is itself derived from the user's synthetic password. (In 257*e1997b9aSAndroid Build Coastguard Worker /// most cases, the user's synthetic password can, in turn, only be decrypted using the user's 258*e1997b9aSAndroid Build Coastguard Worker /// Lock Screen Knowledge Factor or LSKF.) When the user unlocks the device for the first time, 259*e1997b9aSAndroid Build Coastguard Worker /// this key is unlocked, i.e., decrypted, and stays memory resident until the device reboots. 260*e1997b9aSAndroid Build Coastguard Worker after_first_unlock: Option<Arc<SuperKey>>, 261*e1997b9aSAndroid Build Coastguard Worker /// The UnlockedDeviceRequired symmetric super key works like the AfterFirstUnlock super key 262*e1997b9aSAndroid Build Coastguard Worker /// with the distinction that it is cleared from memory when the device is locked. 263*e1997b9aSAndroid Build Coastguard Worker unlocked_device_required_symmetric: Option<Arc<SuperKey>>, 264*e1997b9aSAndroid Build Coastguard Worker /// When the device is locked, keys that use the UnlockedDeviceRequired key parameter can still 265*e1997b9aSAndroid Build Coastguard Worker /// be created, using ECDH public-key encryption. This field holds the decryption private key. 266*e1997b9aSAndroid Build Coastguard Worker unlocked_device_required_private: Option<Arc<SuperKey>>, 267*e1997b9aSAndroid Build Coastguard Worker /// Versions of the above two keys, locked behind a biometric. 268*e1997b9aSAndroid Build Coastguard Worker biometric_unlock: Option<BiometricUnlock>, 269*e1997b9aSAndroid Build Coastguard Worker } 270*e1997b9aSAndroid Build Coastguard Worker 271*e1997b9aSAndroid Build Coastguard Worker #[derive(Default)] 272*e1997b9aSAndroid Build Coastguard Worker struct SkmState { 273*e1997b9aSAndroid Build Coastguard Worker user_keys: HashMap<UserId, UserSuperKeys>, 274*e1997b9aSAndroid Build Coastguard Worker key_index: HashMap<i64, Weak<SuperKey>>, 275*e1997b9aSAndroid Build Coastguard Worker boot_level_key_cache: Option<Mutex<BootLevelKeyCache>>, 276*e1997b9aSAndroid Build Coastguard Worker } 277*e1997b9aSAndroid Build Coastguard Worker 278*e1997b9aSAndroid Build Coastguard Worker impl SkmState { add_key_to_key_index(&mut self, super_key: &Arc<SuperKey>) -> Result<()>279*e1997b9aSAndroid Build Coastguard Worker fn add_key_to_key_index(&mut self, super_key: &Arc<SuperKey>) -> Result<()> { 280*e1997b9aSAndroid Build Coastguard Worker if let SuperKeyIdentifier::DatabaseId(id) = super_key.id { 281*e1997b9aSAndroid Build Coastguard Worker self.key_index.insert(id, Arc::downgrade(super_key)); 282*e1997b9aSAndroid Build Coastguard Worker Ok(()) 283*e1997b9aSAndroid Build Coastguard Worker } else { 284*e1997b9aSAndroid Build Coastguard Worker Err(Error::sys()).context(ks_err!("Cannot add key with ID {:?}", super_key.id)) 285*e1997b9aSAndroid Build Coastguard Worker } 286*e1997b9aSAndroid Build Coastguard Worker } 287*e1997b9aSAndroid Build Coastguard Worker } 288*e1997b9aSAndroid Build Coastguard Worker 289*e1997b9aSAndroid Build Coastguard Worker #[derive(Default)] 290*e1997b9aSAndroid Build Coastguard Worker pub struct SuperKeyManager { 291*e1997b9aSAndroid Build Coastguard Worker data: SkmState, 292*e1997b9aSAndroid Build Coastguard Worker } 293*e1997b9aSAndroid Build Coastguard Worker 294*e1997b9aSAndroid Build Coastguard Worker impl SuperKeyManager { set_up_boot_level_cache(skm: &Arc<RwLock<Self>>, db: &mut KeystoreDB) -> Result<()>295*e1997b9aSAndroid Build Coastguard Worker pub fn set_up_boot_level_cache(skm: &Arc<RwLock<Self>>, db: &mut KeystoreDB) -> Result<()> { 296*e1997b9aSAndroid Build Coastguard Worker let mut skm_guard = skm.write().unwrap(); 297*e1997b9aSAndroid Build Coastguard Worker if skm_guard.data.boot_level_key_cache.is_some() { 298*e1997b9aSAndroid Build Coastguard Worker log::info!("In set_up_boot_level_cache: called for a second time"); 299*e1997b9aSAndroid Build Coastguard Worker return Ok(()); 300*e1997b9aSAndroid Build Coastguard Worker } 301*e1997b9aSAndroid Build Coastguard Worker let level_zero_key = 302*e1997b9aSAndroid Build Coastguard Worker get_level_zero_key(db).context(ks_err!("get_level_zero_key failed"))?; 303*e1997b9aSAndroid Build Coastguard Worker skm_guard.data.boot_level_key_cache = 304*e1997b9aSAndroid Build Coastguard Worker Some(Mutex::new(BootLevelKeyCache::new(level_zero_key))); 305*e1997b9aSAndroid Build Coastguard Worker log::info!("Starting boot level watcher."); 306*e1997b9aSAndroid Build Coastguard Worker let clone = skm.clone(); 307*e1997b9aSAndroid Build Coastguard Worker std::thread::spawn(move || { 308*e1997b9aSAndroid Build Coastguard Worker Self::watch_boot_level(clone) 309*e1997b9aSAndroid Build Coastguard Worker .unwrap_or_else(|e| log::error!("watch_boot_level failed:\n{:?}", e)); 310*e1997b9aSAndroid Build Coastguard Worker }); 311*e1997b9aSAndroid Build Coastguard Worker Ok(()) 312*e1997b9aSAndroid Build Coastguard Worker } 313*e1997b9aSAndroid Build Coastguard Worker 314*e1997b9aSAndroid Build Coastguard Worker /// Watch the `keystore.boot_level` system property, and keep boot level up to date. 315*e1997b9aSAndroid Build Coastguard Worker /// Blocks waiting for system property changes, so must be run in its own thread. watch_boot_level(skm: Arc<RwLock<Self>>) -> Result<()>316*e1997b9aSAndroid Build Coastguard Worker fn watch_boot_level(skm: Arc<RwLock<Self>>) -> Result<()> { 317*e1997b9aSAndroid Build Coastguard Worker let mut w = PropertyWatcher::new("keystore.boot_level") 318*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("PropertyWatcher::new failed"))?; 319*e1997b9aSAndroid Build Coastguard Worker loop { 320*e1997b9aSAndroid Build Coastguard Worker let level = w 321*e1997b9aSAndroid Build Coastguard Worker .read(|_n, v| v.parse::<usize>().map_err(std::convert::Into::into)) 322*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("read of property failed"))?; 323*e1997b9aSAndroid Build Coastguard Worker 324*e1997b9aSAndroid Build Coastguard Worker // This scope limits the skm_guard life, so we don't hold the skm_guard while 325*e1997b9aSAndroid Build Coastguard Worker // waiting. 326*e1997b9aSAndroid Build Coastguard Worker { 327*e1997b9aSAndroid Build Coastguard Worker let mut skm_guard = skm.write().unwrap(); 328*e1997b9aSAndroid Build Coastguard Worker let boot_level_key_cache = skm_guard 329*e1997b9aSAndroid Build Coastguard Worker .data 330*e1997b9aSAndroid Build Coastguard Worker .boot_level_key_cache 331*e1997b9aSAndroid Build Coastguard Worker .as_mut() 332*e1997b9aSAndroid Build Coastguard Worker .ok_or_else(Error::sys) 333*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Boot level cache not initialized"))? 334*e1997b9aSAndroid Build Coastguard Worker .get_mut() 335*e1997b9aSAndroid Build Coastguard Worker .unwrap(); 336*e1997b9aSAndroid Build Coastguard Worker if level < MAX_MAX_BOOT_LEVEL { 337*e1997b9aSAndroid Build Coastguard Worker log::info!("Read keystore.boot_level value {}", level); 338*e1997b9aSAndroid Build Coastguard Worker boot_level_key_cache 339*e1997b9aSAndroid Build Coastguard Worker .advance_boot_level(level) 340*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("advance_boot_level failed"))?; 341*e1997b9aSAndroid Build Coastguard Worker } else { 342*e1997b9aSAndroid Build Coastguard Worker log::info!( 343*e1997b9aSAndroid Build Coastguard Worker "keystore.boot_level {} hits maximum {}, finishing.", 344*e1997b9aSAndroid Build Coastguard Worker level, 345*e1997b9aSAndroid Build Coastguard Worker MAX_MAX_BOOT_LEVEL 346*e1997b9aSAndroid Build Coastguard Worker ); 347*e1997b9aSAndroid Build Coastguard Worker boot_level_key_cache.finish(); 348*e1997b9aSAndroid Build Coastguard Worker break; 349*e1997b9aSAndroid Build Coastguard Worker } 350*e1997b9aSAndroid Build Coastguard Worker } 351*e1997b9aSAndroid Build Coastguard Worker w.wait(None).context(ks_err!("property wait failed"))?; 352*e1997b9aSAndroid Build Coastguard Worker } 353*e1997b9aSAndroid Build Coastguard Worker Ok(()) 354*e1997b9aSAndroid Build Coastguard Worker } 355*e1997b9aSAndroid Build Coastguard Worker level_accessible(&self, boot_level: i32) -> bool356*e1997b9aSAndroid Build Coastguard Worker pub fn level_accessible(&self, boot_level: i32) -> bool { 357*e1997b9aSAndroid Build Coastguard Worker self.data 358*e1997b9aSAndroid Build Coastguard Worker .boot_level_key_cache 359*e1997b9aSAndroid Build Coastguard Worker .as_ref() 360*e1997b9aSAndroid Build Coastguard Worker .map_or(false, |c| c.lock().unwrap().level_accessible(boot_level as usize)) 361*e1997b9aSAndroid Build Coastguard Worker } 362*e1997b9aSAndroid Build Coastguard Worker forget_all_keys_for_user(&mut self, user: UserId)363*e1997b9aSAndroid Build Coastguard Worker pub fn forget_all_keys_for_user(&mut self, user: UserId) { 364*e1997b9aSAndroid Build Coastguard Worker self.data.user_keys.remove(&user); 365*e1997b9aSAndroid Build Coastguard Worker } 366*e1997b9aSAndroid Build Coastguard Worker install_after_first_unlock_key_for_user( &mut self, user: UserId, super_key: Arc<SuperKey>, ) -> Result<()>367*e1997b9aSAndroid Build Coastguard Worker fn install_after_first_unlock_key_for_user( 368*e1997b9aSAndroid Build Coastguard Worker &mut self, 369*e1997b9aSAndroid Build Coastguard Worker user: UserId, 370*e1997b9aSAndroid Build Coastguard Worker super_key: Arc<SuperKey>, 371*e1997b9aSAndroid Build Coastguard Worker ) -> Result<()> { 372*e1997b9aSAndroid Build Coastguard Worker self.data 373*e1997b9aSAndroid Build Coastguard Worker .add_key_to_key_index(&super_key) 374*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("add_key_to_key_index failed"))?; 375*e1997b9aSAndroid Build Coastguard Worker self.data.user_keys.entry(user).or_default().after_first_unlock = Some(super_key); 376*e1997b9aSAndroid Build Coastguard Worker Ok(()) 377*e1997b9aSAndroid Build Coastguard Worker } 378*e1997b9aSAndroid Build Coastguard Worker lookup_key(&self, key_id: &SuperKeyIdentifier) -> Result<Option<Arc<SuperKey>>>379*e1997b9aSAndroid Build Coastguard Worker fn lookup_key(&self, key_id: &SuperKeyIdentifier) -> Result<Option<Arc<SuperKey>>> { 380*e1997b9aSAndroid Build Coastguard Worker Ok(match key_id { 381*e1997b9aSAndroid Build Coastguard Worker SuperKeyIdentifier::DatabaseId(id) => { 382*e1997b9aSAndroid Build Coastguard Worker self.data.key_index.get(id).and_then(|k| k.upgrade()) 383*e1997b9aSAndroid Build Coastguard Worker } 384*e1997b9aSAndroid Build Coastguard Worker SuperKeyIdentifier::BootLevel(level) => self 385*e1997b9aSAndroid Build Coastguard Worker .data 386*e1997b9aSAndroid Build Coastguard Worker .boot_level_key_cache 387*e1997b9aSAndroid Build Coastguard Worker .as_ref() 388*e1997b9aSAndroid Build Coastguard Worker .map(|b| b.lock().unwrap().aes_key(*level as usize)) 389*e1997b9aSAndroid Build Coastguard Worker .transpose() 390*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("aes_key failed"))? 391*e1997b9aSAndroid Build Coastguard Worker .flatten() 392*e1997b9aSAndroid Build Coastguard Worker .map(|key| { 393*e1997b9aSAndroid Build Coastguard Worker Arc::new(SuperKey { 394*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm::Aes256Gcm, 395*e1997b9aSAndroid Build Coastguard Worker key, 396*e1997b9aSAndroid Build Coastguard Worker id: *key_id, 397*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: None, 398*e1997b9aSAndroid Build Coastguard Worker }) 399*e1997b9aSAndroid Build Coastguard Worker }), 400*e1997b9aSAndroid Build Coastguard Worker }) 401*e1997b9aSAndroid Build Coastguard Worker } 402*e1997b9aSAndroid Build Coastguard Worker 403*e1997b9aSAndroid Build Coastguard Worker /// Returns the AfterFirstUnlock superencryption key for the given user ID, or None if the user 404*e1997b9aSAndroid Build Coastguard Worker /// has not yet unlocked the device since boot. get_after_first_unlock_key_by_user_id( &self, user_id: UserId, ) -> Option<Arc<dyn AesGcm + Send + Sync>>405*e1997b9aSAndroid Build Coastguard Worker pub fn get_after_first_unlock_key_by_user_id( 406*e1997b9aSAndroid Build Coastguard Worker &self, 407*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 408*e1997b9aSAndroid Build Coastguard Worker ) -> Option<Arc<dyn AesGcm + Send + Sync>> { 409*e1997b9aSAndroid Build Coastguard Worker self.get_after_first_unlock_key_by_user_id_internal(user_id) 410*e1997b9aSAndroid Build Coastguard Worker .map(|sk| -> Arc<dyn AesGcm + Send + Sync> { sk }) 411*e1997b9aSAndroid Build Coastguard Worker } 412*e1997b9aSAndroid Build Coastguard Worker get_after_first_unlock_key_by_user_id_internal( &self, user_id: UserId, ) -> Option<Arc<SuperKey>>413*e1997b9aSAndroid Build Coastguard Worker fn get_after_first_unlock_key_by_user_id_internal( 414*e1997b9aSAndroid Build Coastguard Worker &self, 415*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 416*e1997b9aSAndroid Build Coastguard Worker ) -> Option<Arc<SuperKey>> { 417*e1997b9aSAndroid Build Coastguard Worker self.data.user_keys.get(&user_id).and_then(|e| e.after_first_unlock.as_ref().cloned()) 418*e1997b9aSAndroid Build Coastguard Worker } 419*e1997b9aSAndroid Build Coastguard Worker 420*e1997b9aSAndroid Build Coastguard Worker /// Check if a given key is super-encrypted, from its metadata. If so, unwrap the key using 421*e1997b9aSAndroid Build Coastguard Worker /// the relevant super key. unwrap_key_if_required<'a>( &self, metadata: &BlobMetaData, blob: &'a [u8], ) -> Result<KeyBlob<'a>>422*e1997b9aSAndroid Build Coastguard Worker pub fn unwrap_key_if_required<'a>( 423*e1997b9aSAndroid Build Coastguard Worker &self, 424*e1997b9aSAndroid Build Coastguard Worker metadata: &BlobMetaData, 425*e1997b9aSAndroid Build Coastguard Worker blob: &'a [u8], 426*e1997b9aSAndroid Build Coastguard Worker ) -> Result<KeyBlob<'a>> { 427*e1997b9aSAndroid Build Coastguard Worker Ok(if let Some(key_id) = SuperKeyIdentifier::from_metadata(metadata) { 428*e1997b9aSAndroid Build Coastguard Worker let super_key = self 429*e1997b9aSAndroid Build Coastguard Worker .lookup_key(&key_id) 430*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("lookup_key failed"))? 431*e1997b9aSAndroid Build Coastguard Worker .ok_or(Error::Rc(ResponseCode::LOCKED)) 432*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Required super decryption key is not in memory."))?; 433*e1997b9aSAndroid Build Coastguard Worker KeyBlob::Sensitive { 434*e1997b9aSAndroid Build Coastguard Worker key: Self::unwrap_key_with_key(blob, metadata, &super_key) 435*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("unwrap_key_with_key failed"))?, 436*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: super_key.reencrypt_with.as_ref().unwrap_or(&super_key).clone(), 437*e1997b9aSAndroid Build Coastguard Worker force_reencrypt: super_key.reencrypt_with.is_some(), 438*e1997b9aSAndroid Build Coastguard Worker } 439*e1997b9aSAndroid Build Coastguard Worker } else { 440*e1997b9aSAndroid Build Coastguard Worker KeyBlob::Ref(blob) 441*e1997b9aSAndroid Build Coastguard Worker }) 442*e1997b9aSAndroid Build Coastguard Worker } 443*e1997b9aSAndroid Build Coastguard Worker 444*e1997b9aSAndroid Build Coastguard Worker /// Unwraps an encrypted key blob given an encryption key. unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec>445*e1997b9aSAndroid Build Coastguard Worker fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec> { 446*e1997b9aSAndroid Build Coastguard Worker match key.algorithm { 447*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionAlgorithm::Aes256Gcm => match (metadata.iv(), metadata.aead_tag()) { 448*e1997b9aSAndroid Build Coastguard Worker (Some(iv), Some(tag)) => { 449*e1997b9aSAndroid Build Coastguard Worker key.decrypt(blob, iv, tag).context(ks_err!("Failed to decrypt the key blob.")) 450*e1997b9aSAndroid Build Coastguard Worker } 451*e1997b9aSAndroid Build Coastguard Worker (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!( 452*e1997b9aSAndroid Build Coastguard Worker "Key has incomplete metadata. Present: iv: {}, aead_tag: {}.", 453*e1997b9aSAndroid Build Coastguard Worker iv.is_some(), 454*e1997b9aSAndroid Build Coastguard Worker tag.is_some(), 455*e1997b9aSAndroid Build Coastguard Worker )), 456*e1997b9aSAndroid Build Coastguard Worker }, 457*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionAlgorithm::EcdhP521 => { 458*e1997b9aSAndroid Build Coastguard Worker match (metadata.public_key(), metadata.salt(), metadata.iv(), metadata.aead_tag()) { 459*e1997b9aSAndroid Build Coastguard Worker (Some(public_key), Some(salt), Some(iv), Some(aead_tag)) => { 460*e1997b9aSAndroid Build Coastguard Worker ECDHPrivateKey::from_private_key(&key.key) 461*e1997b9aSAndroid Build Coastguard Worker .and_then(|k| k.decrypt_message(public_key, salt, iv, blob, aead_tag)) 462*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to decrypt the key blob with ECDH.")) 463*e1997b9aSAndroid Build Coastguard Worker } 464*e1997b9aSAndroid Build Coastguard Worker (public_key, salt, iv, aead_tag) => { 465*e1997b9aSAndroid Build Coastguard Worker Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!( 466*e1997b9aSAndroid Build Coastguard Worker concat!( 467*e1997b9aSAndroid Build Coastguard Worker "Key has incomplete metadata. ", 468*e1997b9aSAndroid Build Coastguard Worker "Present: public_key: {}, salt: {}, iv: {}, aead_tag: {}." 469*e1997b9aSAndroid Build Coastguard Worker ), 470*e1997b9aSAndroid Build Coastguard Worker public_key.is_some(), 471*e1997b9aSAndroid Build Coastguard Worker salt.is_some(), 472*e1997b9aSAndroid Build Coastguard Worker iv.is_some(), 473*e1997b9aSAndroid Build Coastguard Worker aead_tag.is_some(), 474*e1997b9aSAndroid Build Coastguard Worker )) 475*e1997b9aSAndroid Build Coastguard Worker } 476*e1997b9aSAndroid Build Coastguard Worker } 477*e1997b9aSAndroid Build Coastguard Worker } 478*e1997b9aSAndroid Build Coastguard Worker } 479*e1997b9aSAndroid Build Coastguard Worker } 480*e1997b9aSAndroid Build Coastguard Worker 481*e1997b9aSAndroid Build Coastguard Worker /// Checks if the user's AfterFirstUnlock super key exists in the database (or legacy database). 482*e1997b9aSAndroid Build Coastguard Worker /// The reference to self is unused but it is required to prevent calling this function 483*e1997b9aSAndroid Build Coastguard Worker /// concurrently with skm state database changes. super_key_exists_in_db_for_user( &self, db: &mut KeystoreDB, legacy_importer: &LegacyImporter, user_id: UserId, ) -> Result<bool>484*e1997b9aSAndroid Build Coastguard Worker fn super_key_exists_in_db_for_user( 485*e1997b9aSAndroid Build Coastguard Worker &self, 486*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 487*e1997b9aSAndroid Build Coastguard Worker legacy_importer: &LegacyImporter, 488*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 489*e1997b9aSAndroid Build Coastguard Worker ) -> Result<bool> { 490*e1997b9aSAndroid Build Coastguard Worker let key_in_db = db 491*e1997b9aSAndroid Build Coastguard Worker .key_exists( 492*e1997b9aSAndroid Build Coastguard Worker Domain::APP, 493*e1997b9aSAndroid Build Coastguard Worker user_id as u64 as i64, 494*e1997b9aSAndroid Build Coastguard Worker USER_AFTER_FIRST_UNLOCK_SUPER_KEY.alias, 495*e1997b9aSAndroid Build Coastguard Worker KeyType::Super, 496*e1997b9aSAndroid Build Coastguard Worker ) 497*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!())?; 498*e1997b9aSAndroid Build Coastguard Worker 499*e1997b9aSAndroid Build Coastguard Worker if key_in_db { 500*e1997b9aSAndroid Build Coastguard Worker Ok(key_in_db) 501*e1997b9aSAndroid Build Coastguard Worker } else { 502*e1997b9aSAndroid Build Coastguard Worker legacy_importer.has_super_key(user_id).context(ks_err!("Trying to query legacy db.")) 503*e1997b9aSAndroid Build Coastguard Worker } 504*e1997b9aSAndroid Build Coastguard Worker } 505*e1997b9aSAndroid Build Coastguard Worker 506*e1997b9aSAndroid Build Coastguard Worker // Helper function to populate super key cache from the super key blob loaded from the database. populate_cache_from_super_key_blob( &mut self, user_id: UserId, algorithm: SuperEncryptionAlgorithm, entry: KeyEntry, pw: &Password, ) -> Result<Arc<SuperKey>>507*e1997b9aSAndroid Build Coastguard Worker fn populate_cache_from_super_key_blob( 508*e1997b9aSAndroid Build Coastguard Worker &mut self, 509*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 510*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm, 511*e1997b9aSAndroid Build Coastguard Worker entry: KeyEntry, 512*e1997b9aSAndroid Build Coastguard Worker pw: &Password, 513*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Arc<SuperKey>> { 514*e1997b9aSAndroid Build Coastguard Worker let super_key = Self::extract_super_key_from_key_entry(algorithm, entry, pw, None) 515*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to extract super key from key entry"))?; 516*e1997b9aSAndroid Build Coastguard Worker self.install_after_first_unlock_key_for_user(user_id, super_key.clone()) 517*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to install AfterFirstUnlock super key for user!"))?; 518*e1997b9aSAndroid Build Coastguard Worker Ok(super_key) 519*e1997b9aSAndroid Build Coastguard Worker } 520*e1997b9aSAndroid Build Coastguard Worker 521*e1997b9aSAndroid Build Coastguard Worker /// Extracts super key from the entry loaded from the database. extract_super_key_from_key_entry( algorithm: SuperEncryptionAlgorithm, entry: KeyEntry, pw: &Password, reencrypt_with: Option<Arc<SuperKey>>, ) -> Result<Arc<SuperKey>>522*e1997b9aSAndroid Build Coastguard Worker pub fn extract_super_key_from_key_entry( 523*e1997b9aSAndroid Build Coastguard Worker algorithm: SuperEncryptionAlgorithm, 524*e1997b9aSAndroid Build Coastguard Worker entry: KeyEntry, 525*e1997b9aSAndroid Build Coastguard Worker pw: &Password, 526*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: Option<Arc<SuperKey>>, 527*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Arc<SuperKey>> { 528*e1997b9aSAndroid Build Coastguard Worker if let Some((blob, metadata)) = entry.key_blob_info() { 529*e1997b9aSAndroid Build Coastguard Worker let key = match ( 530*e1997b9aSAndroid Build Coastguard Worker metadata.encrypted_by(), 531*e1997b9aSAndroid Build Coastguard Worker metadata.salt(), 532*e1997b9aSAndroid Build Coastguard Worker metadata.iv(), 533*e1997b9aSAndroid Build Coastguard Worker metadata.aead_tag(), 534*e1997b9aSAndroid Build Coastguard Worker ) { 535*e1997b9aSAndroid Build Coastguard Worker (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => { 536*e1997b9aSAndroid Build Coastguard Worker // Note that password encryption is AES no matter the value of algorithm. 537*e1997b9aSAndroid Build Coastguard Worker let key = pw 538*e1997b9aSAndroid Build Coastguard Worker .derive_key_hkdf(salt, AES_256_KEY_LENGTH) 539*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to derive key from password."))?; 540*e1997b9aSAndroid Build Coastguard Worker 541*e1997b9aSAndroid Build Coastguard Worker aes_gcm_decrypt(blob, iv, tag, &key).or_else(|_e| { 542*e1997b9aSAndroid Build Coastguard Worker // Handle old key stored before the switch to HKDF. 543*e1997b9aSAndroid Build Coastguard Worker let key = pw 544*e1997b9aSAndroid Build Coastguard Worker .derive_key_pbkdf2(salt, AES_256_KEY_LENGTH) 545*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to derive key from password (PBKDF2)."))?; 546*e1997b9aSAndroid Build Coastguard Worker aes_gcm_decrypt(blob, iv, tag, &key) 547*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to decrypt key blob.")) 548*e1997b9aSAndroid Build Coastguard Worker })? 549*e1997b9aSAndroid Build Coastguard Worker } 550*e1997b9aSAndroid Build Coastguard Worker (enc_by, salt, iv, tag) => { 551*e1997b9aSAndroid Build Coastguard Worker return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!( 552*e1997b9aSAndroid Build Coastguard Worker concat!( 553*e1997b9aSAndroid Build Coastguard Worker "Super key has incomplete metadata.", 554*e1997b9aSAndroid Build Coastguard Worker "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}." 555*e1997b9aSAndroid Build Coastguard Worker ), 556*e1997b9aSAndroid Build Coastguard Worker enc_by, 557*e1997b9aSAndroid Build Coastguard Worker salt.is_some(), 558*e1997b9aSAndroid Build Coastguard Worker iv.is_some(), 559*e1997b9aSAndroid Build Coastguard Worker tag.is_some() 560*e1997b9aSAndroid Build Coastguard Worker )); 561*e1997b9aSAndroid Build Coastguard Worker } 562*e1997b9aSAndroid Build Coastguard Worker }; 563*e1997b9aSAndroid Build Coastguard Worker Ok(Arc::new(SuperKey { 564*e1997b9aSAndroid Build Coastguard Worker algorithm, 565*e1997b9aSAndroid Build Coastguard Worker key, 566*e1997b9aSAndroid Build Coastguard Worker id: SuperKeyIdentifier::DatabaseId(entry.id()), 567*e1997b9aSAndroid Build Coastguard Worker reencrypt_with, 568*e1997b9aSAndroid Build Coastguard Worker })) 569*e1997b9aSAndroid Build Coastguard Worker } else { 570*e1997b9aSAndroid Build Coastguard Worker Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!("No key blob info.")) 571*e1997b9aSAndroid Build Coastguard Worker } 572*e1997b9aSAndroid Build Coastguard Worker } 573*e1997b9aSAndroid Build Coastguard Worker 574*e1997b9aSAndroid Build Coastguard Worker /// Encrypts the super key from a key derived from the password, before storing in the database. 575*e1997b9aSAndroid Build Coastguard Worker /// This does not stretch the password; i.e., it assumes that the password is a high-entropy 576*e1997b9aSAndroid Build Coastguard Worker /// synthetic password, not a low-entropy user provided password. encrypt_with_password( super_key: &[u8], pw: &Password, ) -> Result<(Vec<u8>, BlobMetaData)>577*e1997b9aSAndroid Build Coastguard Worker pub fn encrypt_with_password( 578*e1997b9aSAndroid Build Coastguard Worker super_key: &[u8], 579*e1997b9aSAndroid Build Coastguard Worker pw: &Password, 580*e1997b9aSAndroid Build Coastguard Worker ) -> Result<(Vec<u8>, BlobMetaData)> { 581*e1997b9aSAndroid Build Coastguard Worker let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?; 582*e1997b9aSAndroid Build Coastguard Worker let derived_key = pw 583*e1997b9aSAndroid Build Coastguard Worker .derive_key_hkdf(&salt, AES_256_KEY_LENGTH) 584*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to derive key from password."))?; 585*e1997b9aSAndroid Build Coastguard Worker let mut metadata = BlobMetaData::new(); 586*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password)); 587*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::Salt(salt)); 588*e1997b9aSAndroid Build Coastguard Worker let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key) 589*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to encrypt new super key."))?; 590*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::Iv(iv)); 591*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::AeadTag(tag)); 592*e1997b9aSAndroid Build Coastguard Worker Ok((encrypted_key, metadata)) 593*e1997b9aSAndroid Build Coastguard Worker } 594*e1997b9aSAndroid Build Coastguard Worker 595*e1997b9aSAndroid Build Coastguard Worker // Helper function to encrypt a key with the given super key. Callers should select which super 596*e1997b9aSAndroid Build Coastguard Worker // key to be used. This is called when a key is super encrypted at its creation as well as at 597*e1997b9aSAndroid Build Coastguard Worker // its upgrade. encrypt_with_aes_super_key( key_blob: &[u8], super_key: &SuperKey, ) -> Result<(Vec<u8>, BlobMetaData)>598*e1997b9aSAndroid Build Coastguard Worker fn encrypt_with_aes_super_key( 599*e1997b9aSAndroid Build Coastguard Worker key_blob: &[u8], 600*e1997b9aSAndroid Build Coastguard Worker super_key: &SuperKey, 601*e1997b9aSAndroid Build Coastguard Worker ) -> Result<(Vec<u8>, BlobMetaData)> { 602*e1997b9aSAndroid Build Coastguard Worker if super_key.algorithm != SuperEncryptionAlgorithm::Aes256Gcm { 603*e1997b9aSAndroid Build Coastguard Worker return Err(Error::sys()).context(ks_err!("unexpected algorithm")); 604*e1997b9aSAndroid Build Coastguard Worker } 605*e1997b9aSAndroid Build Coastguard Worker let mut metadata = BlobMetaData::new(); 606*e1997b9aSAndroid Build Coastguard Worker let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key)) 607*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to encrypt new super key."))?; 608*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::Iv(iv)); 609*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::AeadTag(tag)); 610*e1997b9aSAndroid Build Coastguard Worker super_key.id.add_to_metadata(&mut metadata); 611*e1997b9aSAndroid Build Coastguard Worker Ok((encrypted_key, metadata)) 612*e1997b9aSAndroid Build Coastguard Worker } 613*e1997b9aSAndroid Build Coastguard Worker 614*e1997b9aSAndroid Build Coastguard Worker // Encrypts a given key_blob using a hybrid approach, which can either use the symmetric super 615*e1997b9aSAndroid Build Coastguard Worker // key or the public super key depending on which is available. 616*e1997b9aSAndroid Build Coastguard Worker // 617*e1997b9aSAndroid Build Coastguard Worker // If the symmetric_key is available, the key_blob is encrypted using symmetric encryption with 618*e1997b9aSAndroid Build Coastguard Worker // the provided symmetric super key. Otherwise, the function loads the public super key from 619*e1997b9aSAndroid Build Coastguard Worker // the KeystoreDB and encrypts the key_blob using ECDH encryption and marks the keyblob to be 620*e1997b9aSAndroid Build Coastguard Worker // re-encrypted with the symmetric super key on the first use. 621*e1997b9aSAndroid Build Coastguard Worker // 622*e1997b9aSAndroid Build Coastguard Worker // This hybrid scheme allows keys that use the UnlockedDeviceRequired key parameter to be 623*e1997b9aSAndroid Build Coastguard Worker // created while the device is locked. encrypt_with_hybrid_super_key( key_blob: &[u8], symmetric_key: Option<&SuperKey>, public_key_type: &SuperKeyType, db: &mut KeystoreDB, user_id: UserId, ) -> Result<(Vec<u8>, BlobMetaData)>624*e1997b9aSAndroid Build Coastguard Worker fn encrypt_with_hybrid_super_key( 625*e1997b9aSAndroid Build Coastguard Worker key_blob: &[u8], 626*e1997b9aSAndroid Build Coastguard Worker symmetric_key: Option<&SuperKey>, 627*e1997b9aSAndroid Build Coastguard Worker public_key_type: &SuperKeyType, 628*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 629*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 630*e1997b9aSAndroid Build Coastguard Worker ) -> Result<(Vec<u8>, BlobMetaData)> { 631*e1997b9aSAndroid Build Coastguard Worker if let Some(super_key) = symmetric_key { 632*e1997b9aSAndroid Build Coastguard Worker Self::encrypt_with_aes_super_key(key_blob, super_key).context(ks_err!( 633*e1997b9aSAndroid Build Coastguard Worker "Failed to encrypt with UnlockedDeviceRequired symmetric super key." 634*e1997b9aSAndroid Build Coastguard Worker )) 635*e1997b9aSAndroid Build Coastguard Worker } else { 636*e1997b9aSAndroid Build Coastguard Worker // Symmetric key is not available, use public key encryption 637*e1997b9aSAndroid Build Coastguard Worker let loaded = db 638*e1997b9aSAndroid Build Coastguard Worker .load_super_key(public_key_type, user_id) 639*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("load_super_key failed."))?; 640*e1997b9aSAndroid Build Coastguard Worker let (key_id_guard, key_entry) = 641*e1997b9aSAndroid Build Coastguard Worker loaded.ok_or_else(Error::sys).context(ks_err!("User ECDH super key missing."))?; 642*e1997b9aSAndroid Build Coastguard Worker let public_key = key_entry 643*e1997b9aSAndroid Build Coastguard Worker .metadata() 644*e1997b9aSAndroid Build Coastguard Worker .sec1_public_key() 645*e1997b9aSAndroid Build Coastguard Worker .ok_or_else(Error::sys) 646*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("sec1_public_key missing."))?; 647*e1997b9aSAndroid Build Coastguard Worker let mut metadata = BlobMetaData::new(); 648*e1997b9aSAndroid Build Coastguard Worker let (ephem_key, salt, iv, encrypted_key, aead_tag) = 649*e1997b9aSAndroid Build Coastguard Worker ECDHPrivateKey::encrypt_message(public_key, key_blob) 650*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("ECDHPrivateKey::encrypt_message failed."))?; 651*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::PublicKey(ephem_key)); 652*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::Salt(salt)); 653*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::Iv(iv)); 654*e1997b9aSAndroid Build Coastguard Worker metadata.add(BlobMetaEntry::AeadTag(aead_tag)); 655*e1997b9aSAndroid Build Coastguard Worker SuperKeyIdentifier::DatabaseId(key_id_guard.id()).add_to_metadata(&mut metadata); 656*e1997b9aSAndroid Build Coastguard Worker Ok((encrypted_key, metadata)) 657*e1997b9aSAndroid Build Coastguard Worker } 658*e1997b9aSAndroid Build Coastguard Worker } 659*e1997b9aSAndroid Build Coastguard Worker 660*e1997b9aSAndroid Build Coastguard Worker /// Check if super encryption is required and if so, super-encrypt the key to be stored in 661*e1997b9aSAndroid Build Coastguard Worker /// the database. 662*e1997b9aSAndroid Build Coastguard Worker #[allow(clippy::too_many_arguments)] handle_super_encryption_on_key_init( &self, db: &mut KeystoreDB, legacy_importer: &LegacyImporter, domain: &Domain, key_parameters: &[KeyParameter], flags: Option<i32>, user_id: UserId, key_blob: &[u8], ) -> Result<(Vec<u8>, BlobMetaData)>663*e1997b9aSAndroid Build Coastguard Worker pub fn handle_super_encryption_on_key_init( 664*e1997b9aSAndroid Build Coastguard Worker &self, 665*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 666*e1997b9aSAndroid Build Coastguard Worker legacy_importer: &LegacyImporter, 667*e1997b9aSAndroid Build Coastguard Worker domain: &Domain, 668*e1997b9aSAndroid Build Coastguard Worker key_parameters: &[KeyParameter], 669*e1997b9aSAndroid Build Coastguard Worker flags: Option<i32>, 670*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 671*e1997b9aSAndroid Build Coastguard Worker key_blob: &[u8], 672*e1997b9aSAndroid Build Coastguard Worker ) -> Result<(Vec<u8>, BlobMetaData)> { 673*e1997b9aSAndroid Build Coastguard Worker match Enforcements::super_encryption_required(domain, key_parameters, flags) { 674*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())), 675*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionType::AfterFirstUnlock => { 676*e1997b9aSAndroid Build Coastguard Worker // Encrypt the given key blob with the user's AfterFirstUnlock super key. If the 677*e1997b9aSAndroid Build Coastguard Worker // user has not unlocked the device since boot or the super keys were never 678*e1997b9aSAndroid Build Coastguard Worker // initialized for the user for some reason, an error is returned. 679*e1997b9aSAndroid Build Coastguard Worker match self 680*e1997b9aSAndroid Build Coastguard Worker .get_user_state(db, legacy_importer, user_id) 681*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to get user state for user {user_id}"))? 682*e1997b9aSAndroid Build Coastguard Worker { 683*e1997b9aSAndroid Build Coastguard Worker UserState::AfterFirstUnlock(super_key) => { 684*e1997b9aSAndroid Build Coastguard Worker Self::encrypt_with_aes_super_key(key_blob, &super_key).context(ks_err!( 685*e1997b9aSAndroid Build Coastguard Worker "Failed to encrypt with AfterFirstUnlock super key for user {user_id}" 686*e1997b9aSAndroid Build Coastguard Worker )) 687*e1997b9aSAndroid Build Coastguard Worker } 688*e1997b9aSAndroid Build Coastguard Worker UserState::BeforeFirstUnlock => { 689*e1997b9aSAndroid Build Coastguard Worker Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked.")) 690*e1997b9aSAndroid Build Coastguard Worker } 691*e1997b9aSAndroid Build Coastguard Worker UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED)) 692*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("User {user_id} does not have super keys")), 693*e1997b9aSAndroid Build Coastguard Worker } 694*e1997b9aSAndroid Build Coastguard Worker } 695*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionType::UnlockedDeviceRequired => { 696*e1997b9aSAndroid Build Coastguard Worker let symmetric_key = self 697*e1997b9aSAndroid Build Coastguard Worker .data 698*e1997b9aSAndroid Build Coastguard Worker .user_keys 699*e1997b9aSAndroid Build Coastguard Worker .get(&user_id) 700*e1997b9aSAndroid Build Coastguard Worker .and_then(|e| e.unlocked_device_required_symmetric.as_ref()) 701*e1997b9aSAndroid Build Coastguard Worker .map(|arc| arc.as_ref()); 702*e1997b9aSAndroid Build Coastguard Worker Self::encrypt_with_hybrid_super_key( 703*e1997b9aSAndroid Build Coastguard Worker key_blob, 704*e1997b9aSAndroid Build Coastguard Worker symmetric_key, 705*e1997b9aSAndroid Build Coastguard Worker &USER_UNLOCKED_DEVICE_REQUIRED_P521_SUPER_KEY, 706*e1997b9aSAndroid Build Coastguard Worker db, 707*e1997b9aSAndroid Build Coastguard Worker user_id, 708*e1997b9aSAndroid Build Coastguard Worker ) 709*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to encrypt with UnlockedDeviceRequired hybrid scheme.")) 710*e1997b9aSAndroid Build Coastguard Worker } 711*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionType::BootLevel(level) => { 712*e1997b9aSAndroid Build Coastguard Worker let key_id = SuperKeyIdentifier::BootLevel(level); 713*e1997b9aSAndroid Build Coastguard Worker let super_key = self 714*e1997b9aSAndroid Build Coastguard Worker .lookup_key(&key_id) 715*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("lookup_key failed"))? 716*e1997b9aSAndroid Build Coastguard Worker .ok_or(Error::Rc(ResponseCode::LOCKED)) 717*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Boot stage key absent"))?; 718*e1997b9aSAndroid Build Coastguard Worker Self::encrypt_with_aes_super_key(key_blob, &super_key) 719*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to encrypt with BootLevel key.")) 720*e1997b9aSAndroid Build Coastguard Worker } 721*e1997b9aSAndroid Build Coastguard Worker } 722*e1997b9aSAndroid Build Coastguard Worker } 723*e1997b9aSAndroid Build Coastguard Worker 724*e1997b9aSAndroid Build Coastguard Worker /// Check if a given key needs re-super-encryption, from its KeyBlob type. 725*e1997b9aSAndroid Build Coastguard Worker /// If so, re-super-encrypt the key and return a new set of metadata, 726*e1997b9aSAndroid Build Coastguard Worker /// containing the new super encryption information. reencrypt_if_required<'a>( key_blob_before_upgrade: &KeyBlob, key_after_upgrade: &'a [u8], ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)>727*e1997b9aSAndroid Build Coastguard Worker pub fn reencrypt_if_required<'a>( 728*e1997b9aSAndroid Build Coastguard Worker key_blob_before_upgrade: &KeyBlob, 729*e1997b9aSAndroid Build Coastguard Worker key_after_upgrade: &'a [u8], 730*e1997b9aSAndroid Build Coastguard Worker ) -> Result<(KeyBlob<'a>, Option<BlobMetaData>)> { 731*e1997b9aSAndroid Build Coastguard Worker match key_blob_before_upgrade { 732*e1997b9aSAndroid Build Coastguard Worker KeyBlob::Sensitive { reencrypt_with: super_key, .. } => { 733*e1997b9aSAndroid Build Coastguard Worker let (key, metadata) = 734*e1997b9aSAndroid Build Coastguard Worker Self::encrypt_with_aes_super_key(key_after_upgrade, super_key) 735*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to re-super-encrypt key."))?; 736*e1997b9aSAndroid Build Coastguard Worker Ok((KeyBlob::NonSensitive(key), Some(metadata))) 737*e1997b9aSAndroid Build Coastguard Worker } 738*e1997b9aSAndroid Build Coastguard Worker _ => Ok((KeyBlob::Ref(key_after_upgrade), None)), 739*e1997b9aSAndroid Build Coastguard Worker } 740*e1997b9aSAndroid Build Coastguard Worker } 741*e1997b9aSAndroid Build Coastguard Worker create_super_key( &mut self, db: &mut KeystoreDB, user_id: UserId, key_type: &SuperKeyType, password: &Password, reencrypt_with: Option<Arc<SuperKey>>, ) -> Result<Arc<SuperKey>>742*e1997b9aSAndroid Build Coastguard Worker fn create_super_key( 743*e1997b9aSAndroid Build Coastguard Worker &mut self, 744*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 745*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 746*e1997b9aSAndroid Build Coastguard Worker key_type: &SuperKeyType, 747*e1997b9aSAndroid Build Coastguard Worker password: &Password, 748*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: Option<Arc<SuperKey>>, 749*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Arc<SuperKey>> { 750*e1997b9aSAndroid Build Coastguard Worker log::info!("Creating {} for user {}", key_type.name, user_id); 751*e1997b9aSAndroid Build Coastguard Worker let (super_key, public_key) = match key_type.algorithm { 752*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionAlgorithm::Aes256Gcm => { 753*e1997b9aSAndroid Build Coastguard Worker (generate_aes256_key().context(ks_err!("Failed to generate AES-256 key."))?, None) 754*e1997b9aSAndroid Build Coastguard Worker } 755*e1997b9aSAndroid Build Coastguard Worker SuperEncryptionAlgorithm::EcdhP521 => { 756*e1997b9aSAndroid Build Coastguard Worker let key = 757*e1997b9aSAndroid Build Coastguard Worker ECDHPrivateKey::generate().context(ks_err!("Failed to generate ECDH key"))?; 758*e1997b9aSAndroid Build Coastguard Worker ( 759*e1997b9aSAndroid Build Coastguard Worker key.private_key().context(ks_err!("private_key failed"))?, 760*e1997b9aSAndroid Build Coastguard Worker Some(key.public_key().context(ks_err!("public_key failed"))?), 761*e1997b9aSAndroid Build Coastguard Worker ) 762*e1997b9aSAndroid Build Coastguard Worker } 763*e1997b9aSAndroid Build Coastguard Worker }; 764*e1997b9aSAndroid Build Coastguard Worker // Derive an AES-256 key from the password and re-encrypt the super key before we insert it 765*e1997b9aSAndroid Build Coastguard Worker // in the database. 766*e1997b9aSAndroid Build Coastguard Worker let (encrypted_super_key, blob_metadata) = 767*e1997b9aSAndroid Build Coastguard Worker Self::encrypt_with_password(&super_key, password).context(ks_err!())?; 768*e1997b9aSAndroid Build Coastguard Worker let mut key_metadata = KeyMetaData::new(); 769*e1997b9aSAndroid Build Coastguard Worker if let Some(pk) = public_key { 770*e1997b9aSAndroid Build Coastguard Worker key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk)); 771*e1997b9aSAndroid Build Coastguard Worker } 772*e1997b9aSAndroid Build Coastguard Worker let key_entry = db 773*e1997b9aSAndroid Build Coastguard Worker .store_super_key(user_id, key_type, &encrypted_super_key, &blob_metadata, &key_metadata) 774*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to store super key."))?; 775*e1997b9aSAndroid Build Coastguard Worker Ok(Arc::new(SuperKey { 776*e1997b9aSAndroid Build Coastguard Worker algorithm: key_type.algorithm, 777*e1997b9aSAndroid Build Coastguard Worker key: super_key, 778*e1997b9aSAndroid Build Coastguard Worker id: SuperKeyIdentifier::DatabaseId(key_entry.id()), 779*e1997b9aSAndroid Build Coastguard Worker reencrypt_with, 780*e1997b9aSAndroid Build Coastguard Worker })) 781*e1997b9aSAndroid Build Coastguard Worker } 782*e1997b9aSAndroid Build Coastguard Worker 783*e1997b9aSAndroid Build Coastguard Worker /// Fetch a superencryption key from the database, or create it if it doesn't already exist. 784*e1997b9aSAndroid Build Coastguard Worker /// When this is called, the caller must hold the lock on the SuperKeyManager. 785*e1997b9aSAndroid Build Coastguard Worker /// So it's OK that the check and creation are different DB transactions. get_or_create_super_key( &mut self, db: &mut KeystoreDB, user_id: UserId, key_type: &SuperKeyType, password: &Password, reencrypt_with: Option<Arc<SuperKey>>, ) -> Result<Arc<SuperKey>>786*e1997b9aSAndroid Build Coastguard Worker fn get_or_create_super_key( 787*e1997b9aSAndroid Build Coastguard Worker &mut self, 788*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 789*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 790*e1997b9aSAndroid Build Coastguard Worker key_type: &SuperKeyType, 791*e1997b9aSAndroid Build Coastguard Worker password: &Password, 792*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: Option<Arc<SuperKey>>, 793*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Arc<SuperKey>> { 794*e1997b9aSAndroid Build Coastguard Worker let loaded_key = db.load_super_key(key_type, user_id)?; 795*e1997b9aSAndroid Build Coastguard Worker if let Some((_, key_entry)) = loaded_key { 796*e1997b9aSAndroid Build Coastguard Worker Ok(Self::extract_super_key_from_key_entry( 797*e1997b9aSAndroid Build Coastguard Worker key_type.algorithm, 798*e1997b9aSAndroid Build Coastguard Worker key_entry, 799*e1997b9aSAndroid Build Coastguard Worker password, 800*e1997b9aSAndroid Build Coastguard Worker reencrypt_with, 801*e1997b9aSAndroid Build Coastguard Worker )?) 802*e1997b9aSAndroid Build Coastguard Worker } else { 803*e1997b9aSAndroid Build Coastguard Worker self.create_super_key(db, user_id, key_type, password, reencrypt_with) 804*e1997b9aSAndroid Build Coastguard Worker } 805*e1997b9aSAndroid Build Coastguard Worker } 806*e1997b9aSAndroid Build Coastguard Worker 807*e1997b9aSAndroid Build Coastguard Worker /// Decrypt the UnlockedDeviceRequired super keys for this user using the password and store 808*e1997b9aSAndroid Build Coastguard Worker /// them in memory. If these keys don't exist yet, create them. unlock_unlocked_device_required_keys( &mut self, db: &mut KeystoreDB, user_id: UserId, password: &Password, ) -> Result<()>809*e1997b9aSAndroid Build Coastguard Worker pub fn unlock_unlocked_device_required_keys( 810*e1997b9aSAndroid Build Coastguard Worker &mut self, 811*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 812*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 813*e1997b9aSAndroid Build Coastguard Worker password: &Password, 814*e1997b9aSAndroid Build Coastguard Worker ) -> Result<()> { 815*e1997b9aSAndroid Build Coastguard Worker let (symmetric, private) = self 816*e1997b9aSAndroid Build Coastguard Worker .data 817*e1997b9aSAndroid Build Coastguard Worker .user_keys 818*e1997b9aSAndroid Build Coastguard Worker .get(&user_id) 819*e1997b9aSAndroid Build Coastguard Worker .map(|e| { 820*e1997b9aSAndroid Build Coastguard Worker ( 821*e1997b9aSAndroid Build Coastguard Worker e.unlocked_device_required_symmetric.clone(), 822*e1997b9aSAndroid Build Coastguard Worker e.unlocked_device_required_private.clone(), 823*e1997b9aSAndroid Build Coastguard Worker ) 824*e1997b9aSAndroid Build Coastguard Worker }) 825*e1997b9aSAndroid Build Coastguard Worker .unwrap_or((None, None)); 826*e1997b9aSAndroid Build Coastguard Worker 827*e1997b9aSAndroid Build Coastguard Worker if symmetric.is_some() && private.is_some() { 828*e1997b9aSAndroid Build Coastguard Worker // Already unlocked. 829*e1997b9aSAndroid Build Coastguard Worker return Ok(()); 830*e1997b9aSAndroid Build Coastguard Worker } 831*e1997b9aSAndroid Build Coastguard Worker 832*e1997b9aSAndroid Build Coastguard Worker let aes = if let Some(symmetric) = symmetric { 833*e1997b9aSAndroid Build Coastguard Worker // This is weird. If this point is reached only one of the UnlockedDeviceRequired super 834*e1997b9aSAndroid Build Coastguard Worker // keys was initialized. This should never happen. 835*e1997b9aSAndroid Build Coastguard Worker symmetric 836*e1997b9aSAndroid Build Coastguard Worker } else { 837*e1997b9aSAndroid Build Coastguard Worker self.get_or_create_super_key( 838*e1997b9aSAndroid Build Coastguard Worker db, 839*e1997b9aSAndroid Build Coastguard Worker user_id, 840*e1997b9aSAndroid Build Coastguard Worker &USER_UNLOCKED_DEVICE_REQUIRED_SYMMETRIC_SUPER_KEY, 841*e1997b9aSAndroid Build Coastguard Worker password, 842*e1997b9aSAndroid Build Coastguard Worker None, 843*e1997b9aSAndroid Build Coastguard Worker ) 844*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Trying to get or create symmetric key."))? 845*e1997b9aSAndroid Build Coastguard Worker }; 846*e1997b9aSAndroid Build Coastguard Worker 847*e1997b9aSAndroid Build Coastguard Worker let ecdh = if let Some(private) = private { 848*e1997b9aSAndroid Build Coastguard Worker // This is weird. If this point is reached only one of the UnlockedDeviceRequired super 849*e1997b9aSAndroid Build Coastguard Worker // keys was initialized. This should never happen. 850*e1997b9aSAndroid Build Coastguard Worker private 851*e1997b9aSAndroid Build Coastguard Worker } else { 852*e1997b9aSAndroid Build Coastguard Worker self.get_or_create_super_key( 853*e1997b9aSAndroid Build Coastguard Worker db, 854*e1997b9aSAndroid Build Coastguard Worker user_id, 855*e1997b9aSAndroid Build Coastguard Worker &USER_UNLOCKED_DEVICE_REQUIRED_P521_SUPER_KEY, 856*e1997b9aSAndroid Build Coastguard Worker password, 857*e1997b9aSAndroid Build Coastguard Worker Some(aes.clone()), 858*e1997b9aSAndroid Build Coastguard Worker ) 859*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Trying to get or create asymmetric key."))? 860*e1997b9aSAndroid Build Coastguard Worker }; 861*e1997b9aSAndroid Build Coastguard Worker 862*e1997b9aSAndroid Build Coastguard Worker self.data.add_key_to_key_index(&aes)?; 863*e1997b9aSAndroid Build Coastguard Worker self.data.add_key_to_key_index(&ecdh)?; 864*e1997b9aSAndroid Build Coastguard Worker let entry = self.data.user_keys.entry(user_id).or_default(); 865*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric = Some(aes); 866*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_private = Some(ecdh); 867*e1997b9aSAndroid Build Coastguard Worker Ok(()) 868*e1997b9aSAndroid Build Coastguard Worker } 869*e1997b9aSAndroid Build Coastguard Worker 870*e1997b9aSAndroid Build Coastguard Worker /// Protects the user's UnlockedDeviceRequired super keys in a way such that they can only be 871*e1997b9aSAndroid Build Coastguard Worker /// unlocked by the enabled unlock methods. lock_unlocked_device_required_keys( &mut self, db: &mut KeystoreDB, user_id: UserId, unlocking_sids: &[i64], weak_unlock_enabled: bool, )872*e1997b9aSAndroid Build Coastguard Worker pub fn lock_unlocked_device_required_keys( 873*e1997b9aSAndroid Build Coastguard Worker &mut self, 874*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 875*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 876*e1997b9aSAndroid Build Coastguard Worker unlocking_sids: &[i64], 877*e1997b9aSAndroid Build Coastguard Worker weak_unlock_enabled: bool, 878*e1997b9aSAndroid Build Coastguard Worker ) { 879*e1997b9aSAndroid Build Coastguard Worker let entry = self.data.user_keys.entry(user_id).or_default(); 880*e1997b9aSAndroid Build Coastguard Worker if unlocking_sids.is_empty() { 881*e1997b9aSAndroid Build Coastguard Worker entry.biometric_unlock = None; 882*e1997b9aSAndroid Build Coastguard Worker } else if let (Some(aes), Some(ecdh)) = ( 883*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric.as_ref().cloned(), 884*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_private.as_ref().cloned(), 885*e1997b9aSAndroid Build Coastguard Worker ) { 886*e1997b9aSAndroid Build Coastguard Worker // If class 3 biometric unlock methods are enabled, create a biometric-encrypted copy of 887*e1997b9aSAndroid Build Coastguard Worker // the keys. Do this even if weak unlock methods are enabled too; in that case we'll 888*e1997b9aSAndroid Build Coastguard Worker // also retain a plaintext copy of the keys, but that copy will be wiped later if weak 889*e1997b9aSAndroid Build Coastguard Worker // unlock methods expire. So we need the biometric-encrypted copy too just in case. 890*e1997b9aSAndroid Build Coastguard Worker let res = (|| -> Result<()> { 891*e1997b9aSAndroid Build Coastguard Worker let key_desc = 892*e1997b9aSAndroid Build Coastguard Worker KeyMintDevice::internal_descriptor(format!("biometric_unlock_key_{}", user_id)); 893*e1997b9aSAndroid Build Coastguard Worker let encrypting_key = generate_aes256_key()?; 894*e1997b9aSAndroid Build Coastguard Worker let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT) 895*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("KeyMintDevice::get failed"))?; 896*e1997b9aSAndroid Build Coastguard Worker let mut key_params = vec![ 897*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::Algorithm(Algorithm::AES), 898*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::KeySize(256), 899*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::BlockMode(BlockMode::GCM), 900*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::PaddingMode(PaddingMode::NONE), 901*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::CallerNonce, 902*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::KeyPurpose(KeyPurpose::DECRYPT), 903*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::MinMacLength(128), 904*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::AuthTimeout(BIOMETRIC_AUTH_TIMEOUT_S), 905*e1997b9aSAndroid Build Coastguard Worker KeyParameterValue::HardwareAuthenticatorType( 906*e1997b9aSAndroid Build Coastguard Worker HardwareAuthenticatorType::FINGERPRINT, 907*e1997b9aSAndroid Build Coastguard Worker ), 908*e1997b9aSAndroid Build Coastguard Worker ]; 909*e1997b9aSAndroid Build Coastguard Worker for sid in unlocking_sids { 910*e1997b9aSAndroid Build Coastguard Worker key_params.push(KeyParameterValue::UserSecureID(*sid)); 911*e1997b9aSAndroid Build Coastguard Worker } 912*e1997b9aSAndroid Build Coastguard Worker let key_params: Vec<KmKeyParameter> = 913*e1997b9aSAndroid Build Coastguard Worker key_params.into_iter().map(|x| x.into()).collect(); 914*e1997b9aSAndroid Build Coastguard Worker km_dev.create_and_store_key( 915*e1997b9aSAndroid Build Coastguard Worker db, 916*e1997b9aSAndroid Build Coastguard Worker &key_desc, 917*e1997b9aSAndroid Build Coastguard Worker KeyType::Client, /* TODO Should be Super b/189470584 */ 918*e1997b9aSAndroid Build Coastguard Worker |dev| { 919*e1997b9aSAndroid Build Coastguard Worker let _wp = 920*e1997b9aSAndroid Build Coastguard Worker wd::watch("SKM::lock_unlocked_device_required_keys: calling IKeyMintDevice::importKey."); 921*e1997b9aSAndroid Build Coastguard Worker dev.importKey(key_params.as_slice(), KeyFormat::RAW, &encrypting_key, None) 922*e1997b9aSAndroid Build Coastguard Worker }, 923*e1997b9aSAndroid Build Coastguard Worker )?; 924*e1997b9aSAndroid Build Coastguard Worker entry.biometric_unlock = Some(BiometricUnlock { 925*e1997b9aSAndroid Build Coastguard Worker sids: unlocking_sids.into(), 926*e1997b9aSAndroid Build Coastguard Worker key_desc, 927*e1997b9aSAndroid Build Coastguard Worker symmetric: LockedKey::new(&encrypting_key, &aes)?, 928*e1997b9aSAndroid Build Coastguard Worker private: LockedKey::new(&encrypting_key, &ecdh)?, 929*e1997b9aSAndroid Build Coastguard Worker }); 930*e1997b9aSAndroid Build Coastguard Worker Ok(()) 931*e1997b9aSAndroid Build Coastguard Worker })(); 932*e1997b9aSAndroid Build Coastguard Worker if let Err(e) = res { 933*e1997b9aSAndroid Build Coastguard Worker log::error!("Error setting up biometric unlock: {:#?}", e); 934*e1997b9aSAndroid Build Coastguard Worker // The caller can't do anything about the error, and for security reasons we still 935*e1997b9aSAndroid Build Coastguard Worker // wipe the keys (unless a weak unlock method is enabled). So just log the error. 936*e1997b9aSAndroid Build Coastguard Worker } 937*e1997b9aSAndroid Build Coastguard Worker } 938*e1997b9aSAndroid Build Coastguard Worker // Wipe the plaintext copy of the keys, unless a weak unlock method is enabled. 939*e1997b9aSAndroid Build Coastguard Worker if !weak_unlock_enabled { 940*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric = None; 941*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_private = None; 942*e1997b9aSAndroid Build Coastguard Worker } 943*e1997b9aSAndroid Build Coastguard Worker Self::log_status_of_unlocked_device_required_keys(user_id, entry); 944*e1997b9aSAndroid Build Coastguard Worker } 945*e1997b9aSAndroid Build Coastguard Worker wipe_plaintext_unlocked_device_required_keys(&mut self, user_id: UserId)946*e1997b9aSAndroid Build Coastguard Worker pub fn wipe_plaintext_unlocked_device_required_keys(&mut self, user_id: UserId) { 947*e1997b9aSAndroid Build Coastguard Worker let entry = self.data.user_keys.entry(user_id).or_default(); 948*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric = None; 949*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_private = None; 950*e1997b9aSAndroid Build Coastguard Worker Self::log_status_of_unlocked_device_required_keys(user_id, entry); 951*e1997b9aSAndroid Build Coastguard Worker } 952*e1997b9aSAndroid Build Coastguard Worker wipe_all_unlocked_device_required_keys(&mut self, user_id: UserId)953*e1997b9aSAndroid Build Coastguard Worker pub fn wipe_all_unlocked_device_required_keys(&mut self, user_id: UserId) { 954*e1997b9aSAndroid Build Coastguard Worker let entry = self.data.user_keys.entry(user_id).or_default(); 955*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric = None; 956*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_private = None; 957*e1997b9aSAndroid Build Coastguard Worker entry.biometric_unlock = None; 958*e1997b9aSAndroid Build Coastguard Worker Self::log_status_of_unlocked_device_required_keys(user_id, entry); 959*e1997b9aSAndroid Build Coastguard Worker } 960*e1997b9aSAndroid Build Coastguard Worker log_status_of_unlocked_device_required_keys(user_id: UserId, entry: &UserSuperKeys)961*e1997b9aSAndroid Build Coastguard Worker fn log_status_of_unlocked_device_required_keys(user_id: UserId, entry: &UserSuperKeys) { 962*e1997b9aSAndroid Build Coastguard Worker let status = match ( 963*e1997b9aSAndroid Build Coastguard Worker // Note: the status of the symmetric and private keys should always be in sync. 964*e1997b9aSAndroid Build Coastguard Worker // So we only check one here. 965*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric.is_some(), 966*e1997b9aSAndroid Build Coastguard Worker entry.biometric_unlock.is_some(), 967*e1997b9aSAndroid Build Coastguard Worker ) { 968*e1997b9aSAndroid Build Coastguard Worker (false, false) => "fully protected", 969*e1997b9aSAndroid Build Coastguard Worker (false, true) => "biometric-encrypted", 970*e1997b9aSAndroid Build Coastguard Worker (true, false) => "retained in plaintext", 971*e1997b9aSAndroid Build Coastguard Worker (true, true) => "retained in plaintext, with biometric-encrypted copy too", 972*e1997b9aSAndroid Build Coastguard Worker }; 973*e1997b9aSAndroid Build Coastguard Worker log::info!("UnlockedDeviceRequired super keys for user {user_id} are {status}."); 974*e1997b9aSAndroid Build Coastguard Worker } 975*e1997b9aSAndroid Build Coastguard Worker 976*e1997b9aSAndroid Build Coastguard Worker /// User has unlocked, not using a password. See if any of our stored auth tokens can be used 977*e1997b9aSAndroid Build Coastguard Worker /// to unlock the keys protecting UNLOCKED_DEVICE_REQUIRED keys. try_unlock_user_with_biometric( &mut self, db: &mut KeystoreDB, user_id: UserId, ) -> Result<()>978*e1997b9aSAndroid Build Coastguard Worker pub fn try_unlock_user_with_biometric( 979*e1997b9aSAndroid Build Coastguard Worker &mut self, 980*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 981*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 982*e1997b9aSAndroid Build Coastguard Worker ) -> Result<()> { 983*e1997b9aSAndroid Build Coastguard Worker let entry = self.data.user_keys.entry(user_id).or_default(); 984*e1997b9aSAndroid Build Coastguard Worker if entry.unlocked_device_required_symmetric.is_some() 985*e1997b9aSAndroid Build Coastguard Worker && entry.unlocked_device_required_private.is_some() 986*e1997b9aSAndroid Build Coastguard Worker { 987*e1997b9aSAndroid Build Coastguard Worker // If the keys are already cached in plaintext, then there is no need to decrypt the 988*e1997b9aSAndroid Build Coastguard Worker // biometric-encrypted copy. Both copies can be present here if the user has both 989*e1997b9aSAndroid Build Coastguard Worker // class 3 biometric and weak unlock methods enabled, and the device was unlocked before 990*e1997b9aSAndroid Build Coastguard Worker // the weak unlock methods expired. 991*e1997b9aSAndroid Build Coastguard Worker return Ok(()); 992*e1997b9aSAndroid Build Coastguard Worker } 993*e1997b9aSAndroid Build Coastguard Worker if let Some(biometric) = entry.biometric_unlock.as_ref() { 994*e1997b9aSAndroid Build Coastguard Worker let (key_id_guard, key_entry) = db 995*e1997b9aSAndroid Build Coastguard Worker .load_key_entry( 996*e1997b9aSAndroid Build Coastguard Worker &biometric.key_desc, 997*e1997b9aSAndroid Build Coastguard Worker KeyType::Client, // This should not be a Client key. 998*e1997b9aSAndroid Build Coastguard Worker KeyEntryLoadBits::KM, 999*e1997b9aSAndroid Build Coastguard Worker AID_KEYSTORE, 1000*e1997b9aSAndroid Build Coastguard Worker |_, _| Ok(()), 1001*e1997b9aSAndroid Build Coastguard Worker ) 1002*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("load_key_entry failed"))?; 1003*e1997b9aSAndroid Build Coastguard Worker let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT) 1004*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("KeyMintDevice::get failed"))?; 1005*e1997b9aSAndroid Build Coastguard Worker let mut errs = vec![]; 1006*e1997b9aSAndroid Build Coastguard Worker for sid in &biometric.sids { 1007*e1997b9aSAndroid Build Coastguard Worker let sid = *sid; 1008*e1997b9aSAndroid Build Coastguard Worker if let Some(auth_token_entry) = db.find_auth_token_entry(|entry| { 1009*e1997b9aSAndroid Build Coastguard Worker entry.auth_token().userId == sid || entry.auth_token().authenticatorId == sid 1010*e1997b9aSAndroid Build Coastguard Worker }) { 1011*e1997b9aSAndroid Build Coastguard Worker let res: Result<(Arc<SuperKey>, Arc<SuperKey>)> = (|| { 1012*e1997b9aSAndroid Build Coastguard Worker let symmetric = biometric.symmetric.decrypt( 1013*e1997b9aSAndroid Build Coastguard Worker db, 1014*e1997b9aSAndroid Build Coastguard Worker &km_dev, 1015*e1997b9aSAndroid Build Coastguard Worker &key_id_guard, 1016*e1997b9aSAndroid Build Coastguard Worker &key_entry, 1017*e1997b9aSAndroid Build Coastguard Worker auth_token_entry.auth_token(), 1018*e1997b9aSAndroid Build Coastguard Worker None, 1019*e1997b9aSAndroid Build Coastguard Worker )?; 1020*e1997b9aSAndroid Build Coastguard Worker let private = biometric.private.decrypt( 1021*e1997b9aSAndroid Build Coastguard Worker db, 1022*e1997b9aSAndroid Build Coastguard Worker &km_dev, 1023*e1997b9aSAndroid Build Coastguard Worker &key_id_guard, 1024*e1997b9aSAndroid Build Coastguard Worker &key_entry, 1025*e1997b9aSAndroid Build Coastguard Worker auth_token_entry.auth_token(), 1026*e1997b9aSAndroid Build Coastguard Worker Some(symmetric.clone()), 1027*e1997b9aSAndroid Build Coastguard Worker )?; 1028*e1997b9aSAndroid Build Coastguard Worker Ok((symmetric, private)) 1029*e1997b9aSAndroid Build Coastguard Worker })(); 1030*e1997b9aSAndroid Build Coastguard Worker match res { 1031*e1997b9aSAndroid Build Coastguard Worker Ok((symmetric, private)) => { 1032*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_symmetric = Some(symmetric.clone()); 1033*e1997b9aSAndroid Build Coastguard Worker entry.unlocked_device_required_private = Some(private.clone()); 1034*e1997b9aSAndroid Build Coastguard Worker self.data.add_key_to_key_index(&symmetric)?; 1035*e1997b9aSAndroid Build Coastguard Worker self.data.add_key_to_key_index(&private)?; 1036*e1997b9aSAndroid Build Coastguard Worker log::info!("Successfully unlocked user {user_id} with biometric {sid}",); 1037*e1997b9aSAndroid Build Coastguard Worker return Ok(()); 1038*e1997b9aSAndroid Build Coastguard Worker } 1039*e1997b9aSAndroid Build Coastguard Worker Err(e) => { 1040*e1997b9aSAndroid Build Coastguard Worker // Don't log an error yet, as some other biometric SID might work. 1041*e1997b9aSAndroid Build Coastguard Worker errs.push((sid, e)); 1042*e1997b9aSAndroid Build Coastguard Worker } 1043*e1997b9aSAndroid Build Coastguard Worker } 1044*e1997b9aSAndroid Build Coastguard Worker } 1045*e1997b9aSAndroid Build Coastguard Worker } 1046*e1997b9aSAndroid Build Coastguard Worker if !errs.is_empty() { 1047*e1997b9aSAndroid Build Coastguard Worker log::warn!("biometric unlock failed for all SIDs, with errors:"); 1048*e1997b9aSAndroid Build Coastguard Worker for (sid, err) in errs { 1049*e1997b9aSAndroid Build Coastguard Worker log::warn!(" biometric {sid}: {err}"); 1050*e1997b9aSAndroid Build Coastguard Worker } 1051*e1997b9aSAndroid Build Coastguard Worker } 1052*e1997b9aSAndroid Build Coastguard Worker } 1053*e1997b9aSAndroid Build Coastguard Worker Ok(()) 1054*e1997b9aSAndroid Build Coastguard Worker } 1055*e1997b9aSAndroid Build Coastguard Worker 1056*e1997b9aSAndroid Build Coastguard Worker /// Returns the keystore locked state of the given user. It requires the thread local 1057*e1997b9aSAndroid Build Coastguard Worker /// keystore database and a reference to the legacy migrator because it may need to 1058*e1997b9aSAndroid Build Coastguard Worker /// import the super key from the legacy blob database to the keystore database. get_user_state( &self, db: &mut KeystoreDB, legacy_importer: &LegacyImporter, user_id: UserId, ) -> Result<UserState>1059*e1997b9aSAndroid Build Coastguard Worker pub fn get_user_state( 1060*e1997b9aSAndroid Build Coastguard Worker &self, 1061*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 1062*e1997b9aSAndroid Build Coastguard Worker legacy_importer: &LegacyImporter, 1063*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 1064*e1997b9aSAndroid Build Coastguard Worker ) -> Result<UserState> { 1065*e1997b9aSAndroid Build Coastguard Worker match self.get_after_first_unlock_key_by_user_id_internal(user_id) { 1066*e1997b9aSAndroid Build Coastguard Worker Some(super_key) => Ok(UserState::AfterFirstUnlock(super_key)), 1067*e1997b9aSAndroid Build Coastguard Worker None => { 1068*e1997b9aSAndroid Build Coastguard Worker // Check if a super key exists in the database or legacy database. 1069*e1997b9aSAndroid Build Coastguard Worker // If so, return locked user state. 1070*e1997b9aSAndroid Build Coastguard Worker if self 1071*e1997b9aSAndroid Build Coastguard Worker .super_key_exists_in_db_for_user(db, legacy_importer, user_id) 1072*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!())? 1073*e1997b9aSAndroid Build Coastguard Worker { 1074*e1997b9aSAndroid Build Coastguard Worker Ok(UserState::BeforeFirstUnlock) 1075*e1997b9aSAndroid Build Coastguard Worker } else { 1076*e1997b9aSAndroid Build Coastguard Worker Ok(UserState::Uninitialized) 1077*e1997b9aSAndroid Build Coastguard Worker } 1078*e1997b9aSAndroid Build Coastguard Worker } 1079*e1997b9aSAndroid Build Coastguard Worker } 1080*e1997b9aSAndroid Build Coastguard Worker } 1081*e1997b9aSAndroid Build Coastguard Worker 1082*e1997b9aSAndroid Build Coastguard Worker /// Deletes all keys and super keys for the given user. 1083*e1997b9aSAndroid Build Coastguard Worker /// This is called when a user is deleted. remove_user( &mut self, db: &mut KeystoreDB, legacy_importer: &LegacyImporter, user_id: UserId, ) -> Result<()>1084*e1997b9aSAndroid Build Coastguard Worker pub fn remove_user( 1085*e1997b9aSAndroid Build Coastguard Worker &mut self, 1086*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 1087*e1997b9aSAndroid Build Coastguard Worker legacy_importer: &LegacyImporter, 1088*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 1089*e1997b9aSAndroid Build Coastguard Worker ) -> Result<()> { 1090*e1997b9aSAndroid Build Coastguard Worker log::info!("remove_user(user={user_id})"); 1091*e1997b9aSAndroid Build Coastguard Worker // Mark keys created on behalf of the user as unreferenced. 1092*e1997b9aSAndroid Build Coastguard Worker legacy_importer 1093*e1997b9aSAndroid Build Coastguard Worker .bulk_delete_user(user_id, false) 1094*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Trying to delete legacy keys."))?; 1095*e1997b9aSAndroid Build Coastguard Worker db.unbind_keys_for_user(user_id).context(ks_err!("Error in unbinding keys."))?; 1096*e1997b9aSAndroid Build Coastguard Worker 1097*e1997b9aSAndroid Build Coastguard Worker // Delete super key in cache, if exists. 1098*e1997b9aSAndroid Build Coastguard Worker self.forget_all_keys_for_user(user_id); 1099*e1997b9aSAndroid Build Coastguard Worker Ok(()) 1100*e1997b9aSAndroid Build Coastguard Worker } 1101*e1997b9aSAndroid Build Coastguard Worker 1102*e1997b9aSAndroid Build Coastguard Worker /// Initializes the given user by creating their super keys, both AfterFirstUnlock and 1103*e1997b9aSAndroid Build Coastguard Worker /// UnlockedDeviceRequired. If allow_existing is true, then the user already being initialized 1104*e1997b9aSAndroid Build Coastguard Worker /// is not considered an error. initialize_user( &mut self, db: &mut KeystoreDB, legacy_importer: &LegacyImporter, user_id: UserId, password: &Password, allow_existing: bool, ) -> Result<()>1105*e1997b9aSAndroid Build Coastguard Worker pub fn initialize_user( 1106*e1997b9aSAndroid Build Coastguard Worker &mut self, 1107*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 1108*e1997b9aSAndroid Build Coastguard Worker legacy_importer: &LegacyImporter, 1109*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 1110*e1997b9aSAndroid Build Coastguard Worker password: &Password, 1111*e1997b9aSAndroid Build Coastguard Worker allow_existing: bool, 1112*e1997b9aSAndroid Build Coastguard Worker ) -> Result<()> { 1113*e1997b9aSAndroid Build Coastguard Worker // Create the AfterFirstUnlock super key. 1114*e1997b9aSAndroid Build Coastguard Worker if self.super_key_exists_in_db_for_user(db, legacy_importer, user_id)? { 1115*e1997b9aSAndroid Build Coastguard Worker log::info!("AfterFirstUnlock super key already exists"); 1116*e1997b9aSAndroid Build Coastguard Worker if !allow_existing { 1117*e1997b9aSAndroid Build Coastguard Worker return Err(Error::sys()).context(ks_err!("Tried to re-init an initialized user!")); 1118*e1997b9aSAndroid Build Coastguard Worker } 1119*e1997b9aSAndroid Build Coastguard Worker } else { 1120*e1997b9aSAndroid Build Coastguard Worker let super_key = self 1121*e1997b9aSAndroid Build Coastguard Worker .create_super_key(db, user_id, &USER_AFTER_FIRST_UNLOCK_SUPER_KEY, password, None) 1122*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to create AfterFirstUnlock super key"))?; 1123*e1997b9aSAndroid Build Coastguard Worker 1124*e1997b9aSAndroid Build Coastguard Worker self.install_after_first_unlock_key_for_user(user_id, super_key) 1125*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to install AfterFirstUnlock super key for user"))?; 1126*e1997b9aSAndroid Build Coastguard Worker } 1127*e1997b9aSAndroid Build Coastguard Worker 1128*e1997b9aSAndroid Build Coastguard Worker // Create the UnlockedDeviceRequired super keys. 1129*e1997b9aSAndroid Build Coastguard Worker self.unlock_unlocked_device_required_keys(db, user_id, password) 1130*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to create UnlockedDeviceRequired super keys")) 1131*e1997b9aSAndroid Build Coastguard Worker } 1132*e1997b9aSAndroid Build Coastguard Worker 1133*e1997b9aSAndroid Build Coastguard Worker /// Unlocks the given user with the given password. 1134*e1997b9aSAndroid Build Coastguard Worker /// 1135*e1997b9aSAndroid Build Coastguard Worker /// If the user state is BeforeFirstUnlock: 1136*e1997b9aSAndroid Build Coastguard Worker /// - Unlock the user's AfterFirstUnlock super key 1137*e1997b9aSAndroid Build Coastguard Worker /// - Unlock the user's UnlockedDeviceRequired super keys 1138*e1997b9aSAndroid Build Coastguard Worker /// 1139*e1997b9aSAndroid Build Coastguard Worker /// If the user state is AfterFirstUnlock: 1140*e1997b9aSAndroid Build Coastguard Worker /// - Unlock the user's UnlockedDeviceRequired super keys only 1141*e1997b9aSAndroid Build Coastguard Worker /// unlock_user( &mut self, db: &mut KeystoreDB, legacy_importer: &LegacyImporter, user_id: UserId, password: &Password, ) -> Result<()>1142*e1997b9aSAndroid Build Coastguard Worker pub fn unlock_user( 1143*e1997b9aSAndroid Build Coastguard Worker &mut self, 1144*e1997b9aSAndroid Build Coastguard Worker db: &mut KeystoreDB, 1145*e1997b9aSAndroid Build Coastguard Worker legacy_importer: &LegacyImporter, 1146*e1997b9aSAndroid Build Coastguard Worker user_id: UserId, 1147*e1997b9aSAndroid Build Coastguard Worker password: &Password, 1148*e1997b9aSAndroid Build Coastguard Worker ) -> Result<()> { 1149*e1997b9aSAndroid Build Coastguard Worker log::info!("unlock_user(user={user_id})"); 1150*e1997b9aSAndroid Build Coastguard Worker match self.get_user_state(db, legacy_importer, user_id)? { 1151*e1997b9aSAndroid Build Coastguard Worker UserState::AfterFirstUnlock(_) => { 1152*e1997b9aSAndroid Build Coastguard Worker self.unlock_unlocked_device_required_keys(db, user_id, password) 1153*e1997b9aSAndroid Build Coastguard Worker } 1154*e1997b9aSAndroid Build Coastguard Worker UserState::Uninitialized => { 1155*e1997b9aSAndroid Build Coastguard Worker Err(Error::sys()).context(ks_err!("Tried to unlock an uninitialized user!")) 1156*e1997b9aSAndroid Build Coastguard Worker } 1157*e1997b9aSAndroid Build Coastguard Worker UserState::BeforeFirstUnlock => { 1158*e1997b9aSAndroid Build Coastguard Worker let alias = &USER_AFTER_FIRST_UNLOCK_SUPER_KEY; 1159*e1997b9aSAndroid Build Coastguard Worker let result = legacy_importer 1160*e1997b9aSAndroid Build Coastguard Worker .with_try_import_super_key(user_id, password, || { 1161*e1997b9aSAndroid Build Coastguard Worker db.load_super_key(alias, user_id) 1162*e1997b9aSAndroid Build Coastguard Worker }) 1163*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed to load super key"))?; 1164*e1997b9aSAndroid Build Coastguard Worker 1165*e1997b9aSAndroid Build Coastguard Worker match result { 1166*e1997b9aSAndroid Build Coastguard Worker Some((_, entry)) => { 1167*e1997b9aSAndroid Build Coastguard Worker self.populate_cache_from_super_key_blob( 1168*e1997b9aSAndroid Build Coastguard Worker user_id, 1169*e1997b9aSAndroid Build Coastguard Worker alias.algorithm, 1170*e1997b9aSAndroid Build Coastguard Worker entry, 1171*e1997b9aSAndroid Build Coastguard Worker password, 1172*e1997b9aSAndroid Build Coastguard Worker ) 1173*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Failed when unlocking user."))?; 1174*e1997b9aSAndroid Build Coastguard Worker self.unlock_unlocked_device_required_keys(db, user_id, password) 1175*e1997b9aSAndroid Build Coastguard Worker } 1176*e1997b9aSAndroid Build Coastguard Worker None => { 1177*e1997b9aSAndroid Build Coastguard Worker Err(Error::sys()).context(ks_err!("Locked user does not have a super key!")) 1178*e1997b9aSAndroid Build Coastguard Worker } 1179*e1997b9aSAndroid Build Coastguard Worker } 1180*e1997b9aSAndroid Build Coastguard Worker } 1181*e1997b9aSAndroid Build Coastguard Worker } 1182*e1997b9aSAndroid Build Coastguard Worker } 1183*e1997b9aSAndroid Build Coastguard Worker } 1184*e1997b9aSAndroid Build Coastguard Worker 1185*e1997b9aSAndroid Build Coastguard Worker /// This enum represents different states of the user's life cycle in the device. 1186*e1997b9aSAndroid Build Coastguard Worker /// For now, only three states are defined. More states may be added later. 1187*e1997b9aSAndroid Build Coastguard Worker pub enum UserState { 1188*e1997b9aSAndroid Build Coastguard Worker // The user's super keys exist, and the user has unlocked the device at least once since boot. 1189*e1997b9aSAndroid Build Coastguard Worker // Hence, the AfterFirstUnlock super key is available in the cache. 1190*e1997b9aSAndroid Build Coastguard Worker AfterFirstUnlock(Arc<SuperKey>), 1191*e1997b9aSAndroid Build Coastguard Worker // The user's super keys exist, but the user hasn't unlocked the device at least once since 1192*e1997b9aSAndroid Build Coastguard Worker // boot. Hence, the AfterFirstUnlock and UnlockedDeviceRequired super keys are not available in 1193*e1997b9aSAndroid Build Coastguard Worker // the cache. However, they exist in the database in encrypted form. 1194*e1997b9aSAndroid Build Coastguard Worker BeforeFirstUnlock, 1195*e1997b9aSAndroid Build Coastguard Worker // The user's super keys don't exist. I.e., there's no user with the given user ID, or the user 1196*e1997b9aSAndroid Build Coastguard Worker // is in the process of being created or destroyed. 1197*e1997b9aSAndroid Build Coastguard Worker Uninitialized, 1198*e1997b9aSAndroid Build Coastguard Worker } 1199*e1997b9aSAndroid Build Coastguard Worker 1200*e1997b9aSAndroid Build Coastguard Worker /// This enum represents three states a KeyMint Blob can be in, w.r.t super encryption. 1201*e1997b9aSAndroid Build Coastguard Worker /// `Sensitive` holds the non encrypted key and a reference to its super key. 1202*e1997b9aSAndroid Build Coastguard Worker /// `NonSensitive` holds a non encrypted key that is never supposed to be encrypted. 1203*e1997b9aSAndroid Build Coastguard Worker /// `Ref` holds a reference to a key blob when it does not need to be modified if its 1204*e1997b9aSAndroid Build Coastguard Worker /// life time allows it. 1205*e1997b9aSAndroid Build Coastguard Worker pub enum KeyBlob<'a> { 1206*e1997b9aSAndroid Build Coastguard Worker Sensitive { 1207*e1997b9aSAndroid Build Coastguard Worker key: ZVec, 1208*e1997b9aSAndroid Build Coastguard Worker /// If KeyMint reports that the key must be upgraded, we must 1209*e1997b9aSAndroid Build Coastguard Worker /// re-encrypt the key before writing to the database; we use 1210*e1997b9aSAndroid Build Coastguard Worker /// this key. 1211*e1997b9aSAndroid Build Coastguard Worker reencrypt_with: Arc<SuperKey>, 1212*e1997b9aSAndroid Build Coastguard Worker /// If this key was decrypted with an ECDH key, we want to 1213*e1997b9aSAndroid Build Coastguard Worker /// re-encrypt it on first use whether it was upgraded or not; 1214*e1997b9aSAndroid Build Coastguard Worker /// this field indicates that that's necessary. 1215*e1997b9aSAndroid Build Coastguard Worker force_reencrypt: bool, 1216*e1997b9aSAndroid Build Coastguard Worker }, 1217*e1997b9aSAndroid Build Coastguard Worker NonSensitive(Vec<u8>), 1218*e1997b9aSAndroid Build Coastguard Worker Ref(&'a [u8]), 1219*e1997b9aSAndroid Build Coastguard Worker } 1220*e1997b9aSAndroid Build Coastguard Worker 1221*e1997b9aSAndroid Build Coastguard Worker impl<'a> KeyBlob<'a> { force_reencrypt(&self) -> bool1222*e1997b9aSAndroid Build Coastguard Worker pub fn force_reencrypt(&self) -> bool { 1223*e1997b9aSAndroid Build Coastguard Worker if let KeyBlob::Sensitive { force_reencrypt, .. } = self { 1224*e1997b9aSAndroid Build Coastguard Worker *force_reencrypt 1225*e1997b9aSAndroid Build Coastguard Worker } else { 1226*e1997b9aSAndroid Build Coastguard Worker false 1227*e1997b9aSAndroid Build Coastguard Worker } 1228*e1997b9aSAndroid Build Coastguard Worker } 1229*e1997b9aSAndroid Build Coastguard Worker } 1230*e1997b9aSAndroid Build Coastguard Worker 1231*e1997b9aSAndroid Build Coastguard Worker /// Deref returns a reference to the key material in any variant. 1232*e1997b9aSAndroid Build Coastguard Worker impl<'a> Deref for KeyBlob<'a> { 1233*e1997b9aSAndroid Build Coastguard Worker type Target = [u8]; 1234*e1997b9aSAndroid Build Coastguard Worker deref(&self) -> &Self::Target1235*e1997b9aSAndroid Build Coastguard Worker fn deref(&self) -> &Self::Target { 1236*e1997b9aSAndroid Build Coastguard Worker match self { 1237*e1997b9aSAndroid Build Coastguard Worker Self::Sensitive { key, .. } => key, 1238*e1997b9aSAndroid Build Coastguard Worker Self::NonSensitive(key) => key, 1239*e1997b9aSAndroid Build Coastguard Worker Self::Ref(key) => key, 1240*e1997b9aSAndroid Build Coastguard Worker } 1241*e1997b9aSAndroid Build Coastguard Worker } 1242*e1997b9aSAndroid Build Coastguard Worker } 1243