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::context("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).await.map_err(RecursiveError::context(
33 "loading all conversations to check if the credential to be removed is present",
34 ))?;
35 let relevant_crl_uris =
36 Self::get_crl_uris(trust_anchors.iter(), credentials.iter(), conversations.values()).await?;
37
38 self.clean_up_irrelevant_crls(&relevant_crl_uris).await?;
39
40 let crls = env
41 .fetch_crls(relevant_crl_uris.iter().map(AsRef::as_ref))
42 .await
43 .map_err(RecursiveError::e2e_identity("fetching crls"))?;
44
45 for (crl_uri, crl) in crls {
47 env.save_crl(&inner.transaction, &crl_uri, &crl)
48 .await
49 .map_err(RecursiveError::e2e_identity("saving CRL"))?;
50 }
51
52 let mut invalid_credential_refs = Vec::new();
53
54 for credential in credentials {
58 if credential.check(&env).await.is_err() {
59 invalid_credential_refs.push(CredentialRef::from_credential(&credential));
60 }
61 }
62
63 if !invalid_credential_refs.is_empty() {
64 return Err(Error::InvalidCredentials(invalid_credential_refs));
65 }
66
67 Ok(())
68 }
69
70 async fn get_crl_uris(
75 trust_anchors: impl Iterator<Item = &Certificate>,
76 credentials: impl Iterator<Item = &Credential>,
77 conversations: impl Iterator<Item = &Conversation>,
78 ) -> Result<CrlUris> {
79 let mls_credentials = credentials
80 .filter(|credential| credential.credential_type == CredentialType::X509)
81 .map(|credential| credential.mls_credential().mls_credential());
82
83 let mut crl_uris = extract_crl_uris_from_credentials(mls_credentials)
84 .map_err(RecursiveError::context("extracting CRL URLs from stored credentials"))?;
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::context("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 inner = self.inner().await?;
105 for db_crl in inner
106 .transaction
107 .load_all::<X509Crl>()
108 .await
109 .map_err(KeystoreError::wrap("getting all database CRLs"))?
110 {
111 if !relevant_crl_uris.contains(&db_crl.distribution_point) {
112 X509Crl::delete(inner.transaction(), &db_crl.distribution_point)
113 .map_err(KeystoreError::wrap("removing irrelevant CRL"))?;
114 }
115 }
116 Ok(())
117 }
118}