core_crypto/transaction_context/credential/
check.rs1use core_crypto_keystore::{entities::X509Crl, 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 inner = self.inner().await?;
21 let env = self.pki_environment().await?;
22
23 let credentials = Credential::get_all(&inner.transaction)
24 .await
25 .map_err(RecursiveError::context("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).await.map_err(RecursiveError::context(
30 "loading all conversations to check if the credential to be removed is present",
31 ))?;
32 let relevant_crl_uris =
33 Self::get_crl_uris(trust_anchors.iter(), credentials.iter(), conversations.values()).await?;
34
35 self.clean_up_irrelevant_crls(&relevant_crl_uris).await?;
36
37 let crls = env
38 .fetch_crls(relevant_crl_uris.iter().map(AsRef::as_ref))
39 .await
40 .map_err(RecursiveError::e2e_identity("fetching crls"))?;
41
42 for (crl_uri, crl) in crls {
44 env.save_crl(&inner.transaction, &crl_uri, &crl)
45 .await
46 .map_err(RecursiveError::e2e_identity("saving CRL"))?;
47 }
48
49 let mut invalid_credential_refs = Vec::new();
50
51 for credential in credentials {
55 if credential.check(&env).await.is_err() {
56 invalid_credential_refs.push(CredentialRef::from_credential(&credential));
57 }
58 }
59
60 if !invalid_credential_refs.is_empty() {
61 return Err(Error::InvalidCredentials(invalid_credential_refs));
62 }
63
64 Ok(())
65 }
66
67 async fn get_crl_uris(
72 trust_anchors: impl Iterator<Item = &Certificate>,
73 credentials: impl Iterator<Item = &Credential>,
74 conversations: impl Iterator<Item = &Conversation>,
75 ) -> Result<CrlUris> {
76 let mls_credentials = credentials
77 .filter(|credential| credential.credential_type == CredentialType::X509)
78 .map(|credential| credential.mls_credential().mls_credential());
79
80 let mut crl_uris = extract_crl_uris_from_credentials(mls_credentials)
81 .map_err(RecursiveError::context("extracting CRL URLs from stored credentials"))?;
82
83 for trust_anchor in trust_anchors {
84 crl_uris.extend(
85 extract_crl_uris(trust_anchor)
86 .map_err(RecursiveError::e2e_identity("extracting CRL URL from trust anchor"))?
87 .unwrap_or_default(),
88 );
89 }
90
91 for conversation in conversations {
92 let uris_from_group = extract_crl_uris_from_group(&*conversation.group().await)
93 .map_err(RecursiveError::context("extracting CRL URLs from MLS groups"))?;
94 crl_uris.extend(uris_from_group);
95 }
96
97 Ok(crl_uris)
98 }
99
100 async fn clean_up_irrelevant_crls(&self, relevant_crl_uris: &CrlUris) -> Result<()> {
101 let inner = self.inner().await?;
102 for db_crl in inner
103 .transaction
104 .load_all::<X509Crl>()
105 .await
106 .map_err(KeystoreError::wrap("getting all database CRLs"))?
107 {
108 if !relevant_crl_uris.contains(&db_crl.distribution_point) {
109 inner
110 .transaction
111 .remove::<X509Crl>(&db_crl.distribution_point)
112 .await
113 .map_err(KeystoreError::wrap("removing irrelevant CRL"))?;
114 }
115 }
116 Ok(())
117 }
118}