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)
54pub fn is_tls_payload(data: &[u8]) -> bool {
55    if data.len() < TLS_RECORD_HEADER_LEN {
56        return false;
57    }
58
59    // Check content type (20-24 are valid)
60    let content_type = data[0];
61    if !(20..=24).contains(&content_type) {
62        // Also check for SSLv2 format (MSB set in first byte)
63        if data.len() >= 2 && (data[0] & 0x80) != 0 {
64            // SSLv2 2-byte header: length with MSB set
65            return true;
66        }
67        return false;
68    }
69
70    // Check version (should be 0x0300-0x0304 or draft versions)
71    let version = u16::from_be_bytes([data[1], data[2]]);
72    let valid_version = matches!(
73        version,
74        0x0300..=0x0304 | 0x7f00..=0x7fff
75    );
76    if !valid_version {
77        return false;
78    }
79
80    // Check length is reasonable
81    let length = u16::from_be_bytes([data[3], data[4]]) as usize;
82    length <= TLS_RECORD_HEADER_LEN + record::TLS_MAX_CIPHERTEXT_LEN
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn test_is_tls_payload_valid() {
91        // Valid TLS 1.2 Handshake record header
92        let data = vec![0x16, 0x03, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00];
93        assert!(is_tls_payload(&data));
94    }
95
96    #[test]
97    fn test_is_tls_payload_alert() {
98        let data = vec![0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28];
99        assert!(is_tls_payload(&data));
100    }
101
102    #[test]
103    fn test_is_tls_payload_ccs() {
104        let data = vec![0x14, 0x03, 0x03, 0x00, 0x01, 0x01];
105        assert!(is_tls_payload(&data));
106    }
107
108    #[test]
109    fn test_is_tls_payload_app_data() {
110        let data = vec![0x17, 0x03, 0x03, 0x00, 0x03, 0xaa, 0xbb, 0xcc];
111        assert!(is_tls_payload(&data));
112    }
113
114    #[test]
115    fn test_is_tls_payload_tls10() {
116        let data = vec![0x16, 0x03, 0x01, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00];
117        assert!(is_tls_payload(&data));
118    }
119
120    #[test]
121    fn test_is_tls_payload_invalid_type() {
122        let data = vec![0x19, 0x03, 0x03, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05];
123        assert!(!is_tls_payload(&data));
124    }
125
126    #[test]
127    fn test_is_tls_payload_invalid_version() {
128        let data = vec![0x16, 0x04, 0x00, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05];
129        assert!(!is_tls_payload(&data));
130    }
131
132    #[test]
133    fn test_is_tls_payload_too_short() {
134        let data = vec![0x16, 0x03, 0x03, 0x00];
135        assert!(!is_tls_payload(&data));
136    }
137
138    #[test]
139    fn test_is_tls_payload_http() {
140        assert!(!is_tls_payload(b"HTTP/1.1 200 OK\r\n"));
141    }
142
143    #[test]
144    fn test_is_tls_payload_sslv2() {
145        // SSLv2 ClientHello starts with 0x80 (MSB set)
146        let data = vec![0x80, 0x2e, 0x01, 0x00, 0x02];
147        assert!(is_tls_payload(&data));
148    }
149}