Skip to main content

core_crypto/mls/conversation/
welcome.rs

1use core_crypto_keystore::{Database, entities::PersistedMlsPendingGroup, traits::FetchFromDatabase};
2use openmls::prelude::{MlsGroup, MlsMessageIn, MlsMessageOut, Welcome};
3use openmls_traits::OpenMlsCryptoProvider;
4use tls_codec::{Deserialize as _, Serialize as _};
5
6use super::{Error, Result};
7use crate::{
8    ConversationId, LeafError, MlsConversation, MlsConversationConfiguration, MlsError, group_store::GroupStore,
9    mls_provider::MlsCryptoProvider,
10};
11
12/// A Welcome Message as defined in RFC 9420.
13///
14/// This type is fallibly parseable from raw bytes.
15#[derive(Debug, Clone, derive_more::From, derive_more::Into)]
16pub struct WelcomeMessage(pub(crate) MlsMessageIn);
17
18impl TryFrom<&[u8]> for WelcomeMessage {
19    type Error = Error;
20
21    fn try_from(bytes: &[u8]) -> Result<Self> {
22        MlsMessageIn::tls_deserialize_exact(bytes)
23            .map(Self)
24            .map_err(Error::tls_deserialize("deserializing welcome message as MlsMessageIn"))
25    }
26}
27
28impl TryFrom<Vec<u8>> for WelcomeMessage {
29    type Error = Error;
30
31    fn try_from(value: Vec<u8>) -> Result<Self> {
32        value.as_slice().try_into()
33    }
34}
35
36impl From<MlsMessageOut> for WelcomeMessage {
37    fn from(value: MlsMessageOut) -> Self {
38        Self(value.into())
39    }
40}
41
42impl WelcomeMessage {
43    /// Serialize this message per the TLS encoding in the spec
44    pub fn serialize(&self) -> Result<Vec<u8>> {
45        MlsMessageOut::from(self.0.clone())
46            .tls_serialize_detached()
47            .map_err(Error::tls_serialize("serializing welcome message as MlsMessageOut"))
48    }
49}
50
51impl MlsConversation {
52    // ? Do we need to provide the ratchet_tree to the MlsGroup? Does everything crumble down if we can't actually get
53    // it?
54    /// Create the MLS conversation from an MLS Welcome message
55    pub(crate) async fn from_welcome_message(
56        welcome: Welcome,
57        configuration: MlsConversationConfiguration,
58        provider: &MlsCryptoProvider,
59        database: &Database,
60        mls_groups: &mut GroupStore<MlsConversation>,
61    ) -> Result<Self> {
62        let mls_group_config = configuration.as_openmls_default_configuration()?;
63
64        let group = MlsGroup::new_from_welcome(provider, &mls_group_config, welcome, None)
65            .await
66            .map_err(|err| {
67                use openmls::prelude::WelcomeError;
68                match err {
69                    WelcomeError::NoMatchingKeyPackage | WelcomeError::NoMatchingEncryptionKey => Error::OrphanWelcome,
70                    _ => MlsError::wrap("group could not be created from welcome")(err).into(),
71                }
72            })?;
73
74        let id = ConversationId::from(group.group_id().as_slice());
75        let existing_conversation = mls_groups.get_fetch(&id, database, None).await;
76        let conversation_exists = existing_conversation.ok().flatten().is_some();
77
78        let pending_group = provider
79            .key_store()
80            .get_borrowed::<PersistedMlsPendingGroup>(id.as_ref())
81            .await;
82        let pending_group_exists = pending_group.ok().flatten().is_some();
83
84        if conversation_exists || pending_group_exists {
85            return Err(LeafError::ConversationAlreadyExists(id).into());
86        }
87
88        Self::from_mls_group(group, configuration, database).await
89    }
90}