fxfs/object_store/
key_manager.rs

1// Copyright 2023 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
5use crate::errors::FxfsError;
6use crate::log::*;
7use crate::object_store::object_record::EncryptionKeys;
8use crate::object_store::{FSCRYPT_KEY_ID, VOLUME_DATA_KEY_ID};
9use anyhow::Error;
10use event_listener::Event;
11use fuchsia_sync::Mutex;
12use fxfs_crypto::{Cipher, CipherHolder, CipherSet, Crypt, FindKeyResult};
13use scopeguard::ScopeGuard;
14use std::cell::UnsafeCell;
15use std::collections::BTreeMap;
16use std::collections::btree_map::Entry;
17use std::future::Future;
18use std::sync::Arc;
19use std::time::Duration;
20use {fuchsia_async as fasync, zx_status as zx};
21
22/// This timeout controls when entries are moved from `hash` to `pending_purge` and then dumped.
23/// Entries will remain in the cache until they remain inactive from between PURGE_TIMEOUT and 2 *
24/// PURGE_TIMEOUT.  This is deliberately set to 37 seconds (rather than a round number) to reduce
25/// the chance that this timer ends up always firing at the same time as other timers.
26const PURGE_TIMEOUT: Duration = Duration::from_secs(37);
27
28/// A simple cache that purges entries periodically when `purge` is called.  The API is similar to
29/// HashMap's.
30struct Cache<V> {
31    hash: BTreeMap<u64, V>,
32    pending_purge: BTreeMap<u64, V>,
33    permanent: BTreeMap<u64, V>,
34}
35
36impl<V> Cache<V> {
37    fn new() -> Self {
38        Self { hash: BTreeMap::new(), pending_purge: BTreeMap::new(), permanent: BTreeMap::new() }
39    }
40
41    fn get(&mut self, key: u64) -> Option<&V> {
42        match self.hash.entry(key) {
43            Entry::Occupied(o) => Some(o.into_mut()),
44            Entry::Vacant(v) => {
45                // If we find an entry in `pending_purge`, move it into `hash`.
46                if let Some(value) = self.pending_purge.remove(&key) {
47                    Some(v.insert(value))
48                } else {
49                    self.permanent.get(&key)
50                }
51            }
52        }
53    }
54
55    fn insert(&mut self, key: u64, value: V, permanent: bool) {
56        if permanent {
57            self.permanent.insert(key, value);
58        } else {
59            self.hash.insert(key, value);
60        }
61    }
62
63    fn merge(&mut self, key: u64, merge: impl FnOnce(Option<&V>) -> V) {
64        match self.hash.entry(key) {
65            Entry::Occupied(mut o) => {
66                let new = merge(Some(o.get()));
67                *o.get_mut() = new;
68            }
69            Entry::Vacant(v) => {
70                // If we find an entry in `pending_purge`, move it into `hash`.
71                if let Some(value) = self.pending_purge.remove(&key) {
72                    v.insert(merge(Some(&value)));
73                } else {
74                    v.insert(merge(None));
75                }
76            }
77        }
78    }
79
80    /// This purges entries that haven't been accessed since the last call to purge.
81    ///
82    /// Returns true if the cache no longer has any purgeable entries.
83    fn purge(&mut self) -> bool {
84        self.pending_purge = std::mem::take(&mut self.hash);
85        self.pending_purge.is_empty()
86    }
87
88    fn clear(&mut self) {
89        self.hash.clear();
90        self.pending_purge.clear();
91        self.permanent.clear();
92    }
93
94    fn remove(&mut self, key: u64) {
95        self.hash.remove(&key);
96        self.pending_purge.remove(&key);
97        self.permanent.remove(&key);
98    }
99}
100
101pub struct KeyManager {
102    inner: Arc<Mutex<Inner>>,
103}
104
105struct Inner {
106    keys: Cache<Arc<CipherSet>>,
107    unwrapping: BTreeMap<u64, Arc<UnwrapResult>>,
108    purge_task: Option<fasync::Task<()>>,
109}
110
111impl Inner {
112    fn start_purge_task(&mut self, inner: &Arc<Mutex<Inner>>) {
113        self.purge_task.get_or_insert_with(move || {
114            let inner = inner.clone();
115            fasync::Task::spawn(async move {
116                loop {
117                    fasync::Timer::new(PURGE_TIMEOUT).await;
118                    let mut inner = inner.lock();
119                    if inner.keys.purge() {
120                        inner.purge_task = None;
121                        break;
122                    }
123                }
124            })
125        });
126    }
127}
128
129struct UnwrapResult {
130    event: Event,
131    error: UnsafeCell<zx::Status>,
132    // Protected by the mutex on Inner.
133    cancelled: UnsafeCell<bool>,
134}
135
136impl UnwrapResult {
137    fn new() -> Arc<Self> {
138        Arc::new(UnwrapResult {
139            event: Event::new(),
140            error: UnsafeCell::new(zx::Status::OK),
141            cancelled: UnsafeCell::new(false),
142        })
143    }
144
145    /// Returns true if cancelled.
146    fn set(
147        &self,
148        inner: &Arc<Mutex<Inner>>,
149        object_id: u64,
150        permanent: bool,
151        result: Result<Option<Arc<CipherSet>>, zx::Status>,
152    ) -> bool {
153        let mut guard = inner.lock();
154        // SAFETY: Safe because we hold the lock on `inner`.
155        let cancelled = unsafe { *self.cancelled.get() };
156        let set_error = |error| {
157            // SAFETY: This is safe because we have exclusive access until we call notify below.
158            unsafe {
159                *self.error.get() = error;
160            }
161        };
162        if cancelled {
163            set_error(zx::Status::CANCELED);
164        } else if let Err(error) = &result {
165            error!(error:?, oid = object_id; "Failed to unwrap keys");
166            set_error(*error);
167        }
168        if let Entry::Occupied(o) = guard.unwrapping.entry(object_id) {
169            if std::ptr::eq(Arc::as_ptr(o.get()), self) {
170                o.remove();
171                if !cancelled {
172                    if let Ok(Some(keys)) = &result {
173                        guard.keys.insert(object_id, keys.clone(), permanent);
174                        guard.start_purge_task(inner);
175                    }
176                }
177            }
178        }
179        self.event.notify(usize::MAX);
180        cancelled
181    }
182}
183
184unsafe impl Send for UnwrapResult {}
185unsafe impl Sync for UnwrapResult {}
186
187impl KeyManager {
188    pub fn new() -> Self {
189        let inner = Arc::new(Mutex::new(Inner {
190            keys: Cache::new(),
191            unwrapping: BTreeMap::new(),
192            purge_task: None,
193        }));
194
195        Self { inner }
196    }
197
198    /// Retrieves the key with id VOLUME_DATA_KEY_ID from the cache but won't initiate unwrapping if
199    /// no key is present.  If the key is currently in the process of being unwrapped, this will
200    /// wait until that has finished.  This should be used with permanent keys.  This will return
201    /// None if the key isn't present in the cache, but can also return None if they key isn't
202    /// present in the set of keys.
203    pub async fn get(&self, object_id: u64) -> Result<Option<Arc<dyn Cipher>>, Error> {
204        loop {
205            let (unwrap_result, listener) = {
206                let mut inner = self.inner.lock();
207
208                if let Some(keys) = inner.keys.get(object_id) {
209                    return match keys.find_key(VOLUME_DATA_KEY_ID) {
210                        FindKeyResult::NotFound => Ok(None),
211                        FindKeyResult::Unavailable(_) => Err(FxfsError::NoKey.into()),
212                        FindKeyResult::Key(key) => Ok(Some(key)),
213                    };
214                }
215                let unwrap_result = match inner.unwrapping.entry(object_id) {
216                    Entry::Vacant(_) => return Ok(None),
217                    Entry::Occupied(o) => o.get().clone(),
218                };
219                let listener = unwrap_result.event.listen();
220                (unwrap_result, listener)
221            };
222            listener.await;
223            // SAFETY: This is safe because there can be no mutations happening at this point.
224            let error = unsafe { *unwrap_result.error.get().clone() };
225            match error {
226                zx::Status::OK => {}
227                _ => return Err(error.into()),
228            }
229        }
230    }
231
232    /// This retrieves keys from the cache or initiates unwrapping if they are not in the cache.  If
233    /// `force` is true, then this will always attempt to unwrap the keys again, even if the keys
234    /// are present in the cache.  `encryption_keys` is a future to be used to retrieve the wrapped
235    /// keys.  It is passed in an `Option` so that callers can tell if the keys were freshly
236    /// retrieved.
237    pub async fn get_keys(
238        &self,
239        object_id: u64,
240        crypt: &dyn Crypt,
241        encryption_keys: &mut Option<impl AsyncFnOnce() -> Result<EncryptionKeys, Error>>,
242        permanent: bool,
243        force: bool,
244    ) -> Result<Arc<CipherSet>, Error> {
245        let inner = self.inner.clone();
246        let mut unwrap_result;
247
248        loop {
249            let listener = {
250                let mut inner = inner.lock();
251
252                if !force {
253                    if let Some(keys) = inner.keys.get(object_id) {
254                        return Ok(keys.clone());
255                    }
256                }
257
258                match inner.unwrapping.entry(object_id) {
259                    Entry::Vacant(v) => {
260                        unwrap_result = UnwrapResult::new();
261                        v.insert(unwrap_result.clone());
262                        break;
263                    }
264                    Entry::Occupied(o) => {
265                        unwrap_result = o.get().clone();
266                        let listener = unwrap_result.event.listen();
267                        listener
268                    }
269                }
270            };
271
272            listener.await;
273            // SAFETY: This is safe because there can be no mutations happening at this
274            // point.
275            let error = unsafe { *unwrap_result.error.get().clone() };
276            match error {
277                zx::Status::OK => {}
278                _ => return Err(error.into()),
279            }
280        }
281
282        // Use a guard in case we're dropped.
283        let mut result = scopeguard::guard(Ok(None), |result| {
284            unwrap_result.set(&inner, object_id, permanent, result);
285        });
286
287        let encryption_keys = match encryption_keys.take().unwrap()().await {
288            Ok(encryption_keys) => encryption_keys,
289            Err(error) => {
290                error!(error:?; "Failed to get key specs");
291                *result = Err(zx::Status::INTERNAL);
292                return Err(zx::Status::INTERNAL.into());
293            }
294        };
295
296        // TODO(b/418125391): Extend crypt protocol and interfaces in fxfs-crypto to support
297        // additional key types.
298        let wrapped_keys = encryption_keys.into();
299        match crypt.unwrap_keys(&wrapped_keys, object_id).await {
300            Ok(cipher_set) => {
301                let keys = Arc::new(cipher_set);
302                let _ = ScopeGuard::into_inner(result);
303                if unwrap_result.set(&inner, object_id, permanent, Ok(Some(keys.clone()))) {
304                    Err(zx::Status::CANCELED.into())
305                } else {
306                    Ok(keys)
307                }
308            }
309            Err(error) => {
310                *result = Err(error);
311                Err(error.into())
312            }
313        }
314    }
315
316    /// Returns a cipher for the key specified by `key_id`.
317    /// Returns Fxfs::NotFound if the key_id is unknown.
318    /// Returns Fxfs::NoKey if the requested key is not available (i.e. is locked).
319    pub async fn get_key(
320        &self,
321        object_id: u64,
322        crypt: &dyn Crypt,
323        encryption_keys: impl AsyncFnOnce() -> Result<EncryptionKeys, Error>,
324        key_id: u64,
325    ) -> Result<Arc<dyn Cipher>, Error> {
326        let mut encryption_keys = Some(encryption_keys);
327        let mut force = false;
328        loop {
329            let keys = self
330                .get_keys(
331                    object_id,
332                    crypt,
333                    &mut encryption_keys,
334                    /* permanent= */ false,
335                    force,
336                )
337                .await?;
338            return match keys.find_key(key_id) {
339                FindKeyResult::NotFound => Err(FxfsError::NotFound.into()),
340                FindKeyResult::Unavailable(_) => {
341                    if force || encryption_keys.is_none() {
342                        Err(FxfsError::NoKey.into())
343                    } else {
344                        force = true;
345                        continue;
346                    }
347                }
348                FindKeyResult::Key(k) => Ok(k),
349            };
350        }
351    }
352
353    /// For files, the only way we can tell whether it has an fscrypt encryption key is if there's a
354    /// key with id FSCRYPT_KEY_ID.  This function will return that key if it is present, but will
355    /// otherwise fall back to the the key with id VOLUME_DATA_KEY_ID.  If the fscrypt encryption
356    /// key cannot be unwrapped, this will return FxfsError::NoKey.
357    pub async fn get_fscrypt_key_if_present(
358        &self,
359        object_id: u64,
360        crypt: &dyn Crypt,
361        encryption_keys: impl AsyncFnOnce() -> Result<EncryptionKeys, Error>,
362    ) -> Result<(u64, Arc<dyn Cipher>), Error> {
363        let mut encryption_keys = Some(encryption_keys);
364        let mut force = false;
365        loop {
366            let keys = self
367                .get_keys(
368                    object_id,
369                    crypt,
370                    &mut encryption_keys,
371                    /* permanent= */ false,
372                    force,
373                )
374                .await?;
375            return match keys.find_key(FSCRYPT_KEY_ID) {
376                FindKeyResult::NotFound => {
377                    Ok((VOLUME_DATA_KEY_ID, to_result(keys.find_key(VOLUME_DATA_KEY_ID))?))
378                }
379                FindKeyResult::Unavailable(_) => {
380                    if force || encryption_keys.is_none() {
381                        Err(FxfsError::NoKey.into())
382                    } else {
383                        force = true;
384                        continue;
385                    }
386                }
387                FindKeyResult::Key(k) => Ok((FSCRYPT_KEY_ID, k)),
388            };
389        }
390    }
391
392    /// This function is for directories which know whether they should be using an fscrypt
393    /// encryption key, and can tolerate the key being unavailable.  This returns None if
394    /// the key is currently unavailable.
395    pub async fn get_fscrypt_key(
396        &self,
397        object_id: u64,
398        crypt: &dyn Crypt,
399        encryption_keys: impl AsyncFnOnce() -> Result<EncryptionKeys, Error>,
400    ) -> Result<CipherHolder, Error> {
401        let mut encryption_keys = Some(encryption_keys);
402        let mut force = false;
403        loop {
404            let keys = self
405                .get_keys(
406                    object_id,
407                    crypt,
408                    &mut encryption_keys,
409                    /* permanent= */ false,
410                    force,
411                )
412                .await?;
413            return match keys.find_key(FSCRYPT_KEY_ID) {
414                FindKeyResult::NotFound => Err(FxfsError::NotFound.into()),
415                FindKeyResult::Unavailable(key_type) => {
416                    if force || encryption_keys.is_none() {
417                        Ok(CipherHolder::Unavailable(key_type))
418                    } else {
419                        force = true;
420                        continue;
421                    }
422                }
423                FindKeyResult::Key(k) => Ok(CipherHolder::Cipher(k)),
424            };
425        }
426    }
427
428    /// This inserts the keys into the cache.  Any existing keys will be overwritten.  It's
429    /// unspecified what happens if keys for the object are currently being unwrapped.
430    pub fn insert(&self, object_id: u64, keys: Arc<CipherSet>, permanent: bool) {
431        let mut inner = self.inner.lock();
432        inner.keys.insert(object_id, keys, permanent);
433        inner.start_purge_task(&self.inner);
434    }
435
436    /// This merges into the cache.  `merge` is a callback that receives the existing keys, if any,
437    /// as an argument.  It's unspecified what happens if keys for the object are currently being
438    /// unwrapped.
439    pub fn merge(
440        &self,
441        object_id: u64,
442        merge: impl FnOnce(Option<&Arc<CipherSet>>) -> Arc<CipherSet>,
443    ) {
444        let mut inner = self.inner.lock();
445        inner.keys.merge(object_id, merge);
446        inner.start_purge_task(&self.inner);
447    }
448
449    /// Removes keys.  Returns a future that can (optionally) be awaited after which any
450    /// task that might be running to fetch keys will have finished.
451    pub fn remove(&self, object_id: u64) -> impl Future<Output = ()> {
452        {
453            let mut inner = self.inner.lock();
454            inner.keys.remove(object_id);
455            if let Some(u) = inner.unwrapping.get(&object_id) {
456                // SAFETY: Safe because of lock on `inner`.
457                unsafe { *u.cancelled.get() = true };
458            }
459        }
460        let inner = self.inner.clone();
461        async move {
462            let listener = {
463                if let Some(u) = inner.lock().unwrapping.get(&object_id) {
464                    u.event.listen()
465                } else {
466                    return;
467                }
468            };
469            listener.await;
470        }
471    }
472
473    /// This clears the caches of all keys.
474    pub fn clear(&self) {
475        let mut inner = self.inner.lock();
476        inner.keys.clear();
477        inner.unwrapping.clear();
478    }
479}
480
481fn to_result(find_key_result: FindKeyResult) -> Result<Arc<dyn Cipher>, FxfsError> {
482    match find_key_result {
483        FindKeyResult::NotFound => Err(FxfsError::NotFound),
484        FindKeyResult::Unavailable(_) => Err(FxfsError::NoKey),
485        FindKeyResult::Key(k) => Ok(k),
486    }
487}
488
489#[cfg(target_os = "fuchsia")]
490#[cfg(test)]
491mod tests {
492    use super::{EncryptionKeys, KeyManager, PURGE_TIMEOUT, to_result};
493    use crate::log::*;
494    use async_trait::async_trait;
495    use fuchsia_async::{self as fasync, MonotonicInstant, TestExecutor};
496
497    use crate::object_store::object_record::EncryptionKey;
498    use futures::channel::oneshot;
499    use futures::join;
500    use fxfs_crypto::{
501        Cipher, CipherHolder, Crypt, FXFS_KEY_SIZE, FXFS_WRAPPED_KEY_SIZE, FxfsCipher, FxfsKey,
502        KeyPurpose, ObjectType, UnwrappedKey, WrappedKey, WrappedKeyBytes, WrappingKeyId,
503    };
504    use std::future::pending;
505    use std::sync::Arc;
506    use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
507
508    const PLAIN_TEXT: &[u8] = b"The quick brown fox jumps over the lazy dog";
509    const ERROR_COUNTER: u8 = 0xff;
510
511    fn unwrapped_key(counter: u8) -> UnwrappedKey {
512        UnwrappedKey::new([counter; FXFS_KEY_SIZE].to_vec())
513    }
514    fn cipher(counter: u8) -> Arc<dyn Cipher> {
515        Arc::new(FxfsCipher::new(&unwrapped_key(counter)))
516    }
517
518    fn padded_plain_text() -> Vec<u8> {
519        let mut text = PLAIN_TEXT.to_vec();
520        text.resize(4096, 0); // Encryption requires block aligned inputs
521        text
522    }
523
524    fn cipher_text(counter: u8) -> Vec<u8> {
525        let mut text = padded_plain_text();
526        cipher(counter).encrypt(0, 0, 0, &mut text).expect("encrypt failed");
527        // Ensure that encrypt changed the text.
528        assert_ne!(&text, &padded_plain_text());
529        text
530    }
531
532    fn encryption_keys() -> EncryptionKeys {
533        vec![(
534            0,
535            EncryptionKey::Fxfs(FxfsKey {
536                wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
537                key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
538            }),
539        )]
540        .into()
541    }
542
543    struct TestCrypt {
544        counter: AtomicU8,
545        unwrap_delay: std::time::Duration,
546    }
547
548    impl TestCrypt {
549        fn new(counter: u8) -> Arc<Self> {
550            Arc::new(Self {
551                counter: AtomicU8::new(counter),
552                unwrap_delay: std::time::Duration::from_secs(1),
553            })
554        }
555
556        fn with_unwrap_delay(counter: u8, unwrap_delay: std::time::Duration) -> Arc<Self> {
557            Arc::new(Self { counter: AtomicU8::new(counter), unwrap_delay })
558        }
559    }
560
561    #[async_trait]
562    impl Crypt for TestCrypt {
563        async fn create_key(
564            &self,
565            _owner: u64,
566            _purpose: KeyPurpose,
567        ) -> Result<(FxfsKey, UnwrappedKey), zx::Status> {
568            unimplemented!("Not used in tests");
569        }
570
571        async fn create_key_with_id(
572            &self,
573            _owner: u64,
574            _wrapping_key_id: WrappingKeyId,
575            _object_type: ObjectType,
576        ) -> Result<(fxfs_crypto::EncryptionKey, UnwrappedKey), zx::Status> {
577            unimplemented!("Not used in tests");
578        }
579
580        async fn unwrap_key(
581            &self,
582            _wrapped_key: &WrappedKey,
583            _owner: u64,
584        ) -> Result<UnwrappedKey, zx::Status> {
585            if !self.unwrap_delay.is_zero() {
586                fasync::Timer::new(self.unwrap_delay).await;
587            }
588            let counter = self.counter.fetch_add(1, Ordering::Relaxed);
589            if counter == ERROR_COUNTER {
590                error!("Unwrap failed!");
591                Err(zx::Status::INTERNAL)
592            } else {
593                Ok(unwrapped_key(counter))
594            }
595        }
596    }
597
598    #[fuchsia::test(allow_stalls = false)]
599    async fn test_get_keys() {
600        TestExecutor::advance_to(MonotonicInstant::from_nanos(0)).await;
601
602        let crypt = TestCrypt::new(0);
603        let manager1 = Arc::new(KeyManager::new());
604        let manager2 = manager1.clone();
605        let manager3 = manager1.clone();
606        let crypt1 = crypt.clone();
607        let crypt2 = crypt.clone();
608
609        let task1 = fasync::Task::spawn(async move {
610            let mut buf = cipher_text(0);
611            to_result(
612                manager1
613                    .get_keys(
614                        1,
615                        crypt1.as_ref(),
616                        &mut Some(async || Ok(encryption_keys())),
617                        false,
618                        false,
619                    )
620                    .await
621                    .expect("get_keys failed")
622                    .find_key(0),
623            )
624            .unwrap()
625            .decrypt(0, 0, 0, &mut buf)
626            .expect("decrypt failed");
627            assert_eq!(&buf, &padded_plain_text());
628        });
629        let task2 = fasync::Task::spawn(async move {
630            let mut buf = cipher_text(0);
631            to_result(
632                manager2
633                    .get_keys(
634                        1,
635                        crypt2.as_ref(),
636                        &mut Some(async || Ok(encryption_keys())),
637                        false,
638                        false,
639                    )
640                    .await
641                    .expect("get_keys failed")
642                    .find_key(0),
643            )
644            .unwrap()
645            .decrypt(0, 0, 0, &mut buf)
646            .expect("decrypt failed");
647            assert_eq!(&buf, &padded_plain_text());
648        });
649        let task3 = fasync::Task::spawn(async move {
650            // Make sure this starts after the get_keys.
651            fasync::Timer::new(zx::MonotonicDuration::from_millis(500)).await;
652            let mut buf = cipher_text(0);
653            manager3
654                .get(1)
655                .await
656                .expect("get failed")
657                .expect("missing key")
658                .decrypt(0, 0, 0, &mut buf)
659                .expect("decrypt failed");
660            assert_eq!(&buf, &padded_plain_text());
661        });
662
663        TestExecutor::advance_to(MonotonicInstant::after(zx::MonotonicDuration::from_millis(1500)))
664            .await;
665
666        task1.await;
667        task2.await;
668        task3.await;
669    }
670
671    #[fuchsia::test]
672    async fn test_insert_and_remove() {
673        let manager = Arc::new(KeyManager::new());
674
675        manager.insert(1, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), false);
676        let mut buf = cipher_text(0);
677        manager
678            .get(1)
679            .await
680            .expect("get failed")
681            .expect("missing key")
682            .decrypt(0, 0, 0, &mut buf)
683            .expect("decrypt failed");
684        assert_eq!(&buf, &padded_plain_text());
685        let _ = manager.remove(1);
686        assert!(manager.get(1).await.expect("get failed").is_none());
687    }
688
689    #[fuchsia::test(allow_stalls = false)]
690    async fn test_purge() {
691        TestExecutor::advance_to(MonotonicInstant::from_nanos(0)).await;
692
693        let manager = Arc::new(KeyManager::new());
694        manager.insert(1, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), false);
695
696        TestExecutor::advance_to(MonotonicInstant::after(PURGE_TIMEOUT.into())).await;
697
698        // After 1 period, the key should still be present.
699        manager.get(1).await.expect("get failed").expect("missing key");
700
701        TestExecutor::advance_to(MonotonicInstant::after(PURGE_TIMEOUT.into())).await;
702
703        // The last access should have reset the timer and it should still be present.
704        manager.get(1).await.expect("get failed").expect("missing key");
705
706        TestExecutor::advance_to(MonotonicInstant::after((2 * PURGE_TIMEOUT).into())).await;
707
708        // The key should have been evicted since two periods passed.
709        assert!(manager.get(1).await.expect("get failed").is_none());
710    }
711
712    #[fuchsia::test(allow_stalls = false)]
713    async fn test_permanent() {
714        TestExecutor::advance_to(MonotonicInstant::from_nanos(0)).await;
715
716        let manager = Arc::new(KeyManager::new());
717        manager.insert(1, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), true);
718        manager.insert(2, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), false);
719
720        // Skip forward two periods which should cause 2 to be purged but not 1.
721        TestExecutor::advance_to(MonotonicInstant::after((2 * PURGE_TIMEOUT).into())).await;
722
723        assert!(manager.get(1).await.expect("get failed").is_some());
724        assert!(manager.get(2).await.expect("get failed").is_none());
725    }
726
727    #[fuchsia::test(allow_stalls = false)]
728    async fn test_clear() {
729        TestExecutor::advance_to(MonotonicInstant::from_nanos(0)).await;
730
731        let manager = Arc::new(KeyManager::new());
732        manager.insert(1, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), true);
733        manager.insert(2, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), false);
734        manager.insert(3, Arc::new(vec![(0, CipherHolder::Cipher(cipher(0)))].into()), false);
735
736        // Skip forward 1 period which should make keys 2 and 3 pending deletion.
737        TestExecutor::advance_to(MonotonicInstant::after(PURGE_TIMEOUT.into())).await;
738
739        // Touch the the second key which should promote it to the active list.
740        assert!(manager.get(2).await.expect("get failed").is_some());
741
742        manager.clear();
743
744        // Clearing should have removed all three keys.
745        assert!(manager.get(1).await.expect("get failed").is_none());
746        assert!(manager.get(2).await.expect("get failed").is_none());
747        assert!(manager.get(3).await.expect("get failed").is_none());
748    }
749
750    #[fuchsia::test(allow_stalls = false)]
751    async fn test_error() {
752        TestExecutor::advance_to(MonotonicInstant::from_nanos(0)).await;
753
754        let crypt = TestCrypt::new(ERROR_COUNTER);
755        let manager1 = Arc::new(KeyManager::new());
756        let manager2 = manager1.clone();
757        let crypt1 = crypt.clone();
758        let crypt2 = crypt.clone();
759
760        let task1 = fasync::Task::spawn(async move {
761            assert!(
762                manager1
763                    .get_keys(
764                        1,
765                        crypt1.as_ref(),
766                        &mut Some(async || Ok(encryption_keys())),
767                        false,
768                        false,
769                    )
770                    .await
771                    .is_err()
772            );
773        });
774        let task2 = fasync::Task::spawn(async move {
775            assert!(
776                manager2
777                    .get_keys(
778                        1,
779                        crypt2.as_ref(),
780                        &mut Some(async || Ok(encryption_keys())),
781                        false,
782                        false,
783                    )
784                    .await
785                    .is_err()
786            );
787        });
788
789        TestExecutor::advance_to(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(1)))
790            .await;
791
792        task1.await;
793        task2.await;
794    }
795
796    #[fuchsia::test(allow_stalls = false)]
797    async fn test_wait_after_remove() {
798        let manager = Arc::new(KeyManager::new());
799        let crypt = TestCrypt::with_unwrap_delay(0, std::time::Duration::ZERO);
800        let (sender, receiver) = oneshot::channel();
801        let dropped = AtomicBool::new(false);
802
803        assert!(
804            join!(
805                async {
806                    let mut unwrap_keys = Some(async || {
807                        struct OnDrop<'a>(&'a AtomicBool);
808                        impl Drop for OnDrop<'_> {
809                            fn drop(&mut self) {
810                                self.0.store(true, Ordering::Relaxed);
811                            }
812                        }
813                        let _on_drop = OnDrop(&dropped);
814                        sender.send(()).unwrap();
815                        // This should wait until both the remove calls below are waiting.
816                        let _ = TestExecutor::poll_until_stalled(pending::<()>()).await;
817                        Ok(encryption_keys())
818                    });
819                    manager.get_keys(1, crypt.as_ref(), &mut unwrap_keys, false, false).await
820                },
821                async {
822                    let _ = receiver.await;
823                    join!(
824                        async {
825                            manager.remove(1).await;
826                            assert!(dropped.load(Ordering::Relaxed));
827                        },
828                        async {
829                            manager.remove(1).await;
830                            assert!(dropped.load(Ordering::Relaxed));
831                        }
832                    );
833                },
834            )
835            .0
836            .is_err()
837        );
838    }
839}