1use serde::{Deserialize, Serialize};
2use tls_codec::{Deserialize as _, Serialize as _, *};
3
4#[cfg(feature = "extensions-draft")]
5use crate::component::ComponentId;
6#[cfg(feature = "extensions-draft")]
7use crate::messages::proposals::AppDataUpdateOperation;
8use crate::schedule::PreSharedKeyId;
9
10use super::{extensions::FrankenExtension, FrankenKeyPackage, FrankenLeafNode};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum FrankenProposalType {
14 Add,
15 Update,
16 Remove,
17 PreSharedKey,
18 Reinit,
19 ExternalInit,
20 GroupContextExtensions,
21 #[cfg(feature = "extensions-draft")]
22 AppEphemeral,
23 #[cfg(feature = "extensions-draft")]
24 AppDataUpdate,
25 Custom(u16),
26}
27
28impl From<u16> for FrankenProposalType {
29 fn from(value: u16) -> Self {
30 match value {
31 1 => FrankenProposalType::Add,
32 2 => FrankenProposalType::Update,
33 3 => FrankenProposalType::Remove,
34 4 => FrankenProposalType::PreSharedKey,
35 5 => FrankenProposalType::Reinit,
36 6 => FrankenProposalType::ExternalInit,
37 7 => FrankenProposalType::GroupContextExtensions,
38 #[cfg(feature = "extensions-draft")]
39 8 => FrankenProposalType::AppDataUpdate,
40 #[cfg(feature = "extensions-draft")]
41 0x0009 => FrankenProposalType::AppEphemeral,
42 other => FrankenProposalType::Custom(other),
43 }
44 }
45}
46
47impl From<FrankenProposalType> for u16 {
48 fn from(value: FrankenProposalType) -> Self {
49 match value {
50 FrankenProposalType::Add => 1,
51 FrankenProposalType::Update => 2,
52 FrankenProposalType::Remove => 3,
53 FrankenProposalType::PreSharedKey => 4,
54 FrankenProposalType::Reinit => 5,
55 FrankenProposalType::ExternalInit => 6,
56 FrankenProposalType::GroupContextExtensions => 7,
57 #[cfg(feature = "extensions-draft")]
58 FrankenProposalType::AppDataUpdate => 8,
59 #[cfg(feature = "extensions-draft")]
60 FrankenProposalType::AppEphemeral => 0x0009,
61 FrankenProposalType::Custom(id) => id,
62 }
63 }
64}
65
66impl FrankenProposal {
67 pub fn proposal_type(&self) -> FrankenProposalType {
68 match self {
69 FrankenProposal::Add(_) => FrankenProposalType::Add,
70 FrankenProposal::Update(_) => FrankenProposalType::Update,
71 FrankenProposal::Remove(_) => FrankenProposalType::Remove,
72 FrankenProposal::PreSharedKey(_) => FrankenProposalType::PreSharedKey,
73 FrankenProposal::ReInit(_) => FrankenProposalType::Reinit,
74 FrankenProposal::ExternalInit(_) => FrankenProposalType::ExternalInit,
75 FrankenProposal::GroupContextExtensions(_) => {
76 FrankenProposalType::GroupContextExtensions
77 }
78 #[cfg(feature = "extensions-draft")]
79 FrankenProposal::AppEphemeral(_) => FrankenProposalType::AppEphemeral,
80 #[cfg(feature = "extensions-draft")]
81 FrankenProposal::AppDataUpdate(_) => FrankenProposalType::AppDataUpdate,
82 FrankenProposal::Custom(FrankenCustomProposal {
83 proposal_type,
84 payload: _,
85 }) => FrankenProposalType::Custom(proposal_type.to_owned()),
86 }
87 }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
91#[repr(u16)]
92pub enum FrankenProposal {
93 Add(FrankenAddProposal),
94 Update(FrankenUpdateProposal),
95 Remove(FrankenRemoveProposal),
96 PreSharedKey(FrankenPreSharedKeyProposal),
97 ReInit(FrankenReInitProposal),
98 ExternalInit(FrankenExternalInitProposal),
99 GroupContextExtensions(Vec<FrankenExtension>),
100 #[cfg(feature = "extensions-draft")]
101 AppEphemeral(FrankenAppEphemeralProposal),
102 #[cfg(feature = "extensions-draft")]
103 AppDataUpdate(FrankenAppDataUpdateProposal),
104 Custom(FrankenCustomProposal),
105}
106
107#[cfg(feature = "extensions-draft")]
108#[derive(
109 Debug,
110 PartialEq,
111 Eq,
112 Clone,
113 Serialize,
114 Deserialize,
115 TlsSize,
116 TlsSerialize,
117 TlsDeserialize,
118 TlsDeserializeBytes,
119)]
120pub struct FrankenAppDataUpdateProposal {
121 pub component_id: ComponentId,
122 pub operation: AppDataUpdateOperation,
123}
124
125#[derive(
126 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
127)]
128pub struct FrankenAddProposal {
129 pub key_package: FrankenKeyPackage,
130}
131
132#[derive(
133 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
134)]
135pub struct FrankenUpdateProposal {
136 pub leaf_node: FrankenLeafNode,
137}
138
139#[derive(
140 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
141)]
142pub struct FrankenRemoveProposal {
143 pub removed: u32,
144}
145
146#[derive(
147 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
148)]
149pub struct FrankenPreSharedKeyProposal {
150 pub psk: FrankenPreSharedKeyId,
151}
152
153#[derive(
154 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
155)]
156pub struct FrankenPreSharedKeyId {
157 pub psk: FrankenPsk,
158 pub psk_nonce: VLBytes,
159}
160
161impl From<PreSharedKeyId> for FrankenPreSharedKeyId {
162 fn from(ln: PreSharedKeyId) -> Self {
163 FrankenPreSharedKeyId::tls_deserialize(&mut ln.tls_serialize_detached().unwrap().as_slice())
164 .unwrap()
165 }
166}
167
168impl From<FrankenPreSharedKeyId> for PreSharedKeyId {
169 fn from(fln: FrankenPreSharedKeyId) -> Self {
170 PreSharedKeyId::tls_deserialize(&mut fln.tls_serialize_detached().unwrap().as_slice())
171 .unwrap()
172 }
173}
174
175impl From<&FrankenPreSharedKeyId> for PreSharedKeyId {
176 fn from(fln: &FrankenPreSharedKeyId) -> Self {
177 PreSharedKeyId::tls_deserialize(&mut fln.tls_serialize_detached().unwrap().as_slice())
178 .unwrap()
179 }
180}
181
182#[derive(
183 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
184)]
185#[repr(u8)]
186pub enum FrankenPsk {
187 #[tls_codec(discriminant = 1)]
188 External(FrankenExternalPsk),
189 #[tls_codec(discriminant = 2)]
190 Resumption(FrankenResumptionPsk),
191}
192
193#[derive(
194 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
195)]
196pub struct FrankenExternalPsk {
197 pub psk_id: VLBytes,
198}
199
200#[derive(
201 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
202)]
203pub struct FrankenResumptionPsk {
204 pub usage: FrankenResumptionPskUsage,
205 pub psk_group_id: VLBytes,
206 pub psk_epoch: u64,
207}
208
209#[derive(
210 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
211)]
212#[repr(u8)]
213pub enum FrankenResumptionPskUsage {
214 Application = 1,
215 Reinit = 2,
216 Branch = 3,
217}
218
219#[derive(
220 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
221)]
222pub struct FrankenReInitProposal {
223 pub group_id: VLBytes,
224 pub version: u16,
225 pub ciphersuite: u16,
226 pub extensions: Vec<FrankenExtension>,
227}
228
229#[derive(
230 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
231)]
232pub struct FrankenExternalInitProposal {
233 pub kem_output: VLBytes,
234}
235
236#[derive(
237 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
238)]
239pub struct FrankenMessageRange {
240 pub sender: VLBytes,
241 pub first_generation: u32,
242 pub last_generation: u32,
243}
244
245#[cfg(feature = "extensions-draft")]
246#[derive(
247 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
248)]
249pub struct FrankenAppEphemeralProposal {
250 pub component_id: u16,
251 pub data: VLBytes,
252}
253
254#[derive(
255 Debug, Clone, PartialEq, Eq, TlsSerialize, TlsDeserialize, TlsDeserializeBytes, TlsSize,
256)]
257pub struct FrankenCustomProposal {
258 pub proposal_type: u16,
259 pub payload: VLBytes,
260}