Skip to main content

core_crypto/mls/session/
key_package.rs

1use std::sync::Arc;
2
3use core_crypto_keystore::{entities::StoredKeyPackage, traits::FetchFromDatabase};
4
5use super::Result;
6use crate::{Keypackage, KeypackageRef, KeystoreError, Session, mls::key_package::KeypackageExt};
7
8pub(crate) fn from_stored(stored_keypackage: Arc<StoredKeyPackage>) -> Result<Keypackage> {
9    core_crypto_keystore::deser::<Keypackage>(&stored_keypackage.key_package)
10        .map_err(KeystoreError::wrap("deserializing keypackage"))
11        .map_err(Into::into)
12}
13
14impl Session {
15    /// Get all [`Keypackage`]s in the database.
16    pub(crate) async fn get_key_packages(&self) -> Result<Vec<Keypackage>> {
17        let stored_keypackages = self
18            .database
19            .load_all::<StoredKeyPackage>()
20            .await
21            .map_err(KeystoreError::wrap("finding all keypackages"))?;
22
23        let keypackages = stored_keypackages
24            .into_iter()
25            .map(from_stored)
26            // if any ref from loading all fails to load now, skip it
27            // strictly we could panic, but this is safer--maybe someone removed it concurrently
28            .filter_map(|kp| kp.ok())
29            .collect();
30
31        Ok(keypackages)
32    }
33
34    /// Get all [`KeypackageRef`]s in the database.
35    pub async fn get_keypackage_refs(&self) -> Result<Vec<KeypackageRef>> {
36        self.get_key_packages()
37            .await?
38            .iter()
39            .map(|keypackage| keypackage.make_ref().map_err(Into::into))
40            .collect()
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use std::time::Duration;
47
48    use openmls::prelude::{KeyPackageIn, ProtocolVersion};
49    use openmls_traits::types::VerifiableCiphersuite;
50
51    use crate::{ConversationConfiguration, mls::key_package::KeypackageExt as _, test_utils::*};
52
53    #[apply(all_cred_cipher)]
54    async fn can_assess_keypackage_expiration(case: TestContext) {
55        let [session] = case.sessions().await;
56
57        // 90-day standard expiration
58        let kp_std_exp = session.new_keypackage(&case).await;
59        assert!(kp_std_exp.is_valid());
60
61        // 1-second expiration
62        let kp_1s_exp = session
63            .new_keypackage_with_lifetime(&case, Some(Duration::from_secs(1)))
64            .await;
65
66        // Sleep 2 seconds to make sure we make the kp expire
67        smol::Timer::after(std::time::Duration::from_secs(2)).await;
68        assert!(!kp_1s_exp.is_valid());
69    }
70
71    #[apply(all_cred_cipher)]
72    async fn new_keypackage_has_correct_extensions(case: TestContext) {
73        let [cc] = case.sessions().await;
74        Box::pin(async move {
75            let kp = cc.new_keypackage(&case).await;
76
77            // make sure it's valid
78            let _ = KeyPackageIn::from(kp.clone())
79                .standalone_validate(
80                    &cc.transaction.crypto_provider().await.unwrap(),
81                    ProtocolVersion::Mls10,
82                    true,
83                )
84                .await
85                .unwrap();
86
87            // see https://www.rfc-editor.org/rfc/rfc9420.html#section-10-10
88            assert!(kp.extensions().is_empty());
89
90            assert_eq!(kp.leaf_node().capabilities().versions(), &[ProtocolVersion::Mls10]);
91            assert_eq!(
92                kp.leaf_node().capabilities().ciphersuites().to_vec(),
93                ConversationConfiguration::DEFAULT_SUPPORTED_CIPHERSUITES
94                    .iter()
95                    .map(|c| VerifiableCiphersuite::from(*c))
96                    .collect::<Vec<_>>()
97            );
98            assert!(kp.leaf_node().capabilities().proposals().is_empty());
99            assert!(kp.leaf_node().capabilities().extensions().is_empty());
100            assert_eq!(
101                kp.leaf_node().capabilities().credentials(),
102                ConversationConfiguration::DEFAULT_SUPPORTED_CREDENTIALS
103            );
104        })
105        .await
106    }
107}