core_crypto/
lib.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
17//! Core Crypto is a wrapper on top of OpenMLS aimed to provide an ergonomic API for usage in web
18//! through Web Assembly and in mobile devices through FFI.
19//!
20//! The goal is provide a easier and less verbose API to create, manage and interact with MLS
21//! groups.
22#![doc = include_str!("../../README.md")]
23#![cfg_attr(not(test), deny(missing_docs))]
24#![allow(clippy::single_component_path_imports)]
25
26use async_lock::Mutex;
27#[cfg(test)]
28pub use core_crypto_macros::{dispotent, durable, idempotent};
29use std::sync::Arc;
30
31pub use self::error::*;
32
33#[cfg(test)]
34#[macro_use]
35pub mod test_utils;
36// both imports above have to be defined at the beginning of the crate for rstest to work
37
38mod error;
39
40/// MLS Abstraction
41pub mod mls;
42
43/// re-export [rusty-jwt-tools](https://github.com/wireapp/rusty-jwt-tools) API
44pub mod e2e_identity;
45
46#[cfg(feature = "proteus")]
47/// Proteus Abstraction
48pub mod proteus;
49
50pub mod context;
51mod group_store;
52mod obfuscate;
53
54mod build_metadata;
55pub use build_metadata::{BuildMetadata, BUILD_METADATA};
56
57/// Common imports that should be useful for most uses of the crate
58pub mod prelude {
59    pub use openmls::{
60        group::{MlsGroup, MlsGroupConfig},
61        prelude::{
62            group_info::VerifiableGroupInfo, Ciphersuite as CiphersuiteName, Credential, GroupEpoch, KeyPackage,
63            KeyPackageIn, KeyPackageRef, MlsMessageIn, Node,
64        },
65    };
66
67    pub use mls_crypto_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed};
68
69    pub use crate::{
70        e2e_identity::{
71            conversation_state::E2eiConversationState,
72            device_status::DeviceStatus,
73            error::{E2eIdentityError, E2eIdentityResult},
74            identity::{WireIdentity, X509Identity},
75            rotate::MlsRotateBundle,
76            types::{E2eiAcmeChallenge, E2eiAcmeDirectory, E2eiNewAcmeAuthz, E2eiNewAcmeOrder},
77            E2eiEnrollment,
78        },
79        error::{CryptoError, CryptoResult, CryptoboxMigrationError, MlsError, ProteusError},
80        mls::{
81            ciphersuite::MlsCiphersuite,
82            client::id::ClientId,
83            client::identifier::ClientIdentifier,
84            client::key_package::INITIAL_KEYING_MATERIAL_COUNT,
85            client::*,
86            config::MlsCentralConfiguration,
87            conversation::{
88                commit::{MlsCommitBundle, MlsConversationCreationMessage},
89                config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
90                decrypt::{self, MlsBufferedConversationDecryptMessage, MlsConversationDecryptMessage},
91                group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
92                proposal::MlsProposalBundle,
93                welcome::WelcomeBundle,
94                ConversationId, MlsConversation,
95            },
96            credential::{typ::MlsCredentialType, x509::CertificateBundle},
97            external_commit::MlsConversationInitBundle,
98            proposal::{MlsProposal, MlsProposalRef},
99            MlsCentral,
100        },
101        CoreCrypto, CoreCryptoCallbacks,
102    };
103}
104
105/// Client callbacks in order to Core Crypto to verify user authorization
106///
107/// This trait is used to provide callback mechanisms for the MlsCentral struct, for example for
108/// operations like adding or removing memebers that can be authorized through a caller provided
109/// authorization method.
110#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
111#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
112pub trait CoreCryptoCallbacks: std::fmt::Debug + Send + Sync {
113    /// Function responsible for authorizing an operation.
114    /// Returns `true` if the operation is authorized.
115    ///
116    /// # Arguments
117    /// * `conversation_id` - id of the group/conversation
118    /// * `client_id` - id of the client to authorize
119    async fn authorize(&self, conversation_id: prelude::ConversationId, client_id: prelude::ClientId) -> bool;
120    /// Function responsible for authorizing an operation for a given user.
121    /// Use `external_client_id` & `existing_clients` to get all the 'client_id' belonging to the same user
122    /// as `external_client_id`. Then, given those client ids, verify that at least one has the right role
123    /// (is authorized) exactly like it's done in [Self::authorize]
124    /// Returns `true` if the operation is authorized.
125    ///
126    /// # Arguments
127    /// * `conversation_id` - id of the group/conversation
128    /// * `external_client_id` - id a client external to the MLS group
129    /// * `existing_clients` - all the clients in the MLS group
130    async fn user_authorize(
131        &self,
132        conversation_id: prelude::ConversationId,
133        external_client_id: prelude::ClientId,
134        existing_clients: Vec<prelude::ClientId>,
135    ) -> bool;
136    /// Validates if the given `client_id` belongs to one of the provided `existing_clients`
137    /// This basically allows to defer the client ID parsing logic to the caller - because CoreCrypto is oblivious to such things
138    ///
139    /// # Arguments
140    /// * `conversation_id` - ID of the conversation
141    /// * `client_id` - client ID of the client referenced within the sent proposal
142    /// * `existing_clients` - all the clients in the MLS group
143    async fn client_is_existing_group_user(
144        &self,
145        conversation_id: prelude::ConversationId,
146        client_id: prelude::ClientId,
147        existing_clients: Vec<prelude::ClientId>,
148        parent_conversation_clients: Option<Vec<prelude::ClientId>>,
149    ) -> bool;
150}
151
152#[derive(Debug)]
153/// Wrapper superstruct for both [mls::MlsCentral] and [proteus::ProteusCentral]
154///
155/// As [std::ops::Deref] is implemented, this struct is automatically dereferred to [mls::MlsCentral] apart from `proteus_*` calls
156pub struct CoreCrypto {
157    mls: mls::MlsCentral,
158    #[cfg(feature = "proteus")]
159    proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
160    #[cfg(not(feature = "proteus"))]
161    #[allow(dead_code)]
162    proteus: (),
163}
164
165impl From<mls::MlsCentral> for CoreCrypto {
166    fn from(mls: mls::MlsCentral) -> Self {
167        Self {
168            mls,
169            proteus: Default::default(),
170        }
171    }
172}
173
174impl std::ops::Deref for CoreCrypto {
175    type Target = mls::MlsCentral;
176
177    fn deref(&self) -> &Self::Target {
178        &self.mls
179    }
180}
181
182impl std::ops::DerefMut for CoreCrypto {
183    fn deref_mut(&mut self) -> &mut Self::Target {
184        &mut self.mls
185    }
186}
187
188impl CoreCrypto {
189    /// Allows to extract the MLS Client from the wrapper superstruct
190    #[inline]
191    pub fn take(self) -> mls::MlsCentral {
192        self.mls
193    }
194}
195
196#[cfg(feature = "uniffi")]
197uniffi::setup_scaffolding!("core_crypto");