core_crypto/mls/session/
e2e_identity.rs1use openmls::{
2 prelude::{Credential, Node, group_info::VerifiableGroupInfo},
3 treesync::RatchetTree,
4};
5use openmls_traits::OpenMlsCryptoProvider as _;
6use wire_e2e_identity::WireIdentityReader as _;
7
8use super::{Result, Session};
9use crate::{
10 CredentialType, E2eiConversationState, OpenMlsError, mls::credential::ext::CredentialExt as _,
11 mls_provider::AuthenticationService,
12};
13
14impl Session {
15 pub async fn e2ei_verify_group_state(&self, group_info: VerifiableGroupInfo) -> Result<E2eiConversationState> {
17 let is_sender = true; let Ok(rt) = group_info.take_ratchet_tree(&self.crypto_provider, is_sender).await else {
19 return Ok(E2eiConversationState::NotVerified);
20 };
21
22 let credentials = rt.iter().filter_map(|n| match n {
23 Some(Node::LeafNode(ln)) => Some(ln.credential()),
24 _ => None,
25 });
26
27 Ok(Self::compute_conversation_state(
28 credentials,
29 CredentialType::X509,
30 self.crypto_provider.authentication_service(),
31 )
32 .await)
33 }
34
35 pub async fn get_credential_in_use(
38 &self,
39 group_info: VerifiableGroupInfo,
40 credential_type: CredentialType,
41 ) -> Result<E2eiConversationState> {
42 let rt = group_info
47 .take_ratchet_tree(&self.crypto_provider, false)
48 .await
49 .map_err(OpenMlsError::wrap("taking ratchet tree"))?;
50 Self::get_credential_in_use_in_ratchet_tree(rt, credential_type, self.crypto_provider.authentication_service())
51 .await
52 }
53 pub(crate) async fn get_credential_in_use_in_ratchet_tree(
54 ratchet_tree: RatchetTree,
55 credential_type: CredentialType,
56 auth_service: &AuthenticationService,
57 ) -> Result<E2eiConversationState> {
58 let credentials = ratchet_tree.iter().filter_map(|n| match n {
59 Some(Node::LeafNode(ln)) => Some(ln.credential()),
60 _ => None,
61 });
62 Ok(Self::compute_conversation_state(credentials, credential_type, auth_service).await)
63 }
64
65 pub(crate) async fn compute_conversation_state<'a>(
68 credentials: impl Iterator<Item = &'a Credential>,
69 _credential_type: CredentialType,
70 auth_service: &AuthenticationService,
71 ) -> E2eiConversationState {
72 let pki_env = auth_service.pki_env().await;
73 let Some(env) = pki_env else {
74 return E2eiConversationState::NotEnabled;
75 };
76
77 let mut is_e2ei = false;
78 let mut state = E2eiConversationState::Verified;
79
80 for credential in credentials {
81 let Ok(Some(cert)) = credential.parse_leaf_cert() else {
82 state = E2eiConversationState::NotVerified;
83 if is_e2ei {
84 break;
85 }
86 continue;
87 };
88
89 is_e2ei = true;
90
91 let invalid_identity = cert.extract_identity(&env).await.is_err();
92
93 use openmls_x509_credential::X509Ext as _;
94 let is_time_valid = cert.is_time_valid().unwrap_or(false);
95 let is_time_invalid = !is_time_valid;
96 let is_revoked_or_invalid = env.validate_cert(&cert).await.is_err();
97 let is_invalid = invalid_identity || is_time_invalid || is_revoked_or_invalid;
98 if is_invalid {
99 state = E2eiConversationState::NotVerified;
100 break;
101 }
102 }
103
104 if is_e2ei {
105 state
106 } else {
107 E2eiConversationState::NotEnabled
108 }
109 }
110}