blob: 4ce9dcebf67bbe7ea3c330437d63991dbface099 [file] [log] [blame]
Paul Crowleyef611e52021-04-20 14:43:04 -07001// 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
17use crate::{
18 database::{
Janis Danisevskisf84d0b02022-01-26 14:11:14 -080019 BlobInfo, BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, KeyEntry,
20 KeyEntryLoadBits, KeyIdGuard, KeyMetaData, KeyMetaEntry, KeyType, KeystoreDB,
21 SubComponentType, Uuid,
Paul Crowleyef611e52021-04-20 14:43:04 -070022 },
Janis Danisevskis5c748212021-05-17 17:13:56 -070023 error::{map_km_error, Error, ErrorCode},
Paul Crowleyef611e52021-04-20 14:43:04 -070024 globals::get_keymint_device,
25 super_key::KeyBlob,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070026 utils::{key_characteristics_to_internal, watchdog as wd, AID_KEYSTORE},
Paul Crowleyef611e52021-04-20 14:43:04 -070027};
28use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskisacebfa22021-05-25 10:56:10 -070029 HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice,
30 IKeyMintOperation::IKeyMintOperation, KeyCharacteristics::KeyCharacteristics,
31 KeyCreationResult::KeyCreationResult, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
32 SecurityLevel::SecurityLevel,
Paul Crowleyef611e52021-04-20 14:43:04 -070033};
34use android_system_keystore2::aidl::android::system::keystore2::{
Paul Crowley618869e2021-04-08 20:30:54 -070035 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
Paul Crowleyef611e52021-04-20 14:43:04 -070036};
37use anyhow::{Context, Result};
38use 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.
49pub struct KeyMintDevice {
Janis Danisevskisacebfa22021-05-25 10:56:10 -070050 km_dev: Strong<dyn IKeyMintDevice>,
Paul Crowleyef611e52021-04-20 14:43:04 -070051 km_uuid: Uuid,
Janis Danisevskis5c748212021-05-17 17:13:56 -070052 version: i32,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070053 security_level: SecurityLevel,
Paul Crowleyef611e52021-04-20 14:43:04 -070054}
55
56impl KeyMintDevice {
Janis Danisevskis5c748212021-05-17 17:13:56 -070057 /// 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;
David Drysdalea6c82a92021-12-06 11:24:26 +000063 /// Version number of KeyMintDevice@V2
64 pub const KEY_MINT_V2: i32 = 200;
Janis Danisevskis5c748212021-05-17 17:13:56 -070065
Paul Crowleyef611e52021-04-20 14:43:04 -070066 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
67 pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -070068 let (km_dev, hw_info, km_uuid) = get_keymint_device(&security_level)
Paul Crowleyef611e52021-04-20 14:43:04 -070069 .context("In KeyMintDevice::get: get_keymint_device failed")?;
Janis Danisevskis5c748212021-05-17 17:13:56 -070070
Janis Danisevskisacebfa22021-05-25 10:56:10 -070071 Ok(KeyMintDevice {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -070072 km_dev,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070073 km_uuid,
74 version: hw_info.versionNumber,
75 security_level: hw_info.securityLevel,
76 })
Janis Danisevskis5c748212021-05-17 17:13:56 -070077 }
78
79 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`], return
80 /// [`None`] if the error `HARDWARE_TYPE_UNAVAILABLE` is returned
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.
91 pub fn version(&self) -> i32 {
92 self.version
Paul Crowleyef611e52021-04-20 14:43:04 -070093 }
94
Janis Danisevskisacebfa22021-05-25 10:56:10 -070095 /// 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.
98 pub fn security_level(&self) -> SecurityLevel {
99 self.security_level
100 }
101
Paul Crowley618869e2021-04-08 20:30:54 -0700102 /// Create a KM key and store in the database.
103 pub fn create_and_store_key<F>(
Paul Crowleyef611e52021-04-20 14:43:04 -0700104 &self,
105 db: &mut KeystoreDB,
106 key_desc: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700107 key_type: KeyType,
Paul Crowley618869e2021-04-08 20:30:54 -0700108 creator: F,
109 ) -> Result<()>
110 where
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700111 F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,
Paul Crowley618869e2021-04-08 20:30:54 -0700112 {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700113 let creation_result = map_km_error(creator(&self.km_dev))
114 .context("In create_and_store_key: creator failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700115 let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
116
117 let creation_date =
Paul Crowley618869e2021-04-08 20:30:54 -0700118 DateTime::now().context("In create_and_store_key: DateTime::now() failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700119
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(
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700126 key_desc,
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700127 key_type,
Paul Crowleyef611e52021-04-20 14:43:04 -0700128 &key_parameters,
Janis Danisevskisf84d0b02022-01-26 14:11:14 -0800129 &BlobInfo::new(&creation_result.keyBlob, &blob_metadata),
Paul Crowleyef611e52021-04-20 14:43:04 -0700130 &CertificateInfo::new(None, None),
131 &key_metadata,
132 &self.km_uuid,
133 )
Paul Crowley618869e2021-04-08 20:30:54 -0700134 .context("In create_and_store_key: store_new_key failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700135 Ok(())
136 }
137
Paul Crowley618869e2021-04-08 20:30:54 -0700138 /// Generate a KeyDescriptor for internal-use keys.
139 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.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700149 fn lookup_from_desc(
Paul Crowley618869e2021-04-08 20:30:54 -0700150 db: &mut KeystoreDB,
151 key_desc: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700152 key_type: KeyType,
Paul Crowley618869e2021-04-08 20:30:54 -0700153 ) -> Result<(KeyIdGuard, KeyEntry)> {
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700154 db.load_key_entry(key_desc, key_type, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| Ok(()))
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700155 .context("In lookup_from_desc: load_key_entry failed.")
Paul Crowley618869e2021-04-08 20:30:54 -0700156 }
157
158 /// Look up the key in the database, and return None if it is absent.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700159 fn not_found_is_none(
Paul Crowley618869e2021-04-08 20:30:54 -0700160 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
Paul Crowleyef611e52021-04-20 14:43:04 -0700171 /// This does the lookup and store in separate transactions; caller must
172 /// hold a lock before calling.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700173 pub fn lookup_or_generate_key<F>(
Paul Crowleyef611e52021-04-20 14:43:04 -0700174 &self,
175 db: &mut KeystoreDB,
176 key_desc: &KeyDescriptor,
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700177 key_type: KeyType,
Paul Crowleyef611e52021-04-20 14:43:04 -0700178 params: &[KeyParameter],
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700179 validate_characteristics: F,
180 ) -> Result<(KeyIdGuard, KeyBlob)>
181 where
182 F: FnOnce(&[KeyCharacteristics]) -> bool,
183 {
Paul Crowleyef611e52021-04-20 14:43:04 -0700184 // 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
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700189 let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc, key_type))
Paul Crowley618869e2021-04-08 20:30:54 -0700190 .context("In lookup_or_generate_key: first lookup failed")?;
Janis Danisevskis5c748212021-05-17 17:13:56 -0700191
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700192 if let Some((key_id_guard, mut key_entry)) = lookup {
Janis Danisevskis5c748212021-05-17 17:13:56 -0700193 // 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.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700196 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 };
Paul Crowleyef611e52021-04-20 14:43:04 -0700232 }
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700233
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700234 self.create_and_store_key(db, key_desc, key_type, |km_dev| {
235 km_dev.generateKey(params, None)
Janis Danisevskis0cabd712021-05-25 11:07:10 -0700236 })
237 .context("In lookup_or_generate_key: generate_and_store_key failed")?;
238 Self::lookup_from_desc(db, key_desc, key_type)
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700239 .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 })
Janis Danisevskis5c748212021-05-17 17:13:56 -0700249 .context("In lookup_or_generate_key: second lookup failed")
Paul Crowleyef611e52021-04-20 14:43:04 -0700250 }
251
252 /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
253 /// write the upgraded key to the database.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700254 fn upgrade_keyblob_if_required_with<'a, T, F>(
Paul Crowleyef611e52021-04-20 14:43:04 -0700255 &self,
256 db: &mut KeystoreDB,
Paul Crowley618869e2021-04-08 20:30:54 -0700257 key_id_guard: &KeyIdGuard,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700258 key_blob: KeyBlob<'a>,
Paul Crowleyef611e52021-04-20 14:43:04 -0700259 f: F,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700260 ) -> Result<(T, KeyBlob<'a>)>
Paul Crowleyef611e52021-04-20 14:43:04 -0700261 where
262 F: Fn(&[u8]) -> Result<T, Error>,
263 {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700264 match f(&key_blob) {
Paul Crowleyef611e52021-04-20 14:43:04 -0700265 Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700266 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 );
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700271 self.km_dev.upgradeKey(&key_blob, &[])
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700272 })
273 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700274
275 let mut new_blob_metadata = BlobMetaData::new();
276 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
277
278 db.set_blob(
Paul Crowley618869e2021-04-08 20:30:54 -0700279 key_id_guard,
Paul Crowleyef611e52021-04-20 14:43:04 -0700280 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
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700289 Ok((
290 f(&upgraded_blob).context(
291 "In upgrade_keyblob_if_required_with: Closure failed after upgrade",
292 )?,
293 KeyBlob::NonSensitive(upgraded_blob),
294 ))
Paul Crowleyef611e52021-04-20 14:43:04 -0700295 }
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700296 result => Ok((
297 result.context("In upgrade_keyblob_if_required_with: Closure failed")?,
298 key_blob,
299 )),
Paul Crowleyef611e52021-04-20 14:43:04 -0700300 }
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.
Paul Crowley618869e2021-04-08 20:30:54 -0700305 #[allow(clippy::too_many_arguments)]
Paul Crowleyef611e52021-04-20 14:43:04 -0700306 pub fn use_key_in_one_step(
307 &self,
308 db: &mut KeystoreDB,
Paul Crowley618869e2021-04-08 20:30:54 -0700309 key_id_guard: &KeyIdGuard,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700310 key_blob: &[u8],
Paul Crowleyef611e52021-04-20 14:43:04 -0700311 purpose: KeyPurpose,
312 operation_parameters: &[KeyParameter],
Paul Crowley618869e2021-04-08 20:30:54 -0700313 auth_token: Option<&HardwareAuthToken>,
Paul Crowleyef611e52021-04-20 14:43:04 -0700314 input: &[u8],
315 ) -> Result<Vec<u8>> {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700316 let key_blob = KeyBlob::Ref(key_blob);
Paul Crowleyef611e52021-04-20 14:43:04 -0700317
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700318 let (begin_result, _) = self
319 .upgrade_keyblob_if_required_with(db, key_id_guard, key_blob, |blob| {
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700320 map_km_error({
321 let _wp = wd::watch_millis("In use_key_in_one_step: calling: begin", 500);
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700322 self.km_dev.begin(purpose, blob, operation_parameters, auth_token)
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700323 })
Paul Crowleyef611e52021-04-20 14:43:04 -0700324 })
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")?;
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700330 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.")
Paul Crowleyef611e52021-04-20 14:43:04 -0700335 }
336}