core_crypto/mls/session/
key_package.rs1use core_crypto_keystore::{entities::StoredKeypackage, traits::FetchFromDatabase};
2
3use super::Result;
4use crate::{Keypackage, KeypackageRef, KeystoreError, Session, mls::key_package::KeypackageExt};
5
6fn from_stored(stored_keypackage: &StoredKeypackage) -> Result<Keypackage> {
7 core_crypto_keystore::deser::<Keypackage>(&stored_keypackage.keypackage)
8 .map_err(KeystoreError::wrap("deserializing keypackage"))
9 .map_err(Into::into)
10}
11
12impl<D> Session<D>
13where
14 D: FetchFromDatabase,
15{
16 pub(crate) async fn get_keypackages(&self) -> Result<Vec<Keypackage>> {
18 let stored_keypackages: Vec<StoredKeypackage> = self
19 .database
20 .load_all()
21 .await
22 .map_err(KeystoreError::wrap("finding all keypackages"))?;
23
24 let keypackages = stored_keypackages
25 .iter()
26 .map(from_stored)
27 .filter_map(|kp| kp.ok())
30 .collect();
31
32 Ok(keypackages)
33 }
34
35 pub async fn get_keypackage_refs(&self) -> Result<Vec<KeypackageRef>> {
37 self.get_keypackages()
38 .await?
39 .iter()
40 .map(|keypackage| keypackage.make_ref().map_err(Into::into))
41 .collect()
42 }
43
44 pub(crate) async fn load_keypackage(&self, kp_ref: &KeypackageRef) -> Result<Option<Keypackage>> {
46 self.database
47 .get_borrowed::<StoredKeypackage>(kp_ref.hash_ref())
48 .await
49 .map_err(KeystoreError::wrap("loading keypackage from database"))?
50 .map(|stored_keypackage| from_stored(&stored_keypackage))
51 .transpose()
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use std::time::Duration;
58
59 use openmls::prelude::{KeyPackageIn, ProtocolVersion};
60 use openmls_traits::types::VerifiableCiphersuite;
61
62 use crate::{MlsConversationConfiguration, mls::key_package::KeypackageExt as _, test_utils::*};
63
64 #[apply(all_cred_cipher)]
65 async fn can_assess_keypackage_expiration(case: TestContext) {
66 let [session] = case.sessions().await;
67
68 let kp_std_exp = session.new_keypackage(&case).await;
70 assert!(kp_std_exp.is_valid());
71
72 let kp_1s_exp = session
74 .new_keypackage_with_lifetime(&case, Some(Duration::from_secs(1)))
75 .await;
76
77 smol::Timer::after(std::time::Duration::from_secs(2)).await;
79 assert!(!kp_1s_exp.is_valid());
80 }
81
82 #[apply(all_cred_cipher)]
83 async fn new_keypackage_has_correct_extensions(case: TestContext) {
84 let [cc] = case.sessions().await;
85 Box::pin(async move {
86 let kp = cc.new_keypackage(&case).await;
87
88 let _ = KeyPackageIn::from(kp.clone())
90 .standalone_validate(
91 &cc.transaction.mls_provider().await.unwrap(),
92 ProtocolVersion::Mls10,
93 true,
94 )
95 .await
96 .unwrap();
97
98 assert!(kp.extensions().is_empty());
100
101 assert_eq!(kp.leaf_node().capabilities().versions(), &[ProtocolVersion::Mls10]);
102 assert_eq!(
103 kp.leaf_node().capabilities().ciphersuites().to_vec(),
104 MlsConversationConfiguration::DEFAULT_SUPPORTED_CIPHERSUITES
105 .iter()
106 .map(|c| VerifiableCiphersuite::from(*c))
107 .collect::<Vec<_>>()
108 );
109 assert!(kp.leaf_node().capabilities().proposals().is_empty());
110 assert!(kp.leaf_node().capabilities().extensions().is_empty());
111 assert_eq!(
112 kp.leaf_node().capabilities().credentials(),
113 MlsConversationConfiguration::DEFAULT_SUPPORTED_CREDENTIALS
114 );
115 })
116 .await
117 }
118
119 #[apply(all_cred_cipher)]
120 async fn can_store_and_load_key_packages(case: TestContext) {
121 let [cc] = case.sessions().await;
122
123 let kp = cc.new_keypackage(&case).await;
125
126 let all_keypackages = cc.session.read().await.get_keypackages().await.unwrap();
127 assert_eq!(all_keypackages[0], kp);
128
129 let kp_ref = kp.make_ref().unwrap();
130 let by_ref = cc.session.read().await.load_keypackage(&kp_ref).await.unwrap().unwrap();
131 assert_eq!(kp, by_ref);
132 }
133}