interop/clients/corecrypto/
native.rs

1use color_eyre::eyre::Result;
2use std::cell::Cell;
3use std::sync::Arc;
4use tls_codec::Serialize;
5
6use core_crypto::prelude::*;
7
8use crate::util::MlsTransportSuccessProvider;
9use crate::{
10    CIPHERSUITE_IN_USE,
11    clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedMlsClient},
12};
13
14#[derive(Debug)]
15pub(crate) struct CoreCryptoNativeClient {
16    cc: CoreCrypto,
17    client_id: Vec<u8>,
18    #[cfg(feature = "proteus")]
19    prekey_last_id: Cell<u16>,
20}
21
22#[allow(dead_code)]
23impl CoreCryptoNativeClient {
24    pub(crate) async fn new() -> Result<Self> {
25        Self::internal_new(false).await
26    }
27
28    async fn internal_new(deferred: bool) -> Result<Self> {
29        let client_id = uuid::Uuid::new_v4();
30
31        let ciphersuites = vec![CIPHERSUITE_IN_USE.into()];
32        let cid = if !deferred {
33            Some(client_id.as_hyphenated().to_string().as_bytes().into())
34        } else {
35            None
36        };
37        let key = core_crypto::DatabaseKey::generate();
38        let configuration =
39            MlsClientConfiguration::try_new("whatever".into(), key, cid, ciphersuites, None, Some(100))?;
40
41        let cc = CoreCrypto::from(Session::try_new_in_memory(configuration).await?);
42
43        cc.provide_transport(Arc::new(MlsTransportSuccessProvider::default()))
44            .await;
45
46        Ok(Self {
47            cc,
48            client_id: client_id.into_bytes().into(),
49            #[cfg(feature = "proteus")]
50            prekey_last_id: Cell::new(0),
51        })
52    }
53}
54
55#[async_trait::async_trait(?Send)]
56impl EmulatedClient for CoreCryptoNativeClient {
57    fn client_name(&self) -> &str {
58        "CoreCrypto::native"
59    }
60
61    fn client_type(&self) -> EmulatedClientType {
62        EmulatedClientType::Native
63    }
64
65    fn client_id(&self) -> &[u8] {
66        self.client_id.as_slice()
67    }
68
69    fn client_protocol(&self) -> EmulatedClientProtocol {
70        EmulatedClientProtocol::MLS | EmulatedClientProtocol::PROTEUS
71    }
72
73    async fn wipe(&mut self) -> Result<()> {
74        Ok(())
75    }
76}
77
78#[async_trait::async_trait(?Send)]
79impl EmulatedMlsClient for CoreCryptoNativeClient {
80    async fn get_keypackage(&self) -> Result<Vec<u8>> {
81        let transaction = self.cc.new_transaction().await?;
82        let start = std::time::Instant::now();
83        let kp = transaction
84            .get_or_create_client_keypackages(CIPHERSUITE_IN_USE.into(), MlsCredentialType::Basic, 1)
85            .await?
86            .pop()
87            .unwrap();
88
89        log::info!(
90            "KP Init Key [took {}ms]: Client {} [{}] - {}",
91            start.elapsed().as_millis(),
92            self.client_name(),
93            hex::encode(&self.client_id),
94            hex::encode(kp.hpke_init_key()),
95        );
96        transaction.finish().await?;
97
98        Ok(kp.tls_serialize_detached()?)
99    }
100
101    async fn add_client(&self, conversation_id: &[u8], kp: &[u8]) -> Result<()> {
102        let conversation_id = conversation_id.to_vec();
103        let transaction = self.cc.new_transaction().await?;
104        if !transaction.conversation_exists(&conversation_id).await? {
105            let config = MlsConversationConfiguration {
106                ciphersuite: CIPHERSUITE_IN_USE.into(),
107                ..Default::default()
108            };
109            transaction
110                .new_conversation(&conversation_id, MlsCredentialType::Basic, config)
111                .await?;
112        }
113
114        use tls_codec::Deserialize as _;
115
116        let kp = KeyPackageIn::tls_deserialize(&mut &kp[..])?;
117        transaction
118            .conversation(&conversation_id)
119            .await?
120            .add_members(vec![kp])
121            .await?;
122        transaction.finish().await?;
123
124        Ok(())
125    }
126
127    async fn kick_client(&self, conversation_id: &[u8], client_id: &[u8]) -> Result<()> {
128        let transaction = self.cc.new_transaction().await?;
129        transaction
130            .conversation(&conversation_id.to_owned())
131            .await?
132            .remove_members(&[client_id.to_owned().into()])
133            .await?;
134        transaction.finish().await?;
135
136        Ok(())
137    }
138
139    async fn process_welcome(&self, welcome: &[u8]) -> Result<Vec<u8>> {
140        let transaction = self.cc.new_transaction().await?;
141
142        let result = transaction
143            .process_raw_welcome_message(welcome.into(), MlsCustomConfiguration::default())
144            .await?
145            .id;
146        transaction.finish().await?;
147        Ok(result)
148    }
149
150    async fn encrypt_message(&self, conversation_id: &[u8], message: &[u8]) -> Result<Vec<u8>> {
151        let transaction = self.cc.new_transaction().await?;
152        let result = transaction
153            .conversation(&conversation_id.to_vec())
154            .await?
155            .encrypt_message(message)
156            .await?;
157        transaction.finish().await?;
158        Ok(result)
159    }
160
161    async fn decrypt_message(&self, conversation_id: &[u8], message: &[u8]) -> Result<Option<Vec<u8>>> {
162        let transaction = self.cc.new_transaction().await?;
163        let result = transaction
164            .conversation(&conversation_id.to_vec())
165            .await?
166            .decrypt_message(message)
167            .await?
168            .app_msg;
169        transaction.finish().await?;
170        Ok(result)
171    }
172}
173
174#[cfg(feature = "proteus")]
175#[async_trait::async_trait(?Send)]
176impl crate::clients::EmulatedProteusClient for CoreCryptoNativeClient {
177    async fn init(&mut self) -> Result<()> {
178        let transaction = self.cc.new_transaction().await?;
179        transaction.proteus_init().await?;
180        Ok(transaction.finish().await?)
181    }
182
183    async fn get_prekey(&self) -> Result<Vec<u8>> {
184        let transaction = self.cc.new_transaction().await?;
185        let prekey_last_id = self.prekey_last_id.get() + 1;
186        self.prekey_last_id.replace(prekey_last_id);
187        let result = transaction.proteus_new_prekey(prekey_last_id).await?;
188        transaction.finish().await?;
189        Ok(result)
190    }
191
192    async fn session_from_prekey(&self, session_id: &str, prekey: &[u8]) -> Result<()> {
193        let transaction = self.cc.new_transaction().await?;
194        let _ = transaction.proteus_session_from_prekey(session_id, prekey).await?;
195        transaction.finish().await?;
196        Ok(())
197    }
198
199    async fn session_from_message(&self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
200        let transaction = self.cc.new_transaction().await?;
201        let (_, ret) = transaction.proteus_session_from_message(session_id, message).await?;
202        transaction.finish().await?;
203        Ok(ret)
204    }
205
206    async fn encrypt(&self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
207        let transaction = self.cc.new_transaction().await?;
208        let result = transaction.proteus_encrypt(session_id, plaintext).await?;
209        transaction.finish().await?;
210        Ok(result)
211    }
212
213    async fn decrypt(&self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
214        let transaction = self.cc.new_transaction().await?;
215        let result = transaction.proteus_decrypt(session_id, ciphertext).await?;
216        transaction.finish().await?;
217        Ok(result)
218    }
219
220    async fn fingerprint(&self) -> Result<String> {
221        Ok(self.cc.proteus_fingerprint().await?)
222    }
223}