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