openmls/group/mls_group/
exporting.rs1use errors::{ExportGroupInfoError, ExportSecretError};
2use openmls_traits::signatures::Signer;
3
4use crate::{
5 ciphersuite::HpkePublicKey,
6 schedule::{EpochAuthenticator, ResumptionPskSecret},
7 storage::OpenMlsProvider,
8};
9
10use super::*;
11
12impl MlsGroup {
13 pub fn export_secret<Provider: OpenMlsProvider>(
21 &self,
22 provider: &Provider,
23 label: &str,
24 context: &[u8],
25 key_length: usize,
26 ) -> Result<Vec<u8>, ExportSecretError> {
27 let crypto = provider.crypto();
28
29 if key_length > u16::MAX as usize {
30 log::error!("Got a key that is larger than u16::MAX");
31 return Err(ExportSecretError::KeyLengthTooLong);
32 }
33
34 if self.is_active() {
35 Ok(self
36 .group_epoch_secrets
37 .exporter_secret()
38 .derive_exported_secret(self.ciphersuite(), crypto, label, context, key_length)
39 .map_err(LibraryError::unexpected_crypto_error)?)
40 } else {
41 Err(ExportSecretError::GroupStateError(
42 MlsGroupStateError::UseAfterEviction,
43 ))
44 }
45 }
46
47 pub fn epoch_authenticator(&self) -> &EpochAuthenticator {
49 self.group_epoch_secrets().epoch_authenticator()
50 }
51
52 pub fn resumption_psk_secret(&self) -> &ResumptionPskSecret {
54 self.group_epoch_secrets().resumption_psk()
55 }
56
57 pub fn get_past_resumption_psk(&self, epoch: GroupEpoch) -> Option<&ResumptionPskSecret> {
60 self.resumption_psk_store.get(epoch)
61 }
62
63 pub fn export_group_info<Provider: OpenMlsProvider>(
65 &self,
66 provider: &Provider,
67 signer: &impl Signer,
68 with_ratchet_tree: bool,
69 ) -> Result<MlsMessageOut, ExportGroupInfoError> {
70 let extensions = {
71 let ratchet_tree_extension = || {
72 Extension::RatchetTree(RatchetTreeExtension::new(
73 self.public_group().export_ratchet_tree(),
74 ))
75 };
76
77 let external_pub_extension = || -> Result<Extension, ExportGroupInfoError> {
78 let external_pub = self
79 .group_epoch_secrets()
80 .external_secret()
81 .derive_external_keypair(provider.crypto(), self.ciphersuite())
82 .map_err(LibraryError::unexpected_crypto_error)?
83 .public;
84 Ok(Extension::ExternalPub(ExternalPubExtension::new(
85 HpkePublicKey::from(external_pub),
86 )))
87 };
88
89 if with_ratchet_tree {
90 Extensions::from_vec(vec![ratchet_tree_extension(), external_pub_extension()?])
91 .map_err(|_| {
92 LibraryError::custom(
93 "There should not have been duplicate extensions here.",
94 )
95 })?
96 } else {
97 Extensions::single(external_pub_extension()?)
98 }
99 };
100
101 let group_info_tbs = GroupInfoTBS::new(
103 self.context().clone(),
104 extensions,
105 self.message_secrets()
106 .confirmation_key()
107 .tag(
108 provider.crypto(),
109 self.ciphersuite(),
110 self.context().confirmed_transcript_hash(),
111 )
112 .map_err(LibraryError::unexpected_crypto_error)?,
113 self.own_leaf_index(),
114 );
115
116 let group_info = group_info_tbs
118 .sign(signer)
119 .map_err(|_| LibraryError::custom("Signing failed"))?;
120 Ok(group_info.into())
121 }
122}