Skip to main content

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