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