1use alloc::vec::Vec;
11use core::convert::TryInto;
12
13use crate::{
14 AttemptId, CloseCode, EndpointIdentity, EndpointSigner, EnvelopeId, Error, FederationId,
15 WebRtcBinding, FCP_WIRE_MARKER, FCP_WIRE_VERSION, MAX_CANDIDATE_BYTES, MAX_CFR_CONTROL_BYTES,
16 MAX_DESCRIPTION_BYTES, MAX_ENVELOPE_BYTES, ML_DSA_65_SIGNATURE_BYTES,
17};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21#[repr(u8)]
22pub enum Kind {
23 Offer = 1,
25 Answer = 2,
27 Candidate = 3,
29 Close = 4,
31 CfrControl = 5,
33}
34
35impl TryFrom<u8> for Kind {
36 type Error = Error;
37
38 fn try_from(value: u8) -> Result<Self, Self::Error> {
39 match value {
40 1 => Ok(Self::Offer),
41 2 => Ok(Self::Answer),
42 3 => Ok(Self::Candidate),
43 4 => Ok(Self::Close),
44 5 => Ok(Self::CfrControl),
45 _ => Err(Error::UnknownKind),
46 }
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
52pub enum Body {
53 Offer {
55 binding: WebRtcBinding,
57 description: Vec<u8>,
59 },
60 Answer {
62 offer_id: EnvelopeId,
64 binding: WebRtcBinding,
66 description: Vec<u8>,
68 },
69 Candidate {
71 parent_id: EnvelopeId,
73 sequence: u32,
75 candidate: Vec<u8>,
77 },
78 Close {
80 reason: CloseCode,
82 },
83 CfrControl {
85 payload: Vec<u8>,
87 },
88}
89
90impl Body {
91 pub(crate) fn kind(&self) -> Kind {
92 match self {
93 Self::Offer { .. } => Kind::Offer,
94 Self::Answer { .. } => Kind::Answer,
95 Self::Candidate { .. } => Kind::Candidate,
96 Self::Close { .. } => Kind::Close,
97 Self::CfrControl { .. } => Kind::CfrControl,
98 }
99 }
100
101 fn validate(&self) -> Result<(), Error> {
102 match self {
103 Self::Offer { description, .. } | Self::Answer { description, .. } => {
104 validate_len(description.len(), MAX_DESCRIPTION_BYTES)
105 }
106 Self::Candidate { candidate, .. } => validate_len(candidate.len(), MAX_CANDIDATE_BYTES),
107 Self::Close { .. } => Ok(()),
108 Self::CfrControl { payload } => validate_len(payload.len(), MAX_CFR_CONTROL_BYTES),
109 }
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct Envelope {
120 pub federation: FederationId,
122 pub attempt: AttemptId,
124 pub sender: EndpointIdentity,
126 pub recipient: EndpointIdentity,
128 pub body: Body,
130 classical_signature: [u8; 64],
131 post_quantum_signature: [u8; ML_DSA_65_SIGNATURE_BYTES],
132}
133
134impl Envelope {
135 pub fn sign<S: EndpointSigner>(
137 signer: &S,
138 federation: FederationId,
139 attempt: AttemptId,
140 recipient: EndpointIdentity,
141 body: Body,
142 ) -> Result<Self, Error> {
143 body.validate()?;
144 let mut envelope = Self {
145 federation,
146 attempt,
147 sender: signer.endpoint(),
148 recipient,
149 body,
150 classical_signature: [0; 64],
151 post_quantum_signature: [0; ML_DSA_65_SIGNATURE_BYTES],
152 };
153 let transcript = envelope.signed_bytes()?;
154 envelope.classical_signature = signer.sign_classical(&transcript);
155 envelope.post_quantum_signature = signer.sign_post_quantum(&transcript);
156 Ok(envelope)
157 }
158
159 pub fn decode(wire: &[u8]) -> Result<Self, Error> {
161 if wire.len() > MAX_ENVELOPE_BYTES {
162 return Err(Error::TooLarge);
163 }
164 let mut reader = Reader::new(wire);
165 if reader.fixed::<3>()? != FCP_WIRE_MARKER {
166 return Err(Error::BadMarker);
167 }
168 if reader.u8()? != FCP_WIRE_VERSION {
169 return Err(Error::UnsupportedVersion);
170 }
171 let kind = Kind::try_from(reader.u8()?)?;
172 let federation = FederationId::from_bytes(reader.fixed()?);
173 let attempt = AttemptId::from_bytes(reader.fixed()?);
174 let sender = read_identity(&mut reader)?;
175 let recipient = read_identity(&mut reader)?;
176 let body = match kind {
177 Kind::Offer => Body::Offer {
178 binding: WebRtcBinding::from_bytes(reader.fixed()?),
179 description: reader.bytes(MAX_DESCRIPTION_BYTES)?,
180 },
181 Kind::Answer => Body::Answer {
182 offer_id: EnvelopeId::from_bytes(reader.fixed()?),
183 binding: WebRtcBinding::from_bytes(reader.fixed()?),
184 description: reader.bytes(MAX_DESCRIPTION_BYTES)?,
185 },
186 Kind::Candidate => Body::Candidate {
187 parent_id: EnvelopeId::from_bytes(reader.fixed()?),
188 sequence: reader.u32()?,
189 candidate: reader.bytes(MAX_CANDIDATE_BYTES)?,
190 },
191 Kind::Close => Body::Close {
192 reason: CloseCode::from_u16(reader.u16()?),
193 },
194 Kind::CfrControl => Body::CfrControl {
195 payload: reader.bytes(MAX_CFR_CONTROL_BYTES)?,
196 },
197 };
198 body.validate()?;
199 let classical_signature = reader.fixed()?;
200 let post_quantum_signature = reader.fixed()?;
201 reader.finish()?;
202 let result = Self {
203 federation,
204 attempt,
205 sender,
206 recipient,
207 body,
208 classical_signature,
209 post_quantum_signature,
210 };
211 if result.encode()? != wire {
212 return Err(Error::NonCanonical);
213 }
214 Ok(result)
215 }
216
217 pub fn decode_verified(wire: &[u8]) -> Result<Self, Error> {
219 verify_wire(wire)?;
220 Self::decode(wire)
221 }
222
223 pub fn verify(&self) -> Result<(), Error> {
225 let transcript = self.signed_bytes()?;
226 self.sender
227 .verify_classical(&transcript, &self.classical_signature)?;
228 self.sender
229 .verify_post_quantum(&transcript, &self.post_quantum_signature)
230 }
231
232 #[must_use]
234 pub fn kind(&self) -> Kind {
235 self.body.kind()
236 }
237
238 pub fn id(&self) -> Result<EnvelopeId, Error> {
240 Ok(EnvelopeId::from_bytes(
241 *blake3::hash(&self.encode()?).as_bytes(),
242 ))
243 }
244
245 pub fn encode(&self) -> Result<Vec<u8>, Error> {
247 let mut bytes = self.signed_bytes()?;
248 bytes.extend_from_slice(&self.classical_signature);
249 bytes.extend_from_slice(&self.post_quantum_signature);
250 if bytes.len() > MAX_ENVELOPE_BYTES {
251 return Err(Error::TooLarge);
252 }
253 Ok(bytes)
254 }
255
256 fn signed_bytes(&self) -> Result<Vec<u8>, Error> {
257 self.body.validate()?;
258 let mut writer = Writer::default();
259 writer.fixed(&FCP_WIRE_MARKER);
260 writer.u8(FCP_WIRE_VERSION);
261 writer.u8(self.kind() as u8);
262 writer.fixed(self.federation.as_bytes());
263 writer.fixed(self.attempt.as_bytes());
264 write_identity(&mut writer, &self.sender);
265 write_identity(&mut writer, &self.recipient);
266 match &self.body {
267 Body::Offer {
268 binding,
269 description,
270 } => {
271 writer.fixed(binding.as_bytes());
272 writer.bytes(description)?;
273 }
274 Body::Answer {
275 offer_id,
276 binding,
277 description,
278 } => {
279 writer.fixed(offer_id.as_bytes());
280 writer.fixed(binding.as_bytes());
281 writer.bytes(description)?;
282 }
283 Body::Candidate {
284 parent_id,
285 sequence,
286 candidate,
287 } => {
288 writer.fixed(parent_id.as_bytes());
289 writer.u32(*sequence);
290 writer.bytes(candidate)?;
291 }
292 Body::Close { reason } => writer.u16(reason.as_u16()),
293 Body::CfrControl { payload } => writer.bytes(payload)?,
294 }
295 Ok(writer.finish())
296 }
297}
298
299fn verify_wire(wire: &[u8]) -> Result<(), Error> {
300 if wire.len() > MAX_ENVELOPE_BYTES {
301 return Err(Error::TooLarge);
302 }
303 let mut reader = Reader::new(wire);
304 if reader.fixed::<3>()? != FCP_WIRE_MARKER {
305 return Err(Error::BadMarker);
306 }
307 if reader.u8()? != FCP_WIRE_VERSION {
308 return Err(Error::UnsupportedVersion);
309 }
310 let kind = Kind::try_from(reader.u8()?)?;
311 let _federation = reader.fixed::<32>()?;
312 let _attempt = reader.fixed::<16>()?;
313 let sender = read_identity(&mut reader)?;
314 let _recipient = read_identity(&mut reader)?;
315 match kind {
316 Kind::Offer => {
317 let _binding = reader.fixed::<32>()?;
318 let _description = reader.bytes_ref(MAX_DESCRIPTION_BYTES)?;
319 }
320 Kind::Answer => {
321 let _offer = reader.fixed::<32>()?;
322 let _binding = reader.fixed::<32>()?;
323 let _description = reader.bytes_ref(MAX_DESCRIPTION_BYTES)?;
324 }
325 Kind::Candidate => {
326 let _parent = reader.fixed::<32>()?;
327 let _sequence = reader.u32()?;
328 let _candidate = reader.bytes_ref(MAX_CANDIDATE_BYTES)?;
329 }
330 Kind::Close => {
331 let _reason = reader.u16()?;
332 }
333 Kind::CfrControl => {
334 let _payload = reader.bytes_ref(MAX_CFR_CONTROL_BYTES)?;
335 }
336 }
337 let signed_end = reader.offset;
338 let classical_signature = reader.fixed()?;
339 let post_quantum_signature = reader.fixed()?;
340 reader.finish()?;
341 sender.verify_classical(&wire[..signed_end], &classical_signature)?;
342 sender.verify_post_quantum(&wire[..signed_end], &post_quantum_signature)
343}
344
345fn write_identity(writer: &mut Writer, identity: &EndpointIdentity) {
346 writer.fixed(identity.classical.as_bytes());
347 writer.fixed(&identity.post_quantum);
348}
349
350fn read_identity(reader: &mut Reader<'_>) -> Result<EndpointIdentity, Error> {
351 Ok(EndpointIdentity::new(
352 crate::EndpointKey::from_bytes(reader.fixed()?),
353 reader.fixed()?,
354 ))
355}
356
357fn validate_len(length: usize, maximum: usize) -> Result<(), Error> {
358 if length > maximum || length > u32::MAX as usize {
359 return Err(Error::FieldTooLarge);
360 }
361 Ok(())
362}
363
364#[derive(Default)]
365struct Writer(Vec<u8>);
366
367impl Writer {
368 fn fixed(&mut self, value: &[u8]) {
369 self.0.extend_from_slice(value);
370 }
371
372 fn u8(&mut self, value: u8) {
373 self.0.push(value);
374 }
375
376 fn u16(&mut self, value: u16) {
377 self.fixed(&value.to_be_bytes());
378 }
379
380 fn u32(&mut self, value: u32) {
381 self.fixed(&value.to_be_bytes());
382 }
383
384 fn bytes(&mut self, value: &[u8]) -> Result<(), Error> {
385 validate_len(value.len(), MAX_CFR_CONTROL_BYTES)?;
386 let length = u32::try_from(value.len()).map_err(|_| Error::FieldTooLarge)?;
387 self.u32(length);
388 self.fixed(value);
389 Ok(())
390 }
391
392 fn finish(self) -> Vec<u8> {
393 self.0
394 }
395}
396
397struct Reader<'a> {
398 wire: &'a [u8],
399 offset: usize,
400}
401
402impl<'a> Reader<'a> {
403 const fn new(wire: &'a [u8]) -> Self {
404 Self { wire, offset: 0 }
405 }
406
407 fn fixed<const N: usize>(&mut self) -> Result<[u8; N], Error> {
408 let end = self.offset.checked_add(N).ok_or(Error::Truncated)?;
409 let bytes = self.wire.get(self.offset..end).ok_or(Error::Truncated)?;
410 self.offset = end;
411 bytes.try_into().map_err(|_| Error::Truncated)
412 }
413
414 fn u8(&mut self) -> Result<u8, Error> {
415 Ok(self.fixed::<1>()?[0])
416 }
417
418 fn u16(&mut self) -> Result<u16, Error> {
419 Ok(u16::from_be_bytes(self.fixed()?))
420 }
421
422 fn u32(&mut self) -> Result<u32, Error> {
423 Ok(u32::from_be_bytes(self.fixed()?))
424 }
425
426 fn bytes(&mut self, maximum: usize) -> Result<Vec<u8>, Error> {
427 Ok(self.bytes_ref(maximum)?.to_vec())
428 }
429
430 fn bytes_ref(&mut self, maximum: usize) -> Result<&'a [u8], Error> {
431 let length = usize::try_from(self.u32()?).map_err(|_| Error::FieldTooLarge)?;
432 validate_len(length, maximum)?;
433 let end = self.offset.checked_add(length).ok_or(Error::Truncated)?;
434 let bytes = self.wire.get(self.offset..end).ok_or(Error::Truncated)?;
435 self.offset = end;
436 Ok(bytes)
437 }
438
439 fn finish(&self) -> Result<(), Error> {
440 if self.offset == self.wire.len() {
441 Ok(())
442 } else {
443 Err(Error::TrailingBytes)
444 }
445 }
446}