1use aes_gcm_siv::aead::Aead as _;
11use aes_gcm_siv::{Aes128GcmSiv, Key, KeyInit as _, Nonce};
12use anyhow::{anyhow, bail};
13use fidl::endpoints::{ClientEnd, create_request_stream};
14use fidl_fuchsia_security_keymint::{
15 AdminMarker, AdminRequest, AdminRequestStream, DeleteError, SealError, SealingKeysMarker,
16 SealingKeysRequest, SealingKeysRequestStream, UnsealError, UpgradeError,
17};
18use fuchsia_sync::Mutex;
19use futures::{FutureExt as _, TryStreamExt as _};
20use log::warn;
21use std::collections::BTreeMap;
22use std::collections::btree_map::Entry;
23use std::future::Future;
24use std::pin::pin;
25
26type KeyInfo = Vec<u8>;
27
28struct SealingKey {
29 cipher: Aes128GcmSiv,
30 key_blob: Vec<u8>,
31}
32
33#[derive(Default)]
34struct Inner {
35 sealing_keys: BTreeMap<KeyInfo, SealingKey>,
36 epoch: u64,
39}
40
41impl Inner {
42 const IV: [u8; 12] = [0u8; 12];
43
44 fn derive_key(key_info: &KeyInfo, epoch: u64) -> SealingKey {
49 let mut key_bytes = [0u8; 16];
50 let len = key_info.len().min(16);
51 key_bytes[..len].copy_from_slice(&key_info[..len]);
52
53 let epoch_bytes = epoch.to_le_bytes();
55 for i in 0..8 {
56 key_bytes[i] ^= epoch_bytes[i];
57 }
58
59 let cipher = Aes128GcmSiv::new(Key::<Aes128GcmSiv>::from_slice(&key_bytes));
60 SealingKey { cipher, key_blob: key_info.clone() }
61 }
62
63 fn handle_create_request(&mut self, key_info: KeyInfo) -> Vec<u8> {
64 match self.sealing_keys.entry(key_info.clone()) {
65 Entry::Vacant(vacant) => {
66 vacant.insert(Self::derive_key(&key_info, self.epoch)).key_blob.clone()
67 }
68 Entry::Occupied(occupied) => occupied.get().key_blob.clone(),
69 }
70 }
71
72 fn handle_seal_request(
73 &mut self,
74 key_info: KeyInfo,
75 key_blob: Vec<u8>,
76 secret: Vec<u8>,
77 ) -> anyhow::Result<Vec<u8>> {
78 let sealing_key =
79 self.sealing_keys.get(&key_info).ok_or_else(|| anyhow!("No sealing key"))?;
80 if key_blob != sealing_key.key_blob {
81 bail!("Wrong key blob");
82 }
83 let sealed_secret =
84 sealing_key.cipher.encrypt(&Nonce::from_slice(&Self::IV), &secret[..])?;
85 Ok(sealed_secret)
86 }
87
88 fn handle_unseal_request(
89 &mut self,
90 key_info: KeyInfo,
91 key_blob: Vec<u8>,
92 sealed_secret: Vec<u8>,
93 ) -> anyhow::Result<Vec<u8>> {
94 let sealing_key = self
95 .sealing_keys
96 .entry(key_info.clone())
97 .or_insert_with(|| Self::derive_key(&key_info, self.epoch));
98 if key_blob != sealing_key.key_blob {
99 bail!("Wrong key blob");
100 }
101 let secret =
102 sealing_key.cipher.decrypt(&Nonce::from_slice(&Self::IV), &sealed_secret[..])?;
103 Ok(secret)
104 }
105
106 fn handle_delete_all_keys_request(&mut self) {
107 self.sealing_keys.clear();
108 self.epoch += 1;
109 }
110
111 fn handle_upgrade_request(
112 &mut self,
113 _key_info: KeyInfo,
114 _key_blob: Vec<u8>,
115 ) -> anyhow::Result<Vec<u8>> {
116 Ok(vec![])
120 }
121
122 fn handle_delete_request(&mut self, key_blob: Vec<u8>) -> anyhow::Result<()> {
123 let initial_len = self.sealing_keys.len();
124 self.sealing_keys.retain(|_info, sealing_key| &sealing_key.key_blob != &key_blob);
125 let modified_len = self.sealing_keys.len();
126 if initial_len == modified_len {
127 bail!("Failed to locate matching key for deletion");
128 }
129 if modified_len < initial_len - 1 {
130 bail!("Key blob matched multiple key entries");
131 }
132 Ok(())
133 }
134}
135
136#[derive(Default)]
138pub struct FakeKeymint {
139 inner: Mutex<Inner>,
140}
141
142impl FakeKeymint {
143 pub async fn run_sealing_keys_service(
145 &self,
146 stream: SealingKeysRequestStream,
147 ) -> Result<(), fidl::Error> {
148 stream
149 .try_for_each_concurrent(None, move |request| async move {
150 match request {
151 SealingKeysRequest::CreateSealingKey { key_info, responder } => {
152 responder.send(Ok(&*self.inner.lock().handle_create_request(key_info)))?;
153 }
154 SealingKeysRequest::Seal { key_info, key_blob, secret, responder } => {
155 match self.inner.lock().handle_seal_request(key_info, key_blob, secret) {
156 Ok(sealed_secret) => responder.send(Ok(&*sealed_secret))?,
157 Err(err) => {
158 warn!(err:?; "Failed to seal secret");
159 responder.send(Err(SealError::FailedSeal))?
160 }
161 }
162 }
163 SealingKeysRequest::Unseal { key_info, key_blob, sealed_secret, responder } => {
164 match self.inner.lock().handle_unseal_request(
165 key_info,
166 key_blob,
167 sealed_secret,
168 ) {
169 Ok(secret) => responder.send(Ok(&*secret))?,
170 Err(err) => {
171 warn!(err:?; "Failed to unseal secret");
172 responder.send(Err(UnsealError::FailedUnseal))?
173 }
174 }
175 }
176 SealingKeysRequest::UpgradeSealingKey { key_info, key_blob, responder } => {
177 match self.inner.lock().handle_upgrade_request(key_info, key_blob) {
178 Ok(key) => responder.send(Ok(&*key))?,
179 Err(err) => {
180 warn!(err:?; "Failed to upgrade key");
181 responder.send(Err(UpgradeError::FailedUpgrade))?
182 }
183 }
184 }
185 SealingKeysRequest::DeleteSealingKey { key_blob, responder } => {
186 match self.inner.lock().handle_delete_request(key_blob) {
187 Ok(()) => responder.send(Ok(()))?,
188 Err(err) => {
189 warn!(err:?; "Failed to delete key");
190 responder.send(Err(DeleteError::FailedDelete))?
191 }
192 }
193 }
194 }
195 Ok(())
196 })
197 .await
198 }
199
200 pub async fn run_admin_service(&self, stream: AdminRequestStream) -> Result<(), fidl::Error> {
202 stream
203 .try_for_each_concurrent(None, move |request| async move {
204 match request {
205 AdminRequest::DeleteAllKeys { responder } => {
206 responder.send(Ok(self.inner.lock().handle_delete_all_keys_request()))?;
207 }
208 }
209 Ok(())
210 })
211 .await
212 }
213}
214
215pub async fn with_keymint_service<R, Fut: Future<Output = anyhow::Result<R>>>(
218 f: impl FnOnce(ClientEnd<SealingKeysMarker>, ClientEnd<AdminMarker>) -> Fut,
219) -> anyhow::Result<R> {
220 let (sealing_keys_client, sealing_keys_stream) = create_request_stream::<SealingKeysMarker>();
221 let (admin_client, admin_stream) = create_request_stream::<AdminMarker>();
222 let fake_keymint = FakeKeymint::default();
223 let mut sealing_keys_service =
224 pin!(async { fake_keymint.run_sealing_keys_service(sealing_keys_stream).await }.fuse());
225 let mut admin_service =
226 pin!(async { fake_keymint.run_admin_service(admin_stream).await }.fuse());
227 let mut fut = pin!(f(sealing_keys_client, admin_client).fuse());
228
229 loop {
230 futures::select! {
231 _ = sealing_keys_service => {}
232 _ = admin_service => {}
233 result = fut => return result,
234 }
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 #[fuchsia::test]
243 async fn create_seal_unseal() {
244 with_keymint_service(|keymint, _| async {
245 let keymint = keymint.into_proxy();
246 const KEY_INFO: [u8; 16] = [1u8; 16];
247 let key_blob = keymint
248 .create_sealing_key(&KEY_INFO[..])
249 .await
250 .expect("FIDL error")
251 .expect("create error");
252 const SECRET: [u8; 16] = [0xffu8; 16];
253 let sealed = keymint
254 .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
255 .await
256 .expect("FIDL error")
257 .expect("seal error");
258 assert_ne!(sealed, SECRET);
259 let unsealed = keymint
260 .unseal(&KEY_INFO[..], &key_blob[..], &sealed[..])
261 .await
262 .expect("FIDL error")
263 .expect("unseal error");
264 assert_eq!(unsealed, SECRET);
265 Ok(())
266 })
267 .await
268 .unwrap();
269 }
270
271 #[fuchsia::test]
272 async fn seal_failure_on_wrong_key_info() {
273 with_keymint_service(|keymint, _| async {
274 let keymint = keymint.into_proxy();
275 const KEY_INFO: [u8; 16] = [1u8; 16];
276 let key_blob = keymint
277 .create_sealing_key(&KEY_INFO[..])
278 .await
279 .expect("FIDL error")
280 .expect("create error");
281 const SECRET: [u8; 16] = [0xffu8; 16];
282 keymint
283 .seal(&[2u8; 16], &key_blob[..], &SECRET[..])
284 .await
285 .expect("FIDL error")
286 .expect_err("seal should fail");
287 Ok(())
288 })
289 .await
290 .unwrap();
291 }
292
293 #[fuchsia::test]
294 async fn unseal_failure_on_wrong_sealing_key() {
295 with_keymint_service(|keymint, _| async {
296 let keymint = keymint.into_proxy();
297 const KEY_INFO: [u8; 16] = [1u8; 16];
298 let key_blob = keymint
299 .create_sealing_key(&KEY_INFO[..])
300 .await
301 .expect("FIDL error")
302 .expect("create error");
303 const SECRET: [u8; 16] = [0xffu8; 16];
304 let sealed = keymint
305 .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
306 .await
307 .expect("FIDL error")
308 .expect("seal error");
309 assert_ne!(sealed, SECRET);
310 keymint
311 .unseal(&[2u8; 16], &key_blob[..], &sealed[..])
312 .await
313 .expect("FIDL error")
314 .expect_err("unseal should fail");
315 Ok(())
316 })
317 .await
318 .unwrap();
319 }
320
321 #[fuchsia::test]
322 async fn unseal_failure_on_wrong_secret_blob() {
323 with_keymint_service(|keymint, _| async {
324 let keymint = keymint.into_proxy();
325 const KEY_INFO: [u8; 16] = [1u8; 16];
326 let key_blob = keymint
327 .create_sealing_key(&KEY_INFO[..])
328 .await
329 .expect("FIDL error")
330 .expect("create error");
331 const SECRET: [u8; 16] = [0xffu8; 16];
332 let _ = keymint
333 .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
334 .await
335 .expect("FIDL error")
336 .expect("seal error");
337 keymint
338 .unseal(&KEY_INFO[..], &key_blob[..], &[0u8; 16])
339 .await
340 .expect("FIDL error")
341 .expect_err("unseal should fail");
342 Ok(())
343 })
344 .await
345 .unwrap();
346 }
347
348 #[fuchsia::test]
349 async fn delete_all_keys_renders_key_unusable() {
350 with_keymint_service(|keymint, admin| async {
351 let keymint = keymint.into_proxy();
352 const KEY_INFO: [u8; 16] = [1u8; 16];
353 let key_blob = keymint
354 .create_sealing_key(&KEY_INFO[..])
355 .await
356 .expect("FIDL error")
357 .expect("create error");
358
359 let admin = admin.into_proxy();
360 admin.delete_all_keys().await.expect("FIDL error").expect("create error");
361
362 const SECRET: [u8; 16] = [0xffu8; 16];
363 let _ = keymint
364 .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
365 .await
366 .expect("FIDL error")
367 .expect_err("seal should fail");
368 Ok(())
369 })
370 .await
371 .unwrap();
372 }
373
374 #[fuchsia::test]
375 async fn delete_keys_succeeds() {
376 with_keymint_service(|keymint, _admin| async {
377 let keymint = keymint.into_proxy();
378 const KEY_INFO: [u8; 16] = [1u8; 16];
379 let key_blob = keymint
380 .create_sealing_key(&KEY_INFO[..])
381 .await
382 .expect("FIDL error")
383 .expect("create error");
384
385 keymint.delete_sealing_key(&key_blob).await.expect("FIDL error").expect("delete error");
386 Ok(())
387 })
388 .await
389 .unwrap();
390 }
391
392 #[fuchsia::test]
393 async fn delete_keys_fails_bad_key_blob() {
394 with_keymint_service(|keymint, _admin| async {
395 let keymint = keymint.into_proxy();
396 const KEY_INFO: [u8; 16] = [1u8; 16];
397 let mut key_blob = keymint
398 .create_sealing_key(&KEY_INFO[..])
399 .await
400 .expect("FIDL error")
401 .expect("create error");
402
403 key_blob[0] ^= 0xffu8;
404
405 keymint
406 .delete_sealing_key(&key_blob)
407 .await
408 .expect("FIDL error")
409 .expect_err("delete success");
410 Ok(())
411 })
412 .await
413 .unwrap();
414 }
415}