core_crypto/transaction_context/
key_package.rs1use std::time::Duration;
4
5use core_crypto_keystore::entities::{StoredEncryptionKeyPair, StoredHpkePrivateKey, StoredKeypackage};
6use openmls::prelude::{CryptoConfig, Lifetime};
7
8use super::{Error, Result, TransactionContext};
9use crate::{
10 CredentialRef, Keypackage, KeypackageRef, KeystoreError, MlsConversationConfiguration, RecursiveError,
11 mls::key_package::KeypackageExt as _,
12};
13
14pub const KEYPACKAGE_DEFAULT_LIFETIME: Duration = Duration::from_secs(60 * 60 * 24 * 28 * 3); impl TransactionContext {
18 pub async fn generate_keypackage(
28 &self,
29 credential_ref: &CredentialRef,
30 lifetime: Option<Duration>,
31 ) -> Result<Keypackage> {
32 let lifetime = Lifetime::new(lifetime.unwrap_or(KEYPACKAGE_DEFAULT_LIFETIME).as_secs());
33 let database = &self.database().await?;
34 let credential = credential_ref
35 .load(database)
36 .await
37 .map_err(RecursiveError::mls_credential_ref("loading credential"))?;
38 let config = CryptoConfig {
39 ciphersuite: credential.ciphersuite.into(),
40 version: openmls::versions::ProtocolVersion::default(),
41 };
42
43 Keypackage::builder()
44 .leaf_node_capabilities(MlsConversationConfiguration::default_leaf_capabilities())
45 .key_package_lifetime(lifetime)
46 .build(
47 config,
48 &self.mls_provider().await?,
49 &credential.signature_key_pair,
50 credential.to_mls_credential_with_key(),
51 )
52 .await
53 .map_err(Error::keypackage_new())
54 }
55
56 pub async fn get_keypackage_refs(&self) -> Result<Vec<KeypackageRef>> {
58 let session = self.session().await?;
59 session
60 .get_keypackage_refs()
61 .await
62 .map_err(RecursiveError::mls_client(
63 "getting all key package refs for transaction",
64 ))
65 .map_err(Into::into)
66 }
67
68 pub async fn remove_keypackage(&self, kp_ref: &KeypackageRef) -> Result<()> {
75 let Some(kp) = self
76 .session()
77 .await?
78 .load_keypackage(kp_ref)
79 .await
80 .map_err(RecursiveError::mls_client("loading key packages on session"))?
81 else {
82 return Ok(());
83 };
84
85 let db = self.database().await?;
86 db.remove_borrowed::<StoredKeypackage>(kp_ref.hash_ref())
87 .await
88 .map_err(KeystoreError::wrap("removing key package from keystore"))?;
89 db.remove_borrowed::<StoredHpkePrivateKey>(kp.hpke_init_key().as_slice())
90 .await
91 .map_err(KeystoreError::wrap("removing private key from keystore"))?;
92 db.remove_borrowed::<StoredEncryptionKeyPair>(kp.leaf_node().encryption_key().as_slice())
93 .await
94 .map_err(KeystoreError::wrap("removing encryption keypair from keystore"))?;
95
96 Ok(())
97 }
98
99 pub async fn remove_keypackages_for(&self, credential_ref: &CredentialRef) -> Result<()> {
107 let database = &self.database().await?;
108 let credential = credential_ref
109 .load(database)
110 .await
111 .map_err(RecursiveError::mls_credential_ref("loading credential"))?;
112 let signature_public_key = credential.signature_key_pair.public();
113
114 let mut first_err = None;
115 macro_rules! try_retain_err {
116 ($e:expr) => {
117 match $e {
118 Err(err) => {
119 if first_err.is_none() {
120 first_err = Some(Error::from(err));
121 }
122 continue;
123 }
124 Ok(val) => val,
125 }
126 };
127 }
128
129 let session = self.session().await?;
130 for keypackage in session
131 .get_keypackages()
132 .await
133 .map_err(RecursiveError::mls_client("loading key packages"))?
134 .into_iter()
135 .filter(|keypackage| keypackage.leaf_node().signature_key().as_slice() == signature_public_key)
136 {
137 let kp_ref = try_retain_err!(keypackage.make_ref());
138 try_retain_err!(self.remove_keypackage(&kp_ref).await);
139 }
140
141 match first_err {
142 None => Ok(()),
143 Some(err) => Err(err),
144 }
145 }
146}