core_crypto/transaction_context/credential/
check.rs1use core_crypto_keystore::{
2 entities::X509Crl,
3 traits::{EntityDatabaseMutation, FetchFromDatabase},
4};
5use wire_e2e_identity::x509_check::extract_crl_uris;
6use x509_cert::Certificate;
7
8use super::{Error, Result};
9use crate::{
10 Credential, CredentialRef, CredentialType, KeystoreError, RecursiveError,
11 mls::{
12 conversation::Conversation,
13 credential::crl::{CrlUris, extract_crl_uris_from_credentials, extract_crl_uris_from_group},
14 },
15 transaction_context::TransactionContext,
16};
17
18impl TransactionContext {
19 pub async fn check_credentials(&self) -> Result<()> {
23 let inner = self.inner().await?;
24 let env = self.pki_environment().await?;
25
26 let credentials = Credential::get_all(&inner.transaction)
27 .await
28 .map_err(RecursiveError::mls_credential("getting all credentials"))?;
29 let trust_anchors = env.get_trust_anchors().await;
30
31 let session = self.session().await?;
32 let conversations = Conversation::load_all(session)
33 .await
34 .map_err(RecursiveError::mls_conversation(
35 "loading all conversations to check if the credential to be removed is present",
36 ))?;
37 let relevant_crl_uris =
38 Self::get_crl_uris(trust_anchors.iter(), credentials.iter(), conversations.values()).await?;
39
40 self.clean_up_irrelevant_crls(&relevant_crl_uris).await?;
41
42 let crls = env
43 .fetch_crls(relevant_crl_uris.iter().map(AsRef::as_ref))
44 .await
45 .map_err(RecursiveError::e2e_identity("fetching crls"))?;
46
47 for (crl_uri, crl) in crls {
49 env.save_crl(&inner.transaction, &crl_uri, &crl)
50 .await
51 .map_err(RecursiveError::e2e_identity("saving CRL"))?;
52 }
53
54 let mut invalid_credential_refs = Vec::new();
55
56 for credential in credentials {
60 if credential.check(&env).await.is_err() {
61 invalid_credential_refs.push(CredentialRef::from_credential(&credential));
62 }
63 }
64
65 if !invalid_credential_refs.is_empty() {
66 return Err(Error::InvalidCredentials(invalid_credential_refs));
67 }
68
69 Ok(())
70 }
71
72 async fn get_crl_uris(
77 trust_anchors: impl Iterator<Item = &Certificate>,
78 credentials: impl Iterator<Item = &Credential>,
79 conversations: impl Iterator<Item = &Conversation>,
80 ) -> Result<CrlUris> {
81 let mls_credentials = credentials
82 .filter(|credential| credential.credential_type == CredentialType::X509)
83 .map(|credential| credential.mls_credential().mls_credential());
84
85 let mut crl_uris = extract_crl_uris_from_credentials(mls_credentials).map_err(
86 RecursiveError::mls_credential("extracting CRL URLs from stored credentials"),
87 )?;
88
89 for trust_anchor in trust_anchors {
90 crl_uris.extend(
91 extract_crl_uris(trust_anchor)
92 .map_err(RecursiveError::e2e_identity("extracting CRL URL from trust anchor"))?
93 .unwrap_or_default(),
94 );
95 }
96
97 for conversation in conversations {
98 let uris_from_group = extract_crl_uris_from_group(&*conversation.group().await)
99 .map_err(RecursiveError::mls_credential("extracting CRL URLs from MLS groups"))?;
100 crl_uris.extend(uris_from_group);
101 }
102
103 Ok(crl_uris)
104 }
105
106 async fn clean_up_irrelevant_crls(&self, relevant_crl_uris: &CrlUris) -> Result<()> {
107 let inner = self.inner().await?;
108 for db_crl in inner
109 .transaction
110 .load_all::<X509Crl>()
111 .await
112 .map_err(KeystoreError::wrap("getting all database CRLs"))?
113 {
114 if !relevant_crl_uris.contains(&db_crl.distribution_point) {
115 X509Crl::delete(inner.transaction(), &db_crl.distribution_point)
116 .map_err(KeystoreError::wrap("removing irrelevant CRL"))?;
117 }
118 }
119 Ok(())
120 }
121}