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