blob: 06432fe55cfcb7743486f130acb49e22a88c9871 [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 },
22 error::{map_km_error, Error},
23 globals::get_keymint_device,
24 super_key::KeyBlob,
25 utils::{key_characteristics_to_internal, Asp, AID_KEYSTORE},
26};
27use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Paul Crowley618869e2021-04-08 20:30:54 -070028 BeginResult::BeginResult, ErrorCode::ErrorCode, HardwareAuthToken::HardwareAuthToken,
29 IKeyMintDevice::IKeyMintDevice, IKeyMintOperation::IKeyMintOperation,
30 KeyCreationResult::KeyCreationResult, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
Paul Crowleyef611e52021-04-20 14:43:04 -070031 SecurityLevel::SecurityLevel,
32};
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 {
49 asp: Asp,
50 km_uuid: Uuid,
51}
52
53impl KeyMintDevice {
54 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
55 pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
56 let (asp, _hw_info, km_uuid) = get_keymint_device(&security_level)
57 .context("In KeyMintDevice::get: get_keymint_device failed")?;
58 Ok(KeyMintDevice { asp, km_uuid })
59 }
60
Paul Crowley618869e2021-04-08 20:30:54 -070061 /// Create a KM key and store in the database.
62 pub fn create_and_store_key<F>(
Paul Crowleyef611e52021-04-20 14:43:04 -070063 &self,
64 db: &mut KeystoreDB,
65 key_desc: &KeyDescriptor,
Paul Crowley618869e2021-04-08 20:30:54 -070066 creator: F,
67 ) -> Result<()>
68 where
69 F: FnOnce(Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,
70 {
Paul Crowleyef611e52021-04-20 14:43:04 -070071 let km_dev: Strong<dyn IKeyMintDevice> = self
72 .asp
73 .get_interface()
Paul Crowley618869e2021-04-08 20:30:54 -070074 .context("In create_and_store_key: Failed to get KeyMint device")?;
75 let creation_result =
76 map_km_error(creator(km_dev)).context("In create_and_store_key: creator failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -070077 let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
78
79 let creation_date =
Paul Crowley618869e2021-04-08 20:30:54 -070080 DateTime::now().context("In create_and_store_key: DateTime::now() failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -070081
82 let mut key_metadata = KeyMetaData::new();
83 key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
84 let mut blob_metadata = BlobMetaData::new();
85 blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
86
87 db.store_new_key(
88 &key_desc,
89 &key_parameters,
90 &(&creation_result.keyBlob, &blob_metadata),
91 &CertificateInfo::new(None, None),
92 &key_metadata,
93 &self.km_uuid,
94 )
Paul Crowley618869e2021-04-08 20:30:54 -070095 .context("In create_and_store_key: store_new_key failed")?;
Paul Crowleyef611e52021-04-20 14:43:04 -070096 Ok(())
97 }
98
Paul Crowley618869e2021-04-08 20:30:54 -070099 /// Generate a KeyDescriptor for internal-use keys.
100 pub fn internal_descriptor(alias: String) -> KeyDescriptor {
101 KeyDescriptor {
102 domain: Domain::APP,
103 nspace: AID_KEYSTORE as i64,
104 alias: Some(alias),
105 blob: None,
106 }
107 }
108
109 /// Look up an internal-use key in the database given a key descriptor.
110 pub fn lookup_from_desc(
111 db: &mut KeystoreDB,
112 key_desc: &KeyDescriptor,
113 ) -> Result<(KeyIdGuard, KeyEntry)> {
114 db.load_key_entry(&key_desc, KeyType::Client, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| {
115 Ok(())
116 })
117 .context("In lookup_from_desc: load_key_entry failed")
118 }
119
120 /// Look up the key in the database, and return None if it is absent.
121 pub fn not_found_is_none(
122 lookup: Result<(KeyIdGuard, KeyEntry)>,
123 ) -> Result<Option<(KeyIdGuard, KeyEntry)>> {
124 match lookup {
125 Ok(result) => Ok(Some(result)),
126 Err(e) => match e.root_cause().downcast_ref::<Error>() {
127 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => Ok(None),
128 _ => Err(e),
129 },
130 }
131 }
132
Paul Crowleyef611e52021-04-20 14:43:04 -0700133 /// This does the lookup and store in separate transactions; caller must
134 /// hold a lock before calling.
135 pub fn lookup_or_generate_key(
136 &self,
137 db: &mut KeystoreDB,
138 key_desc: &KeyDescriptor,
139 params: &[KeyParameter],
140 ) -> Result<(KeyIdGuard, KeyEntry)> {
141 // We use a separate transaction for the lookup than for the store
142 // - to keep the code simple
143 // - because the caller needs to hold a lock in any case
144 // - because it avoids holding database locks during slow
145 // KeyMint operations
Paul Crowley618869e2021-04-08 20:30:54 -0700146 let lookup = Self::not_found_is_none(Self::lookup_from_desc(db, key_desc))
147 .context("In lookup_or_generate_key: first lookup failed")?;
148 if let Some(result) = lookup {
149 Ok(result)
150 } else {
151 self.create_and_store_key(db, &key_desc, |km_dev| km_dev.generateKey(&params, None))
152 .context("In lookup_or_generate_key: generate_and_store_key failed")?;
153 Self::lookup_from_desc(db, key_desc)
154 .context("In lookup_or_generate_key: secpnd lookup failed")
Paul Crowleyef611e52021-04-20 14:43:04 -0700155 }
Paul Crowleyef611e52021-04-20 14:43:04 -0700156 }
157
158 /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
159 /// write the upgraded key to the database.
160 fn upgrade_keyblob_if_required_with<T, F>(
161 &self,
162 db: &mut KeystoreDB,
163 km_dev: &Strong<dyn IKeyMintDevice>,
Paul Crowley618869e2021-04-08 20:30:54 -0700164 key_id_guard: &KeyIdGuard,
Paul Crowleyef611e52021-04-20 14:43:04 -0700165 key_blob: &KeyBlob,
166 f: F,
167 ) -> Result<T>
168 where
169 F: Fn(&[u8]) -> Result<T, Error>,
170 {
171 match f(key_blob) {
172 Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
173 let upgraded_blob = map_km_error(km_dev.upgradeKey(key_blob, &[]))
174 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
175
176 let mut new_blob_metadata = BlobMetaData::new();
177 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
178
179 db.set_blob(
Paul Crowley618869e2021-04-08 20:30:54 -0700180 key_id_guard,
Paul Crowleyef611e52021-04-20 14:43:04 -0700181 SubComponentType::KEY_BLOB,
182 Some(&upgraded_blob),
183 Some(&new_blob_metadata),
184 )
185 .context(concat!(
186 "In upgrade_keyblob_if_required_with: ",
187 "Failed to insert upgraded blob into the database"
188 ))?;
189
190 Ok(f(&upgraded_blob).context(concat!(
191 "In upgrade_keyblob_if_required_with: ",
192 "Closure failed after upgrade"
193 ))?)
194 }
195 result => Ok(result.context("In upgrade_keyblob_if_required_with: Closure failed")?),
196 }
197 }
198
199 /// Use the created key in an operation that can be done with
200 /// a call to begin followed by a call to finish.
Paul Crowley618869e2021-04-08 20:30:54 -0700201 #[allow(clippy::too_many_arguments)]
Paul Crowleyef611e52021-04-20 14:43:04 -0700202 pub fn use_key_in_one_step(
203 &self,
204 db: &mut KeystoreDB,
Paul Crowley618869e2021-04-08 20:30:54 -0700205 key_id_guard: &KeyIdGuard,
Paul Crowleyef611e52021-04-20 14:43:04 -0700206 key_entry: &KeyEntry,
207 purpose: KeyPurpose,
208 operation_parameters: &[KeyParameter],
Paul Crowley618869e2021-04-08 20:30:54 -0700209 auth_token: Option<&HardwareAuthToken>,
Paul Crowleyef611e52021-04-20 14:43:04 -0700210 input: &[u8],
211 ) -> Result<Vec<u8>> {
212 let km_dev: Strong<dyn IKeyMintDevice> = self
213 .asp
214 .get_interface()
215 .context("In use_key_in_one_step: Failed to get KeyMint device")?;
216
217 let (key_blob, _blob_metadata) = key_entry
218 .key_blob_info()
219 .as_ref()
220 .ok_or_else(Error::sys)
221 .context("use_key_in_one_step: Keyblob missing")?;
222 let key_blob = KeyBlob::Ref(&key_blob);
223
224 let begin_result: BeginResult = self
225 .upgrade_keyblob_if_required_with(db, &km_dev, key_id_guard, &key_blob, |blob| {
Paul Crowley618869e2021-04-08 20:30:54 -0700226 map_km_error(km_dev.begin(purpose, blob, operation_parameters, auth_token))
Paul Crowleyef611e52021-04-20 14:43:04 -0700227 })
228 .context("In use_key_in_one_step: Failed to begin operation.")?;
229 let operation: Strong<dyn IKeyMintOperation> = begin_result
230 .operation
231 .ok_or_else(Error::sys)
232 .context("In use_key_in_one_step: Operation missing")?;
233 map_km_error(operation.finish(Some(input), None, None, None, None))
234 .context("In use_key_in_one_step: Failed to finish operation.")
235 }
236}