xref: /aosp_15_r20/system/security/keystore2/src/super_key.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
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