core_crypto/mls/session/
credential.rs1use std::sync::Arc;
2
3use openmls::prelude::{SignaturePublicKey, SignatureScheme};
4use openmls_traits::OpenMlsCryptoProvider as _;
5
6use super::{Error, Result};
7use crate::{
8 Credential, CredentialFindFilters, CredentialRef, CredentialType, LeafError, MlsConversation, RecursiveError,
9 Session, mls::session::SessionInner,
10};
11
12impl Session {
13 pub async fn find_credentials(&self, find_filters: CredentialFindFilters<'_>) -> Result<Vec<CredentialRef>> {
17 let guard = self.inner.read().await;
18 let inner = guard.as_ref().ok_or(Error::MlsNotInitialized)?;
19 Ok(inner
20 .identities
21 .find_credential(find_filters)
22 .map(|credential| CredentialRef::from_credential(&credential))
23 .collect())
24 }
25
26 pub async fn get_credentials(&self) -> Result<Vec<CredentialRef>> {
28 self.find_credentials(Default::default()).await
29 }
30
31 pub(crate) async fn add_credential(&self, credential: Credential) -> Result<CredentialRef> {
35 let credential = self.add_credential_producing_arc(credential).await?;
36 Ok(CredentialRef::from_credential(&credential))
37 }
38
39 pub(crate) async fn add_credential_producing_arc(&self, credential: Credential) -> Result<Arc<Credential>> {
47 if *credential.client_id() != self.id().await? {
48 return Err(Error::WrongCredential);
49 }
50
51 self.add_credential_without_clientid_check(credential).await
52 }
53
54 pub(crate) async fn add_credential_without_clientid_check(
60 &self,
61 mut credential: Credential,
62 ) -> Result<Arc<Credential>> {
63 let credential_ref = credential
64 .save(&self.crypto_provider.keystore())
65 .await
66 .map_err(RecursiveError::mls_credential("saving credential"))?;
67
68 let guard = self.inner.upgradable_read().await;
69 let inner = guard.as_ref().ok_or(Error::MlsNotInitialized)?;
70
71 let distinct_result = inner.identities.ensure_distinct(
73 credential_ref.signature_scheme(),
74 credential_ref.r#type(),
75 credential_ref.earliest_validity(),
76 );
77 if let Err(err) = distinct_result {
78 credential
87 .delete(&self.crypto_provider.keystore())
88 .await
89 .map_err(RecursiveError::mls_credential(
90 "deleting nondistinct credential from keystore",
91 ))?;
92 return Err(err);
93 }
94
95 let mut guard = async_lock::RwLockUpgradableReadGuard::upgrade(guard).await;
97 let inner = guard.as_mut().ok_or(Error::MlsNotInitialized)?;
98 let credential = inner.identities.push_credential(credential).await?;
99
100 Ok(credential)
101 }
102
103 pub async fn remove_credential(&self, credential_ref: &CredentialRef) -> Result<()> {
108 if *credential_ref.client_id() != self.id().await? {
110 return Err(Error::WrongCredential);
111 }
112
113 let database = self.crypto_provider.keystore();
114
115 let credentials = credential_ref
116 .load(&database)
117 .await
118 .map_err(RecursiveError::mls_credential_ref(
119 "loading all credentials from ref to remove from session identities",
120 ))?;
121
122 for (conversation_id, conversation) in
128 MlsConversation::load_all(&database)
129 .await
130 .map_err(RecursiveError::mls_conversation(
131 "loading all conversations to check if the credential to be removed is present",
132 ))?
133 {
134 let converation_credential = conversation
135 .own_mls_credential()
136 .map_err(RecursiveError::mls_conversation("geting conversation credential"))?;
137 if credentials
138 .iter()
139 .any(|credential| credential.mls_credential() == converation_credential)
140 {
141 return Err(Error::CredentialStillInUse(conversation_id));
142 }
143 }
144
145 let keypackages = self.find_all_keypackages(&self.crypto_provider.keystore()).await?;
147 let keypackages_from_this_credential = keypackages.iter().filter_map(|(_stored_key_package, key_package)| {
148 credentials
149 .iter()
150 .any(|credential| key_package.leaf_node().credential() == credential.mls_credential())
151 .then(|| key_package.hash_ref(self.crypto_provider.crypto()).ok()).flatten()
153 });
154 self.prune_keypackages(&self.crypto_provider, keypackages_from_this_credential)
155 .await?;
156
157 {
161 let mut inner = self.inner.write().await;
162 let inner = inner.as_mut().ok_or(Error::MlsNotInitialized)?;
163 for credential in &credentials {
164 inner.identities.remove_by_mls_credential(credential.mls_credential());
165 }
166 }
167
168 for credential in credentials {
170 credential
171 .delete(&database)
172 .await
173 .map_err(RecursiveError::mls_credential("deleting credential from keystore"))?;
174 }
175
176 Ok(())
177 }
178
179 pub(crate) async fn find_most_recent_credential(
181 &self,
182 signature_scheme: SignatureScheme,
183 credential_type: CredentialType,
184 ) -> Result<Arc<Credential>> {
185 match &*self.inner.read().await {
186 None => Err(Error::MlsNotInitialized),
187 Some(SessionInner { identities, .. }) => identities
188 .find_most_recent_credential(signature_scheme, credential_type)
189 .await
190 .ok_or(Error::CredentialNotFound(credential_type, signature_scheme)),
191 }
192 }
193
194 pub(crate) async fn find_credential_by_public_key(
196 &self,
197 signature_scheme: SignatureScheme,
198 credential_type: CredentialType,
199 public_key: &SignaturePublicKey,
200 ) -> Result<Arc<Credential>> {
201 match &*self.inner.read().await {
202 None => Err(Error::MlsNotInitialized),
203 Some(SessionInner { identities, .. }) => identities
204 .find_credential_by_public_key(signature_scheme, credential_type, public_key)
205 .await
206 .ok_or(Error::CredentialNotFound(credential_type, signature_scheme)),
207 }
208 }
209
210 pub(crate) async fn find_most_recent_or_create_basic_credential(
214 &self,
215 signature_scheme: SignatureScheme,
216 credential_type: CredentialType,
217 ) -> Result<Arc<Credential>> {
218 let credential = match self
219 .find_most_recent_credential(signature_scheme, credential_type)
220 .await
221 {
222 Ok(credential) => credential,
223 Err(Error::CredentialNotFound(..)) if credential_type == CredentialType::Basic => {
224 let client_id = self.id().await?;
225 let credential = Credential::basic(signature_scheme, client_id, &self.crypto_provider).map_err(
226 RecursiveError::mls_credential(
227 "creating basic credential in find_most_recent_or_create_basic_credential",
228 ),
229 )?;
230 self.add_credential_producing_arc(credential).await?
231 }
232 Err(Error::CredentialNotFound(..)) if credential_type == CredentialType::X509 => {
233 return Err(LeafError::E2eiEnrollmentNotDone.into());
234 }
235 Err(err) => return Err(err),
236 };
237 Ok(credential)
238 }
239}