openmls/messages/
codec.rs

1//! # Codec
2//!
3//! This module contains the encoding and decoding logic for Proposals.
4
5use tls_codec::{Deserialize, DeserializeBytes, Serialize, Size};
6
7use super::{
8    proposals::{
9        ExternalInitProposal, GroupContextExtensionProposal, PreSharedKeyProposal, Proposal,
10        ProposalType, ReInitProposal, RemoveProposal,
11    },
12    proposals_in::{AddProposalIn, ProposalIn, UpdateProposalIn},
13    CustomProposal,
14};
15
16#[cfg(feature = "extensions-draft-08")]
17use super::proposals::AppEphemeralProposal;
18
19impl Size for Proposal {
20    fn tls_serialized_len(&self) -> usize {
21        self.proposal_type().tls_serialized_len()
22            + match self {
23                Proposal::Add(p) => p.tls_serialized_len(),
24                Proposal::Update(p) => p.tls_serialized_len(),
25                Proposal::Remove(p) => p.tls_serialized_len(),
26                Proposal::PreSharedKey(p) => p.tls_serialized_len(),
27                Proposal::ReInit(p) => p.tls_serialized_len(),
28                Proposal::ExternalInit(p) => p.tls_serialized_len(),
29                Proposal::GroupContextExtensions(p) => p.tls_serialized_len(),
30                Proposal::SelfRemove => 0,
31                #[cfg(feature = "extensions-draft-08")]
32                Proposal::AppEphemeral(p) => p.tls_serialized_len(),
33                Proposal::Custom(p) => p.payload().tls_serialized_len(),
34            }
35    }
36}
37
38impl Serialize for Proposal {
39    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
40        let written = self.proposal_type().tls_serialize(writer)?;
41        match self {
42            Proposal::Add(p) => p.tls_serialize(writer),
43            Proposal::Update(p) => p.tls_serialize(writer),
44            Proposal::Remove(p) => p.tls_serialize(writer),
45            Proposal::PreSharedKey(p) => p.tls_serialize(writer),
46            Proposal::ReInit(p) => p.tls_serialize(writer),
47            Proposal::ExternalInit(p) => p.tls_serialize(writer),
48            Proposal::GroupContextExtensions(p) => p.tls_serialize(writer),
49            Proposal::SelfRemove => Ok(0),
50            #[cfg(feature = "extensions-draft-08")]
51            Proposal::AppEphemeral(p) => p.tls_serialize(writer),
52            Proposal::Custom(p) => p.payload().tls_serialize(writer),
53        }
54        .map(|l| written + l)
55    }
56}
57
58impl Size for &ProposalIn {
59    fn tls_serialized_len(&self) -> usize {
60        self.proposal_type().tls_serialized_len()
61            + match self {
62                ProposalIn::Add(p) => p.tls_serialized_len(),
63                ProposalIn::Update(p) => p.tls_serialized_len(),
64                ProposalIn::Remove(p) => p.tls_serialized_len(),
65                ProposalIn::PreSharedKey(p) => p.tls_serialized_len(),
66                ProposalIn::ReInit(p) => p.tls_serialized_len(),
67                ProposalIn::ExternalInit(p) => p.tls_serialized_len(),
68                ProposalIn::GroupContextExtensions(p) => p.tls_serialized_len(),
69                ProposalIn::SelfRemove => 0,
70                #[cfg(feature = "extensions-draft-08")]
71                ProposalIn::AppEphemeral(p) => p.tls_serialized_len(),
72                ProposalIn::Custom(p) => p.payload().tls_serialized_len(),
73            }
74    }
75}
76
77impl Size for ProposalIn {
78    fn tls_serialized_len(&self) -> usize {
79        (&self).tls_serialized_len()
80    }
81}
82
83impl Serialize for &ProposalIn {
84    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
85        let written = self.proposal_type().tls_serialize(writer)?;
86        match self {
87            ProposalIn::Add(p) => p.tls_serialize(writer),
88            ProposalIn::Update(p) => p.tls_serialize(writer),
89            ProposalIn::Remove(p) => p.tls_serialize(writer),
90            ProposalIn::PreSharedKey(p) => p.tls_serialize(writer),
91            ProposalIn::ReInit(p) => p.tls_serialize(writer),
92            ProposalIn::ExternalInit(p) => p.tls_serialize(writer),
93            ProposalIn::GroupContextExtensions(p) => p.tls_serialize(writer),
94            ProposalIn::SelfRemove => Ok(0),
95            #[cfg(feature = "extensions-draft-08")]
96            ProposalIn::AppEphemeral(p) => p.tls_serialize(writer),
97            ProposalIn::Custom(p) => p.payload().tls_serialize(writer),
98        }
99        .map(|l| written + l)
100    }
101}
102
103impl Serialize for ProposalIn {
104    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
105        (&self).tls_serialize(writer)
106    }
107}
108
109impl Deserialize for ProposalIn {
110    fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error>
111    where
112        Self: Sized,
113    {
114        let proposal_type = ProposalType::tls_deserialize(bytes)?;
115        let proposal = match proposal_type {
116            ProposalType::Add => ProposalIn::Add(Box::new(AddProposalIn::tls_deserialize(bytes)?)),
117            ProposalType::Update => {
118                ProposalIn::Update(Box::new(UpdateProposalIn::tls_deserialize(bytes)?))
119            }
120            ProposalType::Remove => {
121                ProposalIn::Remove(Box::new(RemoveProposal::tls_deserialize(bytes)?))
122            }
123            ProposalType::PreSharedKey => {
124                ProposalIn::PreSharedKey(Box::new(PreSharedKeyProposal::tls_deserialize(bytes)?))
125            }
126            ProposalType::Reinit => {
127                ProposalIn::ReInit(Box::new(ReInitProposal::tls_deserialize(bytes)?))
128            }
129            ProposalType::ExternalInit => {
130                ProposalIn::ExternalInit(Box::new(ExternalInitProposal::tls_deserialize(bytes)?))
131            }
132            ProposalType::GroupContextExtensions => ProposalIn::GroupContextExtensions(Box::new(
133                GroupContextExtensionProposal::tls_deserialize(bytes)?,
134            )),
135            ProposalType::SelfRemove => ProposalIn::SelfRemove,
136            #[cfg(feature = "extensions-draft-08")]
137            ProposalType::AppEphemeral => {
138                ProposalIn::AppEphemeral(Box::new(AppEphemeralProposal::tls_deserialize(bytes)?))
139            }
140            ProposalType::Custom(_) => {
141                let payload = Vec::<u8>::tls_deserialize(bytes)?;
142                let custom_proposal = CustomProposal::new(proposal_type.into(), payload);
143                ProposalIn::Custom(Box::new(custom_proposal))
144            }
145        };
146        Ok(proposal)
147    }
148}
149
150impl DeserializeBytes for ProposalIn {
151    fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), tls_codec::Error>
152    where
153        Self: Sized,
154    {
155        let mut bytes_ref = bytes;
156        let proposal = ProposalIn::tls_deserialize(&mut bytes_ref)?;
157        let remainder = &bytes[proposal.tls_serialized_len()..];
158        Ok((proposal, remainder))
159    }
160}