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 can_close(&self) -> bool {
344 self.crypto_provider.can_close().await
345 }
346
347 pub async fn close(self) -> crate::mls::Result<()> {
352 self.crypto_provider
353 .close()
354 .await
355 .map_err(MlsError::wrap("closing connection with keystore"))
356 .map_err(Into::into)
357 }
358
359 pub async fn reseed(&self, seed: Option<EntropySeed>) -> crate::mls::Result<()> {
361 self.crypto_provider
362 .reseed(seed)
363 .map_err(MlsError::wrap("reseeding mls backend"))
364 .map_err(Into::into)
365 }
366
367 pub(crate) async fn generate(
369 &self,
370 identifier: ClientIdentifier,
371 backend: &MlsCryptoProvider,
372 ciphersuites: &[MlsCiphersuite],
373 nb_key_package: usize,
374 ) -> Result<()> {
375 self.ensure_unready().await?;
376 let id = identifier.get_id()?;
377 let signature_schemes = ciphersuites
378 .iter()
379 .map(|cs| cs.signature_algorithm())
380 .collect::<HashSet<_>>();
381 self.replace_inner(SessionInner {
382 id: id.into_owned(),
383 identities: Identities::new(signature_schemes.len()),
384 keypackage_lifetime: KEYPACKAGE_DEFAULT_LIFETIME,
385 })
386 .await;
387
388 let identities = identifier.generate_credential_bundles(backend, signature_schemes)?;
389
390 for (sc, id, cb) in identities {
391 self.save_identity(&backend.keystore(), Some(&id), sc, cb).await?;
392 }
393
394 let guard = self.inner.read().await;
395 let SessionInner { identities, .. } = guard.as_ref().ok_or(Error::MlsNotInitialized)?;
396
397 if nb_key_package != 0 {
398 for ciphersuite in ciphersuites.iter().copied() {
399 let ciphersuite_signature_scheme = ciphersuite.signature_algorithm();
400 for credential_bundle in identities.iter().filter_map(|(signature_scheme, credential_bundle)| {
401 (signature_scheme == ciphersuite_signature_scheme).then_some(credential_bundle)
402 }) {
403 let credential_type = credential_bundle.credential.credential_type().into();
404 self.request_key_packages(nb_key_package, ciphersuite, credential_type, backend)
405 .await?;
406 }
407 }
408 }
409
410 Ok(())
411 }
412
413 pub(crate) async fn load(
415 &self,
416 backend: &MlsCryptoProvider,
417 id: &ClientId,
418 mut credentials: Vec<(Credential, u64)>,
419 signature_schemes: HashSet<SignatureScheme>,
420 ) -> Result<()> {
421 self.ensure_unready().await?;
422 let mut identities = Identities::new(signature_schemes.len());
423
424 credentials.sort_by_key(|(_, timestamp)| *timestamp);
426
427 let stored_signature_keypairs = backend
428 .key_store()
429 .find_all::<MlsSignatureKeyPair>(EntityFindParams::default())
430 .await
431 .map_err(KeystoreError::wrap("finding all mls signature keypairs"))?;
432
433 for signature_scheme in signature_schemes {
434 let signature_keypair = stored_signature_keypairs
435 .iter()
436 .find(|skp| skp.signature_scheme == (signature_scheme as u16));
437
438 let signature_key = if let Some(kp) = signature_keypair {
439 SignatureKeyPair::tls_deserialize(&mut kp.keypair.as_slice())
440 .map_err(Error::tls_deserialize("signature keypair"))?
441 } else {
442 let (private_key, public_key) = backend
443 .crypto()
444 .signature_key_gen(signature_scheme)
445 .map_err(MlsError::wrap("generating signature key"))?;
446 let keypair = SignatureKeyPair::from_raw(signature_scheme, private_key, public_key.clone());
447 let raw_keypair = keypair
448 .tls_serialize_detached()
449 .map_err(Error::tls_serialize("raw keypair"))?;
450 let store_keypair =
451 MlsSignatureKeyPair::new(signature_scheme, public_key, raw_keypair, id.as_slice().into());
452 backend
453 .key_store()
454 .save(store_keypair.clone())
455 .await
456 .map_err(KeystoreError::wrap("storing keypairs in keystore"))?;
457 SignatureKeyPair::tls_deserialize(&mut store_keypair.keypair.as_slice())
458 .map_err(Error::tls_deserialize("signature keypair"))?
459 };
460
461 for (credential, created_at) in &credentials {
462 match credential.mls_credential() {
463 openmls::prelude::MlsCredentialType::Basic(_) => {
464 if id.as_slice() != credential.identity() {
465 return Err(Error::WrongCredential);
466 }
467 }
468 openmls::prelude::MlsCredentialType::X509(cert) => {
469 let spk = cert
470 .extract_public_key()
471 .map_err(RecursiveError::mls_credential("extracting public key"))?
472 .ok_or(LeafError::InternalMlsError)?;
473 if signature_key.public() != spk {
474 return Err(Error::WrongCredential);
475 }
476 }
477 };
478 let cb = CredentialBundle {
479 credential: credential.clone(),
480 signature_key: signature_key.clone(),
481 created_at: *created_at,
482 };
483 identities.push_credential_bundle(signature_scheme, cb).await?;
484 }
485 }
486 self.replace_inner(SessionInner {
487 id: id.clone(),
488 identities,
489 keypackage_lifetime: KEYPACKAGE_DEFAULT_LIFETIME,
490 })
491 .await;
492 Ok(())
493 }
494
495 pub(crate) async fn restore_from_history_secret(&self, history_secret: HistorySecret) -> Result<()> {
497 self.ensure_unready().await?;
498
499 self.replace_inner(SessionInner {
501 id: history_secret.client_id.clone(),
502 identities: Identities::new(0),
503 keypackage_lifetime: KEYPACKAGE_DEFAULT_LIFETIME,
504 })
505 .await;
506
507 history_secret
509 .key_package
510 .store(&self.crypto_provider)
511 .await
512 .map_err(MlsError::wrap("storing key package encapsulation"))?;
513
514 Ok(())
515 }
516
517 pub(crate) async fn save_identity(
518 &self,
519 keystore: &Connection,
520 id: Option<&ClientId>,
521 signature_scheme: SignatureScheme,
522 mut credential_bundle: CredentialBundle,
523 ) -> Result<CredentialBundle> {
524 let mut guard = self.inner.write().await;
525 let SessionInner {
526 id: existing_id,
527 identities,
528 ..
529 } = guard.as_mut().ok_or(Error::MlsNotInitialized)?;
530
531 let id = id.unwrap_or(existing_id);
532
533 let credential = credential_bundle
534 .credential
535 .tls_serialize_detached()
536 .map_err(Error::tls_serialize("credential bundle"))?;
537 let credential = MlsCredential {
538 id: id.clone().into(),
539 credential,
540 created_at: 0,
541 };
542
543 let credential = keystore
544 .save(credential)
545 .await
546 .map_err(KeystoreError::wrap("saving credential"))?;
547
548 let sign_kp = MlsSignatureKeyPair::new(
549 signature_scheme,
550 credential_bundle.signature_key.to_public_vec(),
551 credential_bundle
552 .signature_key
553 .tls_serialize_detached()
554 .map_err(Error::tls_serialize("signature keypair"))?,
555 id.clone().into(),
556 );
557 keystore.save(sign_kp).await.map_err(|e| match e {
558 CryptoKeystoreError::AlreadyExists => Error::CredentialBundleConflict,
559 _ => KeystoreError::wrap("saving mls signature key pair")(e).into(),
560 })?;
561
562 credential_bundle.created_at = credential.created_at;
564
565 identities
566 .push_credential_bundle(signature_scheme, credential_bundle.clone())
567 .await?;
568
569 Ok(credential_bundle)
570 }
571
572 pub async fn id(&self) -> Result<ClientId> {
574 match self.inner.read().await.deref() {
575 None => Err(Error::MlsNotInitialized),
576 Some(SessionInner { id, .. }) => Ok(id.clone()),
577 }
578 }
579
580 pub async fn is_e2ei_capable(&self) -> bool {
582 match self.inner.read().await.deref() {
583 None => false,
584 Some(SessionInner { identities, .. }) => identities
585 .iter()
586 .any(|(_, cred)| cred.credential().credential_type() == CredentialType::X509),
587 }
588 }
589
590 pub(crate) async fn get_most_recent_or_create_credential_bundle(
591 &self,
592 backend: &MlsCryptoProvider,
593 sc: SignatureScheme,
594 ct: MlsCredentialType,
595 ) -> Result<Arc<CredentialBundle>> {
596 match ct {
597 MlsCredentialType::Basic => {
598 self.init_basic_credential_bundle_if_missing(backend, sc).await?;
599 self.find_most_recent_credential_bundle(sc, ct).await
600 }
601 MlsCredentialType::X509 => self
602 .find_most_recent_credential_bundle(sc, ct)
603 .await
604 .map_err(|e| match e {
605 Error::CredentialNotFound(_) => LeafError::E2eiEnrollmentNotDone.into(),
606 _ => e,
607 }),
608 }
609 }
610
611 pub(crate) async fn init_basic_credential_bundle_if_missing(
612 &self,
613 backend: &MlsCryptoProvider,
614 sc: SignatureScheme,
615 ) -> Result<()> {
616 let existing_cb = self
617 .find_most_recent_credential_bundle(sc, MlsCredentialType::Basic)
618 .await;
619 if matches!(existing_cb, Err(Error::CredentialNotFound(_))) {
620 let id = self.id().await?;
621 debug!(id:% = &id; "Initializing basic credential bundle");
622 let cb = Self::new_basic_credential_bundle(&id, sc, backend)?;
623 self.save_identity(&backend.keystore(), None, sc, cb).await?;
624 }
625 Ok(())
626 }
627
628 pub(crate) async fn save_new_x509_credential_bundle(
629 &self,
630 keystore: &Connection,
631 sc: SignatureScheme,
632 cb: CertificateBundle,
633 ) -> Result<CredentialBundle> {
634 let id = cb
635 .get_client_id()
636 .map_err(RecursiveError::mls_credential("getting client id"))?;
637 let cb = Self::new_x509_credential_bundle(cb)?;
638 self.save_identity(keystore, Some(&id), sc, cb).await
639 }
640}
641
642#[cfg(test)]
643mod tests {
644 use super::*;
645 use crate::test_utils::*;
646 use crate::transaction_context::test_utils::EntitiesCount;
647 use core_crypto_keystore::connection::{ConnectionType, DatabaseKey, FetchFromDatabase};
648 use core_crypto_keystore::entities::*;
649 use mls_crypto_provider::MlsCryptoProvider;
650
651 impl Session {
652 #![allow(missing_docs)]
654
655 pub async fn random_generate(
656 &self,
657 case: &crate::test_utils::TestContext,
658 signer: Option<&crate::test_utils::x509::X509Certificate>,
659 provision: bool,
660 ) -> Result<()> {
661 self.reset().await;
662 let user_uuid = uuid::Uuid::new_v4();
663 let rnd_id = rand::random::<usize>();
664 let client_id = format!("{}:{rnd_id:x}@members.wire.com", user_uuid.hyphenated());
665 let identity = match case.credential_type {
666 MlsCredentialType::Basic => ClientIdentifier::Basic(client_id.as_str().into()),
667 MlsCredentialType::X509 => {
668 let signer = signer.expect("Missing intermediate CA");
669 CertificateBundle::rand_identifier(&client_id, &[signer])
670 }
671 };
672 let nb_key_package = if provision {
673 crate::prelude::INITIAL_KEYING_MATERIAL_COUNT
674 } else {
675 0
676 };
677 let backend = self.crypto_provider.clone();
678 self.generate(identity, &backend, &[case.ciphersuite()], nb_key_package)
679 .await?;
680 Ok(())
681 }
682
683 pub async fn find_keypackages(&self, backend: &MlsCryptoProvider) -> Result<Vec<openmls::prelude::KeyPackage>> {
684 use core_crypto_keystore::CryptoKeystoreMls as _;
685 let kps = backend
686 .key_store()
687 .mls_fetch_keypackages::<openmls::prelude::KeyPackage>(u32::MAX)
688 .await
689 .map_err(KeystoreError::wrap("fetching mls keypackages"))?;
690 Ok(kps)
691 }
692
693 pub(crate) async fn generate_one_keypackage(
694 &self,
695 backend: &MlsCryptoProvider,
696 cs: MlsCiphersuite,
697 ct: MlsCredentialType,
698 ) -> Result<openmls::prelude::KeyPackage> {
699 let cb = self
700 .find_most_recent_credential_bundle(cs.signature_algorithm(), ct)
701 .await?;
702 self.generate_one_keypackage_from_credential_bundle(backend, cs, &cb)
703 .await
704 }
705
706 pub async fn count_entities(&self) -> EntitiesCount {
708 let keystore = self.crypto_provider.keystore();
709 let credential = keystore.count::<MlsCredential>().await.unwrap();
710 let encryption_keypair = keystore.count::<MlsEncryptionKeyPair>().await.unwrap();
711 let epoch_encryption_keypair = keystore.count::<MlsEpochEncryptionKeyPair>().await.unwrap();
712 let enrollment = keystore.count::<E2eiEnrollment>().await.unwrap();
713 let group = keystore.count::<PersistedMlsGroup>().await.unwrap();
714 let hpke_private_key = keystore.count::<MlsHpkePrivateKey>().await.unwrap();
715 let key_package = keystore.count::<MlsKeyPackage>().await.unwrap();
716 let pending_group = keystore.count::<PersistedMlsPendingGroup>().await.unwrap();
717 let pending_messages = keystore.count::<MlsPendingMessage>().await.unwrap();
718 let psk_bundle = keystore.count::<MlsPskBundle>().await.unwrap();
719 let signature_keypair = keystore.count::<MlsSignatureKeyPair>().await.unwrap();
720 EntitiesCount {
721 credential,
722 encryption_keypair,
723 epoch_encryption_keypair,
724 enrollment,
725 group,
726 hpke_private_key,
727 key_package,
728 pending_group,
729 pending_messages,
730 psk_bundle,
731 signature_keypair,
732 }
733 }
734 }
735
736 #[apply(all_cred_cipher)]
737 async fn can_generate_session(case: TestContext) {
738 let [alice] = case.sessions().await;
739 let key = DatabaseKey::generate();
740 let key_store = CryptoKeystore::open(ConnectionType::InMemory, &key).await.unwrap();
741 let backend = MlsCryptoProvider::builder().key_store(key_store).build();
742 let x509_test_chain = if case.is_x509() {
743 let x509_test_chain = crate::test_utils::x509::X509TestChain::init_empty(case.signature_scheme());
744 x509_test_chain.register_with_provider(&backend).await;
745 Some(x509_test_chain)
746 } else {
747 None
748 };
749 backend.new_transaction().await.unwrap();
750 let session = alice.session().await;
751 session
752 .random_generate(
753 &case,
754 x509_test_chain.as_ref().map(|chain| chain.find_local_intermediate_ca()),
755 false,
756 )
757 .await
758 .unwrap();
759 }
760}