blob: cdec79bbc0d731b7fd2fed15110d1d9c92577c29 [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::{
28 BeginResult::BeginResult, ErrorCode::ErrorCode, IKeyMintDevice::IKeyMintDevice,
29 IKeyMintOperation::IKeyMintOperation, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
30 SecurityLevel::SecurityLevel,
31};
32use android_system_keystore2::aidl::android::system::keystore2::{
33 KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
34};
35use anyhow::{Context, Result};
36use binder::Strong;
37
38/// Wrapper for operating directly on a KeyMint device.
39/// These methods often mirror methods in [`crate::security_level`]. However
40/// the functions in [`crate::security_level`] make assumptions that hold, and has side effects
41/// that make sense, only if called by an external client through binder.
42/// In addition we are trying to maintain a separation between interface services
43/// so that the architecture is compatible with a future move to multiple thread pools.
44/// So the simplest approach today is to write new implementations of them for internal use.
45/// Because these methods run very early, we don't even try to cooperate with
46/// the operation slot database; we assume there will be plenty of slots.
47pub struct KeyMintDevice {
48 asp: Asp,
49 km_uuid: Uuid,
50}
51
52impl KeyMintDevice {
53 /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
54 pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
55 let (asp, _hw_info, km_uuid) = get_keymint_device(&security_level)
56 .context("In KeyMintDevice::get: get_keymint_device failed")?;
57 Ok(KeyMintDevice { asp, km_uuid })
58 }
59
60 /// Generate a KM key and store in the database.
61 fn generate_and_store_key(
62 &self,
63 db: &mut KeystoreDB,
64 key_desc: &KeyDescriptor,
65 params: &[KeyParameter],
66 ) -> Result<()> {
67 let km_dev: Strong<dyn IKeyMintDevice> = self
68 .asp
69 .get_interface()
70 .context("In generate_and_store_key: Failed to get KeyMint device")?;
71 let creation_result = map_km_error(km_dev.generateKey(params, None))
72 .context("In generate_and_store_key: generateKey failed")?;
73 let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
74
75 let creation_date =
76 DateTime::now().context("In generate_and_store_key: DateTime::now() failed")?;
77
78 let mut key_metadata = KeyMetaData::new();
79 key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
80 let mut blob_metadata = BlobMetaData::new();
81 blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
82
83 db.store_new_key(
84 &key_desc,
85 &key_parameters,
86 &(&creation_result.keyBlob, &blob_metadata),
87 &CertificateInfo::new(None, None),
88 &key_metadata,
89 &self.km_uuid,
90 )
91 .context("In generate_and_store_key: store_new_key failed")?;
92 Ok(())
93 }
94
95 /// This does the lookup and store in separate transactions; caller must
96 /// hold a lock before calling.
97 pub fn lookup_or_generate_key(
98 &self,
99 db: &mut KeystoreDB,
100 key_desc: &KeyDescriptor,
101 params: &[KeyParameter],
102 ) -> Result<(KeyIdGuard, KeyEntry)> {
103 // We use a separate transaction for the lookup than for the store
104 // - to keep the code simple
105 // - because the caller needs to hold a lock in any case
106 // - because it avoids holding database locks during slow
107 // KeyMint operations
108 let lookup = db.load_key_entry(
109 &key_desc,
110 KeyType::Client,
111 KeyEntryLoadBits::KM,
112 AID_KEYSTORE,
113 |_, _| Ok(()),
114 );
115 match lookup {
116 Ok(result) => return Ok(result),
117 Err(e) => match e.root_cause().downcast_ref::<Error>() {
118 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => {}
119 _ => return Err(e),
120 },
121 }
122 self.generate_and_store_key(db, &key_desc, &params)
123 .context("In lookup_or_generate_key: generate_and_store_key failed")?;
124 db.load_key_entry(&key_desc, KeyType::Client, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| {
125 Ok(())
126 })
127 .context("In lookup_or_generate_key: load_key_entry failed")
128 }
129
130 /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
131 /// write the upgraded key to the database.
132 fn upgrade_keyblob_if_required_with<T, F>(
133 &self,
134 db: &mut KeystoreDB,
135 km_dev: &Strong<dyn IKeyMintDevice>,
136 key_id_guard: KeyIdGuard,
137 key_blob: &KeyBlob,
138 f: F,
139 ) -> Result<T>
140 where
141 F: Fn(&[u8]) -> Result<T, Error>,
142 {
143 match f(key_blob) {
144 Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
145 let upgraded_blob = map_km_error(km_dev.upgradeKey(key_blob, &[]))
146 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
147
148 let mut new_blob_metadata = BlobMetaData::new();
149 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
150
151 db.set_blob(
152 &key_id_guard,
153 SubComponentType::KEY_BLOB,
154 Some(&upgraded_blob),
155 Some(&new_blob_metadata),
156 )
157 .context(concat!(
158 "In upgrade_keyblob_if_required_with: ",
159 "Failed to insert upgraded blob into the database"
160 ))?;
161
162 Ok(f(&upgraded_blob).context(concat!(
163 "In upgrade_keyblob_if_required_with: ",
164 "Closure failed after upgrade"
165 ))?)
166 }
167 result => Ok(result.context("In upgrade_keyblob_if_required_with: Closure failed")?),
168 }
169 }
170
171 /// Use the created key in an operation that can be done with
172 /// a call to begin followed by a call to finish.
173 pub fn use_key_in_one_step(
174 &self,
175 db: &mut KeystoreDB,
176 key_id_guard: KeyIdGuard,
177 key_entry: &KeyEntry,
178 purpose: KeyPurpose,
179 operation_parameters: &[KeyParameter],
180 input: &[u8],
181 ) -> Result<Vec<u8>> {
182 let km_dev: Strong<dyn IKeyMintDevice> = self
183 .asp
184 .get_interface()
185 .context("In use_key_in_one_step: Failed to get KeyMint device")?;
186
187 let (key_blob, _blob_metadata) = key_entry
188 .key_blob_info()
189 .as_ref()
190 .ok_or_else(Error::sys)
191 .context("use_key_in_one_step: Keyblob missing")?;
192 let key_blob = KeyBlob::Ref(&key_blob);
193
194 let begin_result: BeginResult = self
195 .upgrade_keyblob_if_required_with(db, &km_dev, key_id_guard, &key_blob, |blob| {
196 map_km_error(km_dev.begin(purpose, blob, operation_parameters, None))
197 })
198 .context("In use_key_in_one_step: Failed to begin operation.")?;
199 let operation: Strong<dyn IKeyMintOperation> = begin_result
200 .operation
201 .ok_or_else(Error::sys)
202 .context("In use_key_in_one_step: Operation missing")?;
203 map_km_error(operation.finish(Some(input), None, None, None, None))
204 .context("In use_key_in_one_step: Failed to finish operation.")
205 }
206}