core_crypto/transaction_context/credential/
check.rs1use core_crypto_keystore::{entities::E2eiCrl, traits::FetchFromDatabase};
2use wire_e2e_identity::{pki_env::PkiEnvironment, 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::{
11 crl::{CrlUris, extract_crl_uris_from_credentials, extract_crl_uris_from_group},
12 ext::CredentialExt as _,
13 },
14 },
15 transaction_context::TransactionContext,
16};
17
18impl TransactionContext {
19 pub async fn check_credentials(&self) -> Result<()> {
22 let database = self.database().await?;
23 let env = self.pki_environment().await?;
24
25 let credentials = Credential::get_all(&database)
26 .await
27 .map_err(RecursiveError::mls_credential("getting all credentials"))?;
28 let trust_anchors = env.get_trust_anchors().await;
29
30 let session = self.session().await?;
31 let conversations = Conversation::load_all(session)
32 .await
33 .map_err(RecursiveError::mls_conversation(
34 "loading all conversations to check if the credential to be removed is present",
35 ))?;
36 let relevant_crl_uris =
37 Self::get_crl_uris(trust_anchors.iter(), credentials.iter(), conversations.values()).await?;
38
39 self.clean_up_irrelevant_crls(&relevant_crl_uris).await?;
40
41 let crls = env
42 .fetch_crls(relevant_crl_uris.iter().map(AsRef::as_ref))
43 .await
44 .map_err(RecursiveError::e2e_identity("fetching crls"))?;
45
46 for (crl_uri, crl) in crls {
48 env.save_crl(&crl_uri, &crl)
49 .await
50 .map_err(RecursiveError::e2e_identity("saving CRL"))?;
51 }
52
53 let mut invalid_credential_refs = Vec::new();
54
55 for credential in credentials {
57 if self.check_credential(&env, &credential).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 check_credential(&self, pki_env: &PkiEnvironment, credential: &Credential) -> Result<()> {
104 let cert = credential
105 .mls_credential()
106 .parse_leaf_cert()
107 .map_err(RecursiveError::mls_credential("parsing leaf certificate"))?
108 .ok_or(Error::InvalidCredential)?;
109 pki_env
110 .validate_cert(&cert)
111 .await
112 .map_err(RecursiveError::e2e_identity("validating credential certificate"))?;
113 Ok(())
114 }
115
116 async fn clean_up_irrelevant_crls(&self, relevant_crl_uris: &CrlUris) -> Result<()> {
117 let database = self.database().await?;
118 for db_crl in database
119 .load_all::<E2eiCrl>()
120 .await
121 .map_err(KeystoreError::wrap("getting all database CRLs"))?
122 {
123 if !relevant_crl_uris.contains(&db_crl.distribution_point) {
124 database
125 .remove::<E2eiCrl>(&db_crl.distribution_point)
126 .await
127 .map_err(KeystoreError::wrap("removing irrelevant CRL"))?;
128 }
129 }
130 Ok(())
131 }
132}