blob: 4e86d394bebd0bf5c4983163d434317ca1d53f60 [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::{
19 BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, KeyEntry, KeyEntryLoadBits,
20 KeyIdGuard, KeyMetaData, KeyMetaEntry, KeyType, KeystoreDB, SubComponentType, Uuid,
21 },
Janis Danisevskis5c748212021-05-17 17:13:56 -070022 error::{map_km_error, Error, ErrorCode},
Paul Crowleyef611e52021-04-20 14:43:04 -070023 globals::get_keymint_device,
24 super_key::KeyBlob,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070025 utils::{key_characteristics_to_internal, watchdog as wd, AID_KEYSTORE},
Paul Crowleyef611e52021-04-20 14:43:04 -070026};
27use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskisacebfa22021-05-25 10:56:10 -070028 HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice,
29 IKeyMintOperation::IKeyMintOperation, KeyCharacteristics::KeyCharacteristics,
30 KeyCreationResult::KeyCreationResult, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
31 SecurityLevel::SecurityLevel,
Paul Crowleyef611e52021-04-20 14:43:04 -070032};
33use android_system_keystore2::aidl::android::system::keystore2::{
Paul Crowley618869e2021-04-08 20:30:54 -070034 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
Paul Crowleyef611e52021-04-20 14:43:04 -070035};
36use anyhow::{Context, Result};
37use 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.
48pub struct KeyMintDevice {
Janis Danisevskisacebfa22021-05-25 10:56:10 -070049 km_dev: Strong<dyn IKeyMintDevice>,
Paul Crowleyef611e52021-04-20 14:43:04 -070050 km_uuid: Uuid,
Janis Danisevskis5c748212021-05-17 17:13:56 -070051 version: i32,
Janis Danisevskisacebfa22021-05-25 10:56:10 -070052 security_level: SecurityLevel,
Paul Crowleyef611e52021-04-20 14:43:04 -070053}
54
55impl KeyMintDevice {
Janis Danisevskis5c748212021-05-17 17:13:56 -070056 /// 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
Paul Crowleyef611e52021-04-20 14:43:04 -070063 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
64 pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
Janis Danisevskis5c748212021-05-17 17:13:56 -070065 let (asp, hw_info, km_uuid) = get_keymint_device(&security_level)
Paul Crowleyef611e52021-04-20 14:43:04 -070066 .context("In KeyMintDevice::get: get_keymint_device failed")?;
Janis Danisevskis5c748212021-05-17 17:13:56 -070067
Janis Danisevskisacebfa22021-05-25 10:56:10 -070068 Ok(KeyMintDevice {
69 km_dev: asp.get_interface()?,
70 km_uuid,
71 version: hw_info.versionNumber,
72 security_level: hw_info.securityLevel,
73 })
Janis Danisevskis5c748212021-05-17 17:13:56 -070074 }
75
76 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`], return
77 /// [`None`] if the error `HARDWARE_TYPE_UNAVAILABLE` is returned
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.
88 pub fn version(&self) -> i32 {
89 self.version
Paul Crowleyef611e52021-04-20 14:43:04 -070090 }
91
Janis Danisevskisacebfa22021-05-25 10:56:10 -070092 /// 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.
95 pub fn security_level(&self) -> SecurityLevel {
96 self.security_level
97 }
98
Paul Crowley618869e2021-04-08 20:30:54 -070099 /// Create a KM key and store in the database.
100 pub fn create_and_store_key<F>(
Paul Crowleyef611e52021-04-20 14:43:04 -0700101 &self,
102 db: &mut KeystoreDB,
103 key_desc: &KeyDescriptor,
Paul Crowley618869e2021-04-08 20:30:54 -0700104 creator: F,
105 ) -> Result<()>
106 where
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700107 F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,
Paul Crowley618869e2021-04-08 20:30:54 -0700108 {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700109 let creation_result = map_km_error(creator(&self.km_dev))
110 .context("In create_and_store_key: creator failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700111 let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
112
113 let creation_date =
Paul Crowley618869e2021-04-08 20:30:54 -0700114 DateTime::now().context("In create_and_store_key: DateTime::now() failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700115
116 let mut key_metadata = KeyMetaData::new();
117 key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
118 let mut blob_metadata = BlobMetaData::new();
119 blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
120
121 db.store_new_key(
122 &key_desc,
123 &key_parameters,
124 &(&creation_result.keyBlob, &blob_metadata),
125 &CertificateInfo::new(None, None),
126 &key_metadata,
127 &self.km_uuid,
128 )
Paul Crowley618869e2021-04-08 20:30:54 -0700129 .context("In create_and_store_key: store_new_key failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700130 Ok(())
131 }
132
Paul Crowley618869e2021-04-08 20:30:54 -0700133 /// Generate a KeyDescriptor for internal-use keys.
134 pub fn internal_descriptor(alias: String) -> KeyDescriptor {
135 KeyDescriptor {
136 domain: Domain::APP,
137 nspace: AID_KEYSTORE as i64,
138 alias: Some(alias),
139 blob: None,
140 }
141 }
142
143 /// Look up an internal-use key in the database given a key descriptor.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700144 fn lookup_from_desc(
Paul Crowley618869e2021-04-08 20:30:54 -0700145 db: &mut KeystoreDB,
146 key_desc: &KeyDescriptor,
147 ) -> Result<(KeyIdGuard, KeyEntry)> {
148 db.load_key_entry(&key_desc, KeyType::Client, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| {
149 Ok(())
150 })
151 .context("In lookup_from_desc: load_key_entry failed")
152 }
153
154 /// Look up the key in the database, and return None if it is absent.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700155 fn not_found_is_none(
Paul Crowley618869e2021-04-08 20:30:54 -0700156 lookup: Result<(KeyIdGuard, KeyEntry)>,
157 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
158 match lookup {
159 Ok(result) => Ok(Some(result)),
160 Err(e) => match e.root_cause().downcast_ref::<Error>() {
161 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
162 _ => Err(e),
163 },
164 }
165 }
166
Paul Crowleyef611e52021-04-20 14:43:04 -0700167 /// This does the lookup and store in separate transactions; caller must
168 /// hold a lock before calling.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700169 pub fn lookup_or_generate_key<F>(
Paul Crowleyef611e52021-04-20 14:43:04 -0700170 &self,
171 db: &mut KeystoreDB,
172 key_desc: &KeyDescriptor,
173 params: &[KeyParameter],
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700174 validate_characteristics: F,
175 ) -> Result<(KeyIdGuard, KeyBlob)>
176 where
177 F: FnOnce(&[KeyCharacteristics]) -> bool,
178 {
Paul Crowleyef611e52021-04-20 14:43:04 -0700179 // We use a separate transaction for the lookup than for the store
180 // - to keep the code simple
181 // - because the caller needs to hold a lock in any case
182 // - because it avoids holding database locks during slow
183 // KeyMint operations
Paul Crowley618869e2021-04-08 20:30:54 -0700184 let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc))
185 .context("In lookup_or_generate_key: first lookup failed")?;
Janis Danisevskis5c748212021-05-17 17:13:56 -0700186
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700187 if let Some((key_id_guard, mut key_entry)) = lookup {
Janis Danisevskis5c748212021-05-17 17:13:56 -0700188 // If the key is associated with a different km instance
189 // or if there is no blob metadata for some reason the key entry
190 // is considered corrupted and needs to be replaced with a new one.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700191 let key_blob = key_entry.take_key_blob_info().and_then(|(key_blob, blob_metadata)| {
192 if Some(&self.km_uuid) == blob_metadata.km_uuid() {
193 Some(key_blob)
194 } else {
195 None
196 }
197 });
198
199 if let Some(key_blob_vec) = key_blob {
200 let (key_characteristics, key_blob) = self
201 .upgrade_keyblob_if_required_with(
202 db,
203 &key_id_guard,
204 KeyBlob::NonSensitive(key_blob_vec),
205 |key_blob| {
206 map_km_error({
207 let _wp = wd::watch_millis(
208 concat!(
209 "In KeyMintDevice::lookup_or_generate_key: ",
210 "calling getKeyCharacteristics."
211 ),
212 500,
213 );
214 self.km_dev.getKeyCharacteristics(key_blob, &[], &[])
215 })
216 },
217 )
218 .context("In lookup_or_generate_key: calling getKeyCharacteristics")?;
219
220 if validate_characteristics(&key_characteristics) {
221 return Ok((key_id_guard, key_blob));
222 }
223
224 // If this point is reached the existing key is considered outdated or corrupted
225 // in some way. It will be replaced with a new key below.
226 };
Paul Crowleyef611e52021-04-20 14:43:04 -0700227 }
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700228
Janis Danisevskis5c748212021-05-17 17:13:56 -0700229 self.create_and_store_key(db, &key_desc, |km_dev| km_dev.generateKey(&params, None))
230 .context("In lookup_or_generate_key: generate_and_store_key failed")?;
231 Self::lookup_from_desc(db, key_desc)
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700232 .and_then(|(key_id_guard, mut key_entry)| {
233 Ok((
234 key_id_guard,
235 key_entry
236 .take_key_blob_info()
237 .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
238 .map(|(key_blob, _)| KeyBlob::NonSensitive(key_blob))
239 .context("Missing key blob info.")?,
240 ))
241 })
Janis Danisevskis5c748212021-05-17 17:13:56 -0700242 .context("In lookup_or_generate_key: second lookup failed")
Paul Crowleyef611e52021-04-20 14:43:04 -0700243 }
244
245 /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
246 /// write the upgraded key to the database.
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700247 fn upgrade_keyblob_if_required_with<'a, T, F>(
Paul Crowleyef611e52021-04-20 14:43:04 -0700248 &self,
249 db: &mut KeystoreDB,
Paul Crowley618869e2021-04-08 20:30:54 -0700250 key_id_guard: &KeyIdGuard,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700251 key_blob: KeyBlob<'a>,
Paul Crowleyef611e52021-04-20 14:43:04 -0700252 f: F,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700253 ) -> Result<(T, KeyBlob<'a>)>
Paul Crowleyef611e52021-04-20 14:43:04 -0700254 where
255 F: Fn(&[u8]) -> Result<T, Error>,
256 {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700257 match f(&key_blob) {
Paul Crowleyef611e52021-04-20 14:43:04 -0700258 Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700259 let upgraded_blob = map_km_error({
260 let _wp = wd::watch_millis(
261 "In KeyMintDevice::upgrade_keyblob_if_required_with: calling upgradeKey.",
262 500,
263 );
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700264 self.km_dev.upgradeKey(&key_blob, &[])
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700265 })
266 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -0700267
268 let mut new_blob_metadata = BlobMetaData::new();
269 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
270
271 db.set_blob(
Paul Crowley618869e2021-04-08 20:30:54 -0700272 key_id_guard,
Paul Crowleyef611e52021-04-20 14:43:04 -0700273 SubComponentType::KEY_BLOB,
274 Some(&upgraded_blob),
275 Some(&new_blob_metadata),
276 )
277 .context(concat!(
278 "In upgrade_keyblob_if_required_with: ",
279 "Failed to insert upgraded blob into the database"
280 ))?;
281
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700282 Ok((
283 f(&upgraded_blob).context(
284 "In upgrade_keyblob_if_required_with: Closure failed after upgrade",
285 )?,
286 KeyBlob::NonSensitive(upgraded_blob),
287 ))
Paul Crowleyef611e52021-04-20 14:43:04 -0700288 }
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700289 result => Ok((
290 result.context("In upgrade_keyblob_if_required_with: Closure failed")?,
291 key_blob,
292 )),
Paul Crowleyef611e52021-04-20 14:43:04 -0700293 }
294 }
295
296 /// Use the created key in an operation that can be done with
297 /// a call to begin followed by a call to finish.
Paul Crowley618869e2021-04-08 20:30:54 -0700298 #[allow(clippy::too_many_arguments)]
Paul Crowleyef611e52021-04-20 14:43:04 -0700299 pub fn use_key_in_one_step(
300 &self,
301 db: &mut KeystoreDB,
Paul Crowley618869e2021-04-08 20:30:54 -0700302 key_id_guard: &KeyIdGuard,
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700303 key_blob: &[u8],
Paul Crowleyef611e52021-04-20 14:43:04 -0700304 purpose: KeyPurpose,
305 operation_parameters: &[KeyParameter],
Paul Crowley618869e2021-04-08 20:30:54 -0700306 auth_token: Option<&HardwareAuthToken>,
Paul Crowleyef611e52021-04-20 14:43:04 -0700307 input: &[u8],
308 ) -> Result<Vec<u8>> {
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700309 let key_blob = KeyBlob::Ref(key_blob);
Paul Crowleyef611e52021-04-20 14:43:04 -0700310
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700311 let (begin_result, _) = self
312 .upgrade_keyblob_if_required_with(db, key_id_guard, key_blob, |blob| {
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700313 map_km_error({
314 let _wp = wd::watch_millis("In use_key_in_one_step: calling: begin", 500);
Janis Danisevskisacebfa22021-05-25 10:56:10 -0700315 self.km_dev.begin(purpose, blob, operation_parameters, auth_token)
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700316 })
Paul Crowleyef611e52021-04-20 14:43:04 -0700317 })
318 .context("In use_key_in_one_step: Failed to begin operation.")?;
319 let operation: Strong<dyn IKeyMintOperation> = begin_result
320 .operation
321 .ok_or_else(Error::sys)
322 .context("In use_key_in_one_step: Operation missing")?;
Janis Danisevskis2ee014b2021-05-05 14:29:08 -0700323 map_km_error({
324 let _wp = wd::watch_millis("In use_key_in_one_step: calling: finish", 500);
325 operation.finish(Some(input), None, None, None, None)
326 })
327 .context("In use_key_in_one_step: Failed to finish operation.")
Paul Crowleyef611e52021-04-20 14:43:04 -0700328 }
329}