Skip to main content

fake_keymint/
lib.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A fake implementation of fuchsia.security.keymint.SealingKeys and
6//! fuchsia.security.keymint.Admin for testing purposes.
7//!
8//! IMPORTANT: This implementation is insecure!
9
10use aes_gcm_siv::aead::Aead as _;
11use aes_gcm_siv::{Aes128GcmSiv, Key, KeyInit as _, Nonce};
12use fidl::endpoints::{ClientEnd, create_request_stream};
13use fidl_fuchsia_security_keymint::{
14    AdminMarker, AdminRequest, AdminRequestStream, DeleteError, SealError, SealingKeysMarker,
15    SealingKeysRequest, SealingKeysRequestStream, UnsealError, UpgradeError,
16};
17use fuchsia_sync::Mutex;
18use futures::{FutureExt as _, TryStreamExt as _};
19use log::warn;
20use std::collections::BTreeMap;
21use std::future::Future;
22use std::pin::pin;
23
24use futures::future::BoxFuture;
25use std::sync::Arc;
26
27type KeyInfo = Vec<u8>;
28
29/// This is the *internal* representation of a sealing key in FakeKeymint.
30///
31/// While an external representation consists of a key_info and key_blob, internally we
32/// are keeping a set of keyblobs to allow for key upgrading.
33struct SealingKey {
34    cipher: Aes128GcmSiv,
35    /// Holds a collection of key blobs (bag of bytes) that are to be considered
36    /// valid for this sealing key. These are added when we create a key and
37    /// when we upgrade a key. They are removed when we delete a sealing key.
38    key_blobs: Vec<Vec<u8>>,
39}
40
41type DeleteHook = Arc<dyn Fn(Vec<u8>) -> BoxFuture<'static, Option<DeleteError>> + Send + Sync>;
42
43#[derive(Default)]
44struct Inner {
45    sealing_keys: BTreeMap<KeyInfo, SealingKey>,
46    // Epoch is mixed into keys, and is incremented each time DeleteAllKeys is called.  This ensures
47    // that previously deleted keys cannot be reused.
48    epoch: u64,
49
50    /// An optional async hook that is called before `DeleteSealingKey` performs the deletion.
51    /// If the hook returns `Some(err)`, that error is returned to the client and the deletion is
52    /// skipped.
53    /// If the hook returns `None`, the deletion proceeds normally.
54    /// The hook can also hang indefinitely to simulate a crash.
55    delete_hook: Option<DeleteHook>,
56}
57
58/// Generate a key blob for a given key_info and epoch.
59fn blob_for_key(key_info: &KeyInfo, epoch: u64) -> Vec<u8> {
60    format!("bL0b_F0r_t3$t_{}|{epoch}", String::from_utf8_lossy(key_info)).into_bytes().to_vec()
61}
62
63/// Extract the epoch from a key_blob.
64fn epoch_from_blob(blob: &[u8]) -> Option<u64> {
65    let blob_str = String::from_utf8_lossy(blob);
66    blob_str.split('|').last().and_then(|s| s.parse().ok())
67}
68
69impl Inner {
70    const IV: [u8; 12] = [0u8; 12];
71
72    // NB: A real Keymint implementation would return a different sealing key each time this is
73    // called, and remember the keys that are created.  Since we don't have anywhere to persist
74    // them, we just derive the sealing key from the key info directly, and then derive the key blob
75    // from the key info and epoch.  Obviously, this is not secure.
76    fn derive_key(key_info: &KeyInfo, epoch: u64) -> SealingKey {
77        let mut key_bytes = [0u8; 16];
78        let len = key_info.len().min(16);
79        key_bytes[..len].copy_from_slice(&key_info[..len]);
80
81        // Cipher should be stable for a given key_info so that we can unseal secrets
82        // after an epoch bump (which triggers a blob upgrade but shouldn't break decryption).
83        let cipher = Aes128GcmSiv::new(Key::<Aes128GcmSiv>::from_slice(&key_bytes));
84        let key_blobs = vec![blob_for_key(key_info, epoch)];
85        SealingKey { cipher, key_blobs }
86    }
87
88    fn handle_create_request(&mut self, key_info: KeyInfo) -> Vec<u8> {
89        let epoch = self.epoch;
90        let sealing_key = self
91            .sealing_keys
92            .entry(key_info.clone())
93            .or_insert_with(|| Self::derive_key(&key_info, epoch));
94        if !sealing_key.key_blobs.iter().any(|b| epoch_from_blob(b) == Some(epoch)) {
95            sealing_key.key_blobs.push(blob_for_key(&key_info, epoch));
96        }
97        sealing_key.key_blobs.iter().find(|b| epoch_from_blob(b) == Some(epoch)).unwrap().clone()
98    }
99
100    /// Handles a seal request.
101    ///
102    /// If the key_blob is not found, or the epoch is too old, it will return an error.
103    /// Otherwise, it will encrypt the secret with the sealing key and return the sealed secret.
104    fn handle_seal_request(
105        &mut self,
106        key_info: KeyInfo,
107        key_blob: Vec<u8>,
108        secret: Vec<u8>,
109    ) -> Result<Vec<u8>, SealError> {
110        let sealing_key = self.sealing_keys.get(&key_info).ok_or_else(|| SealError::FailedSeal)?;
111        if !sealing_key.key_blobs.contains(&key_blob) {
112            warn!("Wrong key blob");
113            return Err(SealError::FailedSeal);
114        }
115        let epoch = epoch_from_blob(&key_blob).ok_or_else(|| {
116            warn!("Invalid key blob");
117            SealError::FailedSeal
118        })?;
119        if epoch < self.epoch {
120            warn!("Key requires upgrade");
121            return Err(SealError::KeyRequiresUpgrade);
122        }
123        let sealed_secret = sealing_key
124            .cipher
125            .encrypt(&Nonce::from_slice(&Self::IV), &secret[..])
126            .map_err(|e| {
127                warn!("Failed to seal secret: {}", e);
128                SealError::FailedSeal
129            })?;
130        Ok(sealed_secret)
131    }
132
133    /// Handles an unseal request.
134    ///
135    /// If the key_blob is not found, or the epoch is too old, it will return an error.
136    /// Otherwise, it will decrypt the sealed secret with the sealing key and return the secret.
137    fn handle_unseal_request(
138        &mut self,
139        key_info: KeyInfo,
140        key_blob: Vec<u8>,
141        sealed_secret: Vec<u8>,
142    ) -> Result<Vec<u8>, UnsealError> {
143        let sealing_key = self
144            .sealing_keys
145            .entry(key_info.clone())
146            .or_insert_with(|| Self::derive_key(&key_info, self.epoch));
147        if !sealing_key.key_blobs.contains(&key_blob) {
148            warn!("Unknown keyblob");
149            return Err(UnsealError::FailedUnseal);
150        }
151        let epoch = epoch_from_blob(&key_blob).ok_or_else(|| {
152            warn!("Invalid key blob");
153            UnsealError::FailedUnseal
154        })?;
155        if epoch < self.epoch {
156            warn!("Key requires upgrade");
157            return Err(UnsealError::KeyRequiresUpgrade);
158        }
159        let secret = sealing_key
160            .cipher
161            .decrypt(&Nonce::from_slice(&Self::IV), &sealed_secret[..])
162            .map_err(|e| {
163                warn!("Failed to unseal secret: {}", e);
164                UnsealError::FailedUnseal
165            })?;
166        Ok(secret)
167    }
168
169    fn handle_delete_all_keys_request(&mut self) {
170        self.sealing_keys.clear();
171        self.epoch += 1;
172    }
173
174    /// Bumps the epoch and returns the new epoch.
175    fn bump_epoch(&mut self) {
176        self.epoch += 1;
177    }
178
179    /// Handles an upgrade request.
180    ///
181    /// If the key_blob is not found, it will return an error.
182    /// Otherwise, it will return a new key blob for the current epoch.
183    /// Note that the old key blob will continue to work (but require an upgrade) until deleted.
184    fn handle_upgrade_request(
185        &mut self,
186        key_info: KeyInfo,
187        key_blob: Vec<u8>,
188    ) -> Result<Vec<u8>, UpgradeError> {
189        let epoch = self.epoch;
190        let sealing_key = self
191            .sealing_keys
192            .entry(key_info.clone())
193            .or_insert_with(|| Self::derive_key(&key_info, epoch));
194        if !sealing_key.key_blobs.contains(&key_blob) {
195            warn!("Wrong key blob for upgrade");
196            return Err(UpgradeError::FailedUpgrade);
197        }
198        let upgraded = blob_for_key(&key_info, self.epoch);
199        if !sealing_key.key_blobs.contains(&upgraded) {
200            sealing_key.key_blobs.push(upgraded.clone());
201        }
202        Ok(upgraded)
203    }
204
205    /// Handles a delete request.
206    ///
207    /// If the key_blob is not found, it will return an error.
208    /// Otherwise, it will remove the key blob from the key blobs.
209    /// The sealing key will no longer be valid after this call.
210    fn handle_delete_request(&mut self, key_blob: &[u8]) -> Result<(), DeleteError> {
211        let mut removed = false;
212        self.sealing_keys.retain(|_, sealing_key| {
213            let initial_len = sealing_key.key_blobs.len();
214            sealing_key.key_blobs.retain(|kb| kb != key_blob);
215            if sealing_key.key_blobs.len() < initial_len {
216                removed = true;
217            }
218            !sealing_key.key_blobs.is_empty()
219        });
220
221        if removed { Ok(()) } else { Err(DeleteError::FailedDelete) }
222    }
223
224    fn has_key_blob(&self, key_blob: &[u8]) -> bool {
225        self.sealing_keys.values().any(|sk| sk.key_blobs.iter().any(|b| b == key_blob))
226    }
227}
228
229#[derive(Default, Clone)]
230pub struct FakeKeymint {
231    inner: Arc<Mutex<Inner>>,
232}
233
234impl FakeKeymint {
235    /// Sets an async hook to be called before `DeleteSealingKey` performs the deletion.
236    pub fn set_delete_hook<F>(&self, hook: F)
237    where
238        F: Fn(Vec<u8>) -> BoxFuture<'static, Option<DeleteError>> + Send + Sync + 'static,
239    {
240        self.inner.lock().delete_hook = Some(Arc::new(hook));
241    }
242
243    /// Checks whether the underlying state currently contains the specified key blob.
244    pub fn has_key_blob(&self, key_blob: &[u8]) -> bool {
245        self.inner.lock().has_key_blob(key_blob)
246    }
247
248    /// Used to force a key upgrade of all sealing keys with the current epoch.
249    pub fn bump_epoch(&self) {
250        self.inner.lock().bump_epoch();
251    }
252
253    /// Injects mock key state directly into FakeKeymint simulating an arbitrary list of key blobs.
254    /// If a key already exists, the injected blobs are appended to the existing state.
255    pub fn insert_sealing_key(&self, key_info: &[u8], blobs: Vec<Vec<u8>>) {
256        let mut inner = self.inner.lock();
257        if let Some(existing) = inner.sealing_keys.get_mut(key_info) {
258            for blob in blobs {
259                if !existing.key_blobs.contains(&blob) {
260                    existing.key_blobs.push(blob);
261                }
262            }
263        } else {
264            inner.sealing_keys.insert(
265                key_info.to_vec(),
266                SealingKey {
267                    cipher: Inner::derive_key(&key_info.to_vec(), 0).cipher,
268                    key_blobs: blobs,
269                },
270            );
271        }
272    }
273
274    /// Generates a mock `sealing_key_blob` payload synchronously without traversing FIDL channels.
275    pub fn generate_static_sealing_key(&self, key_info: &[u8]) -> Vec<u8> {
276        self.inner.lock().handle_create_request(key_info.to_vec()).to_vec()
277    }
278
279    /// Generates a mock `sealed_keys` payload synchronously without traversing FIDL channels.
280    pub fn generate_static_sealed_data(
281        &self,
282        key_info: &[u8],
283        key_blob: &[u8],
284        secret: &[u8],
285    ) -> Vec<u8> {
286        self.inner
287            .lock()
288            .handle_seal_request(key_info.to_vec(), key_blob.to_vec(), secret.to_vec())
289            .expect("Failed static seal request")
290            .to_vec()
291    }
292
293    /// Handles [`SealingKeysRequestStream`] to completion.
294    pub async fn run_sealing_keys_service(
295        &self,
296        stream: SealingKeysRequestStream,
297    ) -> Result<(), fidl::Error> {
298        stream
299            .try_for_each_concurrent(None, move |request| async move {
300                match request {
301                    SealingKeysRequest::CreateSealingKey { key_info, responder } => {
302                        responder.send(Ok(&*self.inner.lock().handle_create_request(key_info)))?;
303                    }
304                    SealingKeysRequest::Seal { key_info, key_blob, secret, responder } => {
305                        match self.inner.lock().handle_seal_request(key_info, key_blob, secret) {
306                            Ok(sealed_secret) => responder.send(Ok(&*sealed_secret))?,
307                            Err(err) => responder.send(Err(err))?,
308                        }
309                    }
310                    SealingKeysRequest::Unseal { key_info, key_blob, sealed_secret, responder } => {
311                        match self.inner.lock().handle_unseal_request(
312                            key_info,
313                            key_blob,
314                            sealed_secret,
315                        ) {
316                            Ok(secret) => responder.send(Ok(&*secret))?,
317                            Err(err) => responder.send(Err(err))?,
318                        }
319                    }
320                    SealingKeysRequest::UpgradeSealingKey { key_info, key_blob, responder } => {
321                        match self.inner.lock().handle_upgrade_request(key_info, key_blob) {
322                            Ok(key) => responder.send(Ok(&*key))?,
323                            Err(err) => responder.send(Err(err))?,
324                        }
325                    }
326                    SealingKeysRequest::DeleteSealingKey { key_blob, responder } => {
327                        let hook = self.inner.lock().delete_hook.clone();
328                        let hook_result =
329                            if let Some(hook) = hook { hook(key_blob.clone()).await } else { None };
330
331                        if let Some(err) = hook_result {
332                            responder.send(Err(err))?;
333                        } else {
334                            let result = self.inner.lock().handle_delete_request(&key_blob);
335                            match result {
336                                Ok(()) => responder.send(Ok(()))?,
337                                Err(e) => responder.send(Err(e))?,
338                            }
339                        }
340                    }
341                }
342                Ok(())
343            })
344            .await
345    }
346
347    /// Handles [`AdminRequestStream`] to completion.
348    pub async fn run_admin_service(&self, stream: AdminRequestStream) -> Result<(), fidl::Error> {
349        stream
350            .try_for_each_concurrent(None, move |request| async move {
351                match request {
352                    AdminRequest::DeleteAllKeys { responder } => {
353                        responder.send(Ok(self.inner.lock().handle_delete_all_keys_request()))?;
354                    }
355                }
356                Ok(())
357            })
358            .await
359    }
360}
361
362/// Runs `f` with a scoped FakeKeymint instance.  The instance will be automatically terminated on
363/// completion.
364pub async fn with_keymint_service<R, Fut: Future<Output = anyhow::Result<R>>>(
365    f: impl FnOnce(ClientEnd<SealingKeysMarker>, ClientEnd<AdminMarker>) -> Fut,
366) -> anyhow::Result<R> {
367    let (sealing_keys_client, sealing_keys_stream) = create_request_stream::<SealingKeysMarker>();
368    let (admin_client, admin_stream) = create_request_stream::<AdminMarker>();
369    let fake_keymint = FakeKeymint::default();
370    let mut sealing_keys_service =
371        pin!(async { fake_keymint.run_sealing_keys_service(sealing_keys_stream).await }.fuse());
372    let mut admin_service =
373        pin!(async { fake_keymint.run_admin_service(admin_stream).await }.fuse());
374    let mut fut = pin!(f(sealing_keys_client, admin_client).fuse());
375
376    loop {
377        futures::select! {
378            _ = sealing_keys_service => {}
379            _ = admin_service => {}
380            result = fut => return result,
381        }
382    }
383}
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    #[fuchsia::test]
390    async fn create_seal_unseal() {
391        with_keymint_service(|keymint, _| async {
392            let keymint = keymint.into_proxy();
393            const KEY_INFO: [u8; 16] = [1u8; 16];
394            let key_blob = keymint
395                .create_sealing_key(&KEY_INFO[..])
396                .await
397                .expect("FIDL error")
398                .expect("create error");
399            const SECRET: [u8; 16] = [0xffu8; 16];
400            let sealed = keymint
401                .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
402                .await
403                .expect("FIDL error")
404                .expect("seal error");
405            assert_ne!(sealed, SECRET);
406            let unsealed = keymint
407                .unseal(&KEY_INFO[..], &key_blob[..], &sealed[..])
408                .await
409                .expect("FIDL error")
410                .expect("unseal error");
411            assert_eq!(unsealed, SECRET);
412            Ok(())
413        })
414        .await
415        .unwrap();
416    }
417
418    #[fuchsia::test]
419    async fn seal_failure_on_wrong_key_info() {
420        with_keymint_service(|keymint, _| async {
421            let keymint = keymint.into_proxy();
422            const KEY_INFO: [u8; 16] = [1u8; 16];
423            let key_blob = keymint
424                .create_sealing_key(&KEY_INFO[..])
425                .await
426                .expect("FIDL error")
427                .expect("create error");
428            const SECRET: [u8; 16] = [0xffu8; 16];
429            keymint
430                .seal(&[2u8; 16], &key_blob[..], &SECRET[..])
431                .await
432                .expect("FIDL error")
433                .expect_err("seal should fail");
434            Ok(())
435        })
436        .await
437        .unwrap();
438    }
439
440    #[fuchsia::test]
441    async fn unseal_failure_on_wrong_sealing_key() {
442        with_keymint_service(|keymint, _| async {
443            let keymint = keymint.into_proxy();
444            const KEY_INFO: [u8; 16] = [1u8; 16];
445            let key_blob = keymint
446                .create_sealing_key(&KEY_INFO[..])
447                .await
448                .expect("FIDL error")
449                .expect("create error");
450            const SECRET: [u8; 16] = [0xffu8; 16];
451            let sealed = keymint
452                .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
453                .await
454                .expect("FIDL error")
455                .expect("seal error");
456            assert_ne!(sealed, SECRET);
457            keymint
458                .unseal(&[2u8; 16], &key_blob[..], &sealed[..])
459                .await
460                .expect("FIDL error")
461                .expect_err("unseal should fail");
462            Ok(())
463        })
464        .await
465        .unwrap();
466    }
467
468    #[fuchsia::test]
469    async fn unseal_failure_on_wrong_secret_blob() {
470        with_keymint_service(|keymint, _| async {
471            let keymint = keymint.into_proxy();
472            const KEY_INFO: [u8; 16] = [1u8; 16];
473            let key_blob = keymint
474                .create_sealing_key(&KEY_INFO[..])
475                .await
476                .expect("FIDL error")
477                .expect("create error");
478            const SECRET: [u8; 16] = [0xffu8; 16];
479            let _ = keymint
480                .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
481                .await
482                .expect("FIDL error")
483                .expect("seal error");
484            keymint
485                .unseal(&KEY_INFO[..], &key_blob[..], &[0u8; 16])
486                .await
487                .expect("FIDL error")
488                .expect_err("unseal should fail");
489            Ok(())
490        })
491        .await
492        .unwrap();
493    }
494
495    #[fuchsia::test]
496    async fn delete_all_keys_renders_key_unusable() {
497        with_keymint_service(|keymint, admin| async {
498            let keymint = keymint.into_proxy();
499            const KEY_INFO: [u8; 16] = [1u8; 16];
500            let key_blob = keymint
501                .create_sealing_key(&KEY_INFO[..])
502                .await
503                .expect("FIDL error")
504                .expect("create error");
505
506            let admin = admin.into_proxy();
507            admin.delete_all_keys().await.expect("FIDL error").expect("create error");
508
509            const SECRET: [u8; 16] = [0xffu8; 16];
510            let _ = keymint
511                .seal(&KEY_INFO[..], &key_blob[..], &SECRET[..])
512                .await
513                .expect("FIDL error")
514                .expect_err("seal should fail");
515            Ok(())
516        })
517        .await
518        .unwrap();
519    }
520
521    #[fuchsia::test]
522    async fn delete_keys_succeeds() {
523        with_keymint_service(|keymint, _admin| async {
524            let keymint = keymint.into_proxy();
525            const KEY_INFO: [u8; 16] = [1u8; 16];
526            let key_blob = keymint
527                .create_sealing_key(&KEY_INFO[..])
528                .await
529                .expect("FIDL error")
530                .expect("create error");
531
532            keymint.delete_sealing_key(&key_blob).await.expect("FIDL error").expect("delete error");
533            Ok(())
534        })
535        .await
536        .unwrap();
537    }
538
539    #[fuchsia::test]
540    async fn delete_keys_fails_bad_key_blob() {
541        with_keymint_service(|keymint, _admin| async {
542            let keymint = keymint.into_proxy();
543            const KEY_INFO: [u8; 16] = [1u8; 16];
544            let mut key_blob = keymint
545                .create_sealing_key(&KEY_INFO[..])
546                .await
547                .expect("FIDL error")
548                .expect("create error");
549
550            key_blob[0] ^= 0xffu8;
551
552            keymint
553                .delete_sealing_key(&key_blob)
554                .await
555                .expect("FIDL error")
556                .expect_err("delete success");
557            Ok(())
558        })
559        .await
560        .unwrap();
561    }
562
563    #[fuchsia::test]
564    async fn set_delete_hook_error() {
565        let fake_keymint = FakeKeymint::default();
566        let (sealing_keys_client, sealing_keys_stream) =
567            create_request_stream::<SealingKeysMarker>();
568        let fake_keymint_clone = fake_keymint.clone();
569        let mut sealing_keys_service = pin!(
570            async { fake_keymint_clone.run_sealing_keys_service(sealing_keys_stream).await }.fuse()
571        );
572        let keymint = sealing_keys_client.into_proxy();
573
574        const KEY_INFO: [u8; 16] = [1u8; 16];
575        let key_blob = fake_keymint.generate_static_sealing_key(&KEY_INFO[..]);
576
577        fake_keymint.set_delete_hook(|_| async { Some(DeleteError::FailedDelete) }.boxed());
578
579        let mut fut = pin!(
580            async {
581                keymint
582                    .delete_sealing_key(&key_blob)
583                    .await
584                    .expect("FIDL error")
585                    .expect_err("delete success")
586            }
587            .fuse()
588        );
589
590        futures::select! {
591            _ = sealing_keys_service => panic!("service ended"),
592            err = fut => {
593                assert_eq!(err, DeleteError::FailedDelete);
594            }
595        }
596    }
597
598    #[fuchsia::test]
599    async fn set_delete_hook_success() {
600        let fake_keymint = FakeKeymint::default();
601        let (sealing_keys_client, sealing_keys_stream) =
602            create_request_stream::<SealingKeysMarker>();
603        let fake_keymint_clone = fake_keymint.clone();
604        let mut sealing_keys_service = pin!(
605            async { fake_keymint_clone.run_sealing_keys_service(sealing_keys_stream).await }.fuse()
606        );
607        let keymint = sealing_keys_client.into_proxy();
608
609        const KEY_INFO: [u8; 16] = [1u8; 16];
610        let key_blob = fake_keymint.generate_static_sealing_key(&KEY_INFO[..]);
611
612        fake_keymint.set_delete_hook(|_| async { None }.boxed());
613
614        let mut fut = pin!(
615            async {
616                keymint
617                    .delete_sealing_key(&key_blob)
618                    .await
619                    .expect("FIDL error")
620                    .expect("delete error");
621            }
622            .fuse()
623        );
624
625        futures::select! {
626            _ = sealing_keys_service => panic!("service ended"),
627            _ = fut => {}
628        }
629
630        assert!(!fake_keymint.has_key_blob(&key_blob));
631    }
632
633    #[fuchsia::test]
634    async fn set_delete_hook_hang_before() {
635        let fake_keymint = FakeKeymint::default();
636        let (sealing_keys_client, sealing_keys_stream) =
637            create_request_stream::<SealingKeysMarker>();
638        let fake_keymint_clone = fake_keymint.clone();
639        let mut sealing_keys_service = pin!(
640            async { fake_keymint_clone.run_sealing_keys_service(sealing_keys_stream).await }.fuse()
641        );
642        let keymint = sealing_keys_client.into_proxy();
643
644        const KEY_INFO: [u8; 16] = [1u8; 16];
645        let key_blob = fake_keymint.generate_static_sealing_key(&KEY_INFO[..]);
646
647        let (tx, mut rx) = futures::channel::oneshot::channel();
648        let tx = Arc::new(Mutex::new(Some(tx)));
649        fake_keymint.set_delete_hook(move |_| {
650            let tx_clone = tx.clone();
651            async move {
652                if let Some(tx) = tx_clone.lock().take() {
653                    let _ = tx.send(());
654                }
655                std::future::pending::<()>().await;
656                None
657            }
658            .boxed()
659        });
660
661        let mut fut = pin!(
662            async {
663                let _ = keymint.delete_sealing_key(&key_blob).await;
664            }
665            .fuse()
666        );
667
668        futures::select! {
669            _ = sealing_keys_service => panic!("service ended"),
670            _ = fut => panic!("delete should hang"),
671            res = rx => {
672                res.expect("channel dropped");
673            }
674        }
675
676        assert!(fake_keymint.has_key_blob(&key_blob));
677    }
678
679    #[fuchsia::test]
680    async fn bump_epoch_and_upgrade() {
681        let fake_keymint = FakeKeymint::default();
682        let (sealing_keys_client, sealing_keys_stream) =
683            create_request_stream::<SealingKeysMarker>();
684        let fake_keymint_clone = fake_keymint.clone();
685        let mut sealing_keys_service = pin!(
686            async { fake_keymint_clone.run_sealing_keys_service(sealing_keys_stream).await }.fuse()
687        );
688        let keymint = sealing_keys_client.into_proxy();
689
690        const KEY_INFO: [u8; 16] = [1u8; 16];
691        let key_blob_v1 = fake_keymint.generate_static_sealing_key(&KEY_INFO[..]);
692        const SECRET: [u8; 16] = [0xffu8; 16];
693        let sealed = fake_keymint.generate_static_sealed_data(&KEY_INFO[..], &key_blob_v1, &SECRET);
694
695        fake_keymint.bump_epoch();
696
697        let mut fut = pin!(
698            async {
699                let err = keymint
700                    .unseal(&KEY_INFO[..], &key_blob_v1, &sealed)
701                    .await
702                    .expect("FIDL error")
703                    .expect_err("should require upgrade");
704                assert_eq!(err, UnsealError::KeyRequiresUpgrade);
705
706                let key_blob_v2 = keymint
707                    .upgrade_sealing_key(&KEY_INFO[..], &key_blob_v1)
708                    .await
709                    .expect("FIDL error")
710                    .expect("upgrade error");
711                // Check that epoch bumping is reflected in blob presence natively
712                let unsealed = keymint
713                    .unseal(&KEY_INFO[..], &key_blob_v2, &sealed)
714                    .await
715                    .expect("FIDL error")
716                    .expect("unseal error");
717                assert_eq!(unsealed, SECRET);
718                key_blob_v2
719            }
720            .fuse()
721        );
722
723        let key_blob_v2 = futures::select! {
724            _ = sealing_keys_service => panic!("service ended"),
725            res = fut => res,
726        };
727
728        assert!(fake_keymint.has_key_blob(&key_blob_v2));
729        assert!(fake_keymint.has_key_blob(&key_blob_v1));
730    }
731
732    #[fuchsia::test]
733    async fn insert_sealing_key_test() {
734        let fake_keymint = FakeKeymint::default();
735        const KEY_INFO: [u8; 16] = [2u8; 16];
736        let blob1 = vec![1, 2, 3];
737        let blob2 = vec![4, 5, 6];
738        fake_keymint.insert_sealing_key(&KEY_INFO[..], vec![blob1.clone(), blob2.clone()]);
739        assert!(fake_keymint.has_key_blob(&blob1));
740        assert!(fake_keymint.has_key_blob(&blob2));
741        assert!(!fake_keymint.has_key_blob(&vec![7, 8, 9]));
742    }
743
744    #[fuchsia::test]
745    async fn insert_sealing_key_append_test() {
746        let fake_keymint = FakeKeymint::default();
747        const KEY_INFO: [u8; 16] = [2u8; 16];
748        let blob1 = vec![1, 2, 3];
749        let blob2 = vec![4, 5, 6];
750        fake_keymint.insert_sealing_key(&KEY_INFO[..], vec![blob1.clone()]);
751        fake_keymint.insert_sealing_key(&KEY_INFO[..], vec![blob2.clone()]);
752        assert!(fake_keymint.has_key_blob(&blob1));
753        assert!(fake_keymint.has_key_blob(&blob2));
754    }
755
756    #[fuchsia::test]
757    async fn bump_epoch_seal_requires_upgrade() {
758        let fake_keymint = FakeKeymint::default();
759        const KEY_INFO: [u8; 16] = [1u8; 16];
760        let key_blob_v1 = fake_keymint.generate_static_sealing_key(&KEY_INFO[..]);
761
762        fake_keymint.bump_epoch();
763
764        const SECRET: [u8; 16] = [0xffu8; 16];
765        let (sealing_keys_client, sealing_keys_stream) =
766            create_request_stream::<SealingKeysMarker>();
767        let mut sealing_keys_service =
768            pin!(async { fake_keymint.run_sealing_keys_service(sealing_keys_stream).await }.fuse());
769        let keymint = sealing_keys_client.into_proxy();
770
771        let mut fut = pin!(
772            async {
773                let err = keymint
774                    .seal(&KEY_INFO[..], &key_blob_v1, &SECRET)
775                    .await
776                    .expect("FIDL error")
777                    .expect_err("should require upgrade");
778                assert_eq!(err, SealError::KeyRequiresUpgrade);
779            }
780            .fuse()
781        );
782
783        futures::select! {
784            _ = sealing_keys_service => panic!("service ended"),
785            _ = fut => {},
786        }
787    }
788
789    #[fuchsia::test]
790    async fn upgrade_wrong_key_blob() {
791        let fake_keymint = FakeKeymint::default();
792        let (sealing_keys_client, sealing_keys_stream) =
793            create_request_stream::<SealingKeysMarker>();
794        let fake_keymint_clone = fake_keymint.clone();
795        let mut sealing_keys_service = pin!(
796            async { fake_keymint_clone.run_sealing_keys_service(sealing_keys_stream).await }.fuse()
797        );
798        let keymint = sealing_keys_client.into_proxy();
799
800        const KEY_INFO: [u8; 16] = [1u8; 16];
801        let _key_blob = fake_keymint.generate_static_sealing_key(&KEY_INFO[..]);
802
803        let mut fut = pin!(
804            async {
805                let err = keymint
806                    .upgrade_sealing_key(&KEY_INFO[..], &[9u8; 16])
807                    .await
808                    .expect("FIDL error")
809                    .expect_err("should fail to upgrade");
810                assert_eq!(err, UpgradeError::FailedUpgrade);
811            }
812            .fuse()
813        );
814
815        futures::select! {
816            _ = sealing_keys_service => panic!("service ended"),
817            _ = fut => {},
818        }
819    }
820}