Crate tls_parser[][src]

Expand description

License: MIT Apache License 2.0 Crates.io Version Github CI Minimum rustc version

TLS Parser

A TLS parser, implemented with the nom parser combinator framework.

The goal of this parser is to implement TLS messages analysis, for example to use rules from a network IDS, for ex during the TLS handshake.

It implements structures and parsing functions for records and messages, but need additional code to handle fragmentation, or to fully inspect messages. Parsing some TLS messages requires to know the previously selected parameters. See the rusticata TLS parser for a full example.

It is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken to ensure security and safety of this crate, including design (recursion limit, defensive programming), tests, and fuzzing. It also aims to be panic-free.

The code is available on Github and is part of the Rusticata project.

Parsing records

The main parsing functions are located in the tls.rs file. The entry functions are:

  • parse_tls_plaintext: parses a record as plaintext
  • parse_tls_encrypted: read an encrypted record. The parser has no crypto or decryption features, so the content will be left as opaque data.

Examples

use tls_parser::parse_tls_plaintext;
use tls_parser::nom::{Err, IResult};

let bytes : &[u8]= include_bytes!("../assets/client_hello_dhe.bin");
// [ 0x16, 0x03, 0x01 ... ];
let res = parse_tls_plaintext(&bytes);
match res {
    Ok((rem,record)) => {
        // rem is the remaining data (not parsed)
        // record is an object of type TlsRecord
    },
    Err(Err::Incomplete(needed)) => {
        eprintln!("Defragmentation required (TLS record)");
    },
    Err(e) => { eprintln!("parse_tls_record_with_header failed: {:?}",e); }
}

Note that knowing if a record is plaintext or not is the responsibility of the caller.

As reading TLS records may imply defragmenting records, some functions are provided to only read the record as opaque data (which ensures the record is complete and gives the record header) and then reading messages from data.

Here is an example of two-steps parsing:


// [ 0x16, 0x03, 0x01 ... ];
match parse_tls_raw_record(bytes) {
    Ok((rem, ref r)) => {
        match parse_tls_record_with_header(r.data, &r.hdr) {
            Ok((rem2,ref msg_list)) => {
                for msg in msg_list {
                    // msg has type TlsMessage
                }
            }
            Err(Err::Incomplete(needed)) => { eprintln!("incomplete record") }
            Err(_) => { eprintln!("error while parsing record") }
        }
    }
    Err(Err::Incomplete(needed)) => { eprintln!("incomplete record header") }
    Err(_) => { eprintln!("error while parsing record header") }
}

Some additional work is required if reading packets from the network, to support reassembly of TCP segments and reassembly of TLS records.

For a complete example of a TLS parser supporting defragmentation and states, see the rusticata/src/tls.rs file of the rusticata crate.

State machine

A TLS state machine is provided in tls_states.rs. The state machine is separated from the parsing functions, and is almost independent. It is implemented as a table of transitions, mainly for the handshake phase.

After reading a TLS message using the previous functions, the TLS state can be updated using the tls_state_transition function. If the transition succeeds, it returns Ok(new_state), otherwise it returns Err(error_state).


struct ParseContext {
    state: TlsState,
}

match tls_state_transition(ctx.state, msg, to_server) {
    Ok(s)  => { ctx.state = s; Ok(()) }
    Err(_) => {
        ctx.state = TlsState::Invalid;
        Err("Invalid state")
    }
}

Implementation notes

When parsing messages, if a field is an integer corresponding to an enum of known values, it is not parsed as an enum type, but as an integer. While this complicates accesses, it allows to read invalid values and continue parsing (for an IDS, it’s better to read values than to get a generic parse error).

Re-exports

pub use nom;

Structs

CtExtensions as defined in [RFC6962 Section 3.2] (https://datatracker.ietf.org/doc/html/rfc6962#section-3.2)

LogID as defined in [RFC6962 Section 3.2] (https://datatracker.ietf.org/doc/html/rfc6962#section-3.2)

Certificate Transparency Version as defined in [RFC6962 Section 3.2] (https://datatracker.ietf.org/doc/html/rfc6962#section-3.2)

DTLS Generic handshake message

DTLS Plaintext record

DTLS Plaintext record header

DigitallySigned structure from [RFC2246] section 4.7 has no algorithm definition. This should be deprecated in favor if DigitallySigned structure from [RFC5246] section 4.7

Elliptic curve

Elliptic curve types, as defined in the IANA EC Curve Type Registry Registry

Elliptic curve parameters, defined in RFC4492 section 5.4

EC Point

Elliptic curve parameters, conveyed verbosely as a prime field, as defined in RFC4492 section 5.4

Hash algorithms, as defined in [RFC5246]

Key update request (TLS 1.3)

Named curves, as defined in RFC4492, RFC7027, RFC7919 and IANA Supported Groups Registry

A raw certificate, which should be a DER-encoded X.509 certificate.

Diffie-Hellman parameters, defined in [RFC5246] section 7.4.3

ECDH parameters defined in RFC4492 section 5.4

Signature algorithms, as defined in [RFC5246]

Signature algorithms, as defined in [RFC8446] 4.2.3

Signed Certificate Timestamp as defined in [RFC6962 Section 3.2] (https://datatracker.ietf.org/doc/html/rfc6962#section-3.2)

TLS alert description

TLS alert severity

The certificate chain, usually composed of the certificate, and all required certificate authorities.

Certificate request, as defined in RFC5246 section 7.4.4

Certificate status response, as defined in RFC6066 section 8

TLS Ciphersuite

TLS Client Hello (from TLS 1.0 to TLS 1.2)

Encrypted TLS record (containing opaque data)

TLS encrypted data

TLS extension types, defined in the IANA Transport Layer Security (TLS) Extensions registry

Handshake type

Heartbeat type, as defined in RFC6520 section 3

TLS Hello Retry Request (TLS 1.3)

TLS alert message

TLS application data

TLS heartbeat message, as defined in RFC6520

Session ticket, as defined in RFC5077

Next protocol response, defined in draft-agl-tls-nextprotoneg-03

TLS plaintext record

Tls Record with raw (unparsed) data

TLS record header

Content type, as defined in IANA TLS ContentType registry

TLS Server Hello (from TLS 1.0 to TLS 1.2)

TLS Server Hello (TLS 1.3 draft 18)

Server key exchange parameters

TLS version

Enums

DTLS plaintext message

DTLS Generic handshake message

Elliptic curve parameters content (depending on EC type)

The Err enum indicates the parser was not successful

Error types for the state machine

Authentication methods

Encryption methods

Encryption modes

Key exchange methods

Message Authentication Code (MAC) methods

Client key exchange parameters

TLS extensions

TLS plaintext message

Generic handshake message

TLS machine possible states

Constants

Max record size (RFC8446 5.1)

Statics

Traits

A trait that both TLS & DTLS satisfy

Functions

Parse DigitallySigned object, depending on the ext parameter which should be true if the TLS client has sent the signature_algorithms extension

Parses as single Signed Certificate Timestamp entry

Parses a list of Signed Certificate Timestamp entries

Parse a DTLS alert message

Parse a DTLS changecipherspec message

Parse a DTLS handshake message

Parse one DTLS plaintext record

Parse multiple DTLS plaintext record

Parse DTLS record, leaving fragment unparsed

DTLS record header

Parse the entire input as a list of named groups (curves)

Parse a single TLS Client Hello extension

Parse zero or more TLS Client Hello extensions

Parse one packet only, as encrypted content

Parse a single TLS extension (of any type)

Defined in [RFC7301]

Encrypt-then-MAC is defined in [RFC7366]

Encrypted Server Name, defined in [draft-ietf-tls-esni]

Extended Master Secret is defined in [RFC7627]

Max fragment length [RFC6066]

Max fragment length [RFC6066]

Renegotiation Info, defined in [RFC5746]

Parse ‘Signature Algorithms’ extension (rfc8446, TLS 1.3 only)

Defined in [RFC6962]

Parse zero or more TLS extensions (of any type)

Parse a TLS alert message

Parse a TLS applicationdata message

Parse a TLS changecipherspec message

Parse a TLS handshake message

Parse a TLS heartbeat message

Parse one packet only, as plaintext A single record can contain multiple messages, they must share the same record type

Read TLS record envelope, but do not decode data

Read TLS record header

Given data and a TLS record header, parse content.

Parse a single TLS Server Hello extension

Parse zero or more TLS Server Hello extensions

tls_parserDeprecated

Parse one packet only, as plaintext This function is deprecated. Use parse_tls_plaintext instead.

Parse one chunk of data, possibly containing multiple TLS plaintext records This function is deprecated. Use parse_tls_plaintext instead, checking if there are remaining bytes, and calling parse_tls_plaintext recursively.

Update the TLS state machine, doing one transition

Type Definitions

Holds the result of parsing functions