1 // Copyright 2021, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This module acts as a bridge between the legacy key database and the keystore2 database.
16 
17 use crate::database::{
18     BlobInfo, BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, EncryptedBy, KeyMetaData,
19     KeyMetaEntry, KeyType, KeystoreDB, Uuid, KEYSTORE_UUID,
20 };
21 use crate::error::{map_km_error, Error};
22 use crate::key_parameter::{KeyParameter, KeyParameterValue};
23 use crate::ks_err;
24 use crate::legacy_blob::{self, Blob, BlobValue, LegacyKeyCharacteristics};
25 use crate::super_key::USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
26 use crate::utils::{
27     key_characteristics_to_internal, uid_to_android_user, upgrade_keyblob_if_required_with,
28     watchdog as wd, AesGcm,
29 };
30 use crate::{async_task::AsyncTask, legacy_blob::LegacyBlobLoader};
31 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
32 use android_system_keystore2::aidl::android::system::keystore2::{
33     Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
34 };
35 use anyhow::{Context, Result};
36 use core::ops::Deref;
37 use keystore2_crypto::{Password, ZVec};
38 use std::collections::{HashMap, HashSet};
39 use std::sync::atomic::{AtomicU8, Ordering};
40 use std::sync::mpsc::channel;
41 use std::sync::{Arc, Mutex};
42 
43 /// Represents LegacyImporter.
44 pub struct LegacyImporter {
45     async_task: Arc<AsyncTask>,
46     initializer: Mutex<
47         Option<
48             Box<
49                 dyn FnOnce() -> (KeystoreDB, HashMap<SecurityLevel, Uuid>, Arc<LegacyBlobLoader>)
50                     + Send
51                     + 'static,
52             >,
53         >,
54     >,
55     /// This atomic is used for cheap interior mutability. It is intended to prevent
56     /// expensive calls into the legacy importer when the legacy database is empty.
57     /// When transitioning from READY to EMPTY, spurious calls may occur for a brief period
58     /// of time. This is tolerable in favor of the common case.
59     state: AtomicU8,
60 }
61 
62 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
63 struct RecentImport {
64     uid: u32,
65     alias: String,
66 }
67 
68 impl RecentImport {
new(uid: u32, alias: String) -> Self69     fn new(uid: u32, alias: String) -> Self {
70         Self { uid, alias }
71     }
72 }
73 
74 enum BulkDeleteRequest {
75     Uid(u32),
76     User(u32),
77 }
78 
79 struct LegacyImporterState {
80     recently_imported: HashSet<RecentImport>,
81     recently_imported_super_key: HashSet<u32>,
82     legacy_loader: Arc<LegacyBlobLoader>,
83     sec_level_to_km_uuid: HashMap<SecurityLevel, Uuid>,
84     db: KeystoreDB,
85 }
86 
87 impl LegacyImporter {
88     const WIFI_NAMESPACE: i64 = 102;
89     const AID_WIFI: u32 = 1010;
90 
91     const STATE_UNINITIALIZED: u8 = 0;
92     const STATE_READY: u8 = 1;
93     const STATE_EMPTY: u8 = 2;
94 
95     /// Constructs a new LegacyImporter using the given AsyncTask object as import
96     /// worker.
new(async_task: Arc<AsyncTask>) -> Self97     pub fn new(async_task: Arc<AsyncTask>) -> Self {
98         Self {
99             async_task,
100             initializer: Default::default(),
101             state: AtomicU8::new(Self::STATE_UNINITIALIZED),
102         }
103     }
104 
105     #[cfg(test)]
set_empty(&mut self)106     pub fn set_empty(&mut self) {
107         self.state = AtomicU8::new(Self::STATE_EMPTY);
108     }
109 
110     /// The legacy importer must be initialized deferred, because keystore starts very early.
111     /// At this time the data partition may not be mounted. So we cannot open database connections
112     /// until we get actual key load requests. This sets the function that the legacy loader
113     /// uses to connect to the database.
set_init<F>(&self, f_init: F) -> Result<()> where F: FnOnce() -> (KeystoreDB, HashMap<SecurityLevel, Uuid>, Arc<LegacyBlobLoader>) + Send + 'static,114     pub fn set_init<F>(&self, f_init: F) -> Result<()>
115     where
116         F: FnOnce() -> (KeystoreDB, HashMap<SecurityLevel, Uuid>, Arc<LegacyBlobLoader>)
117             + Send
118             + 'static,
119     {
120         let mut initializer = self.initializer.lock().expect("Failed to lock initializer.");
121 
122         // If we are not uninitialized we have no business setting the initializer.
123         if self.state.load(Ordering::Relaxed) != Self::STATE_UNINITIALIZED {
124             return Ok(());
125         }
126 
127         // Only set the initializer if it hasn't been set before.
128         if initializer.is_none() {
129             *initializer = Some(Box::new(f_init))
130         }
131 
132         Ok(())
133     }
134 
135     /// This function is called by the import requestor to check if it is worth
136     /// making an import request. It also transitions the state from UNINITIALIZED
137     /// to READY or EMPTY on first use. The deferred initialization is necessary, because
138     /// Keystore 2.0 runs early during boot, where data may not yet be mounted.
139     /// Returns Ok(STATE_READY) if an import request is worth undertaking and
140     /// Ok(STATE_EMPTY) if the database is empty. An error is returned if the loader
141     /// was not initialized and cannot be initialized.
check_state(&self) -> Result<u8>142     fn check_state(&self) -> Result<u8> {
143         let mut first_try = true;
144         loop {
145             match (self.state.load(Ordering::Relaxed), first_try) {
146                 (Self::STATE_EMPTY, _) => {
147                     return Ok(Self::STATE_EMPTY);
148                 }
149                 (Self::STATE_UNINITIALIZED, true) => {
150                     // If we find the legacy loader uninitialized, we grab the initializer lock,
151                     // check if the legacy database is empty, and if not, schedule an initialization
152                     // request. Coming out of the initializer lock, the state is either EMPTY or
153                     // READY.
154                     let mut initializer = self.initializer.lock().unwrap();
155 
156                     if let Some(initializer) = initializer.take() {
157                         let (db, sec_level_to_km_uuid, legacy_loader) = (initializer)();
158 
159                         if legacy_loader.is_empty().context(
160                             "In check_state: Trying to check if the legacy database is empty.",
161                         )? {
162                             self.state.store(Self::STATE_EMPTY, Ordering::Relaxed);
163                             return Ok(Self::STATE_EMPTY);
164                         }
165 
166                         self.async_task.queue_hi(move |shelf| {
167                             shelf.get_or_put_with(|| LegacyImporterState {
168                                 recently_imported: Default::default(),
169                                 recently_imported_super_key: Default::default(),
170                                 legacy_loader,
171                                 sec_level_to_km_uuid,
172                                 db,
173                             });
174                         });
175 
176                         // It is safe to set this here even though the async task may not yet have
177                         // run because any thread observing this will not be able to schedule a
178                         // task that can run before the initialization.
179                         // Also we can only transition out of this state while having the
180                         // initializer lock and having found an initializer.
181                         self.state.store(Self::STATE_READY, Ordering::Relaxed);
182                         return Ok(Self::STATE_READY);
183                     } else {
184                         // There is a chance that we just lost the race from state.load() to
185                         // grabbing the initializer mutex. If that is the case the state must
186                         // be EMPTY or READY after coming out of the lock. So we can give it
187                         // one more try.
188                         first_try = false;
189                         continue;
190                     }
191                 }
192                 (Self::STATE_UNINITIALIZED, false) => {
193                     // Okay, tough luck. The legacy loader was really completely uninitialized.
194                     return Err(Error::sys())
195                         .context(ks_err!("Legacy loader should not be called uninitialized."));
196                 }
197                 (Self::STATE_READY, _) => return Ok(Self::STATE_READY),
198                 (s, _) => panic!("Unknown legacy importer state. {} ", s),
199             }
200         }
201     }
202 
203     /// List all aliases for uid in the legacy database.
list_uid(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>>204     pub fn list_uid(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
205         let _wp = wd::watch("LegacyImporter::list_uid");
206 
207         let uid = match (domain, namespace) {
208             (Domain::APP, namespace) => namespace as u32,
209             (Domain::SELINUX, Self::WIFI_NAMESPACE) => Self::AID_WIFI,
210             _ => return Ok(Vec::new()),
211         };
212         self.do_serialized(move |state| state.list_uid(uid)).unwrap_or_else(|| Ok(Vec::new())).map(
213             |v| {
214                 v.into_iter()
215                     .map(|alias| KeyDescriptor {
216                         domain,
217                         nspace: namespace,
218                         alias: Some(alias),
219                         blob: None,
220                     })
221                     .collect()
222             },
223         )
224     }
225 
226     /// Sends the given closure to the importer thread for execution after calling check_state.
227     /// Returns None if the database was empty and the request was not executed.
228     /// Otherwise returns Some with the result produced by the import request.
229     /// The loader state may transition to STATE_EMPTY during the execution of this function.
do_serialized<F, T: Send + 'static>(&self, f: F) -> Option<Result<T>> where F: FnOnce(&mut LegacyImporterState) -> Result<T> + Send + 'static,230     fn do_serialized<F, T: Send + 'static>(&self, f: F) -> Option<Result<T>>
231     where
232         F: FnOnce(&mut LegacyImporterState) -> Result<T> + Send + 'static,
233     {
234         // Short circuit if the database is empty or not initialized (error case).
235         match self.check_state().context(ks_err!("Checking state.")) {
236             Ok(LegacyImporter::STATE_EMPTY) => return None,
237             Ok(LegacyImporter::STATE_READY) => {}
238             Err(e) => return Some(Err(e)),
239             Ok(s) => panic!("Unknown legacy importer state. {} ", s),
240         }
241 
242         // We have established that there may be a key in the legacy database.
243         // Now we schedule an import request.
244         let (sender, receiver) = channel();
245         self.async_task.queue_hi(move |shelf| {
246             // Get the importer state from the shelf.
247             // There may not be a state. This can happen if this import request was scheduled
248             // before a previous request established that the legacy database was empty
249             // and removed the state from the shelf. Since we know now that the database
250             // is empty, we can return None here.
251             let (new_state, result) = if let Some(legacy_importer_state) =
252                 shelf.get_downcast_mut::<LegacyImporterState>()
253             {
254                 let result = f(legacy_importer_state);
255                 (legacy_importer_state.check_empty(), Some(result))
256             } else {
257                 (Self::STATE_EMPTY, None)
258             };
259 
260             // If the import request determined that the database is now empty, we discard
261             // the state from the shelf to free up the resources we won't need any longer.
262             if result.is_some() && new_state == Self::STATE_EMPTY {
263                 shelf.remove_downcast_ref::<LegacyImporterState>();
264             }
265 
266             // Send the result to the requester.
267             if let Err(e) = sender.send((new_state, result)) {
268                 log::error!("In do_serialized. Error in sending the result. {:?}", e);
269             }
270         });
271 
272         let (new_state, result) = match receiver.recv() {
273             Err(e) => {
274                 return Some(Err(e).context(ks_err!("Failed to receive from the sender.")));
275             }
276             Ok(r) => r,
277         };
278 
279         // We can only transition to EMPTY but never back.
280         // The importer never creates any legacy blobs.
281         if new_state == Self::STATE_EMPTY {
282             self.state.store(Self::STATE_EMPTY, Ordering::Relaxed)
283         }
284 
285         result
286     }
287 
288     /// Runs the key_accessor function and returns its result. If it returns an error and the
289     /// root cause was KEY_NOT_FOUND, tries to import a key with the given parameters from
290     /// the legacy database to the new database and runs the key_accessor function again if
291     /// the import request was successful.
with_try_import<F, T>( &self, key: &KeyDescriptor, caller_uid: u32, super_key: Option<Arc<dyn AesGcm + Send + Sync>>, key_accessor: F, ) -> Result<T> where F: Fn() -> Result<T>,292     pub fn with_try_import<F, T>(
293         &self,
294         key: &KeyDescriptor,
295         caller_uid: u32,
296         super_key: Option<Arc<dyn AesGcm + Send + Sync>>,
297         key_accessor: F,
298     ) -> Result<T>
299     where
300         F: Fn() -> Result<T>,
301     {
302         let _wp = wd::watch("LegacyImporter::with_try_import");
303 
304         // Access the key and return on success.
305         match key_accessor() {
306             Ok(result) => return Ok(result),
307             Err(e) => match e.root_cause().downcast_ref::<Error>() {
308                 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => {}
309                 _ => return Err(e),
310             },
311         }
312 
313         // Filter inputs. We can only load legacy app domain keys and some special rules due
314         // to which we import keys transparently to an SELINUX domain.
315         let uid = match key {
316             KeyDescriptor { domain: Domain::APP, alias: Some(_), .. } => caller_uid,
317             KeyDescriptor { domain: Domain::SELINUX, nspace, alias: Some(_), .. } => {
318                 match *nspace {
319                     Self::WIFI_NAMESPACE => Self::AID_WIFI,
320                     _ => {
321                         return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
322                             .context(format!("No legacy keys for namespace {}", nspace))
323                     }
324                 }
325             }
326             _ => {
327                 return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
328                     .context("No legacy keys for key descriptor.")
329             }
330         };
331 
332         let key_clone = key.clone();
333         let result = self.do_serialized(move |importer_state| {
334             let super_key = super_key.map(|sk| -> Arc<dyn AesGcm> { sk });
335             importer_state.check_and_import(uid, key_clone, super_key)
336         });
337 
338         if let Some(result) = result {
339             result?;
340             // After successful import try again.
341             key_accessor()
342         } else {
343             Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context("Legacy database is empty.")
344         }
345     }
346 
347     /// Calls key_accessor and returns the result on success. In the case of a KEY_NOT_FOUND error
348     /// this function makes an import request and on success retries the key_accessor.
with_try_import_super_key<F, T>( &self, user_id: u32, pw: &Password, mut key_accessor: F, ) -> Result<Option<T>> where F: FnMut() -> Result<Option<T>>,349     pub fn with_try_import_super_key<F, T>(
350         &self,
351         user_id: u32,
352         pw: &Password,
353         mut key_accessor: F,
354     ) -> Result<Option<T>>
355     where
356         F: FnMut() -> Result<Option<T>>,
357     {
358         let _wp = wd::watch("LegacyImporter::with_try_import_super_key");
359 
360         match key_accessor() {
361             Ok(Some(result)) => return Ok(Some(result)),
362             Ok(None) => {}
363             Err(e) => return Err(e),
364         }
365         let pw = pw.try_clone().context(ks_err!("Cloning password."))?;
366         let result = self.do_serialized(move |importer_state| {
367             importer_state.check_and_import_super_key(user_id, &pw)
368         });
369 
370         if let Some(result) = result {
371             result?;
372             // After successful import try again.
373             key_accessor()
374         } else {
375             Ok(None)
376         }
377     }
378 
379     /// Deletes all keys belonging to the given namespace, importing them into the database
380     /// for subsequent garbage collection if necessary.
bulk_delete_uid(&self, domain: Domain, nspace: i64) -> Result<()>381     pub fn bulk_delete_uid(&self, domain: Domain, nspace: i64) -> Result<()> {
382         let _wp = wd::watch("LegacyImporter::bulk_delete_uid");
383 
384         let uid = match (domain, nspace) {
385             (Domain::APP, nspace) => nspace as u32,
386             (Domain::SELINUX, Self::WIFI_NAMESPACE) => Self::AID_WIFI,
387             // Nothing to do.
388             _ => return Ok(()),
389         };
390 
391         let result = self.do_serialized(move |importer_state| {
392             importer_state.bulk_delete(BulkDeleteRequest::Uid(uid), false)
393         });
394 
395         result.unwrap_or(Ok(()))
396     }
397 
398     /// Deletes all keys belonging to the given android user, importing them into the database
399     /// for subsequent garbage collection if necessary.
bulk_delete_user( &self, user_id: u32, keep_non_super_encrypted_keys: bool, ) -> Result<()>400     pub fn bulk_delete_user(
401         &self,
402         user_id: u32,
403         keep_non_super_encrypted_keys: bool,
404     ) -> Result<()> {
405         let _wp = wd::watch("LegacyImporter::bulk_delete_user");
406 
407         let result = self.do_serialized(move |importer_state| {
408             importer_state
409                 .bulk_delete(BulkDeleteRequest::User(user_id), keep_non_super_encrypted_keys)
410         });
411 
412         result.unwrap_or(Ok(()))
413     }
414 
415     /// Queries the legacy database for the presence of a super key for the given user.
has_super_key(&self, user_id: u32) -> Result<bool>416     pub fn has_super_key(&self, user_id: u32) -> Result<bool> {
417         let result =
418             self.do_serialized(move |importer_state| importer_state.has_super_key(user_id));
419         result.unwrap_or(Ok(false))
420     }
421 }
422 
423 impl LegacyImporterState {
get_km_uuid(&self, is_strongbox: bool) -> Result<Uuid>424     fn get_km_uuid(&self, is_strongbox: bool) -> Result<Uuid> {
425         let sec_level = if is_strongbox {
426             SecurityLevel::STRONGBOX
427         } else {
428             SecurityLevel::TRUSTED_ENVIRONMENT
429         };
430 
431         self.sec_level_to_km_uuid.get(&sec_level).copied().ok_or_else(|| {
432             anyhow::anyhow!(Error::sys()).context(ks_err!("No KM instance for blob."))
433         })
434     }
435 
list_uid(&mut self, uid: u32) -> Result<Vec<String>>436     fn list_uid(&mut self, uid: u32) -> Result<Vec<String>> {
437         self.legacy_loader
438             .list_keystore_entries_for_uid(uid)
439             .context("In list_uid: Trying to list legacy entries.")
440     }
441 
442     /// Checks if the key can potentially be unlocked. And deletes the key entry otherwise.
443     /// If the super_key has already been imported, the super key database id is returned.
get_super_key_id_check_unlockable_or_delete( &mut self, uid: u32, alias: &str, ) -> Result<i64>444     fn get_super_key_id_check_unlockable_or_delete(
445         &mut self,
446         uid: u32,
447         alias: &str,
448     ) -> Result<i64> {
449         let user_id = uid_to_android_user(uid);
450 
451         match self
452             .db
453             .load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, user_id)
454             .context(ks_err!("Failed to load super key"))?
455         {
456             Some((_, entry)) => Ok(entry.id()),
457             None => {
458                 // This might be the first time we access the super key,
459                 // and it may not have been imported. We cannot import
460                 // the legacy super_key key now, because we need to reencrypt
461                 // it which we cannot do if we are not unlocked, which we are
462                 // not because otherwise the key would have been imported.
463                 // We can check though if the key exists. If it does,
464                 // we can return Locked. Otherwise, we can delete the
465                 // key and return NotFound, because the key will never
466                 // be unlocked again.
467                 if self.legacy_loader.has_super_key(user_id) {
468                     Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!(
469                         "Cannot import super key of this key while user is locked."
470                     ))
471                 } else {
472                     self.legacy_loader
473                         .remove_keystore_entry(uid, alias)
474                         .context(ks_err!("Trying to remove obsolete key."))?;
475                     Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context(ks_err!("Obsolete key."))
476                 }
477             }
478         }
479     }
480 
characteristics_file_to_cache( &mut self, km_blob_params: Option<(Blob, LegacyKeyCharacteristics)>, super_key: &Option<Arc<dyn AesGcm>>, uid: u32, alias: &str, ) -> Result<(Option<(Blob, Vec<KeyParameter>)>, Option<(LegacyBlob<'static>, BlobMetaData)>)>481     fn characteristics_file_to_cache(
482         &mut self,
483         km_blob_params: Option<(Blob, LegacyKeyCharacteristics)>,
484         super_key: &Option<Arc<dyn AesGcm>>,
485         uid: u32,
486         alias: &str,
487     ) -> Result<(Option<(Blob, Vec<KeyParameter>)>, Option<(LegacyBlob<'static>, BlobMetaData)>)>
488     {
489         let (km_blob, params) = match km_blob_params {
490             Some((km_blob, LegacyKeyCharacteristics::File(params))) => (km_blob, params),
491             Some((km_blob, LegacyKeyCharacteristics::Cache(params))) => {
492                 return Ok((Some((km_blob, params)), None));
493             }
494             None => return Ok((None, None)),
495         };
496 
497         let km_uuid =
498             self.get_km_uuid(km_blob.is_strongbox()).context(ks_err!("Trying to get KM UUID"))?;
499 
500         let blob = match (&km_blob.value(), super_key.as_ref()) {
501             (BlobValue::Encrypted { iv, tag, data }, Some(super_key)) => {
502                 let blob =
503                     super_key.decrypt(data, iv, tag).context(ks_err!("Decryption failed."))?;
504                 LegacyBlob::ZVec(blob)
505             }
506             (BlobValue::Encrypted { .. }, None) => {
507                 return Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!(
508                     "Oh uh, so close. \
509                      This ancient key cannot be imported unless the user is unlocked."
510                 ));
511             }
512             (BlobValue::Decrypted(data), _) => LegacyBlob::Ref(data),
513             _ => {
514                 return Err(Error::sys()).context(ks_err!("Unexpected blob type."));
515             }
516         };
517 
518         let (km_params, upgraded_blob) = get_key_characteristics_without_app_data(&km_uuid, &blob)
519             .context(ks_err!("Failed to get key characteristics from device.",))?;
520 
521         let flags = km_blob.get_flags();
522 
523         let (current_blob, superseded_blob) =
524             if let Some(upgraded_blob) = upgraded_blob {
525                 match (km_blob.take_value(), super_key.as_ref()) {
526                     (BlobValue::Encrypted { iv, tag, data }, Some(super_key)) => {
527                         let super_key_id = self
528                             .get_super_key_id_check_unlockable_or_delete(uid, alias)
529                             .context(ks_err!("How is there a super key but no super key id?"))?;
530 
531                         let mut superseded_metadata = BlobMetaData::new();
532                         superseded_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
533                         superseded_metadata.add(BlobMetaEntry::AeadTag(tag.to_vec()));
534                         superseded_metadata
535                             .add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
536                         superseded_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
537                         let superseded_blob = (LegacyBlob::Vec(data), superseded_metadata);
538 
539                         let (data, iv, tag) = super_key
540                             .encrypt(&upgraded_blob)
541                             .context(ks_err!("Failed to encrypt upgraded key blob."))?;
542                         (
543                             Blob::new(flags, BlobValue::Encrypted { data, iv, tag }),
544                             Some(superseded_blob),
545                         )
546                     }
547                     (BlobValue::Encrypted { .. }, None) => {
548                         return Err(Error::sys()).context(ks_err!(
549                             "This should not be reachable. \
550                          The blob could not have been decrypted above."
551                         ));
552                     }
553                     (BlobValue::Decrypted(data), _) => {
554                         let mut superseded_metadata = BlobMetaData::new();
555                         superseded_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
556                         let superseded_blob = (LegacyBlob::ZVec(data), superseded_metadata);
557                         (
558                             Blob::new(
559                                 flags,
560                                 BlobValue::Decrypted(upgraded_blob.try_into().context(ks_err!(
561                                     "Failed to convert upgraded blob to ZVec."
562                                 ))?),
563                             ),
564                             Some(superseded_blob),
565                         )
566                     }
567                     _ => {
568                         return Err(Error::sys()).context(ks_err!(
569                             "This should not be reachable. \
570                          Any other variant should have resulted in a different error."
571                         ));
572                     }
573                 }
574             } else {
575                 (km_blob, None)
576             };
577 
578         let params =
579             augment_legacy_characteristics_file_with_key_characteristics(km_params, params);
580         Ok((Some((current_blob, params)), superseded_blob))
581     }
582 
583     /// This is a key import request that must run in the importer thread. This must
584     /// be passed to do_serialized.
check_and_import( &mut self, uid: u32, mut key: KeyDescriptor, super_key: Option<Arc<dyn AesGcm>>, ) -> Result<()>585     fn check_and_import(
586         &mut self,
587         uid: u32,
588         mut key: KeyDescriptor,
589         super_key: Option<Arc<dyn AesGcm>>,
590     ) -> Result<()> {
591         let alias = key.alias.clone().ok_or_else(|| {
592             anyhow::anyhow!(Error::sys()).context(ks_err!(
593                 "Must be Some because \
594                  our caller must not have called us otherwise."
595             ))
596         })?;
597 
598         if self.recently_imported.contains(&RecentImport::new(uid, alias.clone())) {
599             return Ok(());
600         }
601 
602         if key.domain == Domain::APP {
603             key.nspace = uid as i64;
604         }
605 
606         // If the key is not found in the cache, try to load from the legacy database.
607         let (km_blob_params, user_cert, ca_cert) = self
608             .legacy_loader
609             .load_by_uid_alias(uid, &alias, &super_key)
610             .map_err(|e| {
611                 if e.root_cause().downcast_ref::<legacy_blob::Error>()
612                     == Some(&legacy_blob::Error::LockedComponent)
613                 {
614                     // There is no chance to succeed at this point. We just check if there is
615                     // a super key so that this entry might be unlockable in the future.
616                     // If not the entry will be deleted and KEY_NOT_FOUND is returned.
617                     // If a super key id was returned we still have to return LOCKED but the key
618                     // may be imported when the user unlocks the device.
619                     self.get_super_key_id_check_unlockable_or_delete(uid, &alias)
620                         .and_then::<i64, _>(|_| {
621                             Err(Error::Rc(ResponseCode::LOCKED))
622                                 .context("Super key present but locked.")
623                         })
624                         .unwrap_err()
625                 } else {
626                     e
627                 }
628             })
629             .context(ks_err!("Trying to load legacy blob."))?;
630 
631         let (km_blob_params, superseded_blob) = self
632             .characteristics_file_to_cache(km_blob_params, &super_key, uid, &alias)
633             .context(ks_err!("Trying to update legacy characteristics."))?;
634 
635         let result = match km_blob_params {
636             Some((km_blob, params)) => {
637                 let is_strongbox = km_blob.is_strongbox();
638 
639                 let (blob, mut blob_metadata) = match km_blob.take_value() {
640                     BlobValue::Encrypted { iv, tag, data } => {
641                         // Get super key id for user id.
642                         let super_key_id = self
643                             .get_super_key_id_check_unlockable_or_delete(uid, &alias)
644                             .context(ks_err!("Failed to get super key id."))?;
645 
646                         let mut blob_metadata = BlobMetaData::new();
647                         blob_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
648                         blob_metadata.add(BlobMetaEntry::AeadTag(tag.to_vec()));
649                         blob_metadata
650                             .add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
651                         (LegacyBlob::Vec(data), blob_metadata)
652                     }
653                     BlobValue::Decrypted(data) => (LegacyBlob::ZVec(data), BlobMetaData::new()),
654                     _ => {
655                         return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
656                             .context(ks_err!("Legacy key has unexpected type."));
657                     }
658                 };
659 
660                 let km_uuid =
661                     self.get_km_uuid(is_strongbox).context(ks_err!("Trying to get KM UUID"))?;
662                 blob_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
663 
664                 let mut metadata = KeyMetaData::new();
665                 let creation_date =
666                     DateTime::now().context(ks_err!("Trying to make creation time."))?;
667                 metadata.add(KeyMetaEntry::CreationDate(creation_date));
668 
669                 let blob_info = BlobInfo::new_with_superseded(
670                     &blob,
671                     &blob_metadata,
672                     superseded_blob.as_ref().map(|(b, m)| (&**b, m)),
673                 );
674                 // Store legacy key in the database.
675                 self.db
676                     .store_new_key(
677                         &key,
678                         KeyType::Client,
679                         &params,
680                         &blob_info,
681                         &CertificateInfo::new(user_cert, ca_cert),
682                         &metadata,
683                         &km_uuid,
684                     )
685                     .context(ks_err!())?;
686                 Ok(())
687             }
688             None => {
689                 if let Some(ca_cert) = ca_cert {
690                     self.db
691                         .store_new_certificate(&key, KeyType::Client, &ca_cert, &KEYSTORE_UUID)
692                         .context(ks_err!("Failed to insert new certificate."))?;
693                     Ok(())
694                 } else {
695                     Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
696                         .context(ks_err!("Legacy key not found."))
697                 }
698             }
699         };
700 
701         match result {
702             Ok(()) => {
703                 // Add the key to the imported_keys list.
704                 self.recently_imported.insert(RecentImport::new(uid, alias.clone()));
705                 // Delete legacy key from the file system
706                 self.legacy_loader
707                     .remove_keystore_entry(uid, &alias)
708                     .context(ks_err!("Trying to remove imported key."))?;
709                 Ok(())
710             }
711             Err(e) => Err(e),
712         }
713     }
714 
check_and_import_super_key(&mut self, user_id: u32, pw: &Password) -> Result<()>715     fn check_and_import_super_key(&mut self, user_id: u32, pw: &Password) -> Result<()> {
716         if self.recently_imported_super_key.contains(&user_id) {
717             return Ok(());
718         }
719 
720         if let Some(super_key) = self
721             .legacy_loader
722             .load_super_key(user_id, pw)
723             .context(ks_err!("Trying to load legacy super key."))?
724         {
725             let (blob, blob_metadata) =
726                 crate::super_key::SuperKeyManager::encrypt_with_password(&super_key, pw)
727                     .context(ks_err!("Trying to encrypt super key."))?;
728 
729             self.db
730                 .store_super_key(
731                     user_id,
732                     &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
733                     &blob,
734                     &blob_metadata,
735                     &KeyMetaData::new(),
736                 )
737                 .context(ks_err!("Trying to insert legacy super_key into the database."))?;
738             self.legacy_loader.remove_super_key(user_id);
739             self.recently_imported_super_key.insert(user_id);
740             Ok(())
741         } else {
742             Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context(ks_err!("No key found do import."))
743         }
744     }
745 
746     /// Key importer request to be run by do_serialized.
747     /// See LegacyImporter::bulk_delete_uid and LegacyImporter::bulk_delete_user.
bulk_delete( &mut self, bulk_delete_request: BulkDeleteRequest, keep_non_super_encrypted_keys: bool, ) -> Result<()>748     fn bulk_delete(
749         &mut self,
750         bulk_delete_request: BulkDeleteRequest,
751         keep_non_super_encrypted_keys: bool,
752     ) -> Result<()> {
753         let (aliases, user_id) = match bulk_delete_request {
754             BulkDeleteRequest::Uid(uid) => (
755                 self.legacy_loader
756                     .list_keystore_entries_for_uid(uid)
757                     .context(ks_err!("Trying to get aliases for uid."))
758                     .map(|aliases| {
759                         let mut h = HashMap::<u32, HashSet<String>>::new();
760                         h.insert(uid, aliases.into_iter().collect());
761                         h
762                     })?,
763                 uid_to_android_user(uid),
764             ),
765             BulkDeleteRequest::User(user_id) => (
766                 self.legacy_loader
767                     .list_keystore_entries_for_user(user_id)
768                     .context(ks_err!("Trying to get aliases for user_id."))?,
769                 user_id,
770             ),
771         };
772 
773         let super_key_id = self
774             .db
775             .load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, user_id)
776             .context(ks_err!("Failed to load super key"))?
777             .map(|(_, entry)| entry.id());
778 
779         for (uid, alias) in aliases
780             .into_iter()
781             .flat_map(|(uid, aliases)| aliases.into_iter().map(move |alias| (uid, alias)))
782         {
783             let (km_blob_params, _, _) = self
784                 .legacy_loader
785                 .load_by_uid_alias(uid, &alias, &None)
786                 .context(ks_err!("Trying to load legacy blob."))?;
787 
788             // Determine if the key needs special handling to be deleted.
789             let (need_gc, is_super_encrypted) = km_blob_params
790                 .as_ref()
791                 .map(|(blob, params)| {
792                     let params = match params {
793                         LegacyKeyCharacteristics::Cache(params)
794                         | LegacyKeyCharacteristics::File(params) => params,
795                     };
796                     (
797                         params.iter().any(|kp| {
798                             KeyParameterValue::RollbackResistance == *kp.key_parameter_value()
799                         }),
800                         blob.is_encrypted(),
801                     )
802                 })
803                 .unwrap_or((false, false));
804 
805             if keep_non_super_encrypted_keys && !is_super_encrypted {
806                 continue;
807             }
808 
809             if need_gc {
810                 let mark_deleted = match km_blob_params
811                     .map(|(blob, _)| (blob.is_strongbox(), blob.take_value()))
812                 {
813                     Some((is_strongbox, BlobValue::Encrypted { iv, tag, data })) => {
814                         let mut blob_metadata = BlobMetaData::new();
815                         if let (Ok(km_uuid), Some(super_key_id)) =
816                             (self.get_km_uuid(is_strongbox), super_key_id)
817                         {
818                             blob_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
819                             blob_metadata.add(BlobMetaEntry::Iv(iv.to_vec()));
820                             blob_metadata.add(BlobMetaEntry::AeadTag(tag.to_vec()));
821                             blob_metadata
822                                 .add(BlobMetaEntry::EncryptedBy(EncryptedBy::KeyId(super_key_id)));
823                             Some((LegacyBlob::Vec(data), blob_metadata))
824                         } else {
825                             // Oh well - we tried our best, but if we cannot determine which
826                             // KeyMint instance we have to send this blob to, we cannot
827                             // do more than delete the key from the file system.
828                             // And if we don't know which key wraps this key we cannot
829                             // unwrap it for KeyMint either.
830                             None
831                         }
832                     }
833                     Some((_, BlobValue::Decrypted(data))) => {
834                         Some((LegacyBlob::ZVec(data), BlobMetaData::new()))
835                     }
836                     _ => None,
837                 };
838 
839                 if let Some((blob, blob_metadata)) = mark_deleted {
840                     self.db.set_deleted_blob(&blob, &blob_metadata).context(ks_err!(
841                         "Trying to insert deleted \
842                             blob into the database for garbage collection."
843                     ))?;
844                 }
845             }
846 
847             self.legacy_loader
848                 .remove_keystore_entry(uid, &alias)
849                 .context(ks_err!("Trying to remove imported key."))?;
850         }
851         Ok(())
852     }
853 
has_super_key(&mut self, user_id: u32) -> Result<bool>854     fn has_super_key(&mut self, user_id: u32) -> Result<bool> {
855         Ok(self.recently_imported_super_key.contains(&user_id)
856             || self.legacy_loader.has_super_key(user_id))
857     }
858 
check_empty(&self) -> u8859     fn check_empty(&self) -> u8 {
860         if self.legacy_loader.is_empty().unwrap_or(false) {
861             LegacyImporter::STATE_EMPTY
862         } else {
863             LegacyImporter::STATE_READY
864         }
865     }
866 }
867 
868 enum LegacyBlob<'a> {
869     Vec(Vec<u8>),
870     ZVec(ZVec),
871     Ref(&'a [u8]),
872 }
873 
874 impl Deref for LegacyBlob<'_> {
875     type Target = [u8];
876 
deref(&self) -> &Self::Target877     fn deref(&self) -> &Self::Target {
878         match self {
879             Self::Vec(v) => v,
880             Self::ZVec(v) => v,
881             Self::Ref(v) => v,
882         }
883     }
884 }
885 
886 /// This function takes two KeyParameter lists. The first is assumed to have been retrieved from the
887 /// KM back end using km_dev.getKeyCharacteristics. The second is assumed to have been retrieved
888 /// from a legacy key characteristics file (not cache) as used in Android P and older. The function
889 /// augments the former with entries from the latter only if no equivalent entry is present ignoring.
890 /// the security level of enforcement. All entries in the latter are assumed to have security level
891 /// KEYSTORE.
augment_legacy_characteristics_file_with_key_characteristics<T>( mut from_km: Vec<KeyParameter>, legacy: T, ) -> Vec<KeyParameter> where T: IntoIterator<Item = KeyParameter>,892 fn augment_legacy_characteristics_file_with_key_characteristics<T>(
893     mut from_km: Vec<KeyParameter>,
894     legacy: T,
895 ) -> Vec<KeyParameter>
896 where
897     T: IntoIterator<Item = KeyParameter>,
898 {
899     for legacy_kp in legacy.into_iter() {
900         if !from_km
901             .iter()
902             .any(|km_kp| km_kp.key_parameter_value() == legacy_kp.key_parameter_value())
903         {
904             from_km.push(legacy_kp);
905         }
906     }
907     from_km
908 }
909 
910 /// Attempts to retrieve the key characteristics for the given blob from the KM back end with the
911 /// given UUID. It may upgrade the key blob in the process. In that case the upgraded blob is
912 /// returned as the second tuple member.
get_key_characteristics_without_app_data( uuid: &Uuid, blob: &[u8], ) -> Result<(Vec<KeyParameter>, Option<Vec<u8>>)>913 fn get_key_characteristics_without_app_data(
914     uuid: &Uuid,
915     blob: &[u8],
916 ) -> Result<(Vec<KeyParameter>, Option<Vec<u8>>)> {
917     let (km_dev, info) = crate::globals::get_keymint_dev_by_uuid(uuid)
918         .with_context(|| ks_err!("Trying to get km device for id {:?}", uuid))?;
919 
920     let (characteristics, upgraded_blob) = upgrade_keyblob_if_required_with(
921         &*km_dev,
922         info.versionNumber,
923         blob,
924         &[],
925         |blob| {
926             let _wd = wd::watch("Calling GetKeyCharacteristics.");
927             map_km_error(km_dev.getKeyCharacteristics(blob, &[], &[]))
928         },
929         |_| Ok(()),
930     )
931     .context(ks_err!())?;
932     Ok((key_characteristics_to_internal(characteristics), upgraded_blob))
933 }
934