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