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