1pub(crate) mod config;
2pub(crate) mod e2e_identity;
3mod epoch_observer;
4mod error;
5mod history_observer;
6pub(crate) mod id;
7pub(crate) mod identifier;
8pub(crate) mod identities;
9pub(crate) mod key_package;
10pub(crate) mod user_id;
11
12use crate::{
13 CoreCrypto, KeystoreError, LeafError, MlsError, MlsTransport, RecursiveError,
14 group_store::GroupStore,
15 mls::{
16 self, HasSessionAndCrypto,
17 conversation::ImmutableConversation,
18 credential::{CredentialBundle, ext::CredentialExt},
19 },
20 prelude::{
21 CertificateBundle, ClientId, ConversationId, HistorySecret, MlsCiphersuite, MlsCredentialType,
22 config::ValidatedSessionConfig, identifier::ClientIdentifier, key_package::KEYPACKAGE_DEFAULT_LIFETIME,
23 },
24};
25use async_lock::RwLock;
26use core_crypto_keystore::{
27 Connection, CryptoKeystoreError,
28 connection::FetchFromDatabase,
29 entities::{EntityFindParams, MlsCredential, MlsSignatureKeyPair},
30};
31pub use epoch_observer::EpochObserver;
32pub(crate) use error::{Error, Result};
33pub use history_observer::HistoryObserver;
34use identities::Identities;
35use log::debug;
36use mls_crypto_provider::{CryptoKeystore, EntropySeed, MlsCryptoProvider};
37use openmls::prelude::{Credential, CredentialType};
38use openmls_basic_credential::SignatureKeyPair;
39use openmls_traits::{OpenMlsCryptoProvider, crypto::OpenMlsCrypto, types::SignatureScheme};
40use openmls_x509_credential::CertificateKeyPair;
41use std::collections::HashSet;
42use std::ops::Deref;
43use std::sync::Arc;
44use tls_codec::{Deserialize, Serialize};
45
46#[derive(Clone, derive_more::Debug)]
57pub struct Session {
58 pub(crate) inner: Arc<RwLock<Option<SessionInner>>>,
59 pub(crate) crypto_provider: MlsCryptoProvider,
60 pub(crate) transport: Arc<RwLock<Option<Arc<dyn MlsTransport + 'static>>>>,
61 #[debug("EpochObserver")]
62 pub(crate) epoch_observer: Arc<RwLock<Option<Arc<dyn EpochObserver + 'static>>>>,
63 #[debug("HistoryObserver")]
64 pub(crate) history_observer: Arc<RwLock<Option<Arc<dyn HistoryObserver + 'static>>>>,
65}
66
67#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
68#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
69impl HasSessionAndCrypto for Session {
70 async fn session(&self) -> mls::Result<Session> {
71 Ok(self.clone())
72 }
73
74 async fn crypto_provider(&self) -> mls::Result<MlsCryptoProvider> {
75 Ok(self.crypto_provider.clone())
76 }
77}
78
79#[derive(Clone, Debug)]
80pub(crate) struct SessionInner {
81 id: ClientId,
82 pub(crate) identities: Identities,
83 keypackage_lifetime: std::time::Duration,
84}
85
86impl Session {
87 pub async fn try_new(
101 ValidatedSessionConfig {
102 db_connection_type,
103 database_key,
104 client_id,
105 external_entropy,
106 ciphersuites,
107 nb_key_packages,
108 }: ValidatedSessionConfig<'_>,
109 ) -> crate::mls::Result<Self> {
110 let key_store = CryptoKeystore::open(db_connection_type, &database_key)
112 .await
113 .map_err(MlsError::wrap("initializing keystore"))?;
114 let mls_backend = MlsCryptoProvider::builder()
115 .key_store(key_store)
116 .entropy_seed_opt(external_entropy)
117 .build();
118
119 let session = Self {
123 crypto_provider: mls_backend.clone(),
124 inner: Default::default(),
125 transport: Arc::new(None.into()),
126 epoch_observer: Arc::new(None.into()),
127 history_observer: Arc::new(None.into()),
128 };
129
130 let cc = CoreCrypto::from(session);
131 let context = cc
132 .new_transaction()
133 .await
134 .map_err(RecursiveError::transaction("starting new transaction"))?;
135
136 if let Some(id) = client_id {
137 cc.mls
138 .init(
139 ClientIdentifier::Basic(id),
140 ciphersuites.as_slice(),
141 &mls_backend,
142 nb_key_packages,
143 )
144 .await
145 .map_err(RecursiveError::mls_client("initializing mls client"))?
146 }
147
148 context
149 .init_pki_env()
150 .await
151 .map_err(RecursiveError::transaction("initializing pki environment"))?;
152 context
153 .finish()
154 .await
155 .map_err(RecursiveError::transaction("finishing transaction"))?;
156
157 Ok(cc.mls)
158 }
159
160 pub async fn provide_transport(&self, transport: Arc<dyn MlsTransport>) {
163 self.transport.write().await.replace(transport);
164 }
165
166 pub async fn init(
178 &self,
179 identifier: ClientIdentifier,
180 ciphersuites: &[MlsCiphersuite],
181 backend: &MlsCryptoProvider,
182 nb_key_packages: usize,
183 ) -> Result<()> {
184 self.ensure_unready().await?;
185 let id = identifier.get_id()?;
186
187 let credentials = backend
188 .key_store()
189 .find_all::<MlsCredential>(EntityFindParams::default())
190 .await
191 .map_err(KeystoreError::wrap("finding all mls credentials"))?;
192
193 let credentials = credentials
194 .into_iter()
195 .filter(|mls_credential| mls_credential.id.as_slice() == id.as_slice())
196 .map(|mls_credential| -> Result<_> {
197 let credential = Credential::tls_deserialize(&mut mls_credential.credential.as_slice())
198 .map_err(Error::tls_deserialize("mls credential"))?;
199 Ok((credential, mls_credential.created_at))
200 })
201 .collect::<Result<Vec<_>>>()?;
202
203 if credentials.is_empty() {
204 debug!(count = nb_key_packages, ciphersuites:? = ciphersuites; "Generating client");
205 self.generate(identifier, backend, ciphersuites, nb_key_packages)
206 .await?;
207 } else {
208 let signature_schemes = ciphersuites
209 .iter()
210 .map(|cs| cs.signature_algorithm())
211 .collect::<HashSet<_>>();
212 let load_result = self.load(backend, id.as_ref(), credentials, signature_schemes).await;
213 if let Err(Error::ClientSignatureNotFound) = load_result {
214 debug!(count = nb_key_packages, ciphersuites:? = ciphersuites; "Client signature not found. Generating client");
215 self.generate(identifier, backend, ciphersuites, nb_key_packages)
216 .await?;
217 } else {
218 load_result?;
219 }
220 };
221
222 Ok(())
223 }
224
225 #[cfg(test)]
227 pub(crate) async fn reset(&self) {
228 let mut inner_lock = self.inner.write().await;
229 *inner_lock = None;
230 }
231
232 pub(crate) async fn is_ready(&self) -> bool {
233 let inner_lock = self.inner.read().await;
234 inner_lock.is_some()
235 }
236
237 async fn ensure_unready(&self) -> Result<()> {
238 if self.is_ready().await {
239 Err(Error::UnexpectedlyReady)
240 } else {
241 Ok(())
242 }
243 }
244
245 async fn replace_inner(&self, new_inner: SessionInner) {
246 let mut inner_lock = self.inner.write().await;
247 *inner_lock = Some(new_inner);
248 }
249
250 pub async fn get_raw_conversation(&self, id: &ConversationId) -> Result<ImmutableConversation> {
256 let raw_conversation = GroupStore::fetch_from_keystore(id, &self.crypto_provider.keystore(), None)
257 .await
258 .map_err(RecursiveError::root("getting conversation by id"))?
259 .ok_or_else(|| LeafError::ConversationNotFound(id.clone()))?;
260 Ok(ImmutableConversation::new(raw_conversation, self.clone()))
261 }
262
263 pub async fn public_key(
270 &self,
271 ciphersuite: MlsCiphersuite,
272 credential_type: MlsCredentialType,
273 ) -> crate::mls::Result<Vec<u8>> {
274 let cb = self
275 .find_most_recent_credential_bundle(ciphersuite.signature_algorithm(), credential_type)
276 .await
277 .map_err(RecursiveError::mls_client("finding most recent credential bundle"))?;
278 Ok(cb.signature_key.to_public_vec())
279 }
280
281 pub(crate) fn new_basic_credential_bundle(
282 id: &ClientId,
283 sc: SignatureScheme,
284 backend: &MlsCryptoProvider,
285 ) -> Result<CredentialBundle> {
286 let (sk, pk) = backend
287 .crypto()
288 .signature_key_gen(sc)
289 .map_err(MlsError::wrap("generating a signature key"))?;
290
291 let signature_key = SignatureKeyPair::from_raw(sc, sk, pk);
292 let credential = Credential::new_basic(id.to_vec());
293 let cb = CredentialBundle {
294 credential,
295 signature_key,
296 created_at: 0,
297 };
298
299 Ok(cb)
300 }
301
302 pub(crate) fn new_x509_credential_bundle(cert: CertificateBundle) -> Result<CredentialBundle> {
303 let created_at = cert
304 .get_created_at()
305 .map_err(RecursiveError::mls_credential("getting credetntial created at"))?;
306 let (sk, ..) = cert.private_key.into_parts();
307 let chain = cert.certificate_chain;
308
309 let kp = CertificateKeyPair::new(sk, chain.clone()).map_err(MlsError::wrap("creating certificate key pair"))?;
310
311 let credential = Credential::new_x509(chain).map_err(MlsError::wrap("creating x509 credential"))?;
312
313 let cb = CredentialBundle {
314 credential,
315 signature_key: kp.0,
316 created_at,
317 };
318 Ok(cb)
319 }
320
321 pub async fn conversation_exists(&self, id: &ConversationId) -> Result<bool> {
323 match self.get_raw_conversation(id).await {
324 Ok(_) => Ok(true),
325 Err(Error::Leaf(LeafError::ConversationNotFound(_))) => Ok(false),
326 Err(e) => Err(e),
327 }
328 }
329
330 pub fn random_bytes(&self, len: usize) -> crate::mls::Result<Vec<u8>> {
332 use openmls_traits::random::OpenMlsRand as _;
333 self.crypto_provider
334 .rand()
335 .random_vec(len)
336 .map_err(MlsError::wrap("generating random vector"))
337 .map_err(Into::into)
338 }
339
340 pub async fn close(self) -> crate::mls::Result<()> {
346 self.crypto_provider
347 .close()
348 .await
349 .map_err(MlsError::wrap("closing connection with keystore"))
350 .map_err(Into::into)
351 }
352
353 pub async fn reseed(&self, seed: Option<EntropySeed>) -> crate::mls::Result<()> {
355 self.crypto_provider
356 .reseed(seed)
357 .map_err(MlsError::wrap("reseeding mls backend"))
358 .map_err(Into::into)
359 }
360
361 pub(crate) async fn generate(
363 &self,
364 identifier: ClientIdentifier,
365 backend: &MlsCryptoProvider,
366 ciphersuites: &[MlsCiphersuite],
367 nb_key_package: usize,
368 ) -> Result<()> {
369 self.ensure_unready().await?;
370 let id = identifier.get_id()?;
371 let signature_schemes = ciphersuites
372 .iter()
373 .map(|cs| cs.signature_algorithm())
374 .collect::<HashSet<_>>();
375 self.replace_inner(SessionInner {
376 id: id.into_owned(),
377 identities: Identities::new(signature_schemes.len()),
378 keypackage_lifetime: KEYPACKAGE_DEFAULT_LIFETIME,
379 })
380 .await;
381
382 let identities = identifier.generate_credential_bundles(backend, signature_schemes)?;
383
384 for (sc, id, cb) in identities {
385 self.save_identity(&backend.keystore(), Some(&id), sc, cb).await?;
386 }
387
388 let guard = self.inner.read().await;
389 let SessionInner { identities, .. } = guard.as_ref().ok_or(Error::MlsNotInitialized)?;
390
391 if nb_key_package != 0 {
392 for ciphersuite in ciphersuites.iter().copied() {
393 let ciphersuite_signature_scheme = ciphersuite.signature_algorithm();
394 for credential_bundle in identities.iter().filter_map(|(signature_scheme, credential_bundle)| {
395 (signature_scheme == ciphersuite_signature_scheme).then_some(credential_bundle)
396 }) {
397 let credential_type = credential_bundle.credential.credential_type().into();
398 self.request_key_packages(nb_key_package, ciphersuite, credential_type, backend)
399 .await?;
400 }
401 }
402 }
403
404 Ok(())
405 }
406
407 pub(crate) async fn load(
409 &self,
410 backend: &MlsCryptoProvider,
411 id: &ClientId,
412 mut credentials: Vec<(Credential, u64)>,
413 signature_schemes: HashSet<SignatureScheme>,
414 ) -> Result<()> {
415 self.ensure_unready().await?;
416 let mut identities = Identities::new(signature_schemes.len());
417
418 credentials.sort_by_key(|(_, timestamp)| *timestamp);
420
421 let stored_signature_keypairs = backend
422 .key_store()
423 .find_all::<MlsSignatureKeyPair>(EntityFindParams::default())
424 .await
425 .map_err(KeystoreError::wrap("finding all mls signature keypairs"))?;
426
427 for signature_scheme in signature_schemes {
428 let signature_keypair = stored_signature_keypairs
429 .iter()
430 .find(|skp| skp.signature_scheme == (signature_scheme as u16));
431
432 let signature_key = if let Some(kp) = signature_keypair {
433 SignatureKeyPair::tls_deserialize(&mut kp.keypair.as_slice())
434 .map_err(Error::tls_deserialize("signature keypair"))?
435 } else {
436 let (private_key, public_key) = backend
437 .crypto()
438 .signature_key_gen(signature_scheme)
439 .map_err(MlsError::wrap("generating signature key"))?;
440 let keypair = SignatureKeyPair::from_raw(signature_scheme, private_key, public_key.clone());
441 let raw_keypair = keypair
442 .tls_serialize_detached()
443 .map_err(Error::tls_serialize("raw keypair"))?;
444 let store_keypair =
445 MlsSignatureKeyPair::new(signature_scheme, public_key, raw_keypair, id.as_slice().into());
446 backend
447 .key_store()
448 .save(store_keypair.clone())
449 .await
450 .map_err(KeystoreError::wrap("storing keypairs in keystore"))?;
451 SignatureKeyPair::tls_deserialize(&mut store_keypair.keypair.as_slice())
452 .map_err(Error::tls_deserialize("signature keypair"))?
453 };
454
455 for (credential, created_at) in &credentials {
456 match credential.mls_credential() {
457 openmls::prelude::MlsCredentialType::Basic(_) => {
458 if id.as_slice() != credential.identity() {
459 return Err(Error::WrongCredential);
460 }
461 }
462 openmls::prelude::MlsCredentialType::X509(cert) => {
463 let spk = cert
464 .extract_public_key()
465 .map_err(RecursiveError::mls_credential("extracting public key"))?
466 .ok_or(LeafError::InternalMlsError)?;
467 if signature_key.public() != spk {
468 return Err(Error::WrongCredential);
469 }
470 }
471 };
472 let cb = CredentialBundle {
473 credential: credential.clone(),
474 signature_key: signature_key.clone(),
475 created_at: *created_at,
476 };
477 identities.push_credential_bundle(signature_scheme, cb).await?;
478 }
479 }
480 self.replace_inner(SessionInner {
481 id: id.clone(),
482 identities,
483 keypackage_lifetime: KEYPACKAGE_DEFAULT_LIFETIME,
484 })
485 .await;
486 Ok(())
487 }
488
489 pub(crate) async fn restore_from_history_secret(&self, history_secret: HistorySecret) -> Result<()> {
491 self.ensure_unready().await?;
492
493 self.replace_inner(SessionInner {
495 id: history_secret.client_id.clone(),
496 identities: Identities::new(0),
497 keypackage_lifetime: KEYPACKAGE_DEFAULT_LIFETIME,
498 })
499 .await;
500
501 history_secret
503 .key_package
504 .store(&self.crypto_provider)
505 .await
506 .map_err(MlsError::wrap("storing key package encapsulation"))?;
507
508 Ok(())
509 }
510
511 pub(crate) async fn save_identity(
512 &self,
513 keystore: &Connection,
514 id: Option<&ClientId>,
515 signature_scheme: SignatureScheme,
516 mut credential_bundle: CredentialBundle,
517 ) -> Result<CredentialBundle> {
518 let mut guard = self.inner.write().await;
519 let SessionInner {
520 id: existing_id,
521 identities,
522 ..
523 } = guard.as_mut().ok_or(Error::MlsNotInitialized)?;
524
525 let id = id.unwrap_or(existing_id);
526
527 let credential = credential_bundle
528 .credential
529 .tls_serialize_detached()
530 .map_err(Error::tls_serialize("credential bundle"))?;
531 let credential = MlsCredential {
532 id: id.clone().into(),
533 credential,
534 created_at: 0,
535 };
536
537 let credential = keystore
538 .save(credential)
539 .await
540 .map_err(KeystoreError::wrap("saving credential"))?;
541
542 let sign_kp = MlsSignatureKeyPair::new(
543 signature_scheme,
544 credential_bundle.signature_key.to_public_vec(),
545 credential_bundle
546 .signature_key
547 .tls_serialize_detached()
548 .map_err(Error::tls_serialize("signature keypair"))?,
549 id.clone().into(),
550 );
551 keystore.save(sign_kp).await.map_err(|e| match e {
552 CryptoKeystoreError::AlreadyExists(_) => Error::CredentialBundleConflict,
553 _ => KeystoreError::wrap("saving mls signature key pair")(e).into(),
554 })?;
555
556 credential_bundle.created_at = credential.created_at;
558
559 identities
560 .push_credential_bundle(signature_scheme, credential_bundle.clone())
561 .await?;
562
563 Ok(credential_bundle)
564 }
565
566 pub async fn id(&self) -> Result<ClientId> {
568 match self.inner.read().await.deref() {
569 None => Err(Error::MlsNotInitialized),
570 Some(SessionInner { id, .. }) => Ok(id.clone()),
571 }
572 }
573
574 pub async fn is_e2ei_capable(&self) -> bool {
576 match self.inner.read().await.deref() {
577 None => false,
578 Some(SessionInner { identities, .. }) => identities
579 .iter()
580 .any(|(_, cred)| cred.credential().credential_type() == CredentialType::X509),
581 }
582 }
583
584 pub(crate) async fn get_most_recent_or_create_credential_bundle(
585 &self,
586 backend: &MlsCryptoProvider,
587 sc: SignatureScheme,
588 ct: MlsCredentialType,
589 ) -> Result<Arc<CredentialBundle>> {
590 match ct {
591 MlsCredentialType::Basic => {
592 self.init_basic_credential_bundle_if_missing(backend, sc).await?;
593 self.find_most_recent_credential_bundle(sc, ct).await
594 }
595 MlsCredentialType::X509 => self
596 .find_most_recent_credential_bundle(sc, ct)
597 .await
598 .map_err(|e| match e {
599 Error::CredentialNotFound(_) => LeafError::E2eiEnrollmentNotDone.into(),
600 _ => e,
601 }),
602 }
603 }
604
605 pub(crate) async fn init_basic_credential_bundle_if_missing(
606 &self,
607 backend: &MlsCryptoProvider,
608 sc: SignatureScheme,
609 ) -> Result<()> {
610 let existing_cb = self
611 .find_most_recent_credential_bundle(sc, MlsCredentialType::Basic)
612 .await;
613 if matches!(existing_cb, Err(Error::CredentialNotFound(_))) {
614 let id = self.id().await?;
615 debug!(id:% = &id; "Initializing basic credential bundle");
616 let cb = Self::new_basic_credential_bundle(&id, sc, backend)?;
617 self.save_identity(&backend.keystore(), None, sc, cb).await?;
618 }
619 Ok(())
620 }
621
622 pub(crate) async fn save_new_x509_credential_bundle(
623 &self,
624 keystore: &Connection,
625 sc: SignatureScheme,
626 cb: CertificateBundle,
627 ) -> Result<CredentialBundle> {
628 let id = cb
629 .get_client_id()
630 .map_err(RecursiveError::mls_credential("getting client id"))?;
631 let cb = Self::new_x509_credential_bundle(cb)?;
632 self.save_identity(keystore, Some(&id), sc, cb).await
633 }
634}
635
636#[cfg(test)]
637mod tests {
638 use super::*;
639 use crate::test_utils::*;
640 use crate::transaction_context::test_utils::EntitiesCount;
641 use core_crypto_keystore::connection::{ConnectionType, DatabaseKey, FetchFromDatabase};
642 use core_crypto_keystore::entities::*;
643 use mls_crypto_provider::MlsCryptoProvider;
644
645 impl Session {
646 #![allow(missing_docs)]
648
649 pub async fn random_generate(
650 &self,
651 case: &crate::test_utils::TestContext,
652 signer: Option<&crate::test_utils::x509::X509Certificate>,
653 provision: bool,
654 ) -> Result<()> {
655 self.reset().await;
656 let user_uuid = uuid::Uuid::new_v4();
657 let rnd_id = rand::random::<usize>();
658 let client_id = format!("{}:{rnd_id:x}@members.wire.com", user_uuid.hyphenated());
659 let identity = match case.credential_type {
660 MlsCredentialType::Basic => ClientIdentifier::Basic(client_id.as_str().into()),
661 MlsCredentialType::X509 => {
662 let signer = signer.expect("Missing intermediate CA");
663 CertificateBundle::rand_identifier(&client_id, &[signer])
664 }
665 };
666 let nb_key_package = if provision {
667 crate::prelude::INITIAL_KEYING_MATERIAL_COUNT
668 } else {
669 0
670 };
671 let backend = self.crypto_provider.clone();
672 self.generate(identity, &backend, &[case.ciphersuite()], nb_key_package)
673 .await?;
674 Ok(())
675 }
676
677 pub async fn find_keypackages(&self, backend: &MlsCryptoProvider) -> Result<Vec<openmls::prelude::KeyPackage>> {
678 use core_crypto_keystore::CryptoKeystoreMls as _;
679 let kps = backend
680 .key_store()
681 .mls_fetch_keypackages::<openmls::prelude::KeyPackage>(u32::MAX)
682 .await
683 .map_err(KeystoreError::wrap("fetching mls keypackages"))?;
684 Ok(kps)
685 }
686
687 pub(crate) async fn generate_one_keypackage(
688 &self,
689 backend: &MlsCryptoProvider,
690 cs: MlsCiphersuite,
691 ct: MlsCredentialType,
692 ) -> Result<openmls::prelude::KeyPackage> {
693 let cb = self
694 .find_most_recent_credential_bundle(cs.signature_algorithm(), ct)
695 .await?;
696 self.generate_one_keypackage_from_credential_bundle(backend, cs, &cb)
697 .await
698 }
699
700 pub async fn count_entities(&self) -> EntitiesCount {
702 let keystore = self.crypto_provider.keystore();
703 let credential = keystore.count::<MlsCredential>().await.unwrap();
704 let encryption_keypair = keystore.count::<MlsEncryptionKeyPair>().await.unwrap();
705 let epoch_encryption_keypair = keystore.count::<MlsEpochEncryptionKeyPair>().await.unwrap();
706 let enrollment = keystore.count::<E2eiEnrollment>().await.unwrap();
707 let group = keystore.count::<PersistedMlsGroup>().await.unwrap();
708 let hpke_private_key = keystore.count::<MlsHpkePrivateKey>().await.unwrap();
709 let key_package = keystore.count::<MlsKeyPackage>().await.unwrap();
710 let pending_group = keystore.count::<PersistedMlsPendingGroup>().await.unwrap();
711 let pending_messages = keystore.count::<MlsPendingMessage>().await.unwrap();
712 let psk_bundle = keystore.count::<MlsPskBundle>().await.unwrap();
713 let signature_keypair = keystore.count::<MlsSignatureKeyPair>().await.unwrap();
714 EntitiesCount {
715 credential,
716 encryption_keypair,
717 epoch_encryption_keypair,
718 enrollment,
719 group,
720 hpke_private_key,
721 key_package,
722 pending_group,
723 pending_messages,
724 psk_bundle,
725 signature_keypair,
726 }
727 }
728 }
729
730 #[apply(all_cred_cipher)]
731 async fn can_generate_session(case: TestContext) {
732 let [alice] = case.sessions().await;
733 let key = DatabaseKey::generate();
734 let key_store = CryptoKeystore::open(ConnectionType::InMemory, &key).await.unwrap();
735 let backend = MlsCryptoProvider::builder().key_store(key_store).build();
736 let x509_test_chain = if case.is_x509() {
737 let x509_test_chain = crate::test_utils::x509::X509TestChain::init_empty(case.signature_scheme());
738 x509_test_chain.register_with_provider(&backend).await;
739 Some(x509_test_chain)
740 } else {
741 None
742 };
743 backend.new_transaction().await.unwrap();
744 let session = alice.session().await;
745 session
746 .random_generate(
747 &case,
748 x509_test_chain.as_ref().map(|chain| chain.find_local_intermediate_ca()),
749 false,
750 )
751 .await
752 .unwrap();
753 }
754}