Skip to main content

core_crypto/mls/
mod.rs

1pub(crate) mod cipher_suite;
2pub mod conversation;
3pub(crate) mod conversation_cache;
4pub mod credential;
5mod error;
6mod external_sender;
7pub mod key_package;
8pub(crate) mod session;
9
10pub use error::{Error, Result};
11pub use external_sender::ExternalSender;
12pub use session::{EpochObserver, HistoryObserver};
13
14#[cfg(test)]
15mod tests {
16    use crate::{
17        CertificateBundle, ClientIdentifier, CoreCrypto, CredentialType,
18        test_utils::{x509::X509TestChain, *},
19        transaction_context::Error as TransactionError,
20    };
21
22    mod conversation_epoch {
23        use super::*;
24
25        #[apply(all_cred_cipher)]
26        async fn can_get_newly_created_conversation_epoch(case: TestContext) {
27            let [session] = case.sessions().await;
28            let conversation = case.create_conversation([&session]).await;
29            let epoch = conversation.guard().await.epoch().await;
30            assert_eq!(epoch, 0);
31        }
32
33        #[apply(all_cred_cipher)]
34        async fn can_get_conversation_epoch(case: TestContext) {
35            let [alice, bob] = case.sessions().await;
36            Box::pin(async move {
37                let conversation = case.create_conversation([&alice, &bob]).await;
38                let epoch = conversation.guard().await.epoch().await;
39                assert_eq!(epoch, 1);
40            })
41            .await;
42        }
43
44        #[apply(all_cred_cipher)]
45        async fn conversation_not_found(case: TestContext) {
46            use crate::LeafError;
47            let [session] = case.sessions().await;
48            let id = conversation_id();
49            let err = session.transaction.conversation(&id).await.unwrap_err();
50            assert!(matches!(
51                err,
52                TransactionError::Leaf(LeafError::ConversationNotFound(i)) if i == id
53            ));
54        }
55    }
56
57    #[apply(all_cred_cipher)]
58    async fn create_conversation_should_fail_when_already_exists(case: TestContext) {
59        use crate::LeafError;
60
61        let [alice] = case.sessions().await;
62        Box::pin(async move {
63            let conversation = case.create_conversation([&alice]).await;
64            let id = conversation.id().clone();
65            let credentials = alice.find_credentials(Default::default()).await.expect("finding credentials");
66            let credential = credentials.first().expect("first credential");
67
68                // creating a conversation should first verify that the conversation does not already exist ; only then create it
69                let repeat_create = alice
70                    .transaction
71                    .new_conversation(&id, credential, case.cfg.clone())
72                    .await;
73                assert!(matches!(repeat_create.unwrap_err(), TransactionError::Leaf(LeafError::ConversationAlreadyExists(i)) if i == id));
74            })
75        .await;
76    }
77
78    // TODO: ignore this test for now, until we fix the test suite (WPB-25356)
79    #[ignore]
80    #[apply(all_cred_cipher)]
81    async fn can_2_phase_init_central(mut case: TestContext) {
82        let db = case.create_persistent_db().await;
83        Box::pin(async move {
84            use std::sync::Arc;
85
86            use wire_e2e_identity::pki_env::PkiEnvironment;
87
88            use crate::{ClientId, Credential, test_utils::DummyPkiEnvironmentHooks};
89
90            let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
91
92            // phase 1: init without initialized mls_client
93            let cc = CoreCrypto::new(db.clone());
94            let context = cc.new_transaction().await.unwrap();
95
96            let hooks = Arc::new(DummyPkiEnvironmentHooks);
97            let pki_env = PkiEnvironment::new(hooks, db).await.expect("creating pki environment");
98            cc.set_pki_environment(Some(Arc::new(pki_env))).await;
99
100            x509_test_chain.register_with_central(&context).await;
101
102            // phase 2: init mls_client
103            let session_id = ClientId::from("alice");
104            let identifier = match case.credential_type {
105                CredentialType::Basic => ClientIdentifier::Basic(session_id),
106                CredentialType::X509 => {
107                    CertificateBundle::rand_identifier(&session_id, &[x509_test_chain.find_local_intermediate_ca()])
108                }
109            };
110            let pki_env = cc.get_pki_environment().await;
111            let session_id = identifier
112                .get_id(pki_env.as_deref())
113                .await
114                .expect("get session_id from identifier")
115                .into_owned();
116            context
117                .mls_init(
118                    session_id.clone(),
119                    Arc::new(CoreCryptoTransportSuccessProvider::default()),
120                )
121                .await
122                .unwrap();
123
124            let credential = Credential::from_identifier(&identifier, case.cipher_suite()).unwrap();
125            let credential_ref = context.add_credential(credential).await.unwrap();
126
127            // expect mls_client to work
128            assert!(context.generate_key_package(&credential_ref, None).await.is_ok());
129        })
130        .await
131    }
132}