Skip to main content

core_crypto/proteus/
core_crypto.rs

1use super::ProteusCentral;
2use crate::{CoreCrypto, Error, Result};
3
4impl CoreCrypto {
5    /// Proteus session exists
6    ///
7    /// Warning: The Proteus client **MUST** be initialized with
8    /// [crate::transaction_context::TransactionContext::proteus_init] first or an error will be
9    /// returned
10    pub async fn proteus_session_exists(&self, session_id: &str) -> Result<bool> {
11        let mut mutex = self.proteus.lock().await;
12        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
13        Ok(proteus.session_exists(session_id, &self.database).await)
14    }
15
16    /// Returns the proteus last resort prekey id (u16::MAX = 65535)
17    pub fn proteus_last_resort_prekey_id() -> u16 {
18        ProteusCentral::last_resort_prekey_id()
19    }
20
21    /// Returns the proteus identity's public key fingerprint
22    ///
23    /// Warning: The Proteus client **MUST** be initialized with
24    /// [crate::transaction_context::TransactionContext::proteus_init] first or an error will be
25    /// returned
26    pub async fn proteus_fingerprint(&self) -> Result<String> {
27        let mutex = self.proteus.lock().await;
28        let proteus = mutex.as_ref().ok_or(Error::ProteusNotInitialized)?;
29        Ok(proteus.fingerprint())
30    }
31
32    /// Returns the proteus identity's public key fingerprint
33    ///
34    /// Warning: The Proteus client **MUST** be initialized with
35    /// [crate::transaction_context::TransactionContext::proteus_init] first or an error will be
36    /// returned
37    pub async fn proteus_fingerprint_local(&self, session_id: &str) -> Result<String> {
38        let mut mutex = self.proteus.lock().await;
39        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
40        proteus.fingerprint_local(session_id, &self.database).await
41    }
42
43    /// Returns the proteus identity's public key fingerprint
44    ///
45    /// Warning: The Proteus client **MUST** be initialized with
46    /// [crate::transaction_context::TransactionContext::proteus_init] first or an error will be
47    /// returned
48    pub async fn proteus_fingerprint_remote(&self, session_id: &str) -> Result<String> {
49        let mut mutex = self.proteus.lock().await;
50        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
51        proteus.fingerprint_remote(session_id, &self.database).await
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use std::sync::Arc;
58
59    use core_crypto_keystore::{ConnectionType, Database, DatabaseKey};
60
61    use super::*;
62    use crate::{
63        CertificateBundle, ClientIdentifier, CredentialType,
64        test_utils::{x509::X509TestChain, *},
65    };
66
67    #[macro_rules_attribute::apply(smol_macros::test)]
68    async fn cc_can_init() {
69        #[cfg(not(target_os = "unknown"))]
70        let (path, db_file) = tmp_db_file();
71        #[cfg(target_os = "unknown")]
72        let (path, _) = tmp_db_file();
73        let db = Database::open(ConnectionType::Persistent(&path), &DatabaseKey::generate())
74            .await
75            .unwrap();
76
77        let cc = CoreCrypto::new(db);
78        let context = cc.new_transaction().await.unwrap();
79        assert!(context.proteus_init().await.is_ok());
80        assert!(context.proteus_new_prekey(1).await.is_ok());
81        context.finish().await.unwrap();
82        #[cfg(not(target_os = "unknown"))]
83        drop(db_file);
84    }
85
86    // TODO: ignore this test for now, until we fix the test suite (WPB-25356)
87    #[ignore]
88    #[apply(all_cred_cipher)]
89    async fn cc_can_2_phase_init(case: TestContext) {
90        use wire_e2e_identity::pki_env::PkiEnvironment;
91
92        use crate::{ClientId, Credential, test_utils::DummyPkiEnvironmentHooks};
93
94        #[cfg(not(target_os = "unknown"))]
95        let (path, db_file) = tmp_db_file();
96        #[cfg(target_os = "unknown")]
97        let (path, _) = tmp_db_file();
98        let db = Database::open(ConnectionType::Persistent(&path), &DatabaseKey::generate())
99            .await
100            .unwrap();
101
102        let cc = CoreCrypto::new(db.clone());
103        let hooks = Arc::new(DummyPkiEnvironmentHooks);
104        let pki_env = PkiEnvironment::new(hooks, db).await.expect("creating pki environment");
105        cc.set_pki_environment(Some(Arc::new(pki_env))).await;
106        let transaction = cc.new_transaction().await.unwrap();
107        let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
108        x509_test_chain.register_with_central(&transaction).await;
109        assert!(transaction.proteus_init().await.is_ok());
110        // proteus is initialized, prekeys can be generated
111        assert!(transaction.proteus_new_prekey(1).await.is_ok());
112        // 👇 and so a unique 'client_id' can be fetched from wire-server
113        let session_id = ClientId::from("alice");
114        let transport = Arc::new(CoreCryptoTransportSuccessProvider::default());
115        let identifier = match case.credential_type {
116            CredentialType::Basic => ClientIdentifier::Basic(session_id),
117            CredentialType::X509 => {
118                CertificateBundle::rand_identifier(&session_id, &[x509_test_chain.find_local_intermediate_ca()])
119            }
120        };
121        let pki_env = cc.get_pki_environment().await;
122        let session_id = identifier
123            .get_id(pki_env.as_deref())
124            .await
125            .expect("Getting session id from identifier")
126            .into_owned();
127        transaction.mls_init(session_id, transport).await.unwrap();
128        let credential = Credential::from_identifier(&identifier, case.cipher_suite()).unwrap();
129        let credential_ref = transaction.add_credential(credential).await.unwrap();
130
131        // expect MLS to work
132        assert!(transaction.generate_key_package(&credential_ref, None).await.is_ok());
133
134        #[cfg(not(target_os = "unknown"))]
135        drop(db_file);
136    }
137}