1use alloc::vec::Vec;
2use core::fmt;
3use core::ops::{Deref, DerefMut, Range};
4
5use crate::crypto::cipher::EncryptionState;
6use crate::enums::{ContentType, ProtocolVersion};
7use crate::error::{Error, InvalidMessage, PeerMisbehaved};
8use crate::msgs::{Codec, HEADER_SIZE, MAX_FRAGMENT_LEN, Reader, hex, read_opaque_message_header};
9
10#[expect(clippy::exhaustive_structs)]
12#[derive(Clone, Debug)]
13pub struct EncodedMessage<P> {
14 pub typ: ContentType,
16 pub version: ProtocolVersion,
18 pub payload: P,
20}
21
22impl<P> EncodedMessage<P> {
23 pub fn new(typ: ContentType, version: ProtocolVersion, payload: P) -> Self {
25 Self {
26 typ,
27 version,
28 payload,
29 }
30 }
31}
32
33impl<'a> EncodedMessage<Payload<'a>> {
34 pub(crate) fn read(r: &mut Reader<'a>) -> Result<Self, MessageError> {
39 let (typ, version, len) = read_opaque_message_header(r)?;
40
41 let content = r
42 .take(len as usize)
43 .ok_or(MessageError::TooShortForLength)?;
44
45 Ok(Self {
46 typ,
47 version,
48 payload: Payload::Borrowed(content),
49 })
50 }
51
52 pub fn into_unencrypted_opaque(self) -> EncodedMessage<OutboundOpaque> {
54 EncodedMessage {
55 typ: self.typ,
56 version: self.version,
57 payload: OutboundOpaque::from(self.payload.bytes()),
58 }
59 }
60
61 pub fn borrow_outbound(&'a self) -> EncodedMessage<OutboundPlain<'a>> {
63 EncodedMessage {
64 typ: self.typ,
65 version: self.version,
66 payload: self.payload.bytes().into(),
67 }
68 }
69
70 pub fn into_owned(self) -> Self {
72 Self {
73 typ: self.typ,
74 version: self.version,
75 payload: self.payload.into_owned(),
76 }
77 }
78}
79
80impl EncodedMessage<&'_ [u8]> {
81 pub(crate) fn is_valid_ccs(&self) -> bool {
87 self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01]
88 }
89}
90
91impl<'a> EncodedMessage<InboundOpaque<'a>> {
92 pub fn into_tls13_unpadded_message(mut self) -> Result<EncodedMessage<&'a [u8]>, Error> {
97 let payload = &mut self.payload;
98
99 if payload.len() > MAX_FRAGMENT_LEN + 1 {
100 return Err(Error::PeerSentOversizedRecord);
101 }
102
103 self.typ = unpad_tls13_payload(payload);
104 if self.typ == ContentType::Unknown(0) {
105 return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into());
106 }
107
108 if payload.len() > MAX_FRAGMENT_LEN {
109 return Err(Error::PeerSentOversizedRecord);
110 }
111
112 self.version = ProtocolVersion::TLSv1_3;
113 Ok(self.into_plain_message())
114 }
115
116 pub fn into_plain_message_range(self, range: Range<usize>) -> EncodedMessage<&'a [u8]> {
125 EncodedMessage {
126 typ: self.typ,
127 version: self.version,
128 payload: &self.payload.into_inner()[range],
129 }
130 }
131
132 pub fn into_plain_message(self) -> EncodedMessage<&'a [u8]> {
138 EncodedMessage {
139 typ: self.typ,
140 version: self.version,
141 payload: self.payload.into_inner(),
142 }
143 }
144}
145
146impl EncodedMessage<OutboundPlain<'_>> {
147 pub(crate) fn to_unencrypted_opaque(&self) -> EncodedMessage<OutboundOpaque> {
148 let mut payload = OutboundOpaque::with_capacity(self.payload.len());
149 payload.extend_from_chunks(&self.payload);
150 EncodedMessage {
151 typ: self.typ,
152 version: self.version,
153 payload,
154 }
155 }
156
157 pub(crate) fn encoded_len(&self, record_layer: &EncryptionState) -> usize {
158 HEADER_SIZE + record_layer.encrypted_len(self.payload.len())
159 }
160}
161
162impl EncodedMessage<OutboundOpaque> {
163 pub fn encode(self) -> Vec<u8> {
165 let length = self.payload.len() as u16;
166 let mut encoded_payload = self.payload.0;
167 encoded_payload[0] = self.typ.into();
168 encoded_payload[1..3].copy_from_slice(&self.version.to_array());
169 encoded_payload[3..5].copy_from_slice(&(length).to_be_bytes());
170 encoded_payload
171 }
172}
173
174#[non_exhaustive]
179#[derive(Debug, Clone)]
180pub enum OutboundPlain<'a> {
181 Single(&'a [u8]),
185 Multiple {
187 chunks: &'a [&'a [u8]],
189 start: usize,
191 end: usize,
193 },
194}
195
196impl<'a> OutboundPlain<'a> {
197 pub fn new(chunks: &'a [&'a [u8]]) -> Self {
200 if chunks.len() == 1 {
201 Self::Single(chunks[0])
202 } else {
203 Self::Multiple {
204 chunks,
205 start: 0,
206 end: chunks
207 .iter()
208 .map(|chunk| chunk.len())
209 .sum(),
210 }
211 }
212 }
213
214 pub fn new_empty() -> Self {
216 Self::Single(&[])
217 }
218
219 pub fn to_vec(&self) -> Vec<u8> {
221 let mut vec = Vec::with_capacity(self.len());
222 self.copy_to_vec(&mut vec);
223 vec
224 }
225
226 pub fn copy_to_vec(&self, vec: &mut Vec<u8>) {
228 match *self {
229 Self::Single(chunk) => vec.extend_from_slice(chunk),
230 Self::Multiple { chunks, start, end } => {
231 let mut size = 0;
232 for chunk in chunks.iter() {
233 let psize = size;
234 let len = chunk.len();
235 size += len;
236 if size <= start || psize >= end {
237 continue;
238 }
239 let start = start.saturating_sub(psize);
240 let end = if end - psize < len { end - psize } else { len };
241 vec.extend_from_slice(&chunk[start..end]);
242 }
243 }
244 }
245 }
246
247 pub(crate) fn split_at(&self, mid: usize) -> (Self, Self) {
250 match *self {
251 Self::Single(chunk) => {
252 let mid = Ord::min(mid, chunk.len());
253 (Self::Single(&chunk[..mid]), Self::Single(&chunk[mid..]))
254 }
255 Self::Multiple { chunks, start, end } => {
256 let mid = Ord::min(start + mid, end);
257 (
258 Self::Multiple {
259 chunks,
260 start,
261 end: mid,
262 },
263 Self::Multiple {
264 chunks,
265 start: mid,
266 end,
267 },
268 )
269 }
270 }
271 }
272
273 pub(crate) fn is_empty(&self) -> bool {
275 self.len() == 0
276 }
277
278 #[expect(clippy::len_without_is_empty)]
280 pub fn len(&self) -> usize {
281 match self {
282 Self::Single(chunk) => chunk.len(),
283 Self::Multiple { start, end, .. } => end - start,
284 }
285 }
286}
287
288impl<'a> From<&'a [u8]> for OutboundPlain<'a> {
289 fn from(payload: &'a [u8]) -> Self {
290 Self::Single(payload)
291 }
292}
293
294#[derive(Clone, Debug)]
301pub struct OutboundOpaque(Vec<u8>);
302
303impl OutboundOpaque {
304 pub fn with_capacity(capacity: usize) -> Self {
308 let mut prefixed_payload = Vec::with_capacity(HEADER_SIZE + capacity);
309 prefixed_payload.resize(HEADER_SIZE, 0);
310 Self(prefixed_payload)
311 }
312
313 pub fn extend_from_slice(&mut self, slice: &[u8]) {
315 self.0.extend_from_slice(slice)
316 }
317
318 pub fn extend_from_chunks(&mut self, chunks: &OutboundPlain<'_>) {
320 chunks.copy_to_vec(&mut self.0)
321 }
322
323 pub fn truncate(&mut self, len: usize) {
325 self.0.truncate(len + HEADER_SIZE)
326 }
327
328 fn len(&self) -> usize {
329 self.0.len() - HEADER_SIZE
330 }
331}
332
333impl AsRef<[u8]> for OutboundOpaque {
334 fn as_ref(&self) -> &[u8] {
335 &self.0[HEADER_SIZE..]
336 }
337}
338
339impl AsMut<[u8]> for OutboundOpaque {
340 fn as_mut(&mut self) -> &mut [u8] {
341 &mut self.0[HEADER_SIZE..]
342 }
343}
344
345impl<'a> Extend<&'a u8> for OutboundOpaque {
346 fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) {
347 self.0.extend(iter)
348 }
349}
350
351impl From<&[u8]> for OutboundOpaque {
352 fn from(content: &[u8]) -> Self {
353 let mut payload = Vec::with_capacity(HEADER_SIZE + content.len());
354 payload.extend(&[0u8; HEADER_SIZE]);
355 payload.extend(content);
356 Self(payload)
357 }
358}
359
360impl<const N: usize> From<&[u8; N]> for OutboundOpaque {
361 fn from(content: &[u8; N]) -> Self {
362 Self::from(&content[..])
363 }
364}
365
366#[non_exhaustive]
372#[derive(Clone, Eq, PartialEq)]
373pub enum Payload<'a> {
374 Borrowed(&'a [u8]),
376 Owned(Vec<u8>),
378}
379
380impl<'a> Payload<'a> {
381 pub fn bytes(&'a self) -> &'a [u8] {
383 match self {
384 Self::Borrowed(bytes) => bytes,
385 Self::Owned(bytes) => bytes,
386 }
387 }
388
389 pub(crate) fn into_owned(self) -> Payload<'static> {
390 Payload::Owned(self.into_vec())
391 }
392
393 pub(crate) fn into_vec(self) -> Vec<u8> {
394 match self {
395 Self::Borrowed(bytes) => bytes.to_vec(),
396 Self::Owned(bytes) => bytes,
397 }
398 }
399
400 pub(crate) fn read(r: &mut Reader<'a>) -> Self {
401 Self::Borrowed(r.rest())
402 }
403}
404
405impl Payload<'static> {
406 pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
408 Self::Owned(bytes.into())
409 }
410}
411
412impl<'a> Codec<'a> for Payload<'a> {
413 fn encode(&self, bytes: &mut Vec<u8>) {
414 bytes.extend_from_slice(self.bytes());
415 }
416
417 fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> {
418 Ok(Self::read(r))
419 }
420}
421
422impl fmt::Debug for Payload<'_> {
423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424 hex(f, self.bytes())
425 }
426}
427
428#[expect(clippy::exhaustive_structs)]
430pub struct InboundOpaque<'a>(pub &'a mut [u8]);
431
432impl<'a> InboundOpaque<'a> {
433 pub fn truncate(&mut self, len: usize) {
435 if len >= self.len() {
436 return;
437 }
438
439 self.0 = core::mem::take(&mut self.0)
440 .split_at_mut(len)
441 .0;
442 }
443
444 pub(crate) fn into_inner(self) -> &'a mut [u8] {
445 self.0
446 }
447
448 pub(crate) fn pop(&mut self) -> Option<u8> {
449 if self.is_empty() {
450 return None;
451 }
452
453 let len = self.len();
454 let last = self[len - 1];
455 self.truncate(len - 1);
456 Some(last)
457 }
458}
459
460impl Deref for InboundOpaque<'_> {
461 type Target = [u8];
462
463 fn deref(&self) -> &Self::Target {
464 self.0
465 }
466}
467
468impl DerefMut for InboundOpaque<'_> {
469 fn deref_mut(&mut self) -> &mut Self::Target {
470 self.0
471 }
472}
473
474fn unpad_tls13_payload(p: &mut InboundOpaque<'_>) -> ContentType {
482 loop {
483 match p.pop() {
484 Some(0) => {}
485 Some(content_type) => return ContentType::from(content_type),
486 None => return ContentType::Unknown(0),
487 }
488 }
489}
490
491#[expect(missing_docs)]
493#[non_exhaustive]
494#[derive(Debug)]
495pub enum MessageError {
496 TooShortForHeader,
497 TooShortForLength,
498 InvalidEmptyPayload,
499 MessageTooLarge,
500 InvalidContentType,
501 UnknownProtocolVersion,
502}
503
504#[cfg(test)]
505mod tests {
506 use std::{println, vec};
507
508 use super::*;
509
510 #[test]
511 fn split_at_with_single_slice() {
512 let owner: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7];
513 let borrowed_payload = OutboundPlain::Single(owner);
514
515 let (before, after) = borrowed_payload.split_at(6);
516 println!("before:{before:?}\nafter:{after:?}");
517 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5]);
518 assert_eq!(after.to_vec(), &[6, 7]);
519 }
520
521 #[test]
522 fn split_at_with_multiple_slices() {
523 let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
524 let borrowed_payload = OutboundPlain::new(&owner);
525
526 let (before, after) = borrowed_payload.split_at(3);
527 println!("before:{before:?}\nafter:{after:?}");
528 assert_eq!(before.to_vec(), &[0, 1, 2]);
529 assert_eq!(after.to_vec(), &[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
530
531 let (before, after) = borrowed_payload.split_at(8);
532 println!("before:{before:?}\nafter:{after:?}");
533 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7]);
534 assert_eq!(after.to_vec(), &[8, 9, 10, 11, 12]);
535
536 let (before, after) = borrowed_payload.split_at(11);
537 println!("before:{before:?}\nafter:{after:?}");
538 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
539 assert_eq!(after.to_vec(), &[11, 12]);
540 }
541
542 #[test]
543 fn split_out_of_bounds() {
544 let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]];
545
546 let single_payload = OutboundPlain::Single(owner[0]);
547 let (before, after) = single_payload.split_at(17);
548 println!("before:{before:?}\nafter:{after:?}");
549 assert_eq!(before.to_vec(), &[0, 1, 2, 3]);
550 assert!(after.is_empty());
551
552 let multiple_payload = OutboundPlain::new(&owner);
553 let (before, after) = multiple_payload.split_at(17);
554 println!("before:{before:?}\nafter:{after:?}");
555 assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
556 assert!(after.is_empty());
557
558 let empty_payload = OutboundPlain::new_empty();
559 let (before, after) = empty_payload.split_at(17);
560 println!("before:{before:?}\nafter:{after:?}");
561 assert!(before.is_empty());
562 assert!(after.is_empty());
563 }
564
565 #[test]
566 fn empty_slices_mixed() {
567 let owner: Vec<&[u8]> = vec![&[], &[], &[0], &[], &[1, 2], &[], &[3], &[4], &[], &[]];
568 let mut borrowed_payload = OutboundPlain::new(&owner);
569 let mut fragment_count = 0;
570 let mut fragment;
571 let expected_fragments: &[&[u8]] = &[&[0, 1], &[2, 3], &[4]];
572
573 while !borrowed_payload.is_empty() {
574 (fragment, borrowed_payload) = borrowed_payload.split_at(2);
575 println!("{fragment:?}");
576 assert_eq!(&expected_fragments[fragment_count], &fragment.to_vec());
577 fragment_count += 1;
578 }
579 assert_eq!(fragment_count, expected_fragments.len());
580 }
581
582 #[test]
583 fn exhaustive_splitting() {
584 let owner: Vec<u8> = (0..127).collect();
585 let slices = (0..7)
586 .map(|i| &owner[((1 << i) - 1)..((1 << (i + 1)) - 1)])
587 .collect::<Vec<_>>();
588 let payload = OutboundPlain::new(&slices);
589
590 assert_eq!(payload.to_vec(), owner);
591 println!("{payload:#?}");
592
593 for start in 0..128 {
594 for end in start..128 {
595 for mid in 0..(end - start) {
596 let witness = owner[start..end].split_at(mid);
597 let split_payload = payload
598 .split_at(end)
599 .0
600 .split_at(start)
601 .1
602 .split_at(mid);
603 assert_eq!(
604 witness.0,
605 split_payload.0.to_vec(),
606 "start: {start}, mid:{mid}, end:{end}"
607 );
608 assert_eq!(
609 witness.1,
610 split_payload.1.to_vec(),
611 "start: {start}, mid:{mid}, end:{end}"
612 );
613 }
614 }
615 }
616 }
617}