Skip to main content

stackforge_core/layer/tls/
mod.rs

1//! TLS (Transport Layer Security) protocol layer.
2//!
3//! Implements parsing and building for the TLS record protocol (RFC 5246, RFC 8446),
4//! including support for `SSLv2`, TLS 1.0-1.2, and TLS 1.3.
5//!
6//! This is a "clean-sheet" implementation that follows Scapy's "Permissive Parser,
7//! Explicit Builder" pattern, allowing construction of malformed packets for
8//! security research and fuzzing.
9//!
10//! ## Record Format
11//!
12//! ```text
13//! ContentType  type;           // 1 byte (20-24)
14//! ProtocolVersion version;     // 2 bytes
15//! uint16 length;               // 2 bytes
16//! opaque fragment[length];     // variable
17//! ```
18
19pub mod builder;
20pub mod cert;
21pub mod crypto;
22pub mod extensions;
23pub mod handshake;
24pub mod keyexchange;
25pub mod record;
26pub mod session;
27pub mod sslv2;
28pub mod types;
29
30pub use builder::{TlsAlertBuilder, TlsCcsBuilder, TlsRecordBuilder};
31pub use cert::TlsCertificate;
32pub use extensions::Extension;
33pub use handshake::{Certificate, ClientHello, Finished, Handshake, HandshakeBody, ServerHello};
34pub use record::{TLS_FIELDS, TLS_RECORD_HEADER_LEN, TlsLayer};
35pub use session::TlsSession;
36pub use sslv2::{Sslv2ClientHello, Sslv2ClientMasterKey, Sslv2ServerHello};
37pub use types::{
38    ExtensionType, HandshakeType, NamedGroup, SignatureScheme, TlsAlertDescription, TlsAlertLevel,
39    TlsContentType, TlsVersion,
40};
41
42/// Standard TLS port (HTTPS).
43pub const TLS_PORT: u16 = 443;
44
45/// Additional common TLS ports.
46pub const TLS_PORTS: &[u16] = &[443, 465, 636, 853, 993, 995, 8443];
47
48/// Check if a TCP payload looks like TLS traffic.
49///
50/// Returns true if the data starts with a valid TLS record header:
51/// - Content type is 20-24 (valid TLS record types)
52/// - Version is a recognized TLS/SSL version
53/// - Length is reasonable (< 2^14 + 2048)
54#[must_use]
55pub fn is_tls_payload(data: &[u8]) -> bool {
56    if data.len() < TLS_RECORD_HEADER_LEN {
57        return false;
58    }
59
60    // Check content type (20-24 are valid)
61    let content_type = data[0];
62    if !(20..=24).contains(&content_type) {
63        // Also check for SSLv2 format (MSB set in first byte)
64        if data.len() >= 2 && (data[0] & 0x80) != 0 {
65            // SSLv2 2-byte header: length with MSB set
66            return true;
67        }
68        return false;
69    }
70
71    // Check version (should be 0x0300-0x0304 or draft versions)
72    let version = u16::from_be_bytes([data[1], data[2]]);
73    let valid_version = matches!(
74        version,
75        0x0300..=0x0304 | 0x7f00..=0x7fff
76    );
77    if !valid_version {
78        return false;
79    }
80
81    // Check length is reasonable
82    let length = u16::from_be_bytes([data[3], data[4]]) as usize;
83    length <= TLS_RECORD_HEADER_LEN + record::TLS_MAX_CIPHERTEXT_LEN
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_is_tls_payload_valid() {
92        // Valid TLS 1.2 Handshake record header
93        let data = vec![0x16, 0x03, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00];
94        assert!(is_tls_payload(&data));
95    }
96
97    #[test]
98    fn test_is_tls_payload_alert() {
99        let data = vec![0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28];
100        assert!(is_tls_payload(&data));
101    }
102
103    #[test]
104    fn test_is_tls_payload_ccs() {
105        let data = vec![0x14, 0x03, 0x03, 0x00, 0x01, 0x01];
106        assert!(is_tls_payload(&data));
107    }
108
109    #[test]
110    fn test_is_tls_payload_app_data() {
111        let data = vec![0x17, 0x03, 0x03, 0x00, 0x03, 0xaa, 0xbb, 0xcc];
112        assert!(is_tls_payload(&data));
113    }
114
115    #[test]
116    fn test_is_tls_payload_tls10() {
117        let data = vec![0x16, 0x03, 0x01, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00];
118        assert!(is_tls_payload(&data));
119    }
120
121    #[test]
122    fn test_is_tls_payload_invalid_type() {
123        let data = vec![0x19, 0x03, 0x03, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05];
124        assert!(!is_tls_payload(&data));
125    }
126
127    #[test]
128    fn test_is_tls_payload_invalid_version() {
129        let data = vec![0x16, 0x04, 0x00, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05];
130        assert!(!is_tls_payload(&data));
131    }
132
133    #[test]
134    fn test_is_tls_payload_too_short() {
135        let data = vec![0x16, 0x03, 0x03, 0x00];
136        assert!(!is_tls_payload(&data));
137    }
138
139    #[test]
140    fn test_is_tls_payload_http() {
141        assert!(!is_tls_payload(b"HTTP/1.1 200 OK\r\n"));
142    }
143
144    #[test]
145    fn test_is_tls_payload_sslv2() {
146        // SSLv2 ClientHello starts with 0x80 (MSB set)
147        let data = vec![0x80, 0x2e, 0x01, 0x00, 0x02];
148        assert!(is_tls_payload(&data));
149    }
150}