iris_core/protocols/stream/tls/
parser.rs1use super::handshake::{
12 Certificate, ClientDHParams, ClientECDHParams, ClientHello, ClientKeyExchange, ClientRSAParams,
13 KeyShareEntry, ServerDHParams, ServerECDHParams, ServerHello, ServerKeyExchange,
14 ServerRSAParams,
15};
16use super::Tls;
17use crate::conntrack::pdu::L4Pdu;
18use crate::protocols::stream::{
19 ConnParsable, ParseResult, ParsingState, ProbeResult, Session, SessionData,
20};
21
22use tls_parser::*;
23
24#[derive(Debug)]
26pub struct TlsParser {
27 sessions: Vec<Tls>,
29}
30
31impl Default for TlsParser {
32 fn default() -> Self {
33 TlsParser {
34 sessions: vec![Tls::new()],
35 }
36 }
37}
38
39impl ConnParsable for TlsParser {
40 fn parse(&mut self, pdu: &L4Pdu) -> ParseResult {
41 log::debug!("Updating parser tls");
42 let offset = pdu.offset();
43 let length = pdu.length();
44 if length == 0 {
45 return ParseResult::Skipped;
46 }
47
48 if let Ok(data) = (pdu.mbuf_ref()).get_data_slice(offset, length) {
49 self.sessions[0].parse_tcp_level(data, pdu.dir)
50 } else {
51 log::warn!("Malformed packet");
52 ParseResult::Skipped
53 }
54 }
55
56 fn probe(&self, pdu: &L4Pdu) -> ProbeResult {
57 if pdu.length() <= 2 {
58 return ProbeResult::Unsure;
59 }
60
61 let offset = pdu.offset();
62 let length = pdu.length();
63 if let Ok(data) = (pdu.mbuf_ref()).get_data_slice(offset, length) {
64 match (data[0], data[1], data[2]) {
68 (0x14..=0x17, 0x03, 0..=3) => ProbeResult::Certain,
69 _ => ProbeResult::NotForUs,
70 }
71 } else {
72 log::warn!("Malformed packet");
73 ProbeResult::Error
74 }
75 }
76
77 fn remove_session(&mut self, _session_id: usize) -> Option<Session> {
78 self.sessions.pop().map(|tls| Session {
79 data: SessionData::Tls(Box::new(tls)),
80 id: 0,
81 })
82 }
83
84 fn drain_sessions(&mut self) -> Vec<Session> {
85 self.sessions
86 .drain(..)
87 .map(|tls| Session {
88 data: SessionData::Tls(Box::new(tls)),
89 id: 0,
90 })
91 .collect()
92 }
93
94 fn session_parsed_state(&self) -> ParsingState {
95 ParsingState::Stop
96 }
97
98 fn body_offset(&mut self) -> Option<usize> {
99 match self.sessions.last_mut() {
100 Some(tls) => std::mem::take(&mut tls.last_body_offset),
101 None => None,
102 }
103 }
104}
105
106impl Tls {
109 pub(crate) fn new() -> Tls {
111 Tls {
112 client_hello: None,
113 server_hello: None,
114 server_certificates: vec![],
115 client_certificates: vec![],
116 server_key_exchange: None,
117 client_key_exchange: None,
118 state: TlsState::None,
119 tcp_buffer: vec![],
120 record_buffer: vec![],
121 last_body_offset: None,
122 }
123 }
124
125 pub(crate) fn parse_handshake_clienthello(&mut self, content: &TlsClientHelloContents) {
127 let mut client_hello = ClientHello {
128 version: content.version,
129 random: content.random.to_vec(),
130 session_id: match content.session_id {
131 Some(v) => v.to_vec(),
132 None => vec![],
133 },
134 cipher_suites: content.ciphers.to_vec(),
135 compression_algs: content.comp.to_vec(),
136 ..ClientHello::default()
137 };
138
139 let ext = parse_tls_client_hello_extensions(content.ext.unwrap_or(b""));
140 log::trace!("client extensions: {:#?}", ext);
141 match &ext {
142 Ok((rem, ref ext_lst)) => {
143 if !rem.is_empty() {
144 log::debug!("warn: extensions not entirely parsed");
145 }
146 for extension in ext_lst {
147 client_hello
148 .extension_list
149 .push(TlsExtensionType::from(extension));
150 match *extension {
151 TlsExtension::SNI(ref v) if !v.is_empty() => {
152 let sni = v[0].1;
153 client_hello.server_name = Some(match std::str::from_utf8(sni) {
154 Ok(name) => name.to_string(),
155 Err(_) => format!("<Invalid UTF-8: {}>", hex::encode(sni)),
156 });
157 }
158 TlsExtension::SupportedGroups(ref v) => {
159 client_hello.supported_groups = v.clone();
160 }
161 TlsExtension::EcPointFormats(v) => {
162 client_hello.ec_point_formats = v.to_vec();
163 }
164 TlsExtension::SignatureAlgorithms(ref v) => {
165 client_hello.signature_algs = v.clone();
166 }
167 TlsExtension::ALPN(ref v) => {
168 for proto in v {
169 client_hello.alpn_protocols.push(
170 match std::str::from_utf8(proto) {
171 Ok(proto) => proto.to_string(),
172 Err(_) => {
173 format!("<Invalid UTF-8: {}>", hex::encode(proto))
174 }
175 },
176 );
177 }
178 }
179 TlsExtension::KeyShare(ref v) => {
180 log::debug!("Client Shares: {:?}", v);
181 client_hello.key_shares = v
182 .iter()
183 .map(|k| KeyShareEntry {
184 group: k.group,
185 kx_data: k.kx.to_vec(),
186 })
187 .collect();
188 }
189 TlsExtension::SupportedVersions(ref v) => {
190 client_hello.supported_versions = v.clone();
191 }
192 _ => (),
193 }
194 }
195 }
196 e => log::debug!("Could not parse extensions: {:?}", e),
197 };
198 self.client_hello = Some(client_hello);
199 }
200
201 fn parse_handshake_serverhello(&mut self, content: &TlsServerHelloContents) {
203 let mut server_hello = ServerHello {
204 version: content.version,
205 random: content.random.to_vec(),
206 session_id: match content.session_id {
207 Some(v) => v.to_vec(),
208 None => vec![],
209 },
210 cipher_suite: content.cipher,
211 compression_alg: content.compression,
212 ..ServerHello::default()
213 };
214
215 let ext = parse_tls_server_hello_extensions(content.ext.unwrap_or(b""));
216 log::debug!("server_hello extensions: {:#?}", ext);
217 match &ext {
218 Ok((rem, ref ext_lst)) => {
219 if !rem.is_empty() {
220 log::debug!("warn: extensions not entirely parsed");
221 }
222 for extension in ext_lst {
223 server_hello
224 .extension_list
225 .push(TlsExtensionType::from(extension));
226 match *extension {
227 TlsExtension::EcPointFormats(v) => {
228 server_hello.ec_point_formats = v.to_vec();
229 }
230 TlsExtension::ALPN(ref v) if !v.is_empty() => {
231 server_hello.alpn_protocol = Some(match std::str::from_utf8(v[0]) {
232 Ok(proto) => proto.to_string(),
233 Err(_) => format!("<Invalid UTF-8: {}>", hex::encode(v[0])),
234 });
235 }
236 TlsExtension::KeyShare(ref v) => {
237 log::debug!("Server Share: {:?}", v);
238 if !v.is_empty() {
239 server_hello.key_share = Some(KeyShareEntry {
240 group: v[0].group,
241 kx_data: v[0].kx.to_vec(),
242 });
243 }
244 }
245 TlsExtension::SupportedVersions(ref v) if !v.is_empty() => {
246 server_hello.selected_version = Some(v[0]);
247 }
248 _ => (),
249 }
250 }
251 }
252 e => log::debug!("Could not parse extensions: {:?}", e),
253 };
254 self.server_hello = Some(server_hello);
255 }
256
257 fn parse_handshake_certificate(&mut self, content: &TlsCertificateContents, direction: bool) {
259 log::trace!("cert chain length: {}", content.cert_chain.len());
260 if direction {
261 for cert in &content.cert_chain {
263 self.client_certificates.push(Certificate {
264 raw: cert.data.to_vec(),
265 })
266 }
267 } else {
268 for cert in &content.cert_chain {
270 self.server_certificates.push(Certificate {
271 raw: cert.data.to_vec(),
272 })
273 }
274 }
275 }
276
277 fn parse_handshake_serverkeyexchange(&mut self, content: &TlsServerKeyExchangeContents) {
279 log::trace!("SKE: {:?}", content);
280 if let Some(cipher) = self.cipher_suite() {
281 match &cipher.kx {
282 TlsCipherKx::Ecdhe | TlsCipherKx::Ecdh => {
283 if let Ok((_sig, ref parsed)) = parse_server_ecdh_params(content.parameters) {
284 if let ECParametersContent::NamedGroup(curve) =
285 parsed.curve_params.params_content
286 {
287 let ecdh_params = ServerECDHParams {
288 curve,
289 kx_data: parsed.public.point.to_vec(),
290 };
291 self.server_key_exchange = Some(ServerKeyExchange::Ecdh(ecdh_params));
292 };
293 }
294 }
295 TlsCipherKx::Dhe | TlsCipherKx::Dh => {
296 if let Ok((_sig, ref parsed)) = parse_server_dh_params(content.parameters) {
297 let dh_params = ServerDHParams {
298 prime: parsed.dh_p.to_vec(),
299 generator: parsed.dh_g.to_vec(),
300 kx_data: parsed.dh_ys.to_vec(),
301 };
302 self.server_key_exchange = Some(ServerKeyExchange::Dh(dh_params));
303 }
304 }
305 TlsCipherKx::Rsa => {
306 if let Ok((_sig, ref parsed)) = parse_server_rsa_params(content.parameters) {
307 let rsa_params = ServerRSAParams {
308 modulus: parsed.modulus.to_vec(),
309 exponent: parsed.exponent.to_vec(),
310 };
311 self.server_key_exchange = Some(ServerKeyExchange::Rsa(rsa_params));
312 }
313 }
314 _ => {
315 self.server_key_exchange =
316 Some(ServerKeyExchange::Unknown(content.parameters.to_vec()))
317 }
318 }
319 }
320 }
321
322 fn parse_handshake_clientkeyexchange(&mut self, content: &TlsClientKeyExchangeContents) {
324 log::trace!("CKE: {:?}", content);
325 if let Some(cipher) = self.cipher_suite() {
326 match &cipher.kx {
327 TlsCipherKx::Ecdhe | TlsCipherKx::Ecdh => {
328 if let Ok((_rem, ref parsed)) = parse_client_ecdh_params(content.parameters) {
329 let ecdh_params = ClientECDHParams {
330 kx_data: parsed.ecdh_yc.point.to_vec(),
331 };
332 self.client_key_exchange = Some(ClientKeyExchange::Ecdh(ecdh_params));
333 }
334 }
335 TlsCipherKx::Dhe | TlsCipherKx::Dh => {
336 if let Ok((_rem, ref parsed)) = parse_client_dh_params(content.parameters) {
337 let dh_params = ClientDHParams {
338 kx_data: parsed.dh_yc.to_vec(),
339 };
340 self.client_key_exchange = Some(ClientKeyExchange::Dh(dh_params));
341 }
342 }
343 TlsCipherKx::Rsa => {
344 if let Ok((_rem, ref parsed)) = parse_client_rsa_params(content.parameters) {
345 let rsa_params = ClientRSAParams {
346 encrypted_pms: parsed.data.to_vec(),
347 };
348 self.client_key_exchange = Some(ClientKeyExchange::Rsa(rsa_params));
349 }
350 }
351 _ => {
352 self.client_key_exchange =
353 Some(ClientKeyExchange::Unknown(content.parameters.to_vec()))
354 }
355 }
356 }
357 }
359
360 pub(crate) fn parse_message_level(&mut self, msg: &TlsMessage, direction: bool) -> ParseResult {
362 log::trace!("parse_message_level {:?}", msg);
363
364 if self.state == TlsState::ClientChangeCipherSpec {
366 log::trace!("TLS session encrypted, activating bypass");
367 return ParseResult::HeadersDone(0);
368 }
369
370 let transition =
376 if self.state == TlsState::ServerHello && matches!(msg, TlsMessage::ChangeCipherSpec) {
377 Ok(TlsState::ClientChangeCipherSpec)
378 } else {
379 tls_state_transition(self.state, msg, direction)
380 };
381 match transition {
382 Ok(s) => self.state = s,
383 Err(_) => {
384 self.state = TlsState::Invalid;
385 }
386 };
387 log::trace!("TLS new state: {:?}", self.state);
388
389 match *msg {
391 TlsMessage::Handshake(ref m) => match *m {
392 TlsMessageHandshake::ClientHello(ref content) => {
393 self.parse_handshake_clienthello(content);
394 }
395 TlsMessageHandshake::ServerHello(ref content) => {
396 self.parse_handshake_serverhello(content);
397 }
398 TlsMessageHandshake::Certificate(ref content) => {
399 self.parse_handshake_certificate(content, direction);
400 }
401 TlsMessageHandshake::ServerKeyExchange(ref content) => {
402 self.parse_handshake_serverkeyexchange(content);
403 }
404 TlsMessageHandshake::ClientKeyExchange(ref content) => {
405 self.parse_handshake_clientkeyexchange(content);
406 }
407
408 _ => (),
409 },
410 TlsMessage::Alert(ref a) if a.severity == TlsAlertSeverity::Fatal => {
411 return ParseResult::HeadersDone(0);
412 }
413 _ => (),
414 }
415
416 ParseResult::Continue(0)
417 }
418
419 pub(crate) fn parse_record_level(
421 &mut self,
422 record: &TlsRawRecord<'_>,
423 direction: bool,
424 pdu_len: usize,
425 ) -> ParseResult {
426 let mut v: Vec<u8>;
427 let mut status = ParseResult::Continue(0);
428
429 log::trace!("parse_record_level ({} bytes)", record.data.len());
430 log::trace!("{:?}", record.hdr);
431 if self.state == TlsState::ClientChangeCipherSpec {
435 log::trace!("TLS session encrypted, activating bypass");
436 return ParseResult::HeadersDone(0);
437 }
438
439 match record.hdr.record_type {
441 TlsRecordType::ChangeCipherSpec => (),
442 TlsRecordType::Handshake => (),
443 TlsRecordType::Alert => (),
444 _ => return ParseResult::Continue(0),
445 }
446
447 let record_buffer = match self.record_buffer.len() {
449 0 => record.data,
450 _ => {
451 if self.record_buffer.len() + record.data.len() > 16_777_216 {
454 return ParseResult::Skipped;
455 };
456 v = self.record_buffer.split_off(0);
457 v.extend_from_slice(record.data);
458 v.as_slice()
459 }
460 };
461
462 match parse_tls_record_with_header(record_buffer, &record.hdr) {
464 Ok((rem, ref msg_list)) => {
465 for msg in msg_list {
466 status = self.parse_message_level(msg, direction);
467 if status != ParseResult::Continue(0) {
468 let remaining = rem.len();
470 if matches!(status, ParseResult::HeadersDone(_))
471 && remaining > 0
472 && remaining < pdu_len
473 {
474 self.last_body_offset = Some(pdu_len - remaining - 1);
475 }
476 return status;
477 }
478 }
479 if !rem.is_empty() {
480 log::debug!("warn: extra bytes in TLS record: {:?}", rem);
481 };
482 }
483 Err(Err::Incomplete(needed)) => {
484 log::trace!(
485 "Defragmentation required (TLS record), missing {:?} bytes",
486 needed
487 );
488 self.record_buffer.extend_from_slice(record.data);
489 }
490 Err(_e) => {
491 log::debug!("warn: parse_tls_record_with_header failed");
492 return ParseResult::Skipped;
493 }
494 };
495
496 status
497 }
498
499 pub(crate) fn parse_tcp_level(&mut self, data: &[u8], direction: bool) -> ParseResult {
501 let mut v: Vec<u8>;
502 let mut status = ParseResult::Continue(0);
503 let pdu_len = data.len(); log::trace!("parse_tcp_level ({} bytes)", data.len());
505 log::trace!("defrag buffer size: {}", self.tcp_buffer.len());
506
507 if self.state == TlsState::ClientChangeCipherSpec {
509 log::trace!("TLS session encrypted, activating bypass");
510 return ParseResult::HeadersDone(0);
511 };
512 let tcp_buffer = match self.tcp_buffer.len() {
514 0 => data,
515 _ => {
516 if self.tcp_buffer.len() + data.len() > 16_777_216 {
519 return ParseResult::Skipped;
520 };
521 v = self.tcp_buffer.split_off(0);
522 v.extend_from_slice(data);
523 v.as_slice()
524 }
525 };
526 let mut cur_data = tcp_buffer;
527 while !cur_data.is_empty() {
528 match parse_tls_raw_record(cur_data) {
530 Ok((rem, ref record)) => {
531 cur_data = rem;
532 status = self.parse_record_level(record, direction, pdu_len);
533 if status != ParseResult::Continue(0) {
534 return status;
535 }
536 }
537 Err(Err::Incomplete(needed)) => {
538 log::trace!(
539 "Defragmentation required (TCP level), missing {:?} bytes",
540 needed
541 );
542 self.tcp_buffer.extend_from_slice(cur_data);
543 break;
544 }
545 Err(_e) => {
546 log::debug!("warn: Parsing raw record failed");
547 break;
548 }
549 }
550 }
551 status
552 }
553}