core_crypto/mls/session/
e2e_identity.rs1use openmls::{
2 prelude::{Credential, Node, SignatureScheme, group_info::VerifiableGroupInfo},
3 treesync::RatchetTree,
4};
5use wire_e2e_identity::prelude::WireIdentityReader as _;
6
7use crate::{
8 MlsError,
9 mls::session::CredentialExt as _,
10 prelude::{E2eiConversationState, MlsCiphersuite, MlsCredentialType},
11};
12use openmls_traits::OpenMlsCryptoProvider as _;
13
14use super::{Error, Result, Session};
15
16impl Session {
17 pub async fn e2ei_is_pki_env_setup(&self) -> bool {
19 self.crypto_provider.is_pki_env_setup().await
20 }
21
22 pub async fn e2ei_is_enabled(&self, signature_scheme: SignatureScheme) -> Result<bool> {
24 let x509_result = self
25 .find_most_recent_credential_bundle(signature_scheme, MlsCredentialType::X509)
26 .await;
27 match x509_result {
28 Err(Error::CredentialNotFound(MlsCredentialType::X509)) => {
29 self.find_most_recent_credential_bundle(signature_scheme, MlsCredentialType::Basic)
30 .await?;
31 Ok(false)
32 }
33 Err(e) => Err(e),
34 Ok(_) => Ok(true),
35 }
36 }
37
38 pub async fn e2ei_verify_group_state(&self, group_info: VerifiableGroupInfo) -> Result<E2eiConversationState> {
40 self.crypto_provider
41 .authentication_service()
42 .refresh_time_of_interest()
43 .await;
44
45 let cs = group_info.ciphersuite().into();
46
47 let is_sender = true; let Ok(rt) = group_info.take_ratchet_tree(&self.crypto_provider, is_sender).await else {
49 return Ok(E2eiConversationState::NotVerified);
50 };
51
52 let credentials = rt.iter().filter_map(|n| match n {
53 Some(Node::LeafNode(ln)) => Some(ln.credential()),
54 _ => None,
55 });
56
57 Ok(Self::compute_conversation_state(
58 cs,
59 credentials,
60 MlsCredentialType::X509,
61 self.crypto_provider.authentication_service().borrow().await.as_ref(),
62 )
63 .await)
64 }
65
66 pub async fn get_credential_in_use(
69 &self,
70 group_info: VerifiableGroupInfo,
71 credential_type: MlsCredentialType,
72 ) -> Result<E2eiConversationState> {
73 let cs = group_info.ciphersuite().into();
74 let rt = group_info
79 .take_ratchet_tree(&self.crypto_provider, false)
80 .await
81 .map_err(MlsError::wrap("taking ratchet tree"))?;
82 Self::get_credential_in_use_in_ratchet_tree(
83 cs,
84 rt,
85 credential_type,
86 self.crypto_provider.authentication_service().borrow().await.as_ref(),
87 )
88 .await
89 }
90 pub(crate) async fn get_credential_in_use_in_ratchet_tree(
91 ciphersuite: MlsCiphersuite,
92 ratchet_tree: RatchetTree,
93 credential_type: MlsCredentialType,
94 env: Option<&wire_e2e_identity::prelude::x509::revocation::PkiEnvironment>,
95 ) -> Result<E2eiConversationState> {
96 let credentials = ratchet_tree.iter().filter_map(|n| match n {
97 Some(Node::LeafNode(ln)) => Some(ln.credential()),
98 _ => None,
99 });
100 Ok(Self::compute_conversation_state(ciphersuite, credentials, credential_type, env).await)
101 }
102
103 pub(crate) async fn compute_conversation_state<'a>(
106 ciphersuite: MlsCiphersuite,
107 credentials: impl Iterator<Item = &'a Credential>,
108 _credential_type: MlsCredentialType,
109 env: Option<&wire_e2e_identity::prelude::x509::revocation::PkiEnvironment>,
110 ) -> E2eiConversationState {
111 let mut is_e2ei = false;
112 let mut state = E2eiConversationState::Verified;
113
114 for credential in credentials {
115 let Ok(Some(cert)) = credential.parse_leaf_cert() else {
116 state = E2eiConversationState::NotVerified;
117 if is_e2ei {
118 break;
119 }
120 continue;
121 };
122
123 is_e2ei = true;
124
125 let invalid_identity = cert.extract_identity(env, ciphersuite.e2ei_hash_alg()).is_err();
126
127 use openmls_x509_credential::X509Ext as _;
128 let is_time_valid = cert.is_time_valid().unwrap_or(false);
129 let is_time_invalid = !is_time_valid;
130 let is_revoked_or_invalid = env
131 .map(|e| e.validate_cert_and_revocation(&cert).is_err())
132 .unwrap_or(false);
133
134 let is_invalid = invalid_identity || is_time_invalid || is_revoked_or_invalid;
135 if is_invalid {
136 state = E2eiConversationState::NotVerified;
137 break;
138 }
139 }
140
141 if is_e2ei {
142 state
143 } else {
144 E2eiConversationState::NotEnabled
145 }
146 }
147}