blob: a658c0277d1f3e0294574f9cdb614cde3cc7ebda [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::{
Paul Crowleyef611e52021-04-20 14:43:04 -070018 Algorithm::Algorithm, Digest::Digest, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
Paul Crowley44c02da2021-04-08 17:04:43 +000019};
20use android_system_keystore2::aidl::android::system::keystore2::{
Paul Crowleyef611e52021-04-20 14:43:04 -070021 Domain::Domain, KeyDescriptor::KeyDescriptor,
Paul Crowley44c02da2021-04-08 17:04:43 +000022};
23use anyhow::{Context, Result};
Paul Crowley44c02da2021-04-08 17:04:43 +000024use keystore2_crypto::{hkdf_expand, ZVec, AES_256_KEY_LENGTH};
25use std::{collections::VecDeque, convert::TryFrom};
26
27use crate::{
Paul Crowleyef611e52021-04-20 14:43:04 -070028 database::KeystoreDB, key_parameter::KeyParameterValue, raw_device::KeyMintDevice,
29 utils::AID_KEYSTORE,
Paul Crowley44c02da2021-04-08 17:04:43 +000030};
31
Paul Crowley44c02da2021-04-08 17:04:43 +000032/// This is not thread safe; caller must hold a lock before calling.
33/// In practice the caller is SuperKeyManager and the lock is the
34/// Mutex on its internal state.
35pub fn get_level_zero_key(db: &mut KeystoreDB) -> Result<ZVec> {
36 let key_desc = KeyDescriptor {
37 domain: Domain::APP,
38 nspace: AID_KEYSTORE as i64,
39 alias: Some("boot_level_key".to_string()),
40 blob: None,
41 };
42 let params = [
43 KeyParameterValue::Algorithm(Algorithm::HMAC).into(),
44 KeyParameterValue::Digest(Digest::SHA_2_256).into(),
45 KeyParameterValue::KeySize(256).into(),
46 KeyParameterValue::MinMacLength(256).into(),
47 KeyParameterValue::KeyPurpose(KeyPurpose::SIGN).into(),
Paul Crowleyeb964cf2021-04-19 18:14:15 -070048 KeyParameterValue::NoAuthRequired.into(),
Paul Crowley44c02da2021-04-08 17:04:43 +000049 KeyParameterValue::MaxUsesPerBoot(1).into(),
50 ];
51 // We use TRUSTED_ENVIRONMENT here because it is the authority on when
52 // the device has rebooted.
53 let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
54 .context("In get_level_zero_key: KeyMintDevice::get failed")?;
55 let (key_id_guard, key_entry) = km_dev
56 .lookup_or_generate_key(db, &key_desc, &params)
57 .context("In get_level_zero_key: lookup_or_generate_key failed")?;
58
59 let params = [KeyParameterValue::MacLength(256).into()];
60 let level_zero_key = km_dev
61 .use_key_in_one_step(
62 db,
63 key_id_guard,
64 &key_entry,
65 KeyPurpose::SIGN,
66 &params,
67 b"Create boot level key",
68 )
69 .context("In get_level_zero_key: use_key_in_one_step failed")?;
70 // TODO: this is rather unsatisfactory, we need a better way to handle
71 // sensitive binder returns.
72 let level_zero_key = ZVec::try_from(level_zero_key)
73 .context("In get_level_zero_key: conversion to ZVec failed")?;
74 Ok(level_zero_key)
75}
76
77/// Holds the key for the current boot level, and a cache of future keys generated as required.
78/// When the boot level advances, keys prior to the current boot level are securely dropped.
79pub struct BootLevelKeyCache {
80 /// Least boot level currently accessible, if any is.
81 current: usize,
82 /// Invariant: cache entry *i*, if it exists, holds the HKDF key for boot level
83 /// *i* + `current`. If the cache is non-empty it can be grown forwards, but it cannot be
84 /// grown backwards, so keys below `current` are inaccessible.
85 /// `cache.clear()` makes all keys inaccessible.
86 cache: VecDeque<ZVec>,
87}
88
89impl BootLevelKeyCache {
90 const HKDF_ADVANCE: &'static [u8] = b"Advance KDF one step";
91 const HKDF_AES: &'static [u8] = b"Generate AES-256-GCM key";
92 const HKDF_KEY_SIZE: usize = 32;
93
94 /// Initialize the cache with the level zero key.
95 pub fn new(level_zero_key: ZVec) -> Self {
96 let mut cache: VecDeque<ZVec> = VecDeque::new();
97 cache.push_back(level_zero_key);
98 Self { current: 0, cache }
99 }
100
101 /// Report whether the key for the given level can be inferred.
102 pub fn level_accessible(&self, boot_level: usize) -> bool {
103 // If the requested boot level is lower than the current boot level
104 // or if we have reached the end (`cache.empty()`) we can't retrieve
105 // the boot key.
106 boot_level >= self.current && !self.cache.is_empty()
107 }
108
109 /// Get the HKDF key for boot level `boot_level`. The key for level *i*+1
110 /// is calculated from the level *i* key using `hkdf_expand`.
111 fn get_hkdf_key(&mut self, boot_level: usize) -> Result<Option<&ZVec>> {
112 if !self.level_accessible(boot_level) {
113 return Ok(None);
114 }
115 // `self.cache.len()` represents the first entry not in the cache,
116 // so `self.current + self.cache.len()` is the first boot level not in the cache.
117 let first_not_cached = self.current + self.cache.len();
118
119 // Grow the cache forwards until it contains the desired boot level.
120 for _level in first_not_cached..=boot_level {
121 // We check at the start that cache is non-empty and future iterations only push,
122 // so this must unwrap.
123 let highest_key = self.cache.back().unwrap();
124 let next_key = hkdf_expand(Self::HKDF_KEY_SIZE, highest_key, Self::HKDF_ADVANCE)
125 .context("In BootLevelKeyCache::get_hkdf_key: Advancing key one step")?;
126 self.cache.push_back(next_key);
127 }
128
129 // If we reach this point, we should have a key at index boot_level - current.
130 Ok(Some(self.cache.get(boot_level - self.current).unwrap()))
131 }
132
133 /// Drop keys prior to the given boot level, while retaining the ability to generate keys for
134 /// that level and later.
135 pub fn advance_boot_level(&mut self, new_boot_level: usize) -> Result<()> {
136 if !self.level_accessible(new_boot_level) {
137 log::error!(
138 concat!(
139 "In BootLevelKeyCache::advance_boot_level: ",
140 "Failed to advance boot level to {}, current is {}, cache size {}"
141 ),
142 new_boot_level,
143 self.current,
144 self.cache.len()
145 );
146 return Ok(());
147 }
148
149 // We `get` the new boot level for the side effect of advancing the cache to a point
150 // where the new boot level is present.
151 self.get_hkdf_key(new_boot_level)
152 .context("In BootLevelKeyCache::advance_boot_level: Advancing cache")?;
153
154 // Then we split the queue at the index of the new boot level and discard the front,
155 // keeping only the keys with the current boot level or higher.
156 self.cache = self.cache.split_off(new_boot_level - self.current);
157
158 // The new cache has the new boot level at index 0, so we set `current` to
159 // `new_boot_level`.
160 self.current = new_boot_level;
161
162 Ok(())
163 }
164
165 /// Drop all keys, effectively raising the current boot level to infinity; no keys can
166 /// be inferred from this point on.
167 pub fn finish(&mut self) {
168 self.cache.clear();
169 }
170
171 fn expand_key(
172 &mut self,
173 boot_level: usize,
174 out_len: usize,
175 info: &[u8],
176 ) -> Result<Option<ZVec>> {
177 self.get_hkdf_key(boot_level)
178 .context("In BootLevelKeyCache::expand_key: Looking up HKDF key")?
179 .map(|k| hkdf_expand(out_len, k, info))
180 .transpose()
181 .context("In BootLevelKeyCache::expand_key: Calling hkdf_expand")
182 }
183
184 /// Return the AES-256-GCM key for the current boot level.
185 pub fn aes_key(&mut self, boot_level: usize) -> Result<Option<ZVec>> {
186 self.expand_key(boot_level, AES_256_KEY_LENGTH, BootLevelKeyCache::HKDF_AES)
187 .context("In BootLevelKeyCache::aes_key: expand_key failed")
188 }
189}
190
191#[cfg(test)]
192mod test {
193 use super::*;
194
195 #[test]
196 fn test_output_is_consistent() -> Result<()> {
197 let initial_key = b"initial key";
198 let mut blkc = BootLevelKeyCache::new(ZVec::try_from(initial_key as &[u8])?);
199 assert_eq!(true, blkc.level_accessible(0));
200 assert_eq!(true, blkc.level_accessible(9));
201 assert_eq!(true, blkc.level_accessible(10));
202 assert_eq!(true, blkc.level_accessible(100));
203 let v0 = blkc.aes_key(0).unwrap().unwrap();
204 let v10 = blkc.aes_key(10).unwrap().unwrap();
205 assert_eq!(Some(&v0), blkc.aes_key(0)?.as_ref());
206 assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref());
207 blkc.advance_boot_level(5)?;
208 assert_eq!(false, blkc.level_accessible(0));
209 assert_eq!(true, blkc.level_accessible(9));
210 assert_eq!(true, blkc.level_accessible(10));
211 assert_eq!(true, blkc.level_accessible(100));
212 assert_eq!(None, blkc.aes_key(0)?);
213 assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref());
214 blkc.advance_boot_level(10)?;
215 assert_eq!(false, blkc.level_accessible(0));
216 assert_eq!(false, blkc.level_accessible(9));
217 assert_eq!(true, blkc.level_accessible(10));
218 assert_eq!(true, blkc.level_accessible(100));
219 assert_eq!(None, blkc.aes_key(0)?);
220 assert_eq!(Some(&v10), blkc.aes_key(10)?.as_ref());
221 blkc.advance_boot_level(0)?;
222 assert_eq!(false, blkc.level_accessible(0));
223 assert_eq!(false, blkc.level_accessible(9));
224 assert_eq!(true, blkc.level_accessible(10));
225 assert_eq!(true, blkc.level_accessible(100));
226 assert_eq!(None, blkc.aes_key(0)?);
227 assert_eq!(Some(v10), blkc.aes_key(10)?);
228 blkc.finish();
229 assert_eq!(false, blkc.level_accessible(0));
230 assert_eq!(false, blkc.level_accessible(9));
231 assert_eq!(false, blkc.level_accessible(10));
232 assert_eq!(false, blkc.level_accessible(100));
233 assert_eq!(None, blkc.aes_key(0)?);
234 assert_eq!(None, blkc.aes_key(10)?);
235 Ok(())
236 }
237}