• 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 //! Provide the [`KeyMintDevice`] wrapper for operating directly on a KeyMint device.
16 
17 use crate::{
18     database::{
19         BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, KeyEntry, KeyEntryLoadBits,
20         KeyIdGuard, KeyMetaData, KeyMetaEntry, KeyType, KeystoreDB, SubComponentType, Uuid,
21     },
22     error::{map_km_error, Error, ErrorCode},
23     globals::get_keymint_device,
24     super_key::KeyBlob,
25     utils::{key_characteristics_to_internal, watchdog as wd, AID_KEYSTORE},
26 };
27 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
28     HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice,
29     IKeyMintOperation::IKeyMintOperation, KeyCharacteristics::KeyCharacteristics,
30     KeyCreationResult::KeyCreationResult, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
31     SecurityLevel::SecurityLevel,
32 };
33 use android_system_keystore2::aidl::android::system::keystore2::{
34     Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
35 };
36 use anyhow::{Context, Result};
37 use binder::Strong;
38 
39 /// Wrapper for operating directly on a KeyMint device.
40 /// These methods often mirror methods in [`crate::security_level`]. However
41 /// the functions in [`crate::security_level`] make assumptions that hold, and has side effects
42 /// that make sense, only if called by an external client through binder.
43 /// In addition we are trying to maintain a separation between interface services
44 /// so that the architecture is compatible with a future move to multiple thread pools.
45 /// So the simplest approach today is to write new implementations of them for internal use.
46 /// Because these methods run very early, we don't even try to cooperate with
47 /// the operation slot database; we assume there will be plenty of slots.
48 pub struct KeyMintDevice {
49     km_dev: Strong<dyn IKeyMintDevice>,
50     km_uuid: Uuid,
51     version: i32,
52     security_level: SecurityLevel,
53 }
54 
55 impl KeyMintDevice {
56     /// Version number of KeyMasterDevice@V4_0
57     pub const KEY_MASTER_V4_0: i32 = 40;
58     /// Version number of KeyMasterDevice@V4_1
59     pub const KEY_MASTER_V4_1: i32 = 41;
60     /// Version number of KeyMintDevice@V1
61     pub const KEY_MINT_V1: i32 = 100;
62 
63     /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
get(security_level: SecurityLevel) -> Result<KeyMintDevice>64     pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
65         let (asp, hw_info, km_uuid) = get_keymint_device(&security_level)
66             .context("In KeyMintDevice::get: get_keymint_device failed")?;
67 
68         Ok(KeyMintDevice {
69             km_dev: asp.get_interface()?,
70             km_uuid,
71             version: hw_info.versionNumber,
72             security_level: hw_info.securityLevel,
73         })
74     }
75 
76     /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`], return
77     /// [`None`] if the error `HARDWARE_TYPE_UNAVAILABLE` is returned
get_or_none(security_level: SecurityLevel) -> Result<Option<KeyMintDevice>>78     pub fn get_or_none(security_level: SecurityLevel) -> Result<Option<KeyMintDevice>> {
79         KeyMintDevice::get(security_level).map(Some).or_else(|e| {
80             match e.root_cause().downcast_ref::<Error>() {
81                 Some(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)) => Ok(None),
82                 _ => Err(e),
83             }
84         })
85     }
86 
87     /// Returns the version of the underlying KeyMint/KeyMaster device.
version(&self) -> i3288     pub fn version(&self) -> i32 {
89         self.version
90     }
91 
92     /// Returns the self advertised security level of the KeyMint device.
93     /// This may differ from the requested security level if the best security level
94     /// on the device is Software.
security_level(&self) -> SecurityLevel95     pub fn security_level(&self) -> SecurityLevel {
96         self.security_level
97     }
98 
99     /// Create a KM key and store in the database.
create_and_store_key<F>( &self, db: &mut KeystoreDB, key_desc: &KeyDescriptor, key_type: KeyType, creator: F, ) -> Result<()> where F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,100     pub fn create_and_store_key<F>(
101         &self,
102         db: &mut KeystoreDB,
103         key_desc: &KeyDescriptor,
104         key_type: KeyType,
105         creator: F,
106     ) -> Result<()>
107     where
108         F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,
109     {
110         let creation_result = map_km_error(creator(&self.km_dev))
111             .context("In create_and_store_key: creator failed")?;
112         let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
113 
114         let creation_date =
115             DateTime::now().context("In create_and_store_key: DateTime::now() failed")?;
116 
117         let mut key_metadata = KeyMetaData::new();
118         key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
119         let mut blob_metadata = BlobMetaData::new();
120         blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
121 
122         db.store_new_key(
123             &key_desc,
124             key_type,
125             &key_parameters,
126             &(&creation_result.keyBlob, &blob_metadata),
127             &CertificateInfo::new(None, None),
128             &key_metadata,
129             &self.km_uuid,
130         )
131         .context("In create_and_store_key: store_new_key failed")?;
132         Ok(())
133     }
134 
135     /// Generate a KeyDescriptor for internal-use keys.
internal_descriptor(alias: String) -> KeyDescriptor136     pub fn internal_descriptor(alias: String) -> KeyDescriptor {
137         KeyDescriptor {
138             domain: Domain::APP,
139             nspace: AID_KEYSTORE as i64,
140             alias: Some(alias),
141             blob: None,
142         }
143     }
144 
145     /// Look up an internal-use key in the database given a key descriptor.
lookup_from_desc( db: &mut KeystoreDB, key_desc: &KeyDescriptor, key_type: KeyType, ) -> Result<(KeyIdGuard, KeyEntry)>146     fn lookup_from_desc(
147         db: &mut KeystoreDB,
148         key_desc: &KeyDescriptor,
149         key_type: KeyType,
150     ) -> Result<(KeyIdGuard, KeyEntry)> {
151         db.load_key_entry(&key_desc, key_type, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| Ok(()))
152             .context("In lookup_from_desc: load_key_entry failed.")
153     }
154 
155     /// Look up the key in the database, and return None if it is absent.
not_found_is_none( lookup: Result<(KeyIdGuard, KeyEntry)>, ) -> Result<Option<(KeyIdGuard, KeyEntry)>>156     fn not_found_is_none(
157         lookup: Result<(KeyIdGuard, KeyEntry)>,
158     ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
159         match lookup {
160             Ok(result) => Ok(Some(result)),
161             Err(e) => match e.root_cause().downcast_ref::<Error>() {
162                 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
163                 _ => Err(e),
164             },
165         }
166     }
167 
168     /// This does the lookup and store in separate transactions; caller must
169     /// hold a lock before calling.
lookup_or_generate_key<F>( &self, db: &mut KeystoreDB, key_desc: &KeyDescriptor, key_type: KeyType, params: &[KeyParameter], validate_characteristics: F, ) -> Result<(KeyIdGuard, KeyBlob)> where F: FnOnce(&[KeyCharacteristics]) -> bool,170     pub fn lookup_or_generate_key<F>(
171         &self,
172         db: &mut KeystoreDB,
173         key_desc: &KeyDescriptor,
174         key_type: KeyType,
175         params: &[KeyParameter],
176         validate_characteristics: F,
177     ) -> Result<(KeyIdGuard, KeyBlob)>
178     where
179         F: FnOnce(&[KeyCharacteristics]) -> bool,
180     {
181         // We use a separate transaction for the lookup than for the store
182         // - to keep the code simple
183         // - because the caller needs to hold a lock in any case
184         // - because it avoids holding database locks during slow
185         //   KeyMint operations
186         let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc, key_type))
187             .context("In lookup_or_generate_key: first lookup failed")?;
188 
189         if let Some((key_id_guard, mut key_entry)) = lookup {
190             // If the key is associated with a different km instance
191             // or if there is no blob metadata for some reason the key entry
192             // is considered corrupted and needs to be replaced with a new one.
193             let key_blob = key_entry.take_key_blob_info().and_then(|(key_blob, blob_metadata)| {
194                 if Some(&self.km_uuid) == blob_metadata.km_uuid() {
195                     Some(key_blob)
196                 } else {
197                     None
198                 }
199             });
200 
201             if let Some(key_blob_vec) = key_blob {
202                 let (key_characteristics, key_blob) = self
203                     .upgrade_keyblob_if_required_with(
204                         db,
205                         &key_id_guard,
206                         KeyBlob::NonSensitive(key_blob_vec),
207                         |key_blob| {
208                             map_km_error({
209                                 let _wp = wd::watch_millis(
210                                     concat!(
211                                         "In KeyMintDevice::lookup_or_generate_key: ",
212                                         "calling getKeyCharacteristics."
213                                     ),
214                                     500,
215                                 );
216                                 self.km_dev.getKeyCharacteristics(key_blob, &[], &[])
217                             })
218                         },
219                     )
220                     .context("In lookup_or_generate_key: calling getKeyCharacteristics")?;
221 
222                 if validate_characteristics(&key_characteristics) {
223                     return Ok((key_id_guard, key_blob));
224                 }
225 
226                 // If this point is reached the existing key is considered outdated or corrupted
227                 // in some way. It will be replaced with a new key below.
228             };
229         }
230 
231         self.create_and_store_key(db, &key_desc, key_type, |km_dev| {
232             km_dev.generateKey(&params, None)
233         })
234         .context("In lookup_or_generate_key: generate_and_store_key failed")?;
235         Self::lookup_from_desc(db, key_desc, key_type)
236             .and_then(|(key_id_guard, mut key_entry)| {
237                 Ok((
238                     key_id_guard,
239                     key_entry
240                         .take_key_blob_info()
241                         .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
242                         .map(|(key_blob, _)| KeyBlob::NonSensitive(key_blob))
243                         .context("Missing key blob info.")?,
244                 ))
245             })
246             .context("In lookup_or_generate_key: second lookup failed")
247     }
248 
249     /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
250     /// write the upgraded key to the database.
upgrade_keyblob_if_required_with<'a, T, F>( &self, db: &mut KeystoreDB, key_id_guard: &KeyIdGuard, key_blob: KeyBlob<'a>, f: F, ) -> Result<(T, KeyBlob<'a>)> where F: Fn(&[u8]) -> Result<T, Error>,251     fn upgrade_keyblob_if_required_with<'a, T, F>(
252         &self,
253         db: &mut KeystoreDB,
254         key_id_guard: &KeyIdGuard,
255         key_blob: KeyBlob<'a>,
256         f: F,
257     ) -> Result<(T, KeyBlob<'a>)>
258     where
259         F: Fn(&[u8]) -> Result<T, Error>,
260     {
261         match f(&key_blob) {
262             Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
263                 let upgraded_blob = map_km_error({
264                     let _wp = wd::watch_millis(
265                         "In KeyMintDevice::upgrade_keyblob_if_required_with: calling upgradeKey.",
266                         500,
267                     );
268                     self.km_dev.upgradeKey(&key_blob, &[])
269                 })
270                 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
271 
272                 let mut new_blob_metadata = BlobMetaData::new();
273                 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
274 
275                 db.set_blob(
276                     key_id_guard,
277                     SubComponentType::KEY_BLOB,
278                     Some(&upgraded_blob),
279                     Some(&new_blob_metadata),
280                 )
281                 .context(concat!(
282                     "In upgrade_keyblob_if_required_with: ",
283                     "Failed to insert upgraded blob into the database"
284                 ))?;
285 
286                 Ok((
287                     f(&upgraded_blob).context(
288                         "In upgrade_keyblob_if_required_with: Closure failed after upgrade",
289                     )?,
290                     KeyBlob::NonSensitive(upgraded_blob),
291                 ))
292             }
293             result => Ok((
294                 result.context("In upgrade_keyblob_if_required_with: Closure failed")?,
295                 key_blob,
296             )),
297         }
298     }
299 
300     /// Use the created key in an operation that can be done with
301     /// a call to begin followed by a call to finish.
302     #[allow(clippy::too_many_arguments)]
use_key_in_one_step( &self, db: &mut KeystoreDB, key_id_guard: &KeyIdGuard, key_blob: &[u8], purpose: KeyPurpose, operation_parameters: &[KeyParameter], auth_token: Option<&HardwareAuthToken>, input: &[u8], ) -> Result<Vec<u8>>303     pub fn use_key_in_one_step(
304         &self,
305         db: &mut KeystoreDB,
306         key_id_guard: &KeyIdGuard,
307         key_blob: &[u8],
308         purpose: KeyPurpose,
309         operation_parameters: &[KeyParameter],
310         auth_token: Option<&HardwareAuthToken>,
311         input: &[u8],
312     ) -> Result<Vec<u8>> {
313         let key_blob = KeyBlob::Ref(key_blob);
314 
315         let (begin_result, _) = self
316             .upgrade_keyblob_if_required_with(db, key_id_guard, key_blob, |blob| {
317                 map_km_error({
318                     let _wp = wd::watch_millis("In use_key_in_one_step: calling: begin", 500);
319                     self.km_dev.begin(purpose, blob, operation_parameters, auth_token)
320                 })
321             })
322             .context("In use_key_in_one_step: Failed to begin operation.")?;
323         let operation: Strong<dyn IKeyMintOperation> = begin_result
324             .operation
325             .ok_or_else(Error::sys)
326             .context("In use_key_in_one_step: Operation missing")?;
327         map_km_error({
328             let _wp = wd::watch_millis("In use_key_in_one_step: calling: finish", 500);
329             operation.finish(Some(input), None, None, None, None)
330         })
331         .context("In use_key_in_one_step: Failed to finish operation.")
332     }
333 }
334