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