core_crypto/transaction_context/
key_package.rs1use std::time::Duration;
4
5use core_crypto_keystore::{
6 entities::{StoredEncryptionKeyPair, StoredHpkePrivateKey, StoredKeypackage},
7 traits::FetchFromDatabase as _,
8};
9use openmls::prelude::{CryptoConfig, Lifetime};
10
11use super::{Error, Result, TransactionContext};
12use crate::{
13 ConversationConfiguration, CredentialRef, Keypackage, KeypackageRef, KeystoreError, RecursiveError,
14 mls::key_package::KeypackageExt as _,
15};
16
17pub const KEYPACKAGE_DEFAULT_LIFETIME: Duration = Duration::from_secs(60 * 60 * 24 * 28 * 3); impl TransactionContext {
21 pub async fn generate_key_package(
31 &self,
32 credential_ref: &CredentialRef,
33 lifetime: Option<Duration>,
34 ) -> Result<Keypackage> {
35 let lifetime = Lifetime::new(lifetime.unwrap_or(KEYPACKAGE_DEFAULT_LIFETIME).as_secs());
36 let database = self.database().await?;
37 let credential = credential_ref
38 .load(&*database)
39 .await
40 .map_err(RecursiveError::mls_credential_ref("loading credential"))?;
41 let config = CryptoConfig {
42 ciphersuite: credential.cipher_suite.into(),
43 version: openmls::versions::ProtocolVersion::default(),
44 };
45
46 Keypackage::builder()
47 .leaf_node_capabilities(ConversationConfiguration::default_leaf_capabilities())
48 .key_package_lifetime(lifetime)
49 .build(
50 config,
51 &self.crypto_provider().await?,
52 &credential.signature_key_pair,
53 credential.to_mls_credential_with_key(),
54 )
55 .await
56 .map_err(Error::key_package_new())
57 }
58
59 pub async fn get_key_package_refs(&self) -> Result<Vec<KeypackageRef>> {
61 let session = self.session().await?;
62 session
63 .get_keypackage_refs()
64 .await
65 .map_err(RecursiveError::mls_client(
66 "getting all key package refs for transaction",
67 ))
68 .map_err(Into::into)
69 }
70
71 pub async fn remove_key_package(&self, kp_ref: &KeypackageRef) -> Result<()> {
78 let Some(kp) = self
79 .session()
80 .await?
81 .load_key_package(kp_ref)
82 .await
83 .map_err(RecursiveError::mls_client("loading key packages on session"))?
84 else {
85 return Ok(());
86 };
87
88 let db = self.database().await?;
89 db.remove_borrowed::<StoredKeypackage>(kp_ref.hash_ref())
90 .await
91 .map_err(KeystoreError::wrap("removing key package from keystore"))?;
92 db.remove_borrowed::<StoredHpkePrivateKey>(kp.hpke_init_key().as_slice())
93 .await
94 .map_err(KeystoreError::wrap("removing private key from keystore"))?;
95 db.remove_borrowed::<StoredEncryptionKeyPair>(kp.leaf_node().encryption_key().as_slice())
96 .await
97 .map_err(KeystoreError::wrap("removing encryption keypair from keystore"))?;
98
99 Ok(())
100 }
101
102 pub async fn remove_key_packages_for(&self, credential_ref: &CredentialRef) -> Result<()> {
110 let database = self.database().await?;
111 let credential = credential_ref
112 .load(&*database)
113 .await
114 .map_err(RecursiveError::mls_credential_ref("loading credential"))?;
115 let signature_public_key = credential.signature_key_pair.public();
116
117 let mut first_err = None;
118 macro_rules! try_retain_err {
119 ($e:expr) => {
120 match $e {
121 Err(err) => {
122 if first_err.is_none() {
123 first_err = Some(Error::from(err));
124 }
125 continue;
126 }
127 Ok(val) => val,
128 }
129 };
130 }
131
132 let session = self.session().await?;
133 for keypackage in session
134 .get_key_packages()
135 .await
136 .map_err(RecursiveError::mls_client("loading key packages"))?
137 .into_iter()
138 .filter(|keypackage| keypackage.leaf_node().signature_key().as_slice() == signature_public_key)
139 {
140 let kp_ref = try_retain_err!(keypackage.make_ref());
141 try_retain_err!(self.remove_key_package(&kp_ref).await);
142 }
143
144 match first_err {
145 None => Ok(()),
146 Some(err) => Err(err),
147 }
148 }
149
150 pub(crate) async fn restore_key_package(&self, key_package_ref: &[u8]) -> Result<()> {
156 let database = self.database().await?;
157 database
158 .restore::<StoredKeypackage>(key_package_ref)
159 .await
160 .map_err(KeystoreError::wrap(
161 "restoring key package deleted in current transaction",
162 ))?;
163
164 let Some(key_package) = database
165 .get_borrowed::<StoredKeypackage>(key_package_ref)
166 .await
167 .map_err(KeystoreError::wrap("loading keypackage from database"))?
168 .map(|stored_keypackage| crate::mls::session::key_package::from_stored(&stored_keypackage))
169 .transpose()
170 .map_err(RecursiveError::mls_client("loading key package"))?
171 else {
172 return Ok(());
173 };
174
175 database
176 .restore::<StoredHpkePrivateKey>(key_package.hpke_init_key().as_slice())
177 .await
178 .map_err(KeystoreError::wrap("restoring private key from keystore"))?;
179 database
180 .restore::<StoredEncryptionKeyPair>(key_package.leaf_node().encryption_key().as_slice())
181 .await
182 .map_err(KeystoreError::wrap("restoring encryption keypair from keystore"))?;
183
184 Ok(())
185 }
186}