Skip to main content

wireforge_app/tls/
handshake.rs

1//! TLS Handshake layer parser (RFC 8446 ยง4).
2
3pub struct TlsHandshake<'a> { buf: &'a [u8] }
4
5impl<'a> TlsHandshake<'a> {
6    pub fn parse(buf: &'a [u8]) -> Option<Self> {
7        if buf.len() < 4 { return None; }
8        Some(Self { buf })
9    }
10
11    pub fn handshake_type(&self) -> u8 { self.buf[0] }
12    /// 3-byte big-endian length (RFC 8446: handshake length is u24)
13    pub fn length(&self) -> u32 {
14        u32::from_be_bytes([0, self.buf[1], self.buf[2], self.buf[3]])
15    }
16    pub fn body(&self) -> &'a [u8] {
17        let end = (4 + self.length() as usize).min(self.buf.len());
18        &self.buf[4..end]
19    }
20}
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25
26    #[test]
27    fn parse_client_hello_handshake() {
28        // handshake_type=1 (client_hello), length=3 (u24: 0x000003), body=3 bytes
29        let data = &[0x01u8, 0x00, 0x00, 0x03, 0xAA, 0xBB, 0xCC];
30        let hs = TlsHandshake::parse(data).unwrap();
31        assert_eq!(hs.handshake_type(), 1);
32        assert_eq!(hs.length(), 3);
33        assert_eq!(hs.body(), &[0xAA, 0xBB, 0xCC]);
34    }
35
36    #[test]
37    fn parse_too_short() {
38        assert!(TlsHandshake::parse(&[]).is_none());
39        assert!(TlsHandshake::parse(&[0x01, 0x00, 0x00]).is_none());
40    }
41}