mls_crypto_provider/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub use core_crypto_keystore::{Connection as CryptoKeystore, DatabaseKey};
4
5mod crypto_provider;
6mod error;
7mod pki;
8
9pub use error::{MlsProviderError, MlsProviderResult};
10
11pub use crypto_provider::RustCrypto;
12
13pub use pki::{CertProfile, CertificateGenerationArgs, PkiKeypair};
14use typed_builder::TypedBuilder;
15
16use crate::pki::PkiEnvironmentProvider;
17
18pub mod reexports {
19    pub use rand_core;
20}
21
22/// 32-byte raw entropy seed
23pub type RawEntropySeed = <rand_chacha::ChaCha20Rng as rand::SeedableRng>::Seed;
24
25#[derive(Debug, Clone, Default, PartialEq, Eq, zeroize::ZeroizeOnDrop)]
26#[repr(transparent)]
27/// Wrapped 32-byte entropy seed with bounds check
28pub struct EntropySeed(RawEntropySeed);
29
30impl EntropySeed {
31    pub const EXPECTED_LEN: usize = std::mem::size_of::<EntropySeed>() / std::mem::size_of::<u8>();
32
33    pub fn try_from_slice(data: &[u8]) -> MlsProviderResult<Self> {
34        if data.len() < Self::EXPECTED_LEN {
35            return Err(MlsProviderError::EntropySeedLengthError {
36                actual: data.len(),
37                expected: Self::EXPECTED_LEN,
38            });
39        }
40
41        let mut inner = RawEntropySeed::default();
42        inner.copy_from_slice(&data[..Self::EXPECTED_LEN]);
43
44        Ok(Self(inner))
45    }
46
47    pub fn from_raw(raw: RawEntropySeed) -> Self {
48        Self(raw)
49    }
50}
51
52impl std::ops::Deref for EntropySeed {
53    type Target = [u8];
54    fn deref(&self) -> &Self::Target {
55        &self.0
56    }
57}
58
59impl std::ops::DerefMut for EntropySeed {
60    fn deref_mut(&mut self) -> &mut Self::Target {
61        &mut self.0
62    }
63}
64
65// we don't want to document this type; it's purely an implementation detail
66// people get the builder from `MlsCryptoProvider::builder`, and the builder produces
67// a `MlsCryptoProvider`
68#[doc(hidden)]
69#[derive(TypedBuilder)]
70#[builder(build_method(into = MlsCryptoProvider))]
71pub struct MlsCryptoProviderConfiguration {
72    key_store: CryptoKeystore,
73    /// External seed for the ChaCha20 PRNG entropy pool
74    #[builder(default, setter(strip_option(fallback=entropy_seed_opt)))]
75    entropy_seed: Option<EntropySeed>,
76}
77
78#[derive(Debug, Clone)]
79pub struct MlsCryptoProvider {
80    crypto: RustCrypto,
81    key_store: CryptoKeystore,
82    pki_env: PkiEnvironmentProvider,
83}
84
85impl From<MlsCryptoProviderConfiguration> for MlsCryptoProvider {
86    fn from(
87        MlsCryptoProviderConfiguration {
88            key_store,
89            entropy_seed,
90        }: MlsCryptoProviderConfiguration,
91    ) -> Self {
92        let crypto = entropy_seed.map(RustCrypto::new_with_seed).unwrap_or_default();
93        let pki_env = PkiEnvironmentProvider::default();
94
95        Self {
96            crypto,
97            key_store,
98            pki_env,
99        }
100    }
101}
102
103impl MlsCryptoProvider {
104    /// Construct a builder which can build a crypto provider.
105    ///
106    /// See also:
107    ///
108    /// - [CryptoKeystore::open]
109    pub fn builder() -> MlsCryptoProviderConfigurationBuilder {
110        MlsCryptoProviderConfiguration::builder()
111    }
112
113    /// Clones the references of the PkiEnvironment and the CryptoProvider into a transaction
114    /// keystore to pass to openmls as the `OpenMlsCryptoProvider`
115    pub async fn new_transaction(&self) -> MlsProviderResult<()> {
116        self.key_store.new_transaction().await.map_err(Into::into)
117    }
118
119    /// Replaces the PKI env currently in place
120    pub async fn update_pki_env(
121        &self,
122        pki_env: wire_e2e_identity::prelude::x509::revocation::PkiEnvironment,
123    ) -> MlsProviderResult<()> {
124        self.pki_env.update_env(pki_env).await
125    }
126
127    /// Returns whether we have a PKI env setup
128    pub async fn is_pki_env_setup(&self) -> bool {
129        self.pki_env.is_env_setup().await
130    }
131
132    /// Reseeds the internal CSPRNG entropy pool with a brand new one.
133    ///
134    /// If [None] is provided, the new entropy will be pulled through the current OS target's capabilities
135    pub fn reseed(&self, entropy_seed: Option<EntropySeed>) -> MlsProviderResult<()> {
136        self.crypto.reseed(entropy_seed)
137    }
138
139    /// Returns whether or not it is currently possible to close this provider.
140    ///
141    /// Reasons why it may not currently be possible:
142    ///
143    /// - A transaction is currently in progress
144    /// - Multiple strong references currently exist to the keystore
145    ///
146    /// As with all such checks, this is vulnerable to TOCTOU issues, but as the current implementation
147    /// of the [`MlsCryptoProvider::close`] function consumes `self`, this is the only way to check in advance whether
148    /// this will in principle work.
149    pub async fn can_close(&self) -> bool {
150        self.key_store.can_close().await
151    }
152
153    /// Closes this provider, which in turns tears down the backing store
154    ///
155    /// Note: This does **not** destroy the data on-disk in case of persistent backing store
156    pub async fn close(self) -> MlsProviderResult<()> {
157        self.key_store.close().await.map_err(Into::into)
158    }
159
160    /// Clone keystore (its an `Arc` internnaly)
161    pub fn keystore(&self) -> CryptoKeystore {
162        self.key_store.clone()
163    }
164
165    /// Allows to retrieve the underlying key store directly
166    pub fn unwrap_keystore(self) -> CryptoKeystore {
167        self.key_store
168    }
169}
170
171impl openmls_traits::OpenMlsCryptoProvider for MlsCryptoProvider {
172    type CryptoProvider = RustCrypto;
173    type RandProvider = RustCrypto;
174    type KeyStoreProvider = CryptoKeystore;
175    type AuthenticationServiceProvider = PkiEnvironmentProvider;
176
177    fn crypto(&self) -> &Self::CryptoProvider {
178        &self.crypto
179    }
180
181    fn rand(&self) -> &Self::RandProvider {
182        &self.crypto
183    }
184
185    fn key_store(&self) -> &Self::KeyStoreProvider {
186        &self.key_store
187    }
188
189    fn authentication_service(&self) -> &Self::AuthenticationServiceProvider {
190        &self.pki_env
191    }
192}