#![doc = include_str!("../README.md")]
pub use core_crypto_keystore::Connection as CryptoKeystore;
mod crypto_provider;
mod error;
mod pki;
pub use error::{MlsProviderError, MlsProviderResult};
pub use crypto_provider::RustCrypto;
pub use pki::{CertProfile, CertificateGenerationArgs, PkiKeypair};
use crate::pki::PkiEnvironmentProvider;
pub mod reexports {
pub use rand_core;
}
pub type RawEntropySeed = <rand_chacha::ChaCha20Rng as rand::SeedableRng>::Seed;
#[derive(Debug, Clone, Default, PartialEq, Eq, zeroize::ZeroizeOnDrop)]
#[repr(transparent)]
pub struct EntropySeed(RawEntropySeed);
impl EntropySeed {
pub const EXPECTED_LEN: usize = std::mem::size_of::<EntropySeed>() / std::mem::size_of::<u8>();
pub fn try_from_slice(data: &[u8]) -> MlsProviderResult<Self> {
if data.len() < Self::EXPECTED_LEN {
return Err(MlsProviderError::EntropySeedLengthError {
actual: data.len(),
expected: Self::EXPECTED_LEN,
});
}
let mut inner = RawEntropySeed::default();
inner.copy_from_slice(&data[..Self::EXPECTED_LEN]);
Ok(Self(inner))
}
pub fn from_raw(raw: RawEntropySeed) -> Self {
Self(raw)
}
}
impl std::ops::Deref for EntropySeed {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for EntropySeed {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MlsCryptoProviderConfiguration<'a> {
pub db_path: &'a str,
pub identity_key: &'a str,
pub in_memory: bool,
pub entropy_seed: Option<EntropySeed>,
}
#[derive(Debug, Clone)]
pub struct MlsCryptoProvider {
crypto: RustCrypto,
key_store: CryptoKeystore,
pki_env: PkiEnvironmentProvider,
}
impl MlsCryptoProvider {
pub async fn try_new_with_configuration(config: MlsCryptoProviderConfiguration<'_>) -> MlsProviderResult<Self> {
let crypto = config.entropy_seed.map(RustCrypto::new_with_seed).unwrap_or_default();
let key_store = if config.in_memory {
CryptoKeystore::open_in_memory_with_key("", config.identity_key).await?
} else {
CryptoKeystore::open_with_key(config.db_path, config.identity_key).await?
};
Ok(Self {
crypto,
key_store,
pki_env: PkiEnvironmentProvider::default(),
})
}
pub async fn try_new(db_path: impl AsRef<str>, identity_key: impl AsRef<str>) -> MlsProviderResult<Self> {
let crypto = RustCrypto::default();
let key_store = CryptoKeystore::open_with_key(db_path, identity_key.as_ref()).await?;
Ok(Self {
crypto,
key_store,
pki_env: PkiEnvironmentProvider::default(),
})
}
pub async fn try_new_in_memory(identity_key: impl AsRef<str>) -> MlsProviderResult<Self> {
let crypto = RustCrypto::default();
let key_store = CryptoKeystore::open_in_memory_with_key("", identity_key.as_ref()).await?;
Ok(Self {
crypto,
key_store,
pki_env: PkiEnvironmentProvider::default(),
})
}
pub fn new_with_store(key_store: CryptoKeystore, entropy_seed: Option<EntropySeed>) -> Self {
let crypto = entropy_seed.map(RustCrypto::new_with_seed).unwrap_or_default();
Self {
crypto,
key_store,
pki_env: PkiEnvironmentProvider::default(),
}
}
pub async fn new_transaction(&self) -> MlsProviderResult<()> {
self.key_store.new_transaction().await.map_err(Into::into)
}
pub async fn update_pki_env(
&self,
pki_env: wire_e2e_identity::prelude::x509::revocation::PkiEnvironment,
) -> MlsProviderResult<()> {
self.pki_env.update_env(pki_env).await
}
pub async fn is_pki_env_setup(&self) -> bool {
self.pki_env.is_env_setup().await
}
pub fn reseed(&self, entropy_seed: Option<EntropySeed>) -> MlsProviderResult<()> {
self.crypto.reseed(entropy_seed)
}
pub async fn close(self) -> MlsProviderResult<()> {
Ok(self.key_store.close().await?)
}
pub async fn destroy_and_reset(self) -> MlsProviderResult<()> {
Ok(self.key_store.wipe().await?)
}
pub fn keystore(&self) -> CryptoKeystore {
self.key_store.clone()
}
pub fn unwrap_keystore(self) -> CryptoKeystore {
self.key_store
}
}
impl openmls_traits::OpenMlsCryptoProvider for MlsCryptoProvider {
type CryptoProvider = RustCrypto;
type RandProvider = RustCrypto;
type KeyStoreProvider = CryptoKeystore;
type AuthenticationServiceProvider = PkiEnvironmentProvider;
fn crypto(&self) -> &Self::CryptoProvider {
&self.crypto
}
fn rand(&self) -> &Self::RandProvider {
&self.crypto
}
fn key_store(&self) -> &Self::KeyStoreProvider {
&self.key_store
}
fn authentication_service(&self) -> &Self::AuthenticationServiceProvider {
&self.pki_env
}
}