use openmls_traits::{random::OpenMlsRand, OpenMlsCryptoProvider};
use crate::context::CentralContext;
use crate::prelude::{CryptoError, CryptoResult, E2eiEnrollment};
use core_crypto_keystore::CryptoKeystoreMls;
use mls_crypto_provider::MlsCryptoProvider;
pub(crate) type EnrollmentHandle = Vec<u8>;
impl E2eiEnrollment {
pub(crate) async fn stash(self, backend: &MlsCryptoProvider) -> CryptoResult<EnrollmentHandle> {
const HANDLE_SIZE: usize = 32;
let content = serde_json::to_vec(&self)?;
let handle = backend.crypto().random_vec(HANDLE_SIZE).map_err(CryptoError::from)?;
backend
.key_store()
.save_e2ei_enrollment(&handle, &content)
.await
.map_err(CryptoError::from)?;
Ok(handle)
}
pub(crate) async fn stash_pop(backend: &MlsCryptoProvider, handle: EnrollmentHandle) -> CryptoResult<Self> {
let content = backend
.key_store()
.pop_e2ei_enrollment(&handle)
.await
.map_err(CryptoError::from)?;
Ok(serde_json::from_slice(&content)?)
}
}
impl CentralContext {
pub async fn e2ei_enrollment_stash(&self, enrollment: E2eiEnrollment) -> CryptoResult<EnrollmentHandle> {
enrollment.stash(&self.mls_provider().await?).await
}
pub async fn e2ei_enrollment_stash_pop(&self, handle: EnrollmentHandle) -> CryptoResult<E2eiEnrollment> {
E2eiEnrollment::stash_pop(&self.mls_provider().await?, handle).await
}
}
#[cfg(test)]
mod tests {
use mls_crypto_provider::MlsCryptoProvider;
use wasm_bindgen_test::*;
use crate::{
e2e_identity::id::WireQualifiedClientId,
e2e_identity::tests::*,
prelude::{E2eiEnrollment, INITIAL_KEYING_MATERIAL_COUNT},
test_utils::{x509::X509TestChain, *},
};
wasm_bindgen_test_configure!(run_in_browser);
#[apply(all_cred_cipher)]
#[wasm_bindgen_test]
async fn stash_and_pop_should_not_abort_enrollment(case: TestCase) {
run_test_wo_clients(case.clone(), move |mut cc| {
Box::pin(async move {
let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
let is_renewal = false;
let (mut enrollment, cert) = e2ei_enrollment(
&mut cc,
&case,
&x509_test_chain,
Some(E2EI_CLIENT_ID_URI),
is_renewal,
init_enrollment,
|e, cc| {
Box::pin(async move {
let handle = cc.e2ei_enrollment_stash(e).await.unwrap();
cc.e2ei_enrollment_stash_pop(handle).await.unwrap()
})
},
)
.await
.unwrap();
assert!(cc
.context
.e2ei_mls_init_only(&mut enrollment, cert, Some(INITIAL_KEYING_MATERIAL_COUNT))
.await
.is_ok());
})
})
.await
}
#[apply(all_cred_cipher)]
#[wasm_bindgen_test]
async fn should_fail_when_restoring_invalid(case: TestCase) {
run_test_wo_clients(case.clone(), move |mut cc| {
Box::pin(async move {
let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
let is_renewal = false;
let result = e2ei_enrollment(
&mut cc,
&case,
&x509_test_chain,
Some(E2EI_CLIENT_ID_URI),
is_renewal,
init_enrollment,
move |e, _cc| {
Box::pin(async move {
let backend = MlsCryptoProvider::try_new_in_memory("new").await.unwrap();
backend.new_transaction().await.unwrap();
let client_id = e.client_id.parse::<WireQualifiedClientId>().unwrap();
E2eiEnrollment::try_new(
client_id.into(),
e.display_name,
e.handle,
e.team,
1,
&backend,
e.ciphersuite,
None,
#[cfg(not(target_family = "wasm"))]
None,
)
.unwrap()
})
},
)
.await;
assert!(result.is_err());
})
})
.await
}
}