ytls_record/
wrapped.rs

1//! Wrapped Record
2
3use crate::error::RecordError;
4
5#[derive(Debug, PartialEq)]
6pub enum WrappedContentType {
7    /// Change Cipher Spec
8    ChangeCipherSpec,
9    /// Alert
10    Alert,
11    /// Handshake
12    Handshake,
13    /// Application Data
14    ApplicationData,
15    /// Unknown
16    Unknown(u8),
17}
18
19impl From<u8> for WrappedContentType {
20    fn from(i: u8) -> Self {
21        match i {
22            20 => Self::ChangeCipherSpec,
23            21 => Self::Alert,
24            22 => Self::Handshake,
25            23 => Self::ApplicationData,
26            _ => Self::Unknown(i),
27        }
28    }
29}
30
31#[derive(Debug, PartialEq)]
32pub struct WrappedRecord<'r> {
33    raw_bytes: &'r [u8],
34    msg: WrappedMsgType<'r>,
35}
36
37#[derive(Debug, PartialEq)]
38pub enum WrappedMsgType<'r> {
39    Handshake(HandshakeMsg<'r>),
40    Alert(AlertMsg<'r>),
41}
42
43use crate::AlertMsg;
44use crate::HandshakeMsg;
45
46impl<'r> WrappedRecord<'r> {
47    #[inline]
48    pub fn msg(&self) -> &WrappedMsgType<'r> {
49        &self.msg
50    }
51    #[inline]
52    pub fn parse_client(wrapped_data: &'r [u8]) -> Result<WrappedRecord<'r>, RecordError> {
53        let w_len = wrapped_data.len();
54
55        let rec_type: WrappedContentType = wrapped_data[w_len - 1].into();
56        let raw_bytes = &wrapped_data[0..w_len - 1];
57
58        let msg = match rec_type {
59            WrappedContentType::Handshake => {
60                let msg = HandshakeMsg::client_wrapped_parse(raw_bytes)?;
61                WrappedMsgType::Handshake(msg)
62            }
63            WrappedContentType::Alert => {
64                let (msg, _r_next) = AlertMsg::client_parse(raw_bytes)?;
65                WrappedMsgType::Alert(msg)
66            }
67            WrappedContentType::Unknown(_) => return Err(RecordError::Validity),
68            _ => todo!("Missing {:?}", rec_type),
69        };
70        Ok(WrappedRecord { raw_bytes, msg })
71    }
72}
73
74#[cfg(test)]
75mod test {
76    use super::*;
77    use hex_literal::hex;
78    use rstest::rstest;
79
80    use crate::ClientFinished;
81
82    #[rstest]
83    #[case(
84        &hex!("14000020a0210258e7c4402ab07807a1e61df4cf0ab58f828b26c6adf29654228ac0b66f16"),
85    )]
86    fn wrapped_ok(#[case] in_data: &[u8]) {
87        let r = WrappedRecord::parse_client(in_data);
88        insta::assert_debug_snapshot!(r);
89    }
90
91    #[rstest]
92    #[case(&hex!("7710"))]
93    #[case(&hex!("1410"))]
94    #[case(&hex!("140010"))]
95    #[case(&hex!("14000010"))]
96    fn wrapped_err(#[case] in_data: &[u8]) {
97        assert_eq!(
98            WrappedRecord::parse_client(in_data),
99            Err(RecordError::Validity)
100        );
101    }
102}