blob: 3d33a26c701b5693305e4b56e29ccdf3844117e5 [file] [log] [blame]
Paul Crowley44c02da2021-04-08 17:04:43 +00001// 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//! Offer keys based on the "boot level" for superencryption.
16
17use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
18 Algorithm::Algorithm, BeginResult::BeginResult, Digest::Digest, ErrorCode::ErrorCode,
19 IKeyMintDevice::IKeyMintDevice, IKeyMintOperation::IKeyMintOperation,
20 KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
21};
22use android_system_keystore2::aidl::android::system::keystore2::{
23 Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
24};
25use anyhow::{Context, Result};
26use binder::Strong;
27use keystore2_crypto::{hkdf_expand, ZVec, AES_256_KEY_LENGTH};
28use std::{collections::VecDeque, convert::TryFrom};
29
30use crate::{
31 database::{
32 BlobMetaData, BlobMetaEntry, CertificateInfo, DateTime, KeyEntry, KeyEntryLoadBits,
33 KeyIdGuard, KeyMetaData, KeyMetaEntry, KeyType, KeystoreDB, SubComponentType, Uuid,
34 },
35 error::{map_km_error, Error},
36 globals::get_keymint_device,
37 key_parameter::KeyParameterValue,
38 super_key::KeyBlob,
39 utils::{key_characteristics_to_internal, Asp, AID_KEYSTORE},
40};
41
42/// Wrapper for operating directly on a KeyMint device.
43/// These methods often mirror methods in [`crate::security_level`]. However
44/// the functions in [`crate::security_level`] make assumptions that hold, and has side effects
45/// that make sense, only if called by an external client through binder.
46/// In addition we are trying to maintain a separation between interface services
47/// so that the architecture is compatible with a future move to multiple thread pools.
48/// So the simplest approach today is to write new implementations of them for internal use.
49/// Because these methods run very early, we don't even try to cooperate with
50/// the operation slot database; we assume there will be plenty of slots.
51struct KeyMintDevice {
52 asp: Asp,
53 km_uuid: Uuid,
54}
55
56impl KeyMintDevice {
57 fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
58 let (asp, _hw_info, km_uuid) = get_keymint_device(&security_level)
59 .context("In KeyMintDevice::get: get_keymint_device failed")?;
60 Ok(KeyMintDevice { asp, km_uuid })
61 }
62
63 /// Generate a KM key and store in the database.
64 fn generate_and_store_key(
65 &self,
66 db: &mut KeystoreDB,
67 key_desc: &KeyDescriptor,
68 params: &[KeyParameter],
69 ) -> Result<()> {
70 let km_dev: Strong<dyn IKeyMintDevice> = self
71 .asp
72 .get_interface()
73 .context("In generate_and_store_key: Failed to get KeyMint device")?;
74 let creation_result = map_km_error(km_dev.generateKey(params, None))
75 .context("In generate_and_store_key: generateKey failed")?;
76 let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
77
78 let creation_date =
79 DateTime::now().context("In generate_and_store_key: DateTime::now() failed")?;
80
81 let mut key_metadata = KeyMetaData::new();
82 key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
83 let mut blob_metadata = BlobMetaData::new();
84 blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
85
86 db.store_new_key(
87 &key_desc,
88 &key_parameters,
89 &(&creation_result.keyBlob, &blob_metadata),
90 &CertificateInfo::new(None, None),
91 &key_metadata,
92 &self.km_uuid,
93 )
94 .context("In generate_and_store_key: store_new_key failed")?;
95 Ok(())
96 }
97
98 /// This does the lookup and store in separate transactions; caller must
99 /// hold a lock before calling.
100 fn lookup_or_generate_key(
101 &self,
102 db: &mut KeystoreDB,
103 key_desc: &KeyDescriptor,
104 params: &[KeyParameter],
105 ) -> Result<(KeyIdGuard, KeyEntry)> {
106 // We use a separate transaction for the lookup than for the store
107 // - to keep the code simple
108 // - because the caller needs to hold a lock in any case
109 // - because it avoids holding database locks during slow
110 // KeyMint operations
111 let lookup = db.load_key_entry(
112 &key_desc,
113 KeyType::Client,
114 KeyEntryLoadBits::KM,
115 AID_KEYSTORE,
116 |_, _| Ok(()),
117 );
118 match lookup {
119 Ok(result) => return Ok(result),
120 Err(e) => match e.root_cause().downcast_ref::<Error>() {
121 Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND)) => {}
122 _ => return Err(e),
123 },
124 }
125 self.generate_and_store_key(db, &key_desc, &params)
126 .context("In lookup_or_generate_key: generate_and_store_key failed")?;
127 db.load_key_entry(&key_desc, KeyType::Client, KeyEntryLoadBits::KM, AID_KEYSTORE, |_, _| {
128 Ok(())
129 })
130 .context("In lookup_or_generate_key: load_key_entry failed")
131 }
132
133 /// Call the passed closure; if it returns `KEY_REQUIRES_UPGRADE`, call upgradeKey, and
134 /// write the upgraded key to the database.
135 fn upgrade_keyblob_if_required_with<T, F>(
136 &self,
137 db: &mut KeystoreDB,
138 km_dev: &Strong<dyn IKeyMintDevice>,
139 key_id_guard: KeyIdGuard,
140 key_blob: &KeyBlob,
141 f: F,
142 ) -> Result<T>
143 where
144 F: Fn(&[u8]) -> Result<T, Error>,
145 {
146 match f(key_blob) {
147 Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => {
148 let upgraded_blob = map_km_error(km_dev.upgradeKey(key_blob, &[]))
149 .context("In upgrade_keyblob_if_required_with: Upgrade failed")?;
150
151 let mut new_blob_metadata = BlobMetaData::new();
152 new_blob_metadata.add(BlobMetaEntry::KmUuid(self.km_uuid));
153
154 db.set_blob(
155 &key_id_guard,
156 SubComponentType::KEY_BLOB,
157 Some(&upgraded_blob),
158 Some(&new_blob_metadata),
159 )
160 .context(concat!(
161 "In upgrade_keyblob_if_required_with: ",
162 "Failed to insert upgraded blob into the database"
163 ))?;
164
165 Ok(f(&upgraded_blob).context(concat!(
166 "In upgrade_keyblob_if_required_with: ",
167 "Closure failed after upgrade"
168 ))?)
169 }
170 result => Ok(result.context("In upgrade_keyblob_if_required_with: Closure failed")?),
171 }
172 }
173
174 /// Use the created key in an operation that can be done with
175 /// a call to begin followed by a call to finish.
176 fn use_key_in_one_step(
177 &self,
178 db: &mut KeystoreDB,
179 key_id_guard: KeyIdGuard,
180 key_entry: &KeyEntry,
181 purpose: KeyPurpose,
182 operation_parameters: &[KeyParameter],
183 input: &[u8],
184 ) -> Result<Vec<u8>> {
185 let km_dev: Strong<dyn IKeyMintDevice> = self
186 .asp
187 .get_interface()
188 .context("In use_key_in_one_step: Failed to get KeyMint device")?;
189
190 let (key_blob, _blob_metadata) = key_entry
191 .key_blob_info()
192 .as_ref()
193 .ok_or_else(Error::sys)
194 .context("use_key_in_one_step: Keyblob missing")?;
195 let key_blob = KeyBlob::Ref(&key_blob);
196
197 let begin_result: BeginResult = self
198 .upgrade_keyblob_if_required_with(db, &km_dev, key_id_guard, &key_blob, |blob| {
199 map_km_error(km_dev.begin(purpose, blob, operation_parameters, &Default::default()))
200 })
201 .context("In use_key_in_one_step: Failed to begin operation.")?;
202 let operation: Strong<dyn IKeyMintOperation> = begin_result
203 .operation
204 .ok_or_else(Error::sys)
205 .context("In use_key_in_one_step: Operation missing")?;
206 map_km_error(operation.finish(Some(input), None, None, None, None))
207 .context("In use_key_in_one_step: Failed to finish operation.")
208 }
209}
210
211/// This is not thread safe; caller must hold a lock before calling.
212/// In practice the caller is SuperKeyManager and the lock is the
213/// Mutex on its internal state.
214pub fn get_level_zero_key(db: &mut KeystoreDB) -> Result<ZVec> {
215 let key_desc = KeyDescriptor {
216 domain: Domain::APP,
217 nspace: AID_KEYSTORE as i64,
218 alias: Some("boot_level_key".to_string()),
219 blob: None,
220 };
221 let params = [
222 KeyParameterValue::Algorithm(Algorithm::HMAC).into(),
223 KeyParameterValue::Digest(Digest::SHA_2_256).into(),
224 KeyParameterValue::KeySize(256).into(),
225 KeyParameterValue::MinMacLength(256).into(),
226 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN).into(),
227 KeyParameterValue::MaxUsesPerBoot(1).into(),
228 ];
229 // We use TRUSTED_ENVIRONMENT here because it is the authority on when
230 // the device has rebooted.
231 let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
232 .context("In get_level_zero_key: KeyMintDevice::get failed")?;
233 let (key_id_guard, key_entry) = km_dev
234 .lookup_or_generate_key(db, &key_desc, &params)
235 .context("In get_level_zero_key: lookup_or_generate_key failed")?;
236
237 let params = [KeyParameterValue::MacLength(256).into()];
238 let level_zero_key = km_dev
239 .use_key_in_one_step(
240 db,
241 key_id_guard,
242 &key_entry,
243 KeyPurpose::SIGN,
244 &params,
245 b"Create boot level key",
246 )
247 .context("In get_level_zero_key: use_key_in_one_step failed")?;
248 // TODO: this is rather unsatisfactory, we need a better way to handle
249 // sensitive binder returns.
250 let level_zero_key = ZVec::try_from(level_zero_key)
251 .context("In get_level_zero_key: conversion to ZVec failed")?;
252 Ok(level_zero_key)
253}
254
255/// Holds the key for the current boot level, and a cache of future keys generated as required.
256/// When the boot level advances, keys prior to the current boot level are securely dropped.
257pub struct BootLevelKeyCache {
258 /// Least boot level currently accessible, if any is.
259 current: usize,
260 /// Invariant: cache entry *i*, if it exists, holds the HKDF key for boot level
261 /// *i* + `current`. If the cache is non-empty it can be grown forwards, but it cannot be
262 /// grown backwards, so keys below `current` are inaccessible.
263 /// `cache.clear()` makes all keys inaccessible.
264 cache: VecDeque<ZVec>,
265}
266
267impl BootLevelKeyCache {
268 const HKDF_ADVANCE: &'static [u8] = b"Advance KDF one step";
269 const HKDF_AES: &'static [u8] = b"Generate AES-256-GCM key";
270 const HKDF_KEY_SIZE: usize = 32;
271
272 /// Initialize the cache with the level zero key.
273 pub fn new(level_zero_key: ZVec) -> Self {
274 let mut cache: VecDeque<ZVec> = VecDeque::new();
275 cache.push_back(level_zero_key);
276 Self { current: 0, cache }
277 }
278
279 /// Report whether the key for the given level can be inferred.
280 pub fn level_accessible(&self, boot_level: usize) -> bool {
281 // If the requested boot level is lower than the current boot level
282 // or if we have reached the end (`cache.empty()`) we can't retrieve
283 // the boot key.
284 boot_level >= self.current && !self.cache.is_empty()
285 }
286
287 /// Get the HKDF key for boot level `boot_level`. The key for level *i*+1
288 /// is calculated from the level *i* key using `hkdf_expand`.
289 fn get_hkdf_key(&mut self, boot_level: usize) -> Result<Option<&ZVec>> {
290 if !self.level_accessible(boot_level) {
291 return Ok(None);
292 }
293 // `self.cache.len()` represents the first entry not in the cache,
294 // so `self.current + self.cache.len()` is the first boot level not in the cache.
295 let first_not_cached = self.current + self.cache.len();
296
297 // Grow the cache forwards until it contains the desired boot level.
298 for _level in first_not_cached..=boot_level {
299 // We check at the start that cache is non-empty and future iterations only push,
300 // so this must unwrap.
301 let highest_key = self.cache.back().unwrap();
302 let next_key = hkdf_expand(Self::HKDF_KEY_SIZE, highest_key, Self::HKDF_ADVANCE)
303 .context("In BootLevelKeyCache::get_hkdf_key: Advancing key one step")?;
304 self.cache.push_back(next_key);
305 }
306
307 // If we reach this point, we should have a key at index boot_level - current.
308 Ok(Some(self.cache.get(boot_level - self.current).unwrap()))
309 }
310
311 /// Drop keys prior to the given boot level, while retaining the ability to generate keys for
312 /// that level and later.
313 pub fn advance_boot_level(&mut self, new_boot_level: usize) -> Result<()> {
314 if !self.level_accessible(new_boot_level) {
315 log::error!(
316 concat!(
317 "In BootLevelKeyCache::advance_boot_level: ",
318 "Failed to advance boot level to {}, current is {}, cache size {}"
319 ),
320 new_boot_level,
321 self.current,
322 self.cache.len()
323 );
324 return Ok(());
325 }
326
327 // We `get` the new boot level for the side effect of advancing the cache to a point
328 // where the new boot level is present.
329 self.get_hkdf_key(new_boot_level)
330 .context("In BootLevelKeyCache::advance_boot_level: Advancing cache")?;
331
332 // Then we split the queue at the index of the new boot level and discard the front,
333 // keeping only the keys with the current boot level or higher.
334 self.cache = self.cache.split_off(new_boot_level - self.current);
335
336 // The new cache has the new boot level at index 0, so we set `current` to
337 // `new_boot_level`.
338 self.current = new_boot_level;
339
340 Ok(())
341 }
342
343 /// Drop all keys, effectively raising the current boot level to infinity; no keys can
344 /// be inferred from this point on.
345 pub fn finish(&mut self) {
346 self.cache.clear();
347 }
348
349 fn expand_key(
350 &mut self,
351 boot_level: usize,
352 out_len: usize,
353 info: &[u8],
354 ) -> Result<Option<ZVec>> {
355 self.get_hkdf_key(boot_level)
356 .context("In BootLevelKeyCache::expand_key: Looking up HKDF key")?
357 .map(|k| hkdf_expand(out_len, k, info))
358 .transpose()
359 .context("In BootLevelKeyCache::expand_key: Calling hkdf_expand")
360 }
361
362 /// Return the AES-256-GCM key for the current boot level.
363 pub fn aes_key(&mut self, boot_level: usize) -> Result<Option<ZVec>> {
364 self.expand_key(boot_level, AES_256_KEY_LENGTH, BootLevelKeyCache::HKDF_AES)
365 .context("In BootLevelKeyCache::aes_key: expand_key failed")
366 }
367}
368
369#[cfg(test)]
370mod test {
371 use super::*;
372
373 #[test]
374 fn test_output_is_consistent() -> Result<()> {
375 let initial_key = b"initial key";
376 let mut blkc = BootLevelKeyCache::new(ZVec::try_from(initial_key as &[u8])?);
377 assert_eq!(true, blkc.level_accessible(0));
378 assert_eq!(true, blkc.level_accessible(9));
379 assert_eq!(true, blkc.level_accessible(10));
380 assert_eq!(true, blkc.level_accessible(100));
381 let v0 = blkc.aes_key(0).unwrap().unwrap();
382 let v10 = blkc.aes_key(10).unwrap().unwrap();
383 assert_eq!(Some(&v0), blkc.aes_key(0)?.as_ref());
384 assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref());
385 blkc.advance_boot_level(5)?;
386 assert_eq!(false, blkc.level_accessible(0));
387 assert_eq!(true, blkc.level_accessible(9));
388 assert_eq!(true, blkc.level_accessible(10));
389 assert_eq!(true, blkc.level_accessible(100));
390 assert_eq!(None, blkc.aes_key(0)?);
391 assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref());
392 blkc.advance_boot_level(10)?;
393 assert_eq!(false, blkc.level_accessible(0));
394 assert_eq!(false, blkc.level_accessible(9));
395 assert_eq!(true, blkc.level_accessible(10));
396 assert_eq!(true, blkc.level_accessible(100));
397 assert_eq!(None, blkc.aes_key(0)?);
398 assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref());
399 blkc.advance_boot_level(0)?;
400 assert_eq!(false, blkc.level_accessible(0));
401 assert_eq!(false, blkc.level_accessible(9));
402 assert_eq!(true, blkc.level_accessible(10));
403 assert_eq!(true, blkc.level_accessible(100));
404 assert_eq!(None, blkc.aes_key(0)?);
405 assert_eq!(Some(v10), blkc.aes_key(10)?);
406 blkc.finish();
407 assert_eq!(false, blkc.level_accessible(0));
408 assert_eq!(false, blkc.level_accessible(9));
409 assert_eq!(false, blkc.level_accessible(10));
410 assert_eq!(false, blkc.level_accessible(100));
411 assert_eq!(None, blkc.aes_key(0)?);
412 assert_eq!(None, blkc.aes_key(10)?);
413 Ok(())
414 }
415}