interop/clients/corecrypto/
native.rs

1// Wire
2// Copyright (C) 2022 Wire Swiss GmbH
3
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see http://www.gnu.org/licenses/.
16
17use color_eyre::eyre::Result;
18use tls_codec::Serialize;
19
20use core_crypto::prelude::*;
21
22use crate::{
23    clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedMlsClient},
24    CIPHERSUITE_IN_USE,
25};
26
27#[derive(Debug)]
28pub(crate) struct CoreCryptoNativeClient {
29    cc: CoreCrypto,
30    client_id: Vec<u8>,
31    #[cfg(feature = "proteus")]
32    prekey_last_id: u16,
33}
34
35#[allow(dead_code)]
36impl CoreCryptoNativeClient {
37    pub(crate) async fn new() -> Result<Self> {
38        Self::internal_new(false).await
39    }
40
41    async fn internal_new(deferred: bool) -> Result<Self> {
42        let client_id = uuid::Uuid::new_v4();
43
44        let ciphersuites = vec![CIPHERSUITE_IN_USE.into()];
45        let cid = if !deferred {
46            Some(client_id.as_hyphenated().to_string().as_bytes().into())
47        } else {
48            None
49        };
50        let configuration =
51            MlsCentralConfiguration::try_new("whatever".into(), "test".into(), cid, ciphersuites, None, Some(100))?;
52
53        let cc = CoreCrypto::from(MlsCentral::try_new_in_memory(configuration).await?);
54
55        Ok(Self {
56            cc,
57            client_id: client_id.into_bytes().into(),
58            #[cfg(feature = "proteus")]
59            prekey_last_id: 0,
60        })
61    }
62}
63
64#[async_trait::async_trait(?Send)]
65impl EmulatedClient for CoreCryptoNativeClient {
66    fn client_name(&self) -> &str {
67        "CoreCrypto::native"
68    }
69
70    fn client_type(&self) -> EmulatedClientType {
71        EmulatedClientType::Native
72    }
73
74    fn client_id(&self) -> &[u8] {
75        self.client_id.as_slice()
76    }
77
78    fn client_protocol(&self) -> EmulatedClientProtocol {
79        EmulatedClientProtocol::MLS | EmulatedClientProtocol::PROTEUS
80    }
81
82    async fn wipe(mut self) -> Result<()> {
83        self.cc.take().wipe().await?;
84        Ok(())
85    }
86}
87
88#[async_trait::async_trait(?Send)]
89impl EmulatedMlsClient for CoreCryptoNativeClient {
90    async fn get_keypackage(&mut self) -> Result<Vec<u8>> {
91        let transaction = self.cc.new_transaction().await?;
92        let start = std::time::Instant::now();
93        let kp = transaction
94            .get_or_create_client_keypackages(CIPHERSUITE_IN_USE.into(), MlsCredentialType::Basic, 1)
95            .await?
96            .pop()
97            .unwrap();
98
99        log::info!(
100            "KP Init Key [took {}ms]: Client {} [{}] - {}",
101            start.elapsed().as_millis(),
102            self.client_name(),
103            hex::encode(&self.client_id),
104            hex::encode(kp.hpke_init_key()),
105        );
106        transaction.finish().await?;
107
108        Ok(kp.tls_serialize_detached()?)
109    }
110
111    async fn add_client(&mut self, conversation_id: &[u8], kp: &[u8]) -> Result<Vec<u8>> {
112        let conversation_id = conversation_id.to_vec();
113        let transaction = self.cc.new_transaction().await?;
114        if !transaction.conversation_exists(&conversation_id).await? {
115            let config = MlsConversationConfiguration {
116                ciphersuite: CIPHERSUITE_IN_USE.into(),
117                ..Default::default()
118            };
119            transaction
120                .new_conversation(&conversation_id, MlsCredentialType::Basic, config)
121                .await?;
122        }
123
124        use tls_codec::Deserialize as _;
125
126        let kp = KeyPackageIn::tls_deserialize(&mut &kp[..])?;
127        let welcome = transaction
128            .add_members_to_conversation(&conversation_id, vec![kp])
129            .await?;
130        transaction.finish().await?;
131
132        Ok(welcome.welcome.tls_serialize_detached()?)
133    }
134
135    async fn kick_client(&mut self, conversation_id: &[u8], client_id: &[u8]) -> Result<Vec<u8>> {
136        let transaction = self.cc.new_transaction().await?;
137        let commit = transaction
138            .remove_members_from_conversation(&conversation_id.to_vec(), &[client_id.to_vec().into()])
139            .await?;
140        transaction.finish().await?;
141
142        Ok(commit.commit.to_bytes()?)
143    }
144
145    async fn process_welcome(&mut self, welcome: &[u8]) -> Result<Vec<u8>> {
146        let transaction = self.cc.new_transaction().await?;
147
148        let result = transaction
149            .process_raw_welcome_message(welcome.into(), MlsCustomConfiguration::default())
150            .await?
151            .id;
152        transaction.finish().await?;
153        Ok(result)
154    }
155
156    async fn encrypt_message(&mut self, conversation_id: &[u8], message: &[u8]) -> Result<Vec<u8>> {
157        let transaction = self.cc.new_transaction().await?;
158        let result = transaction.encrypt_message(&conversation_id.to_vec(), message).await?;
159        transaction.finish().await?;
160        Ok(result)
161    }
162
163    async fn decrypt_message(&mut self, conversation_id: &[u8], message: &[u8]) -> Result<Option<Vec<u8>>> {
164        let transaction = self.cc.new_transaction().await?;
165        let result = transaction
166            .decrypt_message(&conversation_id.to_vec(), 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(&mut self) -> Result<Vec<u8>> {
184        let transaction = self.cc.new_transaction().await?;
185        self.prekey_last_id += 1;
186        let result = transaction.proteus_new_prekey(self.prekey_last_id).await?;
187        transaction.finish().await?;
188        Ok(result)
189    }
190
191    async fn session_from_prekey(&mut self, session_id: &str, prekey: &[u8]) -> Result<()> {
192        let transaction = self.cc.new_transaction().await?;
193        let _ = transaction.proteus_session_from_prekey(session_id, prekey).await?;
194        transaction.finish().await?;
195        Ok(())
196    }
197
198    async fn session_from_message(&mut self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
199        let transaction = self.cc.new_transaction().await?;
200        let (_, ret) = transaction.proteus_session_from_message(session_id, message).await?;
201        transaction.finish().await?;
202        Ok(ret)
203    }
204
205    async fn encrypt(&mut self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
206        let transaction = self.cc.new_transaction().await?;
207        let result = transaction.proteus_encrypt(session_id, plaintext).await?;
208        transaction.finish().await?;
209        Ok(result)
210    }
211
212    async fn decrypt(&mut self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
213        let transaction = self.cc.new_transaction().await?;
214        let result = transaction.proteus_decrypt(session_id, ciphertext).await?;
215        transaction.finish().await?;
216        Ok(result)
217    }
218
219    async fn fingerprint(&self) -> Result<String> {
220        Ok(self.cc.proteus_fingerprint().await?)
221    }
222}