{"id":26794627,"url":"https://github.com/rusticata/tls-parser","last_synced_at":"2025-04-05T18:05:09.231Z","repository":{"id":11744475,"uuid":"70424624","full_name":"rusticata/tls-parser","owner":"rusticata","description":"TLS parser written in rust with nom","archived":false,"fork":false,"pushed_at":"2024-04-23T10:09:12.000Z","size":452,"stargazers_count":89,"open_issues_count":2,"forks_count":23,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-04-23T10:53:52.158Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rusticata.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-09T19:10:03.000Z","updated_at":"2024-06-19T20:03:22.143Z","dependencies_parsed_at":"2024-06-19T20:03:18.492Z","dependency_job_id":null,"html_url":"https://github.com/rusticata/tls-parser","commit_stats":{"total_commits":253,"total_committers":6,"mean_commits":"42.166666666666664","dds":0.03952569169960474,"last_synced_commit":"36a0022029f104e0b3cc6e9dd18ad3da85b106e0"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rusticata%2Ftls-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rusticata%2Ftls-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rusticata%2Ftls-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rusticata%2Ftls-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rusticata","download_url":"https://codeload.github.com/rusticata/tls-parser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247378135,"owners_count":20929296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-29T17:28:19.813Z","updated_at":"2025-04-05T18:05:09.204Z","avatar_url":"https://github.com/rusticata.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tls-parser\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT)\n[![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE)\n[![Crates.io Version](https://img.shields.io/crates/v/tls-parser.svg)](https://crates.io/crates/tls-parser)\n[![GitHub CI](https://github.com/cpu/tls-parser/actions/workflows/rust.yml/badge.svg)](https://github.com/cpu/tls-parser/actions/workflows/rust.yml)\n[![Minimum rustc version](https://img.shields.io/badge/rustc-1.70.0+-lightgray.svg)](#rust-version-requirements)\n\n# TLS Parser\n\nA TLS parser, implemented with the [nom](https://github.com/Geal/nom)\nparser combinator framework.\n\nThe goal of this parser is to implement TLS messages analysis, for example\nto use rules from a network IDS, for ex during the TLS handshake.\n\nIt implements structures and parsing functions for records and messages, but\nneed additional code to handle fragmentation, or to fully inspect messages.\nParsing some TLS messages requires to know the previously selected parameters.\nSee [the rusticata TLS parser](https://github.com/rusticata/rusticata/blob/master/src/tls.rs)\nfor a full example.\n\nIt is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken\nto ensure security and safety of this crate, including design (recursion limit, defensive\nprogramming), tests, and fuzzing. It also aims to be panic-free.\n\nThe code is available on [Github](https://github.com/rusticata/tls-parser)\nand is part of the [Rusticata](https://github.com/rusticata) project.\n\n## Parsing records\n\nThe main parsing functions are located in the [tls.rs](src/tls.rs) file. The entry functions are:\n- `parse_tls_plaintext`: parses a record as plaintext\n- `parse_tls_encrypted`: read an encrypted record. The parser has no crypto or decryption features, so the content\n  will be left as opaque data.\n\n# Examples\n\n```rust\nuse tls_parser::parse_tls_plaintext;\nuse tls_parser::nom::{Err, IResult};\n\nlet bytes : \u0026[u8]= include_bytes!(\"../assets/client_hello_dhe.bin\");\n// [ 0x16, 0x03, 0x01 ... ];\nlet res = parse_tls_plaintext(\u0026bytes);\nmatch res {\n    Ok((rem,record)) =\u003e {\n        // rem is the remaining data (not parsed)\n        // record is an object of type TlsRecord\n    },\n    Err(Err::Incomplete(needed)) =\u003e {\n        eprintln!(\"Defragmentation required (TLS record)\");\n    },\n    Err(e) =\u003e { eprintln!(\"parse_tls_record_with_header failed: {:?}\",e); }\n}\n```\n\nNote that knowing if a record is plaintext or not is the responsibility of the caller.\n\nAs reading TLS records may imply defragmenting records, some functions are\nprovided to only read the record as opaque data (which ensures the record is\ncomplete and gives the record header) and then reading messages from data.\n\nHere is an example of two-steps parsing:\n\n```rust\n\n// [ 0x16, 0x03, 0x01 ... ];\nmatch parse_tls_raw_record(bytes) {\n    Ok((rem, ref r)) =\u003e {\n        match parse_tls_record_with_header(r.data, \u0026r.hdr) {\n            Ok((rem2,ref msg_list)) =\u003e {\n                for msg in msg_list {\n                    // msg has type TlsMessage\n                }\n            }\n            Err(Err::Incomplete(needed)) =\u003e { eprintln!(\"incomplete record\") }\n            Err(_) =\u003e { eprintln!(\"error while parsing record\") }\n        }\n    }\n    Err(Err::Incomplete(needed)) =\u003e { eprintln!(\"incomplete record header\") }\n    Err(_) =\u003e { eprintln!(\"error while parsing record header\") }\n}\n```\n\nSome additional work is required if reading packets from the network, to support\nreassembly of TCP segments and reassembly of TLS records.\n\nFor a complete example of a TLS parser supporting defragmentation and states, see the\n[rusticata/src/tls.rs](https://github.com/rusticata/rusticata/blob/master/src/tls.rs) file of\nthe [rusticata](https://github.com/rusticata/rusticata) crate.\n\n## State machine\n\nA TLS state machine is provided in [tls_states.rs](src/tls_states.rs). The state machine is separated from the\nparsing functions, and is almost independent.\nIt is implemented as a table of transitions, mainly for the handshake phase.\n\nAfter reading a TLS message using the previous functions, the TLS state can be\nupdated using the `tls_state_transition` function. If the transition succeeds,\nit returns `Ok(new_state)`, otherwise it returns `Err(error_state)`.\n\n```rust\n\nstruct ParseContext {\n    state: TlsState,\n}\n\nmatch tls_state_transition(ctx.state, msg, to_server) {\n    Ok(s)  =\u003e { ctx.state = s; Ok(()) }\n    Err(_) =\u003e {\n        ctx.state = TlsState::Invalid;\n        Err(\"Invalid state\")\n    }\n}\n```\n\n# Implementation notes\n\nWhen parsing messages, if a field is an integer corresponding to an enum of known values,\nit is not parsed as an enum type, but as an integer. While this complicates accesses,\nit allows to read invalid values and continue parsing (for an IDS, it's better to read\nvalues than to get a generic parse error).\n\u003c!-- cargo-sync-readme end --\u003e\n\n## Changes\n\n### 0.12.2\n\n- Reintroduce lifetime in `parse_content_and_signature`, compiler infers a wrong lifetime\n  when elided.\n\n### 0.12.1\n\n- Set MAX_RECORD_LEN to 2^14 + 256 for TLSCipherText (#72)\n- Change parse_content_and_signature definition to elide useless lifetimes\n\n### 0.12.0\n\n- Set MSRV to 1.70 (required by num_enum)\n- Make functions to parse handshake messages public (#66)\n- Cargo: use phf without std if no_std was specified (#56)\n- Fix parsing and export of RFCs for SCSV\n- DTLS fragments as DTLSMessageHandshakeBody::Fragment\n- Update ciphersuites with old drafts + new AEGIS\n- Support SSLv3 ServerHello\n- Improve TlsCipherSuite: add PRF and methods to get parameters\n- Remove `rand_time` from `ClientHello`/`ServerHello` (this is deprecated since a long time, and makes\n  getting the entire random value difficult)\n  To access sub elements, use the `rand_time()` and `rand_bytes()` methods\n\nThanks: Daniel McCarney, Lucas Kent, Andrew Finn, Adrien Guinet, Martin Algesten, Benoit Lemarchand\n\n### 0.11.0\n\n- Upgrade to nom 7\n- Add `ClientHello` trait for common CH attributes\n- Get extensions in DTLS `ClientHello`\n- Add example/helper program to list/query ciphersuite information\n- Add pseudo-entries for `TLS_EMPTY_RENEGOTIATION_INFO_SCSV` and `TLS_FALLBACK_SCSV` (#16)\n- Update ciphersuites file\n- Added parsing for SignedCertificateTimestamp list\n- Re-export nom\n- Add support for `no_std`\n\nThanks: @JackLiar, @xonatius\n\n### 0.10.0\n\n- Upgrade to nom 6\n- Remove all macro-base parsers (use functions, and nom-derive when possible)\n- Add support for DTLS (Handshake)\n- Add functions to parse extensions expected in Client/Server Hello\n\n### 0.9.4\n\n- In ServerHello, an empty SNI extension can be sent (RFC 6066)\n\n### 0.9.3\n\n- Fix error in state machine (wrong Client Certificate direction)\n\n### 0.9.2\n\n- Upgrade to phf 0.8\n- Upgrade cookie-factory to 0.3.0\n\n### 0.9.1\n\n- Mark cookie-factory as optional (only used for serialization)\n\n### 0.9.0\n\n- Upgrade to nom 5\n- Rustfmt\n\n### 0.8.1\n\n- Set edition to 2018\n- Check heartbeat message length (subtraction could underflow)\n- Add more checks for record length (RFC compliance, not for parser safety)\n\n### 0.8.0\n\n- Add support for record size limit extension\n- Add support for encrypted server name (eSNI) extension\n- State machine: use direction and support TLS 1.3 0-RTT\n- State machine: add new state to indicate connection is closed (after fatal alert)\n- Use TlsVersion type for SSL record version\n- Update doc, and use cargo sync-readme\n\n### 0.7.1\n\n- Improve state machine, handle resumption failure, and non-fatal alerts\n- Improve handling of Signature/Hash algorithms, and display\n- Update ciphersuites to 2019-03-19\n\n### 0.7.0\n\n- Convert most enums to newtypes\n  - warning: this is a breaking change\n- Update dependencies and remove unused crates\n- Update ciphersuites to 2019-01-23\n\n### 0.6.0\n\n- Upgrade to nom 4.0\n  - warning: this is a breaking change\n- Fix wrong extension ID for padding and signed timestamp\n- Rewrite parse_cipher_suites and parse_compressions_algs to be faster\n- Update ciphersuites to 2018-08-13\n\n## Standards\nHere is a non-exhaustive list of RFCs this parser is based on:\n- [RFC 2246](https://tools.ietf.org/html/rfc2246): The TLS Protocol Version 1.0\n- [RFC 4346](https://tools.ietf.org/html/rfc4346): The Transport Layer Security (TLS) Protocol Version 1.1\n- [RFC 4366](https://tools.ietf.org/html/rfc4366): Transport Layer Security (TLS) Extensions\n- [RFC 4492](https://tools.ietf.org/html/rfc4492): Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)\n- [RFC 4507](https://tools.ietf.org/html/rfc4507): Transport Layer Security (TLS) Session\n  Resumption without Server-Side State\n- [RFC 5077](https://tools.ietf.org/html/rfc5077): Transport Layer Security (TLS) Session\n  Resumption without Server-Side State\n- [RFC 5246](https://tools.ietf.org/html/rfc5246): The Transport Layer Security (TLS) Protocol Version 1.2\n- [RFC 5430](https://tools.ietf.org/html/rfc5430): Suite B Profile for Transport Layer Security (TLS)\n- [RFC 5746](https://tools.ietf.org/html/rfc5746): Transport Layer Security (TLS) Renegotiation Indication Extension\n- [RFC 6066](https://tools.ietf.org/html/rfc6066): Transport Layer Security (TLS) Extensions: Extension Definitions\n- [RFC 6520](https://tools.ietf.org/html/rfc6520): Transport Layer Security (TLS) and\n  Datagram Transport Layer Security (DTLS) Heartbeat Extension\n- [RFC 6961](https://tools.ietf.org/html/rfc6961): The Transport Layer Security (TLS)\n  Multiple Certificate Status Request Extension\n- [RFC 7027](https://tools.ietf.org/html/rfc7027): Elliptic Curve Cryptography (ECC) Brainpool Curves\n  for Transport Layer Security (TLS)\n- [RFC 7301](https://tools.ietf.org/html/rfc7301): Transport Layer Security (TLS)\n  Application-Layer Protocol Negotiation Extension\n- [RFC 7366](https://tools.ietf.org/html/rfc7366): Encrypt-then-MAC for Transport Layer Security (TLS) and\n  Datagram Transport Layer Security (DTLS)\n- [RFC 7627](https://tools.ietf.org/html/rfc7627): Transport Layer Security (TLS) Session Hash and\n  Extended Master Secret Extension\n- [RFC 7919](https://tools.ietf.org/html/rfc7919): Negotiated Finite Field Diffie-Hellman Ephemeral Parameters\n  for Transport Layer Security (TLS)\n- [RFC 8422](https://tools.ietf.org/html/rfc8422): Elliptic Curve Cryptography (ECC) Cipher Suites\n  for Transport Layer Security (TLS) Versions 1.2 and Earlier\n- [RFC 8446](https://tools.ietf.org/html/rfc8446): The Transport Layer Security (TLS) Protocol Version 1.3\n- [draft-agl-tls-nextprotoneg-03](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03): Transport Layer Security (TLS) Next Protocol Negotiation Extension\n\n## FAQ and limitations\n\n### Can the parser decrypt a TLS session if I provide the master secret ?\n\nNo, it's not implemented\n\n### Does the parser support TLS compression ?\n\nNo. Note that most TLS implementations disabled it after the FREAK attack, so\nwhile detecting compression in `ServerHello` is possible in tls-parser, it\nshould probably be interpreted as an alert.\n\n### Where are located the TLS CipherSuites ?\n\nThey are built when running `cargo build`.\n\nTo ease updating the list from the\n[IANA TLS\nparameters](http://www.iana.org/assignments/tls-parameters/tls-parameters.xml),\na script is provided ([scripts/extract-iana-ciphers.py](scripts/extract-iana-ciphers.py)).\nThis script will download and pre-parse the list from IANA, and produce a file containing\nall ciphersuites names and parameters.\n\nDuring the build, [build.rs](build.rs) parses this file and produces a static,\nread-only hash table of all known ciphers and their properties.\n\n## License\n\nLicensed under either of\n\n * Apache License, Version 2.0\n   ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n * MIT license\n   ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frusticata%2Ftls-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frusticata%2Ftls-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frusticata%2Ftls-parser/lists"}