blob: 045f848e6f416f0d8de6e9c09ef161d2977e950d [file] [log] [blame]
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +00001// 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
Janis Danisevskisf84d0b02022-01-26 14:11:14 -080017use crate::database::{
18 BlobInfo, BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, EncryptedBy, KeyMetaData,
19 KeyMetaEntry, KeyType, KeystoreDB, Uuid, KEYSTORE_UUID,
Paul Crowley7a658392021-03-18 17:08:20 -070020};
Janis Danisevskisf84d0b02022-01-26 14:11:14 -080021use crate::error::{map_km_error, Error};
22use crate::key_parameter::{KeyParameter, KeyParameterValue};
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000023use crate::ks_err;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -080024use crate::legacy_blob::{self, Blob, BlobValue, LegacyKeyCharacteristics};
Eric Biggers673d34a2023-10-18 01:54:18 +000025use crate::super_key::USER_AFTER_FIRST_UNLOCK_SUPER_KEY;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -080026use crate::utils::{
27 key_characteristics_to_internal, uid_to_android_user, upgrade_keyblob_if_required_with,
28 watchdog as wd, AesGcm,
29};
30use crate::{async_task::AsyncTask, legacy_blob::LegacyBlobLoader};
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000031use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
32use android_system_keystore2::aidl::android::system::keystore2::{
33 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
34};
35use anyhow::{Context, Result};
36use core::ops::Deref;
Paul Crowleyf61fee72021-03-17 14:38:44 -070037use keystore2_crypto::{Password, ZVec};
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000038use std::collections::{HashMap, HashSet};
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000039use std::sync::atomic::{AtomicU8, Ordering};
40use std::sync::mpsc::channel;
41use std::sync::{Arc, Mutex};
42
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080043/// Represents LegacyImporter.
44pub struct LegacyImporter {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000045 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080056 /// expensive calls into the legacy importer when the legacy database is empty.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000057 /// 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)]
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080063struct RecentImport {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000064 uid: u32,
65 alias: String,
66}
67
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080068impl RecentImport {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000069 fn new(uid: u32, alias: String) -> Self {
70 Self { uid, alias }
71 }
72}
73
Janis Danisevskiseed69842021-02-18 20:04:10 -080074enum BulkDeleteRequest {
75 Uid(u32),
76 User(u32),
77}
78
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080079struct LegacyImporterState {
80 recently_imported: HashSet<RecentImport>,
81 recently_imported_super_key: HashSet<u32>,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000082 legacy_loader: Arc<LegacyBlobLoader>,
83 sec_level_to_km_uuid: HashMap<SecurityLevel, Uuid>,
84 db: KeystoreDB,
85}
86
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080087impl LegacyImporter {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000088 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -080095 /// Constructs a new LegacyImporter using the given AsyncTask object as import
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +000096 /// worker.
97 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
Nathan Huckleberry95dca012023-05-10 18:02:11 +0000105 #[cfg(test)]
106 pub fn set_empty(&mut self) {
107 self.state = AtomicU8::new(Self::STATE_EMPTY);
108 }
109
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800110 /// The legacy importer must be initialized deferred, because keystore starts very early.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000111 /// 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.
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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800135 /// 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
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000137 /// 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.
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800139 /// Returns Ok(STATE_READY) if an import request is worth undertaking and
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000140 /// Ok(STATE_EMPTY) if the database is empty. An error is returned if the loader
141 /// was not initialized and cannot be initialized.
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| {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800167 shelf.get_or_put_with(|| LegacyImporterState {
168 recently_imported: Default::default(),
169 recently_imported_super_key: Default::default(),
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000170 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.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000194 return Err(Error::sys())
195 .context(ks_err!("Legacy loader should not be called uninitialized."));
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000196 }
197 (Self::STATE_READY, _) => return Ok(Self::STATE_READY),
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800198 (s, _) => panic!("Unknown legacy importer state. {} ", s),
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000199 }
200 }
201 }
202
203 /// List all aliases for uid in the legacy database.
204 pub fn list_uid(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
David Drysdale541846b2024-05-23 13:16:07 +0100205 let _wp = wd::watch("LegacyImporter::list_uid");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700206
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000207 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800226 /// Sends the given closure to the importer thread for execution after calling check_state.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000227 /// Returns None if the database was empty and the request was not executed.
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800228 /// Otherwise returns Some with the result produced by the import request.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000229 /// The loader state may transition to STATE_EMPTY during the execution of this function.
230 fn do_serialized<F, T: Send + 'static>(&self, f: F) -> Option<Result<T>>
231 where
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800232 F: FnOnce(&mut LegacyImporterState) -> Result<T> + Send + 'static,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000233 {
234 // Short circuit if the database is empty or not initialized (error case).
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000235 match self.check_state().context(ks_err!("Checking state.")) {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800236 Ok(LegacyImporter::STATE_EMPTY) => return None,
237 Ok(LegacyImporter::STATE_READY) => {}
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000238 Err(e) => return Some(Err(e)),
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800239 Ok(s) => panic!("Unknown legacy importer state. {} ", s),
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000240 }
241
242 // We have established that there may be a key in the legacy database.
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800243 // Now we schedule an import request.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000244 let (sender, receiver) = channel();
245 self.async_task.queue_hi(move |shelf| {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800246 // Get the importer state from the shelf.
247 // There may not be a state. This can happen if this import request was scheduled
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000248 // 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.
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800251 let (new_state, result) = if let Some(legacy_importer_state) =
252 shelf.get_downcast_mut::<LegacyImporterState>()
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000253 {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800254 let result = f(legacy_importer_state);
255 (legacy_importer_state.check_empty(), Some(result))
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000256 } else {
257 (Self::STATE_EMPTY, None)
258 };
259
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800260 // If the import request determined that the database is now empty, we discard
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000261 // 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 {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800263 shelf.remove_downcast_ref::<LegacyImporterState>();
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000264 }
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) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000274 return Some(Err(e).context(ks_err!("Failed to receive from the sender.")));
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000275 }
276 Ok(r) => r,
277 };
278
279 // We can only transition to EMPTY but never back.
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800280 // The importer never creates any legacy blobs.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000281 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800289 /// root cause was KEY_NOT_FOUND, tries to import a key with the given parameters from
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000290 /// the legacy database to the new database and runs the key_accessor function again if
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800291 /// the import request was successful.
292 pub fn with_try_import<F, T>(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000293 &self,
294 key: &KeyDescriptor,
295 caller_uid: u32,
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800296 super_key: Option<Arc<dyn AesGcm + Send + Sync>>,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000297 key_accessor: F,
298 ) -> Result<T>
299 where
300 F: Fn() -> Result<T>,
301 {
David Drysdale541846b2024-05-23 13:16:07 +0100302 let _wp = wd::watch("LegacyImporter::with_try_import");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700303
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000304 // 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800314 // to which we import keys transparently to an SELINUX domain.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000315 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();
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800333 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 });
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000337
338 if let Some(result) = result {
339 result?;
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800340 // After successful import try again.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000341 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800348 /// this function makes an import request and on success retries the key_accessor.
349 pub fn with_try_import_super_key<F, T>(
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000350 &self,
351 user_id: u32,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700352 pw: &Password,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000353 mut key_accessor: F,
354 ) -> Result<Option<T>>
355 where
356 F: FnMut() -> Result<Option<T>>,
357 {
David Drysdale541846b2024-05-23 13:16:07 +0100358 let _wp = wd::watch("LegacyImporter::with_try_import_super_key");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700359
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000360 match key_accessor() {
361 Ok(Some(result)) => return Ok(Some(result)),
362 Ok(None) => {}
363 Err(e) => return Err(e),
364 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000365 let pw = pw.try_clone().context(ks_err!("Cloning password."))?;
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800366 let result = self.do_serialized(move |importer_state| {
367 importer_state.check_and_import_super_key(user_id, &pw)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000368 });
369
370 if let Some(result) = result {
371 result?;
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800372 // After successful import try again.
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000373 key_accessor()
374 } else {
375 Ok(None)
376 }
377 }
378
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800379 /// Deletes all keys belonging to the given namespace, importing them into the database
Janis Danisevskiseed69842021-02-18 20:04:10 -0800380 /// for subsequent garbage collection if necessary.
Janis Danisevskisddd6e752021-02-22 18:46:55 -0800381 pub fn bulk_delete_uid(&self, domain: Domain, nspace: i64) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +0100382 let _wp = wd::watch("LegacyImporter::bulk_delete_uid");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700383
Janis Danisevskisddd6e752021-02-22 18:46:55 -0800384 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
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800391 let result = self.do_serialized(move |importer_state| {
392 importer_state.bulk_delete(BulkDeleteRequest::Uid(uid), false)
Janis Danisevskiseed69842021-02-18 20:04:10 -0800393 });
394
395 result.unwrap_or(Ok(()))
396 }
397
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800398 /// Deletes all keys belonging to the given android user, importing them into the database
Janis Danisevskiseed69842021-02-18 20:04:10 -0800399 /// for subsequent garbage collection if necessary.
400 pub fn bulk_delete_user(
401 &self,
402 user_id: u32,
403 keep_non_super_encrypted_keys: bool,
404 ) -> Result<()> {
David Drysdale541846b2024-05-23 13:16:07 +0100405 let _wp = wd::watch("LegacyImporter::bulk_delete_user");
Janis Danisevskis850d4862021-05-05 08:41:14 -0700406
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800407 let result = self.do_serialized(move |importer_state| {
408 importer_state
Janis Danisevskiseed69842021-02-18 20:04:10 -0800409 .bulk_delete(BulkDeleteRequest::User(user_id), keep_non_super_encrypted_keys)
410 });
411
412 result.unwrap_or(Ok(()))
413 }
414
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000415 /// Queries the legacy database for the presence of a super key for the given user.
416 pub fn has_super_key(&self, user_id: u32) -> Result<bool> {
417 let result =
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800418 self.do_serialized(move |importer_state| importer_state.has_super_key(user_id));
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000419 result.unwrap_or(Ok(false))
420 }
421}
422
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800423impl LegacyImporterState {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000424 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(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000432 anyhow::anyhow!(Error::sys()).context(ks_err!("No KM instance for blob."))
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000433 })
434 }
435
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
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800442 /// 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.
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
Eric Biggers673d34a2023-10-18 01:54:18 +0000453 .load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, user_id)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000454 .context(ks_err!("Failed to load super key"))?
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800455 {
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) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000468 Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!(
469 "Cannot import super key of this key while user is locked."
470 ))
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800471 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000472 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."))
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800476 }
477 }
478 }
479 }
480
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))) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000492 return Ok((Some((km_blob, params)), None));
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800493 }
494 None => return Ok((None, None)),
495 };
496
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000497 let km_uuid =
498 self.get_km_uuid(km_blob.is_strongbox()).context(ks_err!("Trying to get KM UUID"))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800499
500 let blob = match (&km_blob.value(), super_key.as_ref()) {
501 (BlobValue::Encrypted { iv, tag, data }, Some(super_key)) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000502 let blob =
503 super_key.decrypt(data, iv, tag).context(ks_err!("Decryption failed."))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800504 LegacyBlob::ZVec(blob)
505 }
506 (BlobValue::Encrypted { .. }, None) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000507 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 ));
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800511 }
512 (BlobValue::Decrypted(data), _) => LegacyBlob::Ref(data),
513 _ => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000514 return Err(Error::sys()).context(ks_err!("Unexpected blob type."));
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800515 }
516 };
517
Chris Wailesdabb6fe2022-11-16 15:56:19 -0800518 let (km_params, upgraded_blob) = get_key_characteristics_without_app_data(&km_uuid, &blob)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000519 .context(ks_err!("Failed to get key characteristics from device.",))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800520
521 let flags = km_blob.get_flags();
522
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000523 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?"))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800530
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000531 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);
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800538
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000539 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 }
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800573 }
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000574 } else {
575 (km_blob, None)
576 };
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800577
578 let params =
579 augment_legacy_characteristics_file_with_key_characteristics(km_params, params);
580 Ok((Some((current_blob, params)), superseded_blob))
581 }
582
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800583 /// This is a key import request that must run in the importer thread. This must
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000584 /// be passed to do_serialized.
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800585 fn check_and_import(
586 &mut self,
587 uid: u32,
588 mut key: KeyDescriptor,
589 super_key: Option<Arc<dyn AesGcm>>,
590 ) -> Result<()> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000591 let alias = key.alias.clone().ok_or_else(|| {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000592 anyhow::anyhow!(Error::sys()).context(ks_err!(
593 "Must be Some because \
594 our caller must not have called us otherwise."
595 ))
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000596 })?;
597
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800598 if self.recently_imported.contains(&RecentImport::new(uid, alias.clone())) {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000599 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
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800609 .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 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000629 .context(ks_err!("Trying to load legacy blob."))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800630
631 let (km_blob_params, superseded_blob) = self
632 .characteristics_file_to_cache(km_blob_params, &super_key, uid, &alias)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000633 .context(ks_err!("Trying to update legacy characteristics."))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800634
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000635 let result = match km_blob_params {
636 Some((km_blob, params)) => {
637 let is_strongbox = km_blob.is_strongbox();
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800638
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000639 let (blob, mut blob_metadata) = match km_blob.take_value() {
640 BlobValue::Encrypted { iv, tag, data } => {
641 // Get super key id for user id.
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800642 let super_key_id = self
643 .get_super_key_id_check_unlockable_or_delete(uid, &alias)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000644 .context(ks_err!("Failed to get super key id."))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000645
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))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000656 .context(ks_err!("Legacy key has unexpected type."));
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000657 }
658 };
659
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000660 let km_uuid =
661 self.get_km_uuid(is_strongbox).context(ks_err!("Trying to get KM UUID"))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000662 blob_metadata.add(BlobMetaEntry::KmUuid(km_uuid));
663
664 let mut metadata = KeyMetaData::new();
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000665 let creation_date =
666 DateTime::now().context(ks_err!("Trying to make creation time."))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000667 metadata.add(KeyMetaEntry::CreationDate(creation_date));
668
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800669 let blob_info = BlobInfo::new_with_superseded(
670 &blob,
671 &blob_metadata,
672 superseded_blob.as_ref().map(|(b, m)| (&**b, m)),
673 );
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000674 // Store legacy key in the database.
675 self.db
676 .store_new_key(
677 &key,
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700678 KeyType::Client,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000679 &params,
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800680 &blob_info,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000681 &CertificateInfo::new(user_cert, ca_cert),
682 &metadata,
683 &km_uuid,
684 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000685 .context(ks_err!())?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000686 Ok(())
687 }
688 None => {
689 if let Some(ca_cert) = ca_cert {
690 self.db
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700691 .store_new_certificate(&key, KeyType::Client, &ca_cert, &KEYSTORE_UUID)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000692 .context(ks_err!("Failed to insert new certificate."))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000693 Ok(())
694 } else {
695 Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000696 .context(ks_err!("Legacy key not found."))
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000697 }
698 }
699 };
700
701 match result {
702 Ok(()) => {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800703 // Add the key to the imported_keys list.
704 self.recently_imported.insert(RecentImport::new(uid, alias.clone()));
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000705 // Delete legacy key from the file system
706 self.legacy_loader
707 .remove_keystore_entry(uid, &alias)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000708 .context(ks_err!("Trying to remove imported key."))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000709 Ok(())
710 }
711 Err(e) => Err(e),
712 }
713 }
714
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800715 fn check_and_import_super_key(&mut self, user_id: u32, pw: &Password) -> Result<()> {
716 if self.recently_imported_super_key.contains(&user_id) {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000717 return Ok(());
718 }
719
720 if let Some(super_key) = self
721 .legacy_loader
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700722 .load_super_key(user_id, pw)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000723 .context(ks_err!("Trying to load legacy super key."))?
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000724 {
725 let (blob, blob_metadata) =
Paul Crowleyf61fee72021-03-17 14:38:44 -0700726 crate::super_key::SuperKeyManager::encrypt_with_password(&super_key, pw)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000727 .context(ks_err!("Trying to encrypt super key."))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000728
Paul Crowley8d5b2532021-03-19 10:53:07 -0700729 self.db
730 .store_super_key(
731 user_id,
Eric Biggers673d34a2023-10-18 01:54:18 +0000732 &USER_AFTER_FIRST_UNLOCK_SUPER_KEY,
Paul Crowley8d5b2532021-03-19 10:53:07 -0700733 &blob,
734 &blob_metadata,
735 &KeyMetaData::new(),
736 )
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000737 .context(ks_err!("Trying to insert legacy super_key into the database."))?;
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000738 self.legacy_loader.remove_super_key(user_id);
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800739 self.recently_imported_super_key.insert(user_id);
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000740 Ok(())
741 } else {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000742 Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context(ks_err!("No key found do import."))
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000743 }
744 }
745
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800746 /// Key importer request to be run by do_serialized.
747 /// See LegacyImporter::bulk_delete_uid and LegacyImporter::bulk_delete_user.
Janis Danisevskiseed69842021-02-18 20:04:10 -0800748 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)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000757 .context(ks_err!("Trying to get aliases for uid."))
Janis Danisevskiseed69842021-02-18 20:04:10 -0800758 .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)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000768 .context(ks_err!("Trying to get aliases for user_id."))?,
Janis Danisevskiseed69842021-02-18 20:04:10 -0800769 user_id,
770 ),
771 };
772
773 let super_key_id = self
774 .db
Eric Biggers673d34a2023-10-18 01:54:18 +0000775 .load_super_key(&USER_AFTER_FIRST_UNLOCK_SUPER_KEY, user_id)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000776 .context(ks_err!("Failed to load super key"))?
Janis Danisevskiseed69842021-02-18 20:04:10 -0800777 .map(|(_, entry)| entry.id());
778
779 for (uid, alias) in aliases
780 .into_iter()
Chariseea1e1c482022-02-26 01:26:35 +0000781 .flat_map(|(uid, aliases)| aliases.into_iter().map(move |alias| (uid, alias)))
Janis Danisevskiseed69842021-02-18 20:04:10 -0800782 {
783 let (km_blob_params, _, _) = self
784 .legacy_loader
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800785 .load_by_uid_alias(uid, &alias, &None)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000786 .context(ks_err!("Trying to load legacy blob."))?;
Janis Danisevskiseed69842021-02-18 20:04:10 -0800787
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)| {
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800792 let params = match params {
793 LegacyKeyCharacteristics::Cache(params)
794 | LegacyKeyCharacteristics::File(params) => params,
795 };
Janis Danisevskiseed69842021-02-18 20:04:10 -0800796 (
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 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000840 self.db.set_deleted_blob(&blob, &blob_metadata).context(ks_err!(
841 "Trying to insert deleted \
842 blob into the database for garbage collection."
Janis Danisevskiseed69842021-02-18 20:04:10 -0800843 ))?;
844 }
845 }
846
847 self.legacy_loader
848 .remove_keystore_entry(uid, &alias)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000849 .context(ks_err!("Trying to remove imported key."))?;
Janis Danisevskiseed69842021-02-18 20:04:10 -0800850 }
851 Ok(())
852 }
853
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000854 fn has_super_key(&mut self, user_id: u32) -> Result<bool> {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800855 Ok(self.recently_imported_super_key.contains(&user_id)
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000856 || self.legacy_loader.has_super_key(user_id))
857 }
858
859 fn check_empty(&self) -> u8 {
860 if self.legacy_loader.is_empty().unwrap_or(false) {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800861 LegacyImporter::STATE_EMPTY
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000862 } else {
Janis Danisevskis0ffb8a82022-02-06 22:37:21 -0800863 LegacyImporter::STATE_READY
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000864 }
865 }
866}
867
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800868enum LegacyBlob<'a> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000869 Vec(Vec<u8>),
870 ZVec(ZVec),
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800871 Ref(&'a [u8]),
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000872}
873
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800874impl Deref for LegacyBlob<'_> {
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000875 type Target = [u8];
876
877 fn deref(&self) -> &Self::Target {
878 match self {
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700879 Self::Vec(v) => v,
880 Self::ZVec(v) => v,
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800881 Self::Ref(v) => v,
Hasini Gunasinghe3ed5da72021-02-04 15:18:54 +0000882 }
883 }
884}
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800885
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.
892fn augment_legacy_characteristics_file_with_key_characteristics<T>(
893 mut from_km: Vec<KeyParameter>,
894 legacy: T,
895) -> Vec<KeyParameter>
896where
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.
913fn get_key_characteristics_without_app_data(
914 uuid: &Uuid,
915 blob: &[u8],
916) -> Result<(Vec<KeyParameter>, Option<Vec<u8>>)> {
David Drysdale5accbaa2023-04-12 18:47:10 +0100917 let (km_dev, info) = crate::globals::get_keymint_dev_by_uuid(uuid)
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000918 .with_context(|| ks_err!("Trying to get km device for id {:?}", uuid))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800919
920 let (characteristics, upgraded_blob) = upgrade_keyblob_if_required_with(
921 &*km_dev,
David Drysdale5accbaa2023-04-12 18:47:10 +0100922 info.versionNumber,
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800923 blob,
924 &[],
925 |blob| {
David Drysdale541846b2024-05-23 13:16:07 +0100926 let _wd = wd::watch("Calling GetKeyCharacteristics.");
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800927 map_km_error(km_dev.getKeyCharacteristics(blob, &[], &[]))
928 },
929 |_| Ok(()),
930 )
Shaquille Johnsona820ef52024-06-20 13:48:23 +0000931 .context(ks_err!("getKeyCharacteristics failed: possibly invalid keyblob for uuid {uuid:?}"))?;
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800932 Ok((key_characteristics_to_internal(characteristics), upgraded_blob))
933}