1#![expect(unreachable_pub)]
3use std::sync::Arc;
4
5use async_lock::RwLock;
6pub use core_crypto_keystore::Database;
7
8mod crypto_provider;
9mod error;
10
11pub(crate) use crypto_provider::CRYPTO;
12pub use crypto_provider::RustCrypto;
13pub use error::{Error, MlsProviderResult};
14use openmls_traits::{
15 authentication_service::{CredentialAuthenticationStatus, CredentialRef},
16 crypto::OpenMlsCrypto,
17 types::{
18 AeadType, Ciphersuite, CryptoError, ExporterSecret, HashType, HpkeCiphertext, HpkeConfig, HpkeKeyPair,
19 KemOutput, SignatureScheme,
20 },
21};
22#[allow(unused)]
24pub use wire_e2e_identity::pki::{CertificateGenerationArgs, PkiKeypair};
25use wire_e2e_identity::pki_env::PkiEnvironment;
26
27pub type RawEntropySeed = <rand_chacha::ChaCha20Rng as rand::SeedableRng>::Seed;
29
30#[derive(Debug, Clone, Default, PartialEq, Eq, zeroize::ZeroizeOnDrop)]
31#[repr(transparent)]
32pub struct EntropySeed(RawEntropySeed);
34
35impl EntropySeed {
36 pub const EXPECTED_LEN: usize = std::mem::size_of::<EntropySeed>() / std::mem::size_of::<u8>();
38
39 pub fn try_from_slice(data: &[u8]) -> MlsProviderResult<Self> {
41 if data.len() < Self::EXPECTED_LEN {
42 return Err(Error::EntropySeedLength {
43 actual: data.len(),
44 expected: Self::EXPECTED_LEN,
45 });
46 }
47
48 let mut inner = RawEntropySeed::default();
49 inner.copy_from_slice(&data[..Self::EXPECTED_LEN]);
50
51 Ok(Self(inner))
52 }
53
54 pub fn from_raw(raw: RawEntropySeed) -> Self {
56 Self(raw)
57 }
58}
59
60impl std::ops::Deref for EntropySeed {
61 type Target = [u8];
62 fn deref(&self) -> &Self::Target {
63 &self.0
64 }
65}
66
67impl std::ops::DerefMut for EntropySeed {
68 fn deref_mut(&mut self) -> &mut Self::Target {
69 &mut self.0
70 }
71}
72
73#[derive(Debug)]
74pub struct AuthenticationService {
75 pki_env: RwLock<Option<Arc<PkiEnvironment>>>,
84}
85
86impl AuthenticationService {
87 pub async fn pki_env(&self) -> Option<Arc<PkiEnvironment>> {
88 self.pki_env.read().await.clone()
89 }
90}
91
92#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
93#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
94impl openmls_traits::authentication_service::AuthenticationServiceDelegate for AuthenticationService {
95 async fn validate_credential<'a>(&'a self, credential: CredentialRef<'a>) -> CredentialAuthenticationStatus {
96 match credential {
97 CredentialRef::Basic { .. } => CredentialAuthenticationStatus::Valid,
99
100 CredentialRef::X509 { .. } => match self.pki_env.read().await.as_ref() {
101 None => {
102 log::warn!("unable to validate X509 credentials: PKI environment is unset");
103 CredentialAuthenticationStatus::Unknown
104 }
105 Some(pki_env) => {
106 use CredentialAuthenticationStatus::*;
107 match pki_env.validate_credential(credential).await {
110 Revoked => Valid,
111 Expired => Valid,
112 status => status,
113 }
114 }
115 },
116 }
117 }
118}
119
120#[derive(Debug, Clone)]
122pub struct CryptoProvider {
123 crypto: Arc<RustCrypto>,
124 key_store: Arc<Database>,
125 auth_service: Arc<AuthenticationService>,
126}
127
128impl CryptoProvider {
129 pub fn new(key_store: Arc<Database>) -> Self {
135 Self::new_with_pki_env(key_store, None)
136 }
137
138 pub fn new_with_pki_env(key_store: Arc<Database>, pki_env: Option<Arc<PkiEnvironment>>) -> Self {
140 let pki_env = RwLock::new(pki_env);
141 let auth_service = Arc::new(AuthenticationService { pki_env });
142 Self {
143 key_store,
144 crypto: Arc::clone(&CRYPTO),
145 auth_service,
146 }
147 }
148
149 pub async fn set_pki_environment(&mut self, pki_env: Option<Arc<PkiEnvironment>>) {
151 *self.auth_service.pki_env.write().await = pki_env;
152 }
153
154 pub async fn is_pki_env_setup(&self) -> bool {
156 self.auth_service.pki_env.read().await.is_some()
157 }
158
159 pub fn reseed(&self, entropy_seed: Option<EntropySeed>) -> MlsProviderResult<()> {
163 self.crypto.reseed(entropy_seed)
164 }
165
166 #[expect(clippy::too_many_arguments)]
168 pub fn hpke_seal_psk(
169 &self,
170 config: HpkeConfig,
171 pk_r: &[u8],
172 info: &[u8],
173 aad: &[u8],
174 psk: &[u8],
175 psk_id: &[u8],
176 ptxt: &[u8],
177 ) -> Result<HpkeCiphertext, CryptoError> {
178 self.crypto.hpke_seal_psk(config, pk_r, info, aad, psk, psk_id, ptxt)
179 }
180
181 #[expect(clippy::too_many_arguments)]
183 pub fn hpke_open_psk(
184 &self,
185 config: HpkeConfig,
186 input: &HpkeCiphertext,
187 sk_r: &[u8],
188 info: &[u8],
189 aad: &[u8],
190 psk: &[u8],
191 psk_id: &[u8],
192 ) -> Result<Vec<u8>, CryptoError> {
193 self.crypto.hpke_open_psk(config, input, sk_r, info, aad, psk, psk_id)
194 }
195}
196
197impl openmls_traits::OpenMlsCryptoProvider for CryptoProvider {
198 type CryptoProvider = RustCrypto;
199 type RandProvider = RustCrypto;
200 type KeyStoreProvider = Database;
201 type AuthenticationServiceProvider = AuthenticationService;
202
203 fn crypto(&self) -> &Self::CryptoProvider {
204 &self.crypto
205 }
206
207 fn rand(&self) -> &Self::RandProvider {
208 &self.crypto
209 }
210
211 fn key_store(&self) -> &Self::KeyStoreProvider {
212 &self.key_store
213 }
214
215 fn authentication_service(&self) -> &Self::AuthenticationServiceProvider {
216 &self.auth_service
217 }
218}
219
220impl OpenMlsCrypto for &CryptoProvider {
222 fn supports(&self, ciphersuite: Ciphersuite) -> Result<(), CryptoError> {
223 self.crypto.supports(ciphersuite)
224 }
225
226 fn supported_ciphersuites(&self) -> Vec<Ciphersuite> {
227 self.crypto.supported_ciphersuites()
228 }
229
230 fn hkdf_extract(
231 &self,
232 hash_type: HashType,
233 salt: &[u8],
234 ikm: &[u8],
235 ) -> Result<tls_codec::SecretVLBytes, CryptoError> {
236 self.crypto.hkdf_extract(hash_type, salt, ikm)
237 }
238
239 fn hkdf_expand(
240 &self,
241 hash_type: HashType,
242 prk: &[u8],
243 info: &[u8],
244 okm_len: usize,
245 ) -> Result<tls_codec::SecretVLBytes, CryptoError> {
246 self.crypto.hkdf_expand(hash_type, prk, info, okm_len)
247 }
248
249 fn hash(&self, hash_type: HashType, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
250 self.crypto.hash(hash_type, data)
251 }
252
253 fn aead_encrypt(
254 &self,
255 alg: AeadType,
256 key: &[u8],
257 data: &[u8],
258 nonce: &[u8],
259 aad: &[u8],
260 ) -> Result<Vec<u8>, CryptoError> {
261 self.crypto.aead_encrypt(alg, key, data, nonce, aad)
262 }
263
264 fn aead_decrypt(
265 &self,
266 alg: AeadType,
267 key: &[u8],
268 ct_tag: &[u8],
269 nonce: &[u8],
270 aad: &[u8],
271 ) -> Result<Vec<u8>, CryptoError> {
272 self.crypto.aead_decrypt(alg, key, ct_tag, nonce, aad)
273 }
274
275 fn signature_key_gen(&self, alg: SignatureScheme) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
276 self.crypto.signature_key_gen(alg)
277 }
278
279 fn signature_public_key_len(&self, alg: SignatureScheme) -> usize {
280 self.crypto.signature_public_key_len(alg)
281 }
282
283 fn validate_signature_key(&self, alg: SignatureScheme, key: &[u8]) -> Result<(), CryptoError> {
284 self.crypto.validate_signature_key(alg, key)
285 }
286
287 fn verify_signature(
288 &self,
289 alg: SignatureScheme,
290 data: &[u8],
291 pk: &[u8],
292 signature: &[u8],
293 ) -> Result<(), CryptoError> {
294 self.crypto.verify_signature(alg, data, pk, signature)
295 }
296
297 fn sign(&self, alg: SignatureScheme, data: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {
298 self.crypto.sign(alg, data, key)
299 }
300
301 fn hpke_seal(
302 &self,
303 config: HpkeConfig,
304 pk_r: &[u8],
305 info: &[u8],
306 aad: &[u8],
307 ptxt: &[u8],
308 ) -> Result<HpkeCiphertext, CryptoError> {
309 self.crypto.hpke_seal(config, pk_r, info, aad, ptxt)
310 }
311
312 fn hpke_open(
313 &self,
314 config: HpkeConfig,
315 input: &HpkeCiphertext,
316 sk_r: &[u8],
317 info: &[u8],
318 aad: &[u8],
319 ) -> Result<Vec<u8>, CryptoError> {
320 self.crypto.hpke_open(config, input, sk_r, info, aad)
321 }
322
323 fn hpke_setup_sender_and_export(
324 &self,
325 config: HpkeConfig,
326 pk_r: &[u8],
327 info: &[u8],
328 exporter_context: &[u8],
329 exporter_length: usize,
330 ) -> Result<(KemOutput, ExporterSecret), CryptoError> {
331 self.crypto
332 .hpke_setup_sender_and_export(config, pk_r, info, exporter_context, exporter_length)
333 }
334
335 fn hpke_setup_receiver_and_export(
336 &self,
337 config: HpkeConfig,
338 enc: &[u8],
339 sk_r: &[u8],
340 info: &[u8],
341 exporter_context: &[u8],
342 exporter_length: usize,
343 ) -> Result<ExporterSecret, CryptoError> {
344 self.crypto
345 .hpke_setup_receiver_and_export(config, enc, sk_r, info, exporter_context, exporter_length)
346 }
347
348 fn derive_hpke_keypair(&self, config: HpkeConfig, ikm: &[u8]) -> Result<HpkeKeyPair, CryptoError> {
349 self.crypto.derive_hpke_keypair(config, ikm)
350 }
351}