Skip to main content

reqtls/
record.rs

1use super::message::{Message, Payload};
2use super::version::Version;
3use crate::error::RlsResult;
4use crate::{Alert, CipherSuite, RlsError, WriteExt, ALPN};
5
6#[derive(Debug, Copy, Clone)]
7pub enum RecordType {
8    CipherSpec = 0x14,
9    Alert = 0x15,
10    HandShake = 0x16,
11    ApplicationData = 0x17,
12
13}
14
15impl RecordType {
16    pub fn from_byte(byte: u8) -> Option<RecordType> {
17        match byte {
18            0x14 => Some(RecordType::CipherSpec),
19            0x15 => Some(RecordType::Alert),
20            0x16 => Some(RecordType::HandShake),
21            0x17 => Some(RecordType::ApplicationData),
22            _ => None
23        }
24    }
25
26    pub fn as_u8(&self) -> u8 {
27        *self as u8
28    }
29}
30
31
32#[derive(Debug)]
33pub struct RecordLayer<'a> {
34    pub context_type: RecordType,
35    pub version: Version,
36    pub len: u16,
37    pub messages: Vec<Message<'a>>,
38}
39
40impl<'a> RecordLayer<'a> {
41    pub fn new(rt: RecordType) -> RecordLayer<'a> {
42        RecordLayer {
43            context_type: rt,
44            version: Version::TLS_1_2,
45            len: 0,
46            messages: vec![],
47        }
48    }
49
50    pub fn handshake() -> RecordLayer<'a> {
51        RecordLayer::new(RecordType::HandShake)
52    }
53
54    pub fn from_bytes(bytes: &'a mut [u8], payload: bool, suite: Option<&CipherSuite>) -> RlsResult<RecordLayer<'a>> {
55        if bytes.len() < 5 { return Err(RlsError::MessageTooShort); }
56        let (head, messages) = bytes.split_at_mut(5);
57        let mut res = RecordLayer::new(RecordType::from_byte(head[0]).ok_or("LayerType Unknown")?);
58        res.version = Version::new(u16::from_be_bytes([head[1], head[2]]));
59        res.len = u16::from_be_bytes([head[3], head[4]]);
60        if messages.len() < res.len as usize { return Err("record body not enough".into()); }
61        let (mut messages, _) = messages.split_at_mut(res.len as usize);
62        let mut index = 0;
63        let total_len = messages.len();
64
65        while index < total_len {
66            match res.context_type {
67                RecordType::HandShake => {
68                    if !payload {
69                        let msg_len = u32::from_be_bytes([0, messages[1], messages[2], messages[3]]) as usize;
70                        let (message, reset) = messages.split_at_mut(msg_len + 4);
71                        messages = reset;
72                        index = index + 4 + msg_len;
73                        res.messages.push(Message::from_bytes(message, payload, suite)?)
74                    } else {
75                        res.messages.push(Message::Payload(Payload::from_slice(messages)));
76                        break;
77                    }
78                }
79                RecordType::ApplicationData => {
80                    res.messages.push(Message::Payload(Payload::from_slice(messages)));
81                    break;
82                }
83                RecordType::Alert => if payload {
84                    res.messages.push(Message::Payload(Payload::from_slice(messages)));
85                    break;
86                } else {
87                    res.messages.push(Message::Alert(Alert::from_bytes(messages)?));
88                    break;
89                }
90                RecordType::CipherSpec => {
91                    index += 1;
92                    res.messages.push(Message::CipherSpec)
93                }
94            };
95        }
96
97        Ok(res)
98    }
99
100    pub fn write_to<W: WriteExt>(self, writer: &mut W, key_size: u8) -> RlsResult<usize> {
101        let offset = writer.offset().end;
102        let sni = self.messages[0].client().map(|x| x.server_name().unwrap_or("")).unwrap_or("").to_string();
103        let h2 = self.messages[0].client().map(|x| x.alps().map(|x| x.values().iter().any(|x| x == &ALPN::Http20)).unwrap_or(false)).unwrap_or(false);
104        writer.write_u8(self.context_type as u8);
105        writer.write_u16(self.version.into_inner());
106        let len = self.messages.iter().map(|x| x.len(key_size)).sum::<usize>();
107        writer.write_u16(len as u16);
108        for message in self.messages {
109            message.write_to(writer, key_size);
110        }
111        writer.flush(offset, sni, h2)
112    }
113}
114