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