interop/clients/corecrypto/
ffi.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 core_crypto_ffi::{
19    context::TransactionHelper, ClientId, CoreCrypto, CustomConfiguration, MlsCredentialType, UniffiCustomTypeConverter,
20};
21use std::sync::Arc;
22
23use crate::{
24    clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedMlsClient},
25    CIPHERSUITE_IN_USE,
26};
27
28#[derive(Debug)]
29pub(crate) struct CoreCryptoFfiClient {
30    cc: CoreCrypto,
31    client_id: Vec<u8>,
32    #[cfg(feature = "proteus")]
33    prekey_last_id: u16,
34}
35
36impl CoreCryptoFfiClient {
37    pub(crate) async fn new() -> Result<CoreCryptoFfiClient> {
38        let client_id = uuid::Uuid::new_v4();
39        let client_id_bytes: Vec<u8> = client_id.as_hyphenated().to_string().as_bytes().into();
40        let client_id = ClientId::into_custom(client_id_bytes.clone()).unwrap();
41        let ciphersuite = CIPHERSUITE_IN_USE;
42        let cc = CoreCrypto::new(
43            "path".into(),
44            "key".into(),
45            Some(client_id),
46            Some(vec![ciphersuite].into()),
47            None,
48        )
49        .await?;
50        Ok(Self {
51            cc,
52            client_id: client_id_bytes,
53            #[cfg(feature = "proteus")]
54            prekey_last_id: 0,
55        })
56    }
57}
58
59#[async_trait::async_trait(?Send)]
60impl EmulatedClient for CoreCryptoFfiClient {
61    fn client_name(&self) -> &str {
62        "CoreCrypto::ffi"
63    }
64
65    fn client_type(&self) -> EmulatedClientType {
66        EmulatedClientType::Native
67    }
68
69    fn client_id(&self) -> &[u8] {
70        self.client_id.as_slice()
71    }
72
73    fn client_protocol(&self) -> EmulatedClientProtocol {
74        EmulatedClientProtocol::MLS | EmulatedClientProtocol::PROTEUS
75    }
76
77    async fn wipe(mut self) -> Result<()> {
78        Ok(Arc::new(self.cc).wipe().await?)
79    }
80}
81
82#[async_trait::async_trait(?Send)]
83impl EmulatedMlsClient for CoreCryptoFfiClient {
84    async fn get_keypackage(&mut self) -> Result<Vec<u8>> {
85        let ciphersuite = CIPHERSUITE_IN_USE.into();
86        let credential_type = MlsCredentialType::Basic;
87        let extractor = TransactionHelper::new(move |context| async move {
88            Ok(context
89                .client_keypackages(ciphersuite, credential_type, 1)
90                .await?
91                .pop()
92                .unwrap())
93        });
94        self.cc.transaction(extractor.clone()).await?;
95        let kp = extractor.into_return_value();
96        Ok(kp)
97    }
98
99    async fn add_client(&mut self, conversation_id: &[u8], kp: &[u8]) -> Result<Vec<u8>> {
100        if !self.cc.conversation_exists(conversation_id.to_vec()).await? {
101            let cfg = core_crypto_ffi::ConversationConfiguration {
102                ciphersuite: CIPHERSUITE_IN_USE.into(),
103                external_senders: vec![],
104                custom: CustomConfiguration {
105                    key_rotation_span: None,
106                    wire_policy: None,
107                },
108            };
109            let conversation_id = conversation_id.to_vec();
110            self.cc
111                .transaction(TransactionHelper::new(move |context| async move {
112                    context
113                        .create_conversation(conversation_id, MlsCredentialType::Basic, cfg)
114                        .await?;
115                    Ok(())
116                }))
117                .await?;
118        }
119
120        let conversation_id = conversation_id.to_vec();
121        let key_packages = vec![kp.to_vec()];
122        let extractor = TransactionHelper::new(move |context| async move {
123            context.add_clients_to_conversation(conversation_id, key_packages).await
124        });
125        self.cc.transaction(extractor.clone()).await?;
126        let welcome = extractor.into_return_value();
127
128        Ok(welcome.welcome)
129    }
130
131    async fn kick_client(&mut self, conversation_id: &[u8], client_id: &[u8]) -> Result<Vec<u8>> {
132        let client_id = ClientId::into_custom(client_id.to_vec()).unwrap();
133        let conversation_id = conversation_id.to_vec();
134        let extractor = TransactionHelper::new(move |context| async move {
135            context
136                .remove_clients_from_conversation(conversation_id, vec![client_id])
137                .await
138        });
139        self.cc.transaction(extractor.clone()).await?;
140        let commit = extractor.into_return_value();
141
142        Ok(commit.commit)
143    }
144
145    async fn process_welcome(&mut self, welcome: &[u8]) -> Result<Vec<u8>> {
146        let cfg = CustomConfiguration {
147            key_rotation_span: None,
148            wire_policy: None,
149        };
150        let welcome = welcome.to_vec();
151        let extractor =
152            TransactionHelper::new(move |context| async move { context.process_welcome_message(welcome, cfg).await });
153        self.cc.transaction(extractor.clone()).await?;
154        Ok(extractor.into_return_value().id)
155    }
156
157    async fn encrypt_message(&mut self, conversation_id: &[u8], message: &[u8]) -> Result<Vec<u8>> {
158        let conversation_id = conversation_id.to_vec();
159        let message = message.to_vec();
160        let extractor =
161            TransactionHelper::new(
162                move |context| async move { context.encrypt_message(conversation_id, message).await },
163            );
164        self.cc.transaction(extractor.clone()).await?;
165        Ok(extractor.into_return_value())
166    }
167
168    async fn decrypt_message(&mut self, conversation_id: &[u8], message: &[u8]) -> Result<Option<Vec<u8>>> {
169        let conversation_id = conversation_id.to_vec();
170        let message = message.to_vec();
171        let extractor =
172            TransactionHelper::new(
173                move |context| async move { context.decrypt_message(conversation_id, message).await },
174            );
175        self.cc.transaction(extractor.clone()).await?;
176        Ok(extractor.into_return_value().message)
177    }
178}
179
180#[cfg(feature = "proteus")]
181#[async_trait::async_trait(?Send)]
182impl crate::clients::EmulatedProteusClient for CoreCryptoFfiClient {
183    async fn init(&mut self) -> Result<()> {
184        self.cc
185            .transaction(TransactionHelper::new(move |context| async move {
186                context.proteus_init().await
187            }))
188            .await?;
189        Ok(())
190    }
191
192    async fn get_prekey(&mut self) -> Result<Vec<u8>> {
193        self.prekey_last_id += 1;
194        let prekey_last_id = self.prekey_last_id;
195        let extractor =
196            TransactionHelper::new(move |context| async move { context.proteus_new_prekey(prekey_last_id).await });
197        self.cc.transaction(extractor.clone()).await?;
198        Ok(extractor.into_return_value())
199    }
200
201    async fn session_from_prekey(&mut self, session_id: &str, prekey: &[u8]) -> Result<()> {
202        let session_id = session_id.to_string();
203        let prekey = prekey.to_vec();
204        self.cc
205            .transaction(TransactionHelper::new(move |context| async move {
206                context.proteus_session_from_prekey(session_id, prekey).await
207            }))
208            .await?;
209        Ok(())
210    }
211
212    async fn session_from_message(&mut self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
213        let session_id = session_id.to_string();
214        let message = message.to_vec();
215        let extractor = TransactionHelper::new(move |context| async move {
216            context.proteus_session_from_message(session_id, message).await
217        });
218        self.cc.transaction(extractor.clone()).await?;
219        Ok(extractor.into_return_value())
220    }
221
222    async fn encrypt(&mut self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
223        let session_id = session_id.to_string();
224        let plaintext = plaintext.to_vec();
225        let extractor =
226            TransactionHelper::new(move |context| async move { context.proteus_encrypt(session_id, plaintext).await });
227        self.cc.transaction(extractor.clone()).await?;
228        Ok(extractor.into_return_value())
229    }
230
231    async fn decrypt(&mut self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
232        let session_id = session_id.to_string();
233        let ciphertext = ciphertext.to_vec();
234        let extractor =
235            TransactionHelper::new(move |context| async move { context.proteus_decrypt(session_id, ciphertext).await });
236        self.cc.transaction(extractor.clone()).await?;
237        Ok(extractor.into_return_value())
238    }
239
240    async fn fingerprint(&self) -> Result<String> {
241        self.cc.proteus_fingerprint().await.map_err(Into::into)
242    }
243}