mls_crypto_provider/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub use core_crypto_keystore::{Database, DatabaseKey};
4
5mod crypto_provider;
6mod error;
7mod pki;
8
9pub use crypto_provider::RustCrypto;
10pub use error::{MlsProviderError, MlsProviderResult};
11use openmls_traits::{
12    crypto::OpenMlsCrypto,
13    types::{
14        AeadType, Ciphersuite, CryptoError, ExporterSecret, HashType, HpkeCiphertext, HpkeConfig, HpkeKeyPair,
15        KemOutput, SignatureScheme,
16    },
17};
18pub use pki::{CertProfile, CertificateGenerationArgs, PkiKeypair};
19
20use crate::pki::PkiEnvironmentProvider;
21
22pub mod reexports {
23    pub use rand_core;
24}
25
26/// 32-byte raw entropy seed
27pub type RawEntropySeed = <rand_chacha::ChaCha20Rng as rand::SeedableRng>::Seed;
28
29#[derive(Debug, Clone, Default, PartialEq, Eq, zeroize::ZeroizeOnDrop)]
30#[repr(transparent)]
31/// Wrapped 32-byte entropy seed with bounds check
32pub struct EntropySeed(RawEntropySeed);
33
34impl EntropySeed {
35    pub const EXPECTED_LEN: usize = std::mem::size_of::<EntropySeed>() / std::mem::size_of::<u8>();
36
37    pub fn try_from_slice(data: &[u8]) -> MlsProviderResult<Self> {
38        if data.len() < Self::EXPECTED_LEN {
39            return Err(MlsProviderError::EntropySeedLengthError {
40                actual: data.len(),
41                expected: Self::EXPECTED_LEN,
42            });
43        }
44
45        let mut inner = RawEntropySeed::default();
46        inner.copy_from_slice(&data[..Self::EXPECTED_LEN]);
47
48        Ok(Self(inner))
49    }
50
51    pub fn from_raw(raw: RawEntropySeed) -> Self {
52        Self(raw)
53    }
54}
55
56impl std::ops::Deref for EntropySeed {
57    type Target = [u8];
58    fn deref(&self) -> &Self::Target {
59        &self.0
60    }
61}
62
63impl std::ops::DerefMut for EntropySeed {
64    fn deref_mut(&mut self) -> &mut Self::Target {
65        &mut self.0
66    }
67}
68
69#[derive(Debug, Clone)]
70pub struct MlsCryptoProvider {
71    crypto: RustCrypto,
72    key_store: Database,
73    pki_env: PkiEnvironmentProvider,
74}
75
76impl MlsCryptoProvider {
77    /// Construct a crypto provider with defaults and a given [Database].
78    ///
79    /// See also:
80    ///
81    /// - [Database::open]
82    pub fn new(key_store: Database) -> Self {
83        Self {
84            key_store,
85            crypto: Default::default(),
86            pki_env: Default::default(),
87        }
88    }
89
90    /// Clones the references of the PkiEnvironment and the CryptoProvider into a transaction
91    /// keystore to pass to openmls as the `OpenMlsCryptoProvider`
92    pub async fn new_transaction(&self) -> MlsProviderResult<()> {
93        self.key_store.new_transaction().await.map_err(Into::into)
94    }
95
96    /// Replaces the PKI env currently in place
97    pub async fn update_pki_env(
98        &self,
99        pki_env: wire_e2e_identity::prelude::x509::revocation::PkiEnvironment,
100    ) -> MlsProviderResult<()> {
101        self.pki_env.update_env(pki_env).await
102    }
103
104    /// Returns whether we have a PKI env setup
105    pub async fn is_pki_env_setup(&self) -> bool {
106        self.pki_env.is_env_setup().await
107    }
108
109    /// Reseeds the internal CSPRNG entropy pool with a brand new one.
110    ///
111    /// If [None] is provided, the new entropy will be pulled through the current OS target's capabilities
112    pub fn reseed(&self, entropy_seed: Option<EntropySeed>) -> MlsProviderResult<()> {
113        self.crypto.reseed(entropy_seed)
114    }
115
116    /// Wait for any keystore transaction to finish, then close the database connection.
117    ///
118    /// Note: This does **not** destroy the data on-disk in case of persistent backing store
119    pub async fn close(&self) -> MlsProviderResult<()> {
120        self.key_store.close().await?;
121        Ok(())
122    }
123
124    /// Clone keystore (its an `Arc` internnaly)
125    pub fn keystore(&self) -> Database {
126        self.key_store.clone()
127    }
128
129    /// Allows to retrieve the underlying key store directly
130    pub fn unwrap_keystore(self) -> Database {
131        self.key_store
132    }
133}
134
135impl openmls_traits::OpenMlsCryptoProvider for MlsCryptoProvider {
136    type CryptoProvider = RustCrypto;
137    type RandProvider = RustCrypto;
138    type KeyStoreProvider = Database;
139    type AuthenticationServiceProvider = PkiEnvironmentProvider;
140
141    fn crypto(&self) -> &Self::CryptoProvider {
142        &self.crypto
143    }
144
145    fn rand(&self) -> &Self::RandProvider {
146        &self.crypto
147    }
148
149    fn key_store(&self) -> &Self::KeyStoreProvider {
150        &self.key_store
151    }
152
153    fn authentication_service(&self) -> &Self::AuthenticationServiceProvider {
154        &self.pki_env
155    }
156}
157
158/// Passthrough implementation of crypto functionality for references to `MlsCryptoProvider`.
159impl OpenMlsCrypto for &MlsCryptoProvider {
160    fn supports(&self, ciphersuite: Ciphersuite) -> Result<(), CryptoError> {
161        self.crypto.supports(ciphersuite)
162    }
163
164    fn supported_ciphersuites(&self) -> Vec<Ciphersuite> {
165        self.crypto.supported_ciphersuites()
166    }
167
168    fn hkdf_extract(
169        &self,
170        hash_type: HashType,
171        salt: &[u8],
172        ikm: &[u8],
173    ) -> Result<tls_codec::SecretVLBytes, CryptoError> {
174        self.crypto.hkdf_extract(hash_type, salt, ikm)
175    }
176
177    fn hkdf_expand(
178        &self,
179        hash_type: HashType,
180        prk: &[u8],
181        info: &[u8],
182        okm_len: usize,
183    ) -> Result<tls_codec::SecretVLBytes, CryptoError> {
184        self.crypto.hkdf_expand(hash_type, prk, info, okm_len)
185    }
186
187    fn hash(&self, hash_type: HashType, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
188        self.crypto.hash(hash_type, data)
189    }
190
191    fn aead_encrypt(
192        &self,
193        alg: AeadType,
194        key: &[u8],
195        data: &[u8],
196        nonce: &[u8],
197        aad: &[u8],
198    ) -> Result<Vec<u8>, CryptoError> {
199        self.crypto.aead_encrypt(alg, key, data, nonce, aad)
200    }
201
202    fn aead_decrypt(
203        &self,
204        alg: AeadType,
205        key: &[u8],
206        ct_tag: &[u8],
207        nonce: &[u8],
208        aad: &[u8],
209    ) -> Result<Vec<u8>, CryptoError> {
210        self.crypto.aead_decrypt(alg, key, ct_tag, nonce, aad)
211    }
212
213    fn signature_key_gen(&self, alg: SignatureScheme) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
214        self.crypto.signature_key_gen(alg)
215    }
216
217    fn signature_public_key_len(&self, alg: SignatureScheme) -> usize {
218        self.crypto.signature_public_key_len(alg)
219    }
220
221    fn validate_signature_key(&self, alg: SignatureScheme, key: &[u8]) -> Result<(), CryptoError> {
222        self.crypto.validate_signature_key(alg, key)
223    }
224
225    fn verify_signature(
226        &self,
227        alg: SignatureScheme,
228        data: &[u8],
229        pk: &[u8],
230        signature: &[u8],
231    ) -> Result<(), CryptoError> {
232        self.crypto.verify_signature(alg, data, pk, signature)
233    }
234
235    fn sign(&self, alg: SignatureScheme, data: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {
236        self.crypto.sign(alg, data, key)
237    }
238
239    fn hpke_seal(
240        &self,
241        config: HpkeConfig,
242        pk_r: &[u8],
243        info: &[u8],
244        aad: &[u8],
245        ptxt: &[u8],
246    ) -> Result<HpkeCiphertext, CryptoError> {
247        self.crypto.hpke_seal(config, pk_r, info, aad, ptxt)
248    }
249
250    fn hpke_open(
251        &self,
252        config: HpkeConfig,
253        input: &HpkeCiphertext,
254        sk_r: &[u8],
255        info: &[u8],
256        aad: &[u8],
257    ) -> Result<Vec<u8>, CryptoError> {
258        self.crypto.hpke_open(config, input, sk_r, info, aad)
259    }
260
261    fn hpke_setup_sender_and_export(
262        &self,
263        config: HpkeConfig,
264        pk_r: &[u8],
265        info: &[u8],
266        exporter_context: &[u8],
267        exporter_length: usize,
268    ) -> Result<(KemOutput, ExporterSecret), CryptoError> {
269        self.crypto
270            .hpke_setup_sender_and_export(config, pk_r, info, exporter_context, exporter_length)
271    }
272
273    fn hpke_setup_receiver_and_export(
274        &self,
275        config: HpkeConfig,
276        enc: &[u8],
277        sk_r: &[u8],
278        info: &[u8],
279        exporter_context: &[u8],
280        exporter_length: usize,
281    ) -> Result<ExporterSecret, CryptoError> {
282        self.crypto
283            .hpke_setup_receiver_and_export(config, enc, sk_r, info, exporter_context, exporter_length)
284    }
285
286    fn derive_hpke_keypair(&self, config: HpkeConfig, ikm: &[u8]) -> Result<HpkeKeyPair, CryptoError> {
287        self.crypto.derive_hpke_keypair(config, ikm)
288    }
289}