tls-parser-0.12.2/.gitignore000064400000000000000000000000251046102023000137670ustar 00000000000000.*.swp target /.idea tls-parser-0.12.2/Cargo.lock0000644000000375270000000000100112030ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "anstream" version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "clap" version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "clap_lex" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "cookie-factory" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" dependencies = [ "futures", ] [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "futures" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "futures-sink" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex-literal" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "indexmap" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "nom-derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ff943d68b88d0b87a6e0d58615e8fa07f9fd5a1319fa0a72efc1f62275c79a7" dependencies = [ "nom", "nom-derive-impl", "rustversion", ] [[package]] name = "nom-derive-impl" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd0b9a93a84b0d3ec3e70e02d332dc33ac6dfac9cde63e17fcb77172dededa62" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "num_enum" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.77", ] [[package]] name = "phf" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" dependencies = [ "phf_generator", "phf_shared", ] [[package]] name = "phf_generator" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", ] [[package]] name = "phf_shared" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pretty_assertions" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", "yansi", ] [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rusticata-macros" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ "nom", ] [[package]] name = "rustversion" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tls-parser" version = "0.12.2" dependencies = [ "clap", "cookie-factory", "hex-literal", "nom", "nom-derive", "num_enum", "phf", "phf_codegen", "pretty_assertions", "rusticata-macros", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "toml_datetime", "winnow", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] [[package]] name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" tls-parser-0.12.2/Cargo.toml0000644000000052400000000000100112110ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.63" name = "tls-parser" version = "0.12.2" authors = ["Pierre Chifflier "] build = "build.rs" include = [ "LICENSE-*", ".gitignore", "Cargo.toml", "benches/*.rs", "build.rs", "examples/*.rs", "src/*.rs", "tests/*.rs", "scripts/tls-ciphersuites.txt", "scripts/extract-iana-ciphers.py", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Parser for the TLS protocol" homepage = "https://github.com/rusticata/tls-parser" documentation = "https://docs.rs/tls-parser" readme = "README.md" keywords = [ "TLS", "SSL", "protocol", "parser", "nom", ] categories = [ "network-programming", "parser-implementations", ] license = "MIT/Apache-2.0" repository = "https://github.com/rusticata/tls-parser.git" [package.metadata.cargo_check_external_types] allowed_external_types = [ "nom", "nom::*", "nom_derive::*", "num_enum::*", "phf::map::Map", "rusticata_macros", ] [lib] name = "tls_parser" path = "src/lib.rs" [[example]] name = "get-ciphersuite-info" path = "examples/get-ciphersuite-info.rs" [[test]] name = "certificate_transparency" path = "tests/certificate_transparency.rs" [[test]] name = "tls_dh" path = "tests/tls_dh.rs" [[test]] name = "tls_extensions" path = "tests/tls_extensions.rs" [[test]] name = "tls_handshake" path = "tests/tls_handshake.rs" [[test]] name = "tls_tls13" path = "tests/tls_tls13.rs" [[bench]] name = "bench_dh" path = "benches/bench_dh.rs" [[bench]] name = "bench_handshake" path = "benches/bench_handshake.rs" [dependencies.cookie-factory] version = "0.3" optional = true [dependencies.nom] version = "7.0" [dependencies.nom-derive] version = "0.10" [dependencies.num_enum] version = "0.7.2" [dependencies.phf] version = "0.11" default-features = false [dependencies.rusticata-macros] version = "4.0" [dev-dependencies.clap] version = "4.5" features = ["derive"] [dev-dependencies.hex-literal] version = "0.4" [dev-dependencies.pretty_assertions] version = "1.0" [build-dependencies.phf_codegen] version = "0.11" [features] default = ["std"] serialize = ["cookie-factory"] std = ["phf/std"] unstable = [] tls-parser-0.12.2/Cargo.toml.orig000064400000000000000000000025441046102023000146760ustar 00000000000000[package] description = "Parser for the TLS protocol" license = "MIT/Apache-2.0" keywords = ["TLS","SSL","protocol","parser","nom"] homepage = "https://github.com/rusticata/tls-parser" repository = "https://github.com/rusticata/tls-parser.git" documentation = "https://docs.rs/tls-parser" name = "tls-parser" version = "0.12.2" authors = ["Pierre Chifflier "] categories = ["network-programming", "parser-implementations"] edition = "2018" rust-version = "1.63" readme = "README.md" build = "build.rs" include = [ "LICENSE-*", ".gitignore", "Cargo.toml", "benches/*.rs", "build.rs", "examples/*.rs", "src/*.rs", "tests/*.rs", "scripts/tls-ciphersuites.txt", "scripts/extract-iana-ciphers.py" ] [lib] name = "tls_parser" [features] default = ["std"] serialize = ["cookie-factory"] std = ["phf/std"] unstable = [] [dependencies] cookie-factory = { version="0.3", optional=true } num_enum = "0.7.2" nom = "7.0" nom-derive = "0.10" phf = { version="0.11", default-features=false } rusticata-macros = "4.0" [dev-dependencies] clap = { version="4.5", features = ["derive"]} hex-literal = "0.4" pretty_assertions = "1.0" [build-dependencies] phf_codegen = "0.11" [package.metadata.cargo_check_external_types] allowed_external_types = [ "nom", "nom::*", "nom_derive::*", "num_enum::*", "phf::map::Map", "rusticata_macros", ] tls-parser-0.12.2/LICENSE-APACHE000064400000000000000000000251371046102023000137360ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. tls-parser-0.12.2/LICENSE-MIT000064400000000000000000000020441046102023000134360ustar 00000000000000Copyright (c) 2017 Pierre Chifflier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tls-parser-0.12.2/README.md000064400000000000000000000274511046102023000132720ustar 00000000000000# tls-parser [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT) [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE) [![Crates.io Version](https://img.shields.io/crates/v/tls-parser.svg)](https://crates.io/crates/tls-parser) [![GitHub CI](https://github.com/cpu/tls-parser/actions/workflows/rust.yml/badge.svg)](https://github.com/cpu/tls-parser/actions/workflows/rust.yml) [![Minimum rustc version](https://img.shields.io/badge/rustc-1.70.0+-lightgray.svg)](#rust-version-requirements) # TLS Parser A TLS parser, implemented with the [nom](https://github.com/Geal/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](https://github.com/rusticata/rusticata/blob/master/src/tls.rs) 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](https://github.com/rusticata/tls-parser) and is part of the [Rusticata](https://github.com/rusticata) project. ## Parsing records The main parsing functions are located in the [tls.rs](src/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 ```rust 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: ```rust // [ 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](https://github.com/rusticata/rusticata/blob/master/src/tls.rs) file of the [rusticata](https://github.com/rusticata/rusticata) crate. ## State machine A TLS state machine is provided in [tls_states.rs](src/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)`. ```rust 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). ## Changes ### 0.12.2 - Reintroduce lifetime in `parse_content_and_signature`, compiler infers a wrong lifetime when elided. ### 0.12.1 - Set MAX_RECORD_LEN to 2^14 + 256 for TLSCipherText (#72) - Change parse_content_and_signature definition to elide useless lifetimes ### 0.12.0 - Set MSRV to 1.70 (required by num_enum) - Make functions to parse handshake messages public (#66) - Cargo: use phf without std if no_std was specified (#56) - Fix parsing and export of RFCs for SCSV - DTLS fragments as DTLSMessageHandshakeBody::Fragment - Update ciphersuites with old drafts + new AEGIS - Support SSLv3 ServerHello - Improve TlsCipherSuite: add PRF and methods to get parameters - Remove `rand_time` from `ClientHello`/`ServerHello` (this is deprecated since a long time, and makes getting the entire random value difficult) To access sub elements, use the `rand_time()` and `rand_bytes()` methods Thanks: Daniel McCarney, Lucas Kent, Andrew Finn, Adrien Guinet, Martin Algesten, Benoit Lemarchand ### 0.11.0 - Upgrade to nom 7 - Add `ClientHello` trait for common CH attributes - Get extensions in DTLS `ClientHello` - Add example/helper program to list/query ciphersuite information - Add pseudo-entries for `TLS_EMPTY_RENEGOTIATION_INFO_SCSV` and `TLS_FALLBACK_SCSV` (#16) - Update ciphersuites file - Added parsing for SignedCertificateTimestamp list - Re-export nom - Add support for `no_std` Thanks: @JackLiar, @xonatius ### 0.10.0 - Upgrade to nom 6 - Remove all macro-base parsers (use functions, and nom-derive when possible) - Add support for DTLS (Handshake) - Add functions to parse extensions expected in Client/Server Hello ### 0.9.4 - In ServerHello, an empty SNI extension can be sent (RFC 6066) ### 0.9.3 - Fix error in state machine (wrong Client Certificate direction) ### 0.9.2 - Upgrade to phf 0.8 - Upgrade cookie-factory to 0.3.0 ### 0.9.1 - Mark cookie-factory as optional (only used for serialization) ### 0.9.0 - Upgrade to nom 5 - Rustfmt ### 0.8.1 - Set edition to 2018 - Check heartbeat message length (subtraction could underflow) - Add more checks for record length (RFC compliance, not for parser safety) ### 0.8.0 - Add support for record size limit extension - Add support for encrypted server name (eSNI) extension - State machine: use direction and support TLS 1.3 0-RTT - State machine: add new state to indicate connection is closed (after fatal alert) - Use TlsVersion type for SSL record version - Update doc, and use cargo sync-readme ### 0.7.1 - Improve state machine, handle resumption failure, and non-fatal alerts - Improve handling of Signature/Hash algorithms, and display - Update ciphersuites to 2019-03-19 ### 0.7.0 - Convert most enums to newtypes - warning: this is a breaking change - Update dependencies and remove unused crates - Update ciphersuites to 2019-01-23 ### 0.6.0 - Upgrade to nom 4.0 - warning: this is a breaking change - Fix wrong extension ID for padding and signed timestamp - Rewrite parse_cipher_suites and parse_compressions_algs to be faster - Update ciphersuites to 2018-08-13 ## Standards Here is a non-exhaustive list of RFCs this parser is based on: - [RFC 2246](https://tools.ietf.org/html/rfc2246): The TLS Protocol Version 1.0 - [RFC 4346](https://tools.ietf.org/html/rfc4346): The Transport Layer Security (TLS) Protocol Version 1.1 - [RFC 4366](https://tools.ietf.org/html/rfc4366): Transport Layer Security (TLS) Extensions - [RFC 4492](https://tools.ietf.org/html/rfc4492): Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS) - [RFC 4507](https://tools.ietf.org/html/rfc4507): Transport Layer Security (TLS) Session Resumption without Server-Side State - [RFC 5077](https://tools.ietf.org/html/rfc5077): Transport Layer Security (TLS) Session Resumption without Server-Side State - [RFC 5246](https://tools.ietf.org/html/rfc5246): The Transport Layer Security (TLS) Protocol Version 1.2 - [RFC 5430](https://tools.ietf.org/html/rfc5430): Suite B Profile for Transport Layer Security (TLS) - [RFC 5746](https://tools.ietf.org/html/rfc5746): Transport Layer Security (TLS) Renegotiation Indication Extension - [RFC 6066](https://tools.ietf.org/html/rfc6066): Transport Layer Security (TLS) Extensions: Extension Definitions - [RFC 6520](https://tools.ietf.org/html/rfc6520): Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS) Heartbeat Extension - [RFC 6961](https://tools.ietf.org/html/rfc6961): The Transport Layer Security (TLS) Multiple Certificate Status Request Extension - [RFC 7027](https://tools.ietf.org/html/rfc7027): Elliptic Curve Cryptography (ECC) Brainpool Curves for Transport Layer Security (TLS) - [RFC 7301](https://tools.ietf.org/html/rfc7301): Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension - [RFC 7366](https://tools.ietf.org/html/rfc7366): Encrypt-then-MAC for Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS) - [RFC 7627](https://tools.ietf.org/html/rfc7627): Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension - [RFC 7919](https://tools.ietf.org/html/rfc7919): Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security (TLS) - [RFC 8422](https://tools.ietf.org/html/rfc8422): Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS) Versions 1.2 and Earlier - [RFC 8446](https://tools.ietf.org/html/rfc8446): The Transport Layer Security (TLS) Protocol Version 1.3 - [draft-agl-tls-nextprotoneg-03](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03): Transport Layer Security (TLS) Next Protocol Negotiation Extension ## FAQ and limitations ### Can the parser decrypt a TLS session if I provide the master secret ? No, it's not implemented ### Does the parser support TLS compression ? No. Note that most TLS implementations disabled it after the FREAK attack, so while detecting compression in `ServerHello` is possible in tls-parser, it should probably be interpreted as an alert. ### Where are located the TLS CipherSuites ? They are built when running `cargo build`. To ease updating the list from the [IANA TLS parameters](http://www.iana.org/assignments/tls-parameters/tls-parameters.xml), a script is provided ([scripts/extract-iana-ciphers.py](scripts/extract-iana-ciphers.py)). This script will download and pre-parse the list from IANA, and produce a file containing all ciphersuites names and parameters. During the build, [build.rs](build.rs) parses this file and produces a static, read-only hash table of all known ciphers and their properties. ## License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. tls-parser-0.12.2/benches/bench_dh.rs000064400000000000000000000060241046102023000155130ustar 00000000000000#![cfg(all(feature = "unstable", test))] #![feature(test)] extern crate test; extern crate nom; extern crate tls_parser; mod tls_dh { use nom::sequence::pair; use test::Bencher; use tls_parser::*; #[rustfmt::skip] static ECDHE_PARAMS: &[u8] = &[ 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0xd1, 0x50, 0x12, 0xf4, 0xc4, 0xcf, 0xd4, 0xc2, 0x1f, 0xe8, 0xf6, 0x85, 0xdc, 0xde, 0x0b, 0xeb, 0x3c, 0x0d, 0x0f, 0x97, 0x29, 0x36, 0x63, 0xc6, 0xc1, 0x3b, 0xfd, 0x38, 0xce, 0xde, 0x43, 0x7f, 0x7d, 0x57, 0x64, 0x54, 0x6f, 0x89, 0x3c, 0xe7, 0x5e, 0x28, 0x9e, 0x9d, 0x24, 0xca, 0x07, 0x63, 0xd5, 0x03, 0x30, 0x8b, 0xd8, 0x1a, 0xae, 0xb6, 0xa8, 0x5f, 0x10, 0x87, 0x81, 0x29, 0x1b, 0xef, 0xbd, 0x00, 0xeb, 0x29, 0x37, 0xb3, 0xc3, 0xda, 0x8e, 0xad, 0xf3, 0x9c, 0x10, 0xe3, 0x93, 0xeb, 0x0a, 0x53, 0x14, 0xea, 0x3c, 0x05, 0xb7, 0xc1, 0x6b, 0x79, 0xca, 0xfc, 0x9a, 0x5b, 0xc3, 0xaf, 0xf2, 0xdd, 0x9f, 0xdd, 0x07, 0xf5, 0x07, 0xef, 0xb4, 0x24, 0xac, 0xdb, 0xd2, 0x0d, 0x65, 0x37, 0x96, 0xa0, 0x15, 0xef, 0x7c, 0x6d, 0x66, 0x63, 0x0d, 0x41, 0x1d, 0xd7, 0x90, 0x05, 0x66, 0xcf, 0x79, 0x0c, 0x03, 0x02, 0x01, 0x01, 0x00, 0x7c, 0xa7, 0x5f, 0x73, 0x77, 0x2c, 0x92, 0x4c, 0xe4, 0xa7, 0x67, 0x86, 0x76, 0xf2, 0xa3, 0xf8, 0xd1, 0x9d, 0xca, 0x4f, 0x71, 0xd1, 0x67, 0xf4, 0xbe, 0x7e, 0xb3, 0x60, 0xc4, 0xf1, 0x6e, 0x90, 0x22, 0x97, 0xe9, 0xc2, 0x43, 0xc9, 0xfb, 0x46, 0x21, 0xd4, 0xe9, 0xed, 0xdc, 0x46, 0x5b, 0x3e, 0x4c, 0xfb, 0xf2, 0xeb, 0x3f, 0x09, 0x4e, 0x59, 0x5f, 0x6f, 0x60, 0x50, 0x8a, 0x80, 0x50, 0xa7, 0xc3, 0xb9, 0xf0, 0xd1, 0x80, 0xb0, 0x1b, 0x11, 0x53, 0xe4, 0xac, 0x45, 0xa8, 0x75, 0x59, 0x55, 0x1a, 0x20, 0xa5, 0xbb, 0x23, 0xb6, 0x1c, 0x39, 0xa8, 0x4e, 0x62, 0x57, 0xef, 0x4f, 0x11, 0xce, 0x64, 0x87, 0x9b, 0x5a, 0xb8, 0x06, 0xf1, 0x62, 0x63, 0x3d, 0x13, 0x46, 0x72, 0x79, 0x7e, 0x65, 0x5c, 0xb4, 0x0a, 0xe3, 0x63, 0x13, 0x05, 0xc9, 0xaa, 0xc3, 0x93, 0x9b, 0x69, 0x37, 0x04, 0xa6, 0x7b, 0x69, 0xa9, 0x72, 0x67, 0x32, 0x9d, 0xc9, 0x53, 0x05, 0xe5, 0x18, 0x00, 0x73, 0xcb, 0x40, 0xd8, 0x86, 0x81, 0x01, 0x78, 0x36, 0x8f, 0x62, 0x94, 0xb4, 0x88, 0x27, 0xdb, 0x8e, 0xe4, 0x76, 0x56, 0x1d, 0xac, 0x7d, 0x36, 0x4c, 0xb4, 0xad, 0x4c, 0xe0, 0x21, 0x1f, 0xd5, 0x2d, 0x30, 0xa0, 0x78, 0xba, 0x28, 0x0b, 0xb4, 0x6d, 0xf1, 0x95, 0x41, 0x11, 0xdb, 0x64, 0xaf, 0x11, 0xa2, 0x9b, 0x45, 0x07, 0x42, 0x95, 0xf1, 0xe4, 0x0a, 0x16, 0x0c, 0x7f, 0xa7, 0x96, 0xc1, 0x91, 0xf0, 0x7c, 0xf7, 0x67, 0xe6, 0x1c, 0xbd, 0x1d, 0xcb, 0xbc, 0x42, 0x2a, 0x47, 0x35, 0x28, 0x96, 0xc3, 0x08, 0x48, 0x7d, 0xe9, 0xf1, 0x42, 0x00, 0xee, 0xd5, 0x0e, 0xd4, 0x08, 0xd6, 0x34, 0x15, 0xd6, 0x7c, 0x4b, 0xc5, 0x23, 0xf4, 0x8c, 0xfa, 0x70, 0xd8, 0x60, 0x46, 0xd2, 0xa3, 0xba, 0x75, 0xa4, 0x8f ]; #[bench] fn bench_tls_ecdhe_params(b: &mut Bencher) { let bytes = ECDHE_PARAMS; b.iter(|| { let _ = pair(parse_ecdh_params, parse_digitally_signed)(bytes); }) } } // mod tls_dh tls-parser-0.12.2/benches/bench_handshake.rs000064400000000000000000000643251046102023000170560ustar 00000000000000#![cfg(feature = "unstable")] #![cfg(all(feature = "unstable", test))] #![feature(test)] extern crate test; extern crate nom; extern crate tls_parser; mod tls_handshake { use test::Bencher; use tls_parser::*; #[rustfmt::skip] static CH: &[u8] = &[ 0x16, 0x03, 0x01, 0x01, 0x2c, 0x01, 0x00, 0x01, 0x28, 0x03, 0x03, 0xb2, 0x9d, 0xd7, 0x87, 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, 0x00, 0x00, 0xaa, 0xc0, 0x30, 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x0a, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39, 0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88, 0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32, 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f, 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x84, 0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x09, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e, 0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30, 0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97, 0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42, 0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0x00, 0xff, 0x01, 0x00, 0x00, 0x55, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x0f, 0x00, 0x01, 0x01 ]; #[bench] fn bench_tls_record_clienthello(b: &mut Bencher) { b.iter(|| { let _ = parse_tls_plaintext(CH); }) } // tls response, composed of 4 records: // - Server Hello // - Server Certificate // - Server Key Exchange // - Server Hello Done #[rustfmt::skip] static SERVER_REPLY1: &[u8] = &[ 0x16, 0x03, 0x03, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x37, 0x03, 0x03, 0x57, 0xc4, 0x57, 0xda, 0x9c, 0xd3, 0x24, 0x6d, 0x9d, 0x02, 0x26, 0xa2, 0xe5, 0x9a, 0xe8, 0xa5, 0x6f, 0x40, 0xad, 0x94, 0x30, 0xba, 0x49, 0x05, 0x3a, 0x1e, 0x1b, 0xe1, 0x94, 0xa1, 0xba, 0x41, 0x00, 0xc0, 0x2f, 0x00, 0x00, 0x0f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16, 0x03, 0x03, 0x0c, 0x09, 0x0b, 0x00, 0x0c, 0x05, 0x00, 0x0c, 0x02, 0x00, 0x04, 0x84, 0x30, 0x82, 0x04, 0x80, 0x30, 0x82, 0x03, 0x68, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x52, 0x1a, 0x61, 0xda, 0x68, 0xb6, 0xe6, 0x35, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x31, 0x37, 0x31, 0x38, 0x34, 0x39, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x30, 0x39, 0x31, 0x38, 0x32, 0x39, 0x30, 0x30, 0x5a, 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9b, 0x5b, 0x36, 0xcc, 0xce, 0x8c, 0x39, 0x86, 0xbd, 0x05, 0x2f, 0xc3, 0xff, 0x4c, 0x59, 0xa8, 0xfc, 0xe4, 0x6e, 0x0f, 0xc6, 0xbf, 0x23, 0xf6, 0x35, 0xc5, 0x3b, 0xcc, 0xc9, 0x61, 0x2f, 0x60, 0x11, 0x9b, 0x7a, 0x44, 0xd2, 0xd0, 0xd9, 0x62, 0x11, 0x09, 0xbe, 0x08, 0x53, 0x24, 0x73, 0xd9, 0x5f, 0x5e, 0xb0, 0x6f, 0x05, 0x3f, 0x53, 0xa3, 0x2d, 0x98, 0xa4, 0xf4, 0xaf, 0x23, 0x25, 0xb8, 0x80, 0xbc, 0xcc, 0xde, 0xa2, 0x56, 0xcb, 0x6f, 0x9d, 0x1a, 0xda, 0xa5, 0xbe, 0xb0, 0x8a, 0xdc, 0xcf, 0x30, 0xef, 0xe0, 0x68, 0x97, 0xc5, 0x70, 0xad, 0xcf, 0x10, 0x5b, 0xb6, 0x92, 0x98, 0x61, 0x57, 0x3d, 0xbf, 0x3f, 0xd0, 0x5d, 0xbc, 0x76, 0x23, 0xc8, 0xce, 0x35, 0x6d, 0x25, 0x1f, 0x11, 0x5a, 0x4b, 0x76, 0x36, 0xca, 0xd4, 0x57, 0x7e, 0x95, 0x7f, 0x78, 0xfb, 0x2c, 0xe0, 0x9a, 0xbf, 0x64, 0xc6, 0x43, 0x7b, 0xcd, 0xfa, 0x0e, 0xaa, 0x4f, 0x6a, 0xda, 0x04, 0xa4, 0xf5, 0xfa, 0x2d, 0xea, 0xac, 0xc3, 0xa7, 0xf4, 0xd3, 0x7c, 0x57, 0xd4, 0xb8, 0x2c, 0xcb, 0xe0, 0xd5, 0x26, 0x3b, 0x2d, 0x64, 0x0d, 0x20, 0x5a, 0xd5, 0xe4, 0x1a, 0x6e, 0x3a, 0x6a, 0x23, 0xb1, 0x0a, 0xc6, 0x33, 0xee, 0x49, 0x66, 0x13, 0x38, 0x58, 0x76, 0x53, 0x84, 0x4a, 0x8a, 0xaa, 0x77, 0x8e, 0xa8, 0x38, 0xfb, 0xe9, 0x4d, 0xd0, 0x02, 0xf9, 0x7b, 0xf3, 0x67, 0x94, 0xe0, 0x58, 0x9e, 0x04, 0xc1, 0x3b, 0xd8, 0x2b, 0x89, 0x5f, 0x57, 0xf3, 0xb5, 0xf3, 0x41, 0x63, 0x7a, 0x32, 0x98, 0x5e, 0x18, 0x29, 0x04, 0xb7, 0x64, 0xbe, 0x91, 0xf9, 0x15, 0xf7, 0x34, 0x23, 0x0f, 0x4d, 0xd1, 0xeb, 0x80, 0xe9, 0xad, 0xb3, 0x65, 0xc1, 0xcd, 0x7e, 0x68, 0x3f, 0x9b, 0x0c, 0x6d, 0xb2, 0xbf, 0x16, 0x11, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x4b, 0x30, 0x82, 0x01, 0x47, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x19, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x12, 0x30, 0x10, 0x82, 0x0e, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2e, 0x67, 0x92, 0x22, 0x0f, 0xd3, 0xd5, 0xd1, 0xd6, 0x0a, 0x21, 0xf5, 0x3e, 0x2b, 0xe7, 0x87, 0xbe, 0xaf, 0x37, 0x9b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7d, 0x0e, 0x9e, 0x7b, 0xf0, 0x81, 0xd6, 0x19, 0xa5, 0xc1, 0xe3, 0xd4, 0x16, 0xad, 0x17, 0x74, 0x76, 0x80, 0x97, 0x9c, 0x96, 0x7b, 0xfb, 0x8e, 0x3a, 0x12, 0x14, 0x25, 0x48, 0xb9, 0xed, 0x46, 0xc9, 0x07, 0xc6, 0xd9, 0xfd, 0x06, 0xba, 0x9f, 0x66, 0xd6, 0x1c, 0xe4, 0xbb, 0xcb, 0x76, 0x44, 0x95, 0x31, 0x76, 0x4c, 0xfb, 0xb5, 0xad, 0xc7, 0xf0, 0x6a, 0xfa, 0x30, 0xc3, 0x58, 0xa1, 0x8b, 0xcc, 0xe2, 0x70, 0xbb, 0x8a, 0x78, 0x5e, 0x41, 0x60, 0x1e, 0xda, 0x69, 0xc3, 0xcb, 0x9f, 0xa2, 0x10, 0xff, 0x20, 0xfc, 0xa4, 0x35, 0xdb, 0x32, 0xcb, 0x26, 0xba, 0xc0, 0xcf, 0x3f, 0x5c, 0x86, 0x78, 0x2c, 0xaa, 0x73, 0x39, 0xf9, 0x8c, 0xfd, 0xa6, 0x9a, 0x8e, 0x3f, 0x5d, 0x7d, 0x8c, 0x7c, 0x3a, 0xe7, 0xbe, 0x69, 0x73, 0xa8, 0x06, 0x5d, 0x56, 0xe3, 0xe2, 0x80, 0x0d, 0x99, 0xcc, 0x4d, 0x5f, 0x7e, 0xfb, 0x62, 0xd8, 0xcf, 0x55, 0x2d, 0xbc, 0x9f, 0xef, 0xa7, 0xe6, 0x46, 0xda, 0xc9, 0x66, 0x07, 0x0e, 0x13, 0x4d, 0x61, 0xb3, 0x85, 0xf3, 0x72, 0x6d, 0x41, 0xfe, 0x7b, 0xaa, 0xe7, 0xaf, 0xff, 0x61, 0xd9, 0xc6, 0x6c, 0x84, 0x6c, 0x1a, 0x9e, 0xda, 0x86, 0x15, 0xbc, 0x2a, 0xae, 0x84, 0x14, 0x94, 0x67, 0x95, 0xc4, 0xda, 0x35, 0x29, 0x8e, 0x80, 0x23, 0xc0, 0x4a, 0xdd, 0x0e, 0xb3, 0xb1, 0x7d, 0xc7, 0x3d, 0xea, 0x2c, 0x41, 0xb2, 0xed, 0xb4, 0x8b, 0x65, 0xd3, 0x62, 0x81, 0x0a, 0x25, 0x0c, 0x3b, 0xc9, 0x11, 0xa2, 0x50, 0x1f, 0xd0, 0xe9, 0x37, 0x9f, 0xa0, 0x7a, 0x34, 0x01, 0xdf, 0x32, 0x58, 0x3b, 0xf5, 0x4b, 0xd8, 0xab, 0x11, 0x5a, 0x9a, 0x1b, 0x83, 0x43, 0x06, 0xf4, 0x40, 0x1e, 0x5b, 0x92, 0xe8, 0x94, 0x0a, 0xbc, 0x57, 0x2f, 0x19, 0x69, 0xc6, 0xd2, 0x8b, 0x00, 0x03, 0xf4, 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x02, 0x3a, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3, 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a, 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a, 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f, 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1, 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4, 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53, 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f, 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73, 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b, 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb, 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4, 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19, 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65, 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80, 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99, 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75, 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e, 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf, 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2, 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37, 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, 0x4e, 0x04, 0xa7, 0x80, 0x7f, 0x10, 0x16, 0x43, 0x5e, 0x02, 0xad, 0xd7, 0x42, 0x80, 0xf4, 0xb0, 0x8e, 0xd2, 0xae, 0xb3, 0xeb, 0x11, 0x7d, 0x90, 0x84, 0x18, 0x7d, 0xe7, 0x90, 0x15, 0xfb, 0x49, 0x7f, 0xa8, 0x99, 0x05, 0x91, 0xbb, 0x7a, 0xc9, 0xd6, 0x3c, 0x37, 0x18, 0x09, 0x9a, 0xb6, 0xc7, 0x92, 0x20, 0x07, 0x35, 0x33, 0x09, 0xe4, 0x28, 0x63, 0x72, 0x0d, 0xb4, 0xe0, 0x32, 0x9c, 0x87, 0x98, 0xc4, 0x1b, 0x76, 0x89, 0x67, 0xc1, 0x50, 0x58, 0xb0, 0x13, 0xaa, 0x13, 0x1a, 0x1b, 0x32, 0xa5, 0xbe, 0xea, 0x11, 0x95, 0x4c, 0x48, 0x63, 0x49, 0xe9, 0x99, 0x5d, 0x20, 0x37, 0xcc, 0xfe, 0x2a, 0x69, 0x51, 0x16, 0x95, 0x4b, 0xa9, 0xde, 0x49, 0x82, 0xc0, 0x10, 0x70, 0xf4, 0x2c, 0xf3, 0xec, 0xbc, 0x24, 0x24, 0xd0, 0x4e, 0xac, 0xa5, 0xd9, 0x5e, 0x1e, 0x6d, 0x92, 0xc1, 0xa7, 0xac, 0x48, 0x35, 0x81, 0xf9, 0xe5, 0xe4, 0x9c, 0x65, 0x69, 0xcd, 0x87, 0xa4, 0x41, 0x50, 0x3f, 0x2e, 0x57, 0xa5, 0x91, 0x51, 0x12, 0x58, 0x0e, 0x8c, 0x09, 0xa1, 0xac, 0x7a, 0xa4, 0x12, 0xa5, 0x27, 0xf3, 0x9a, 0x10, 0x97, 0x7d, 0x55, 0x03, 0x06, 0xf7, 0x66, 0x58, 0x5f, 0x5f, 0x64, 0xe1, 0xab, 0x5d, 0x6d, 0xa5, 0x39, 0x48, 0x75, 0x98, 0x4c, 0x29, 0x5a, 0x3a, 0x8d, 0xd3, 0x2b, 0xca, 0x9c, 0x55, 0x04, 0xbf, 0xf4, 0xe6, 0x14, 0xd5, 0x80, 0xac, 0x26, 0xed, 0x17, 0x89, 0xa6, 0x93, 0x6c, 0x5c, 0xa4, 0xcc, 0xb8, 0xf0, 0x66, 0x8e, 0x64, 0xe3, 0x7d, 0x9a, 0xe2, 0x00, 0xb3, 0x49, 0xc7, 0xe4, 0x0a, 0xaa, 0xdd, 0x5b, 0x83, 0xc7, 0x70, 0x90, 0x46, 0x4e, 0xbe, 0xd0, 0xdb, 0x59, 0x96, 0x6c, 0x2e, 0xf5, 0x16, 0x36, 0xde, 0x71, 0xcc, 0x01, 0xc2, 0x12, 0xc1, 0x21, 0xc6, 0x16, 0x00, 0x03, 0x81, 0x30, 0x82, 0x03, 0x7d, 0x30, 0x82, 0x02, 0xe6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x12, 0xbb, 0xe6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x32, 0x30, 0x35, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x38, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0xcc, 0x18, 0x63, 0x30, 0xfd, 0xf4, 0x17, 0x23, 0x1a, 0x56, 0x7e, 0x5b, 0xdf, 0x3c, 0x6c, 0x38, 0xe4, 0x71, 0xb7, 0x78, 0x91, 0xd4, 0xbc, 0xa1, 0xd8, 0x4c, 0xf8, 0xa8, 0x43, 0xb6, 0x03, 0xe9, 0x4d, 0x21, 0x07, 0x08, 0x88, 0xda, 0x58, 0x2f, 0x66, 0x39, 0x29, 0xbd, 0x05, 0x78, 0x8b, 0x9d, 0x38, 0xe8, 0x05, 0xb7, 0x6a, 0x7e, 0x71, 0xa4, 0xe6, 0xc4, 0x60, 0xa6, 0xb0, 0xef, 0x80, 0xe4, 0x89, 0x28, 0x0f, 0x9e, 0x25, 0xd6, 0xed, 0x83, 0xf3, 0xad, 0xa6, 0x91, 0xc7, 0x98, 0xc9, 0x42, 0x18, 0x35, 0x14, 0x9d, 0xad, 0x98, 0x46, 0x92, 0x2e, 0x4f, 0xca, 0xf1, 0x87, 0x43, 0xc1, 0x16, 0x95, 0x57, 0x2d, 0x50, 0xef, 0x89, 0x2d, 0x80, 0x7a, 0x57, 0xad, 0xf2, 0xee, 0x5f, 0x6b, 0xd2, 0x00, 0x8d, 0xb9, 0x14, 0xf8, 0x14, 0x15, 0x35, 0xd9, 0xc0, 0x46, 0xa3, 0x7b, 0x72, 0xc8, 0x91, 0xbf, 0xc9, 0x55, 0x2b, 0xcd, 0xd0, 0x97, 0x3e, 0x9c, 0x26, 0x64, 0xcc, 0xdf, 0xce, 0x83, 0x19, 0x71, 0xca, 0x4e, 0xe6, 0xd4, 0xd5, 0x7b, 0xa9, 0x19, 0xcd, 0x55, 0xde, 0xc8, 0xec, 0xd2, 0x5e, 0x38, 0x53, 0xe5, 0x5c, 0x4f, 0x8c, 0x2d, 0xfe, 0x50, 0x23, 0x36, 0xfc, 0x66, 0xe6, 0xcb, 0x8e, 0xa4, 0x39, 0x19, 0x00, 0xb7, 0x95, 0x02, 0x39, 0x91, 0x0b, 0x0e, 0xfe, 0x38, 0x2e, 0xd1, 0x1d, 0x05, 0x9a, 0xf6, 0x4d, 0x3e, 0x6f, 0x0f, 0x07, 0x1d, 0xaf, 0x2c, 0x1e, 0x8f, 0x60, 0x39, 0xe2, 0xfa, 0x36, 0x53, 0x13, 0x39, 0xd4, 0x5e, 0x26, 0x2b, 0xdb, 0x3d, 0xa8, 0x14, 0xbd, 0x32, 0xeb, 0x18, 0x03, 0x28, 0x52, 0x04, 0x71, 0xe5, 0xab, 0x33, 0x3d, 0xe1, 0x38, 0xbb, 0x07, 0x36, 0x84, 0x62, 0x9c, 0x79, 0xea, 0x16, 0x30, 0xf4, 0x5f, 0xc0, 0x2b, 0xe8, 0x71, 0x6b, 0xe4, 0xf9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xf0, 0x30, 0x81, 0xed, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x48, 0xe6, 0x68, 0xf9, 0x2b, 0xd2, 0xb2, 0x95, 0xd7, 0x47, 0xd8, 0x23, 0x20, 0x10, 0x4f, 0x33, 0x98, 0x90, 0x9f, 0xd4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4e, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x47, 0x30, 0x45, 0x30, 0x43, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x76, 0xe1, 0x12, 0x6e, 0x4e, 0x4b, 0x16, 0x12, 0x86, 0x30, 0x06, 0xb2, 0x81, 0x08, 0xcf, 0xf0, 0x08, 0xc7, 0xc7, 0x71, 0x7e, 0x66, 0xee, 0xc2, 0xed, 0xd4, 0x3b, 0x1f, 0xff, 0xf0, 0xf0, 0xc8, 0x4e, 0xd6, 0x43, 0x38, 0xb0, 0xb9, 0x30, 0x7d, 0x18, 0xd0, 0x55, 0x83, 0xa2, 0x6a, 0xcb, 0x36, 0x11, 0x9c, 0xe8, 0x48, 0x66, 0xa3, 0x6d, 0x7f, 0xb8, 0x13, 0xd4, 0x47, 0xfe, 0x8b, 0x5a, 0x5c, 0x73, 0xfc, 0xae, 0xd9, 0x1b, 0x32, 0x19, 0x38, 0xab, 0x97, 0x34, 0x14, 0xaa, 0x96, 0xd2, 0xeb, 0xa3, 0x1c, 0x14, 0x08, 0x49, 0xb6, 0xbb, 0xe5, 0x91, 0xef, 0x83, 0x36, 0xeb, 0x1d, 0x56, 0x6f, 0xca, 0xda, 0xbc, 0x73, 0x63, 0x90, 0xe4, 0x7f, 0x7b, 0x3e, 0x22, 0xcb, 0x3d, 0x07, 0xed, 0x5f, 0x38, 0x74, 0x9c, 0xe3, 0x03, 0x50, 0x4e, 0xa1, 0xaf, 0x98, 0xee, 0x61, 0xf2, 0x84, 0x3f, 0x12, 0x16, 0x03, 0x03, 0x01, 0x4d, 0x0c, 0x00, 0x01, 0x49, 0x03, 0x00, 0x17, 0x41, 0x04, 0x27, 0x7e, 0x6c, 0x81, 0xf1, 0xb4, 0xb5, 0x60, 0x22, 0x45, 0x9b, 0x26, 0x4f, 0xb8, 0xa8, 0xbd, 0xd2, 0x91, 0x88, 0x9b, 0xe0, 0xe8, 0x41, 0x4d, 0x7c, 0xab, 0xcf, 0xf7, 0x3f, 0x8f, 0x23, 0xd1, 0x18, 0xdd, 0xb7, 0x27, 0xbd, 0xcf, 0xd3, 0x14, 0x71, 0xca, 0xf9, 0x7e, 0xb8, 0xe8, 0x15, 0x59, 0xa2, 0x97, 0x66, 0x27, 0x45, 0xc3, 0x40, 0xf7, 0xa8, 0x77, 0x61, 0x05, 0x9b, 0xb2, 0xa9, 0xd0, 0x06, 0x01, 0x01, 0x00, 0x6e, 0xd0, 0x13, 0x15, 0x52, 0x29, 0xdb, 0x2c, 0x60, 0x3c, 0x2d, 0xf3, 0x6f, 0xc5, 0xac, 0x44, 0x53, 0x47, 0x3b, 0x17, 0xbc, 0xaf, 0xaa, 0x9f, 0x5d, 0xf5, 0x2e, 0x7a, 0x9c, 0x32, 0x58, 0xb5, 0x37, 0x1a, 0xce, 0x4c, 0x12, 0x9e, 0x47, 0xf0, 0xfd, 0x85, 0x38, 0x39, 0xc1, 0xec, 0xd8, 0x06, 0xc8, 0x84, 0x87, 0x03, 0xfa, 0x41, 0xf9, 0x88, 0xa0, 0xef, 0x84, 0x87, 0x76, 0x6e, 0x61, 0xfc, 0x1c, 0x78, 0xd8, 0x70, 0xa8, 0x65, 0x3a, 0x1e, 0x84, 0xac, 0x14, 0x78, 0x74, 0x18, 0x7f, 0xdd, 0x35, 0x2e, 0x99, 0xd8, 0x3d, 0x68, 0x66, 0x16, 0x7a, 0x83, 0x16, 0xa6, 0x21, 0x18, 0x71, 0x6f, 0x58, 0x32, 0x60, 0xa3, 0x70, 0xa6, 0xca, 0x04, 0xd5, 0x09, 0xbe, 0xc3, 0x32, 0xc9, 0xee, 0x5d, 0x9a, 0x56, 0xdb, 0xf6, 0x17, 0xf1, 0x2c, 0x6d, 0x71, 0x4f, 0xf7, 0x8a, 0x2a, 0xa3, 0xcf, 0xb9, 0x86, 0x0a, 0xc2, 0xfd, 0x75, 0xab, 0xb2, 0x75, 0x39, 0xb5, 0xf5, 0x2b, 0xb2, 0x80, 0x9e, 0x9b, 0x32, 0x26, 0x25, 0x6c, 0x0e, 0x71, 0xdf, 0xc0, 0x42, 0x4e, 0x74, 0xd8, 0xb0, 0x9b, 0xa5, 0x15, 0xe5, 0x96, 0xd7, 0x30, 0xdf, 0x33, 0x3d, 0xfd, 0xba, 0xf7, 0x59, 0x7d, 0xdb, 0xc9, 0x31, 0x3d, 0x70, 0xe4, 0xd4, 0x91, 0x97, 0x70, 0x2d, 0xf2, 0x48, 0xcd, 0x84, 0x2d, 0x70, 0x48, 0xbc, 0xd6, 0x6b, 0xaf, 0xdd, 0xf6, 0x7d, 0xad, 0xb9, 0x89, 0x94, 0x7c, 0x59, 0x0c, 0x3f, 0x3e, 0xe2, 0x8d, 0x4c, 0x81, 0x4a, 0x15, 0x09, 0xb9, 0xde, 0xc1, 0xe6, 0xe6, 0x5d, 0x28, 0x2d, 0x1d, 0xb8, 0x45, 0x17, 0x42, 0x55, 0xe3, 0x2a, 0xcf, 0x55, 0x26, 0x66, 0x79, 0xf1, 0xbb, 0x2a, 0x25, 0x28, 0x78, 0xa1, 0x63, 0x90, 0xec, 0xec, 0xa7, 0xee, 0x61, 0x1c, 0xac, 0x19, 0x45, 0xdd, 0x82, 0xae, 0x52, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00 ]; #[bench] fn bench_tls_record_serverhello(b: &mut Bencher) { let bytes = &SERVER_REPLY1[0..64]; b.iter(|| { let _ = parse_tls_plaintext(bytes); }) } #[bench] fn bench_tls_record_certificate(b: &mut Bencher) { let bytes = &SERVER_REPLY1[64..3150]; b.iter(|| { let _ = parse_tls_plaintext(bytes); }) } #[bench] fn bench_tls_record_serverkeyexchange(b: &mut Bencher) { let bytes = &SERVER_REPLY1[3150..3488]; b.iter(|| { let _ = parse_tls_plaintext(bytes); }) } #[bench] fn bench_tls_record_serverdone(b: &mut Bencher) { let bytes = &SERVER_REPLY1[3488..]; b.iter(|| { let _ = parse_tls_plaintext(bytes); }) } } // mod tls_handshake tls-parser-0.12.2/build.rs000064400000000000000000000061771046102023000134620ustar 00000000000000extern crate phf_codegen; use std::env; use std::fs::File; use std::io::BufRead; use std::io::{BufReader, BufWriter, Write}; use std::path::Path; fn titlecase_word(word: &str) -> String { word.chars() .enumerate() .map(|(i, c)| { if i == 0 { c.to_uppercase().collect::() } else { c.to_lowercase().collect::() } }) .collect() } fn main() { let path_txt = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("scripts/tls-ciphersuites.txt"); let display = path_txt.display(); let file = match File::open(&path_txt) { // The `description` method of `io::Error` returns a string that // describes the error Err(why) => panic!("couldn't open {}: {}", display, why), Ok(file) => file, }; let f = BufReader::new(file); let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs"); let mut file = BufWriter::new(File::create(path).unwrap()); let mut map = phf_codegen::Map::new(); for line in f.lines() { let l = line.unwrap(); let mut v: Vec<&str> = l.split(':').collect(); if v[5].is_empty() { v[5] = "NULL" } let au = match v[3] { "SRP+DSS" => String::from("Srp_Dss"), "SRP+RSA" => String::from("Srp_Rsa"), _ => titlecase_word(v[3]).replace('+', "_"), }; let enc = match v[4] { "3DES" => String::from("TripleDes"), "CHACHA20_POLY1305" => String::from("Chacha20_Poly1305"), _ => titlecase_word(v[4]), }; let mac = String::from(match v[7] { "NULL" => "Null", "HMAC-MD5" => "HmacMd5", "HMAC-SHA1" => "HmacSha1", "HMAC-SHA256" => "HmacSha256", "HMAC-SHA384" => "HmacSha384", "HMAC-SHA512" => "HmacSha512", "AEAD" => "Aead", _ => panic!("Unknown mac {}", v[7]), }); let prf = titlecase_word(v[9]); let key = u16::from_str_radix(v[0], 16).unwrap(); let val = format!( r#"TlsCipherSuite{{ name:"{}", id:TlsCipherSuiteID(0x{}), kx:TlsCipherKx::{}, au:TlsCipherAu::{}, enc:TlsCipherEnc::{}, enc_mode:TlsCipherEncMode::{}, enc_size:{}, mac:TlsCipherMac::{}, mac_size:{}, prf: TlsPRF::{}, }}"#, v[1], v[0], titlecase_word(v[2]), // kx au, // au enc, // enc titlecase_word(v[5]), // enc_mode v[6], // enc_key_size mac, // mac v[8], // mac_size prf, // prf ) .clone(); map.entry(key, val.as_str()); } writeln!( &mut file, "#[allow(unused_qualifications)]\npub static CIPHERS: phf::Map = {};", map.build() ) .unwrap(); } tls-parser-0.12.2/examples/get-ciphersuite-info.rs000064400000000000000000000065711046102023000202310ustar 00000000000000/* * * Helper program to list/query ciphersuite information * */ use clap::Parser; use std::num::ParseIntError; use tls_parser::TlsCipherSuite; #[derive(Parser)] struct CmdOptions { /// List all known ciphersuites #[arg(short = 'L', long)] list: bool, /// Display details (algorithms, mode, ...) #[arg(short, long)] long: bool, /// Use JSON for output #[arg(short = 'j', long)] to_json: bool, /// Ciphersuite IANA identifier (decimal or hexadecimal prefix by 0x) #[arg(short, long, value_name = "id")] id: Option, /// Ciphersuite IANA name #[arg(short, long, value_name = "name")] name: Option, } fn parse_u16(s: &str) -> Result { if s.starts_with("0x") { let s = s.trim_start_matches("0x"); u16::from_str_radix(s, 16) } else { s.parse::() } } fn print_ciphersuite(cs: &TlsCipherSuite, show_details: bool, to_json: bool) { if to_json { let mut entries = Vec::new(); entries.push(format!("\"id\":{}", cs.id)); entries.push(format!("\"hex_id\":\"0x{:x}\"", cs.id)); entries.push(format!("\"name\":\"{}\"", cs.name)); // if show_details { entries.push(format!("\"kx\":\"{:?}\"", cs.kx)); entries.push(format!("\"au\":\"{:?}\"", cs.au)); entries.push(format!("\"enc\":\"{:?}\"", cs.enc)); entries.push(format!("\"enc_mode\":\"{:?}\"", cs.enc_mode)); entries.push(format!("\"enc_size\":{}", cs.enc_size)); entries.push(format!("\"mac\":\"{:?}\"", cs.mac)); entries.push(format!("\"mac_size\":{}", cs.mac_size)); } let s = entries.join(","); println!("{{ {} }}", s); } else { let details = if show_details { format!( " kx={:?} au={:?} enc={:?} enc_mode={:?} enc_size={} mac={:?} mac_size={}", cs.kx, cs.au, cs.enc, cs.enc_mode, cs.enc_size, cs.mac, cs.mac_size ) } else { "".to_string() }; println!("{:04x} {}{}", cs.id, cs.name, details); } } fn find_by_id(id: u16, show_details: bool, to_json: bool) { let cipher = TlsCipherSuite::from_id(id); if let Some(cipher) = cipher { print_ciphersuite(cipher, show_details, to_json); } else { eprintln!("Unknown ciphersuite"); } } fn find_by_name(name: &str, show_details: bool, to_json: bool) { let cipher = TlsCipherSuite::from_name(name); if let Some(cipher) = cipher { print_ciphersuite(cipher, show_details, to_json); } else { eprintln!("Unknown ciphersuite"); } } fn main() { let options = CmdOptions::parse(); let show_details = options.long; if options.list { let mut id_list = tls_parser::CIPHERS.keys().collect::>(); id_list.sort(); for &id in &id_list { let cipher = TlsCipherSuite::from_id(*id).expect("could not get cipher"); print_ciphersuite(cipher, show_details, options.to_json); } return; } if let Some(str_id) = options.id { let id = parse_u16(&str_id).expect("Could not parse cipher ID"); find_by_id(id, show_details, options.to_json); } else if let Some(name) = options.name { find_by_name(&name, show_details, options.to_json); } else { eprintln!("Missing command"); } } tls-parser-0.12.2/scripts/extract-iana-ciphers.py000075500000000000000000000102741046102023000200650ustar 00000000000000#!/usr/bin/python import urllib2 from BeautifulSoup import BeautifulSoup, ResultSet file = urllib2.urlopen('https://www.iana.org/assignments/tls-parameters/tls-parameters.xml') data = file.read() with open('tls-parameters.xml', 'wb') as myFile: myFile.write(data) file.close() dom = BeautifulSoup(data) #ciphersuites=dom.findAll ("registry")[4] ciphersuites=dom.findAll (id="tls-parameters-4") if isinstance(ciphersuites,ResultSet): ciphersuites = ciphersuites.pop() for i in ciphersuites.findAll ("record"): value = "".join(i.value.contents) desc = "".join (i.description.contents) ignore_keywords = [ "Unassigned", "Reserved", ] f = filter(desc.startswith,ignore_keywords) if len(f) > 0: continue if desc == "TLS_EMPTY_RENEGOTIATION_INFO_SCSV": continue elif desc == "TLS_FALLBACK_SCSV": continue rfc = "NONE" if i.xref: rfc_tmp = filter (lambda (var,val) : var == "data", i.xref.attrs) if len (rfc_tmp) > 0: # rfc = rfc_tmp[0][1][3:7] rfc = rfc_tmp[0][1] real_value = "".join (map (lambda x : "%2.2x" % (int (x, 16)), value.split (","))) minver = 0x0300 maxver = 0xffff if rfc == "rfc8446": kxau = ["TLS13"] encmac = desc[4:] # skip "TLS_" elif rfc == "draft-camwinget-tls-ts13-macciphersuites": kxau = ["TLS13"] encmac = "NULL_" + desc.split("_")[1] # forge string like NULL_SHA256 else: (_kxau, encmac) = desc.split("_WITH_") kxau = _kxau.split ("_")[1:] export = 0 if kxau[-1] == "EXPORT": export = 1 maxver = 0x302 kxau = kxau[:-1] if len (kxau) == 1: kx = kxau[0] au = kxau[0] elif kxau[0] == "SRP": kx = "_".join (kxau[0:1]) au = kx if len (kxau) > 2: au += "+" + "_".join (kxau[2:]) elif kxau[0] == "GOSTR341112": # unsupported suites from https://datatracker.ietf.org/doc/draft-smyshlyaev-tls12-gost-suites/ continue else: kx, au = kxau if au == "anon": au = "NULL" _encmac = encmac.split ("_") hashfun = _encmac [-1] _encstr = "_".join (_encmac [:-1]) _enc = _encmac [:-1] if _encstr == "DES40_CBC": enc = "DES" encmode = "CBC" encsize = 40 elif len (_enc) == 3 and _enc[1] == "CBC" and _enc[2] == "40": enc = _enc[0] encmode = "CBC" encsize = 40 elif _encstr == "DES_CBC": enc = "DES" encmode = "CBC" encsize = 56 elif _encstr == "IDEA_CBC": enc = "IDEA" encmode = "CBC" encsize = 128 elif _encstr == "3DES_EDE_CBC": enc = "3DES" encmode = "CBC" encsize = 168 elif _encstr == "NULL": enc = "NULL" encmode = "" encsize = 0 elif _encstr == "SEED_CBC": enc = "SEED" encmode = "CBC" encsize = 128 elif _encstr == "CHACHA20_POLY1305": enc = "CHACHA20_POLY1305" encmode = "CBC" encsize = 256 elif len (_enc) == 2: enc = _enc[0] encmode = "" encsize = int (_enc[1]) else: enc = _enc[0] encmode = _enc[2] encsize = int (_enc[1]) prf = "DEFAULT" prfsize = 0 # fix crap from recent changes if hashfun == "8": hashfun = "_".join([encmode,hashfun]) encmode = "" if hashfun == "NULL": mac = "NULL" macsize = 0 elif hashfun == "MD5": mac = "HMAC-MD5" macsize = 128 elif hashfun == "SHA": mac = "HMAC-SHA1" macsize = 160 elif hashfun == "SHA256": mac = "HMAC-SHA256" macsize = 256 prf = "SHA256" prfsize = 256 minver = 0x303 elif hashfun == "SHA384": mac = "HMAC-SHA384" macsize = 384 prf = "SHA384" prfsize = 384 minver = 0x303 elif hashfun == "CCM": #print encmode #mac = "CCM" #macsize = 0 minver = 0x303 encmode = "CCM" elif hashfun == "CCM_8": #print encmode #mac = "CCM_8" #macsize = 0 minver = 0x303 encmode = "CCM" else: print desc print encmac print hashfun raise "Unsupported." if encmode == "GCM" or encmode == "CCM": mac = "AEAD" macsize = encsize minver = 0x303 if _encstr == "CHACHA20_POLY1305": mac = "AEAD" macsize = encsize minver = 0x303 print "%s:%s:%s:%s:%s:%s:%d:%s:%d:%s:%d:%s:%d:%4.4x:%4.4x" % (real_value, desc, kx, au, enc, encmode, encsize, mac, macsize, prf, prfsize, rfc, export, minver, maxver) tls-parser-0.12.2/scripts/tls-ciphersuites.txt000064400000000000000000001105351046102023000175460ustar 000000000000000000:TLS_NULL_WITH_NULL_NULL:NULL:NULL:NULL::0:NULL:0:DEFAULT:0:rfc5246:0:0300:ffff 0001:TLS_RSA_WITH_NULL_MD5:RSA:RSA:NULL::0:HMAC-MD5:128:DEFAULT:0:rfc5246:0:0300:ffff 0002:TLS_RSA_WITH_NULL_SHA:RSA:RSA:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0003:TLS_RSA_EXPORT_WITH_RC4_40_MD5:RSA:RSA:RC4::40:HMAC-MD5:128:DEFAULT:0:rfc4346,rfc6347:1:0300:ffff 0004:TLS_RSA_WITH_RC4_128_MD5:RSA:RSA:RC4::128:HMAC-MD5:128:DEFAULT:0:rfc5246,rfc6347:0:0300:ffff 0005:TLS_RSA_WITH_RC4_128_SHA:RSA:RSA:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc5246,rfc6347:0:0300:ffff 0006:TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5:RSA:RSA:RC2:CBC:40:HMAC-MD5:128:DEFAULT:0:rfc4346:1:0300:ffff 0007:TLS_RSA_WITH_IDEA_CBC_SHA:RSA:RSA:IDEA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 0008:TLS_RSA_EXPORT_WITH_DES40_CBC_SHA:RSA:RSA:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc4346:1:0300:ffff 0009:TLS_RSA_WITH_DES_CBC_SHA:RSA:RSA:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 000a:TLS_RSA_WITH_3DES_EDE_CBC_SHA:RSA:RSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 000b:TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:DH:DSS:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc4346:1:0300:ffff 000c:TLS_DH_DSS_WITH_DES_CBC_SHA:DH:DSS:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 000d:TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:DH:DSS:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 000e:TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:DH:RSA:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc4346:1:0300:ffff 000f:TLS_DH_RSA_WITH_DES_CBC_SHA:DH:RSA:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 0010:TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:DH:RSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0011:TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:DHE:DSS:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc4346:1:0300:ffff 0012:TLS_DHE_DSS_WITH_DES_CBC_SHA:DHE:DSS:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 0013:TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:DHE:DSS:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0014:TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:DHE:RSA:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc4346:1:0300:ffff 0015:TLS_DHE_RSA_WITH_DES_CBC_SHA:DHE:RSA:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 0016:TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:DHE:RSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0017:TLS_DH_anon_EXPORT_WITH_RC4_40_MD5:DH:NULL:RC4::40:HMAC-MD5:128:DEFAULT:0:rfc4346,rfc6347:1:0300:ffff 0018:TLS_DH_anon_WITH_RC4_128_MD5:DH:NULL:RC4::128:HMAC-MD5:128:DEFAULT:0:rfc5246,rfc6347:0:0300:ffff 0019:TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA:DH:NULL:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc4346:1:0300:ffff 001a:TLS_DH_anon_WITH_DES_CBC_SHA:DH:NULL:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc8996:0:0300:ffff 001b:TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:DH:NULL:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 001e:TLS_KRB5_WITH_DES_CBC_SHA:KRB5:KRB5:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:rfc2712:0:0300:ffff 001f:TLS_KRB5_WITH_3DES_EDE_CBC_SHA:KRB5:KRB5:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc2712:0:0300:ffff 0020:TLS_KRB5_WITH_RC4_128_SHA:KRB5:KRB5:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc2712,rfc6347:0:0300:ffff 0021:TLS_KRB5_WITH_IDEA_CBC_SHA:KRB5:KRB5:IDEA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc2712:0:0300:ffff 0022:TLS_KRB5_WITH_DES_CBC_MD5:KRB5:KRB5:DES:CBC:56:HMAC-MD5:128:DEFAULT:0:rfc2712:0:0300:ffff 0023:TLS_KRB5_WITH_3DES_EDE_CBC_MD5:KRB5:KRB5:3DES:CBC:168:HMAC-MD5:128:DEFAULT:0:rfc2712:0:0300:ffff 0024:TLS_KRB5_WITH_RC4_128_MD5:KRB5:KRB5:RC4::128:HMAC-MD5:128:DEFAULT:0:rfc2712,rfc6347:0:0300:ffff 0025:TLS_KRB5_WITH_IDEA_CBC_MD5:KRB5:KRB5:IDEA:CBC:128:HMAC-MD5:128:DEFAULT:0:rfc2712:0:0300:ffff 0026:TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA:KRB5:KRB5:DES:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc2712:1:0300:ffff 0027:TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA:KRB5:KRB5:RC2:CBC:40:HMAC-SHA1:160:DEFAULT:0:rfc2712:1:0300:ffff 0028:TLS_KRB5_EXPORT_WITH_RC4_40_SHA:KRB5:KRB5:RC4::40:HMAC-SHA1:160:DEFAULT:0:rfc2712,rfc6347:1:0300:ffff 0029:TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5:KRB5:KRB5:DES:CBC:40:HMAC-MD5:128:DEFAULT:0:rfc2712:1:0300:ffff 002a:TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5:KRB5:KRB5:RC2:CBC:40:HMAC-MD5:128:DEFAULT:0:rfc2712:1:0300:ffff 002b:TLS_KRB5_EXPORT_WITH_RC4_40_MD5:KRB5:KRB5:RC4::40:HMAC-MD5:128:DEFAULT:0:rfc2712,rfc6347:1:0300:ffff 002c:TLS_PSK_WITH_NULL_SHA:PSK:PSK:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc4785:0:0300:ffff 002d:TLS_DHE_PSK_WITH_NULL_SHA:DHE:PSK:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc4785:0:0300:ffff 002e:TLS_RSA_PSK_WITH_NULL_SHA:RSA:PSK:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc4785:0:0300:ffff 002f:TLS_RSA_WITH_AES_128_CBC_SHA:RSA:RSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0030:TLS_DH_DSS_WITH_AES_128_CBC_SHA:DH:DSS:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0031:TLS_DH_RSA_WITH_AES_128_CBC_SHA:DH:RSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0032:TLS_DHE_DSS_WITH_AES_128_CBC_SHA:DHE:DSS:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0033:TLS_DHE_RSA_WITH_AES_128_CBC_SHA:DHE:RSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0034:TLS_DH_anon_WITH_AES_128_CBC_SHA:DH:NULL:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0035:TLS_RSA_WITH_AES_256_CBC_SHA:RSA:RSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0036:TLS_DH_DSS_WITH_AES_256_CBC_SHA:DH:DSS:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0037:TLS_DH_RSA_WITH_AES_256_CBC_SHA:DH:RSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0038:TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE:DSS:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 0039:TLS_DHE_RSA_WITH_AES_256_CBC_SHA:DHE:RSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 003a:TLS_DH_anon_WITH_AES_256_CBC_SHA:DH:NULL:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5246:0:0300:ffff 003b:TLS_RSA_WITH_NULL_SHA256:RSA:RSA:NULL::0:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 003c:TLS_RSA_WITH_AES_128_CBC_SHA256:RSA:RSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 003d:TLS_RSA_WITH_AES_256_CBC_SHA256:RSA:RSA:AES:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 003e:TLS_DH_DSS_WITH_AES_128_CBC_SHA256:DH:DSS:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 003f:TLS_DH_RSA_WITH_AES_128_CBC_SHA256:DH:RSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 0040:TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:DHE:DSS:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 0041:TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:RSA:RSA:CAMELLIA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0042:TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:DH:DSS:CAMELLIA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0043:TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:DH:RSA:CAMELLIA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0044:TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:DHE:DSS:CAMELLIA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0045:TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:DHE:RSA:CAMELLIA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0046:TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:DH:NULL:CAMELLIA:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0067:TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:DHE:RSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 0068:TLS_DH_DSS_WITH_AES_256_CBC_SHA256:DH:DSS:AES:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 0069:TLS_DH_RSA_WITH_AES_256_CBC_SHA256:DH:RSA:AES:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 006a:TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:DHE:DSS:AES:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 006b:TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:DHE:RSA:AES:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 006c:TLS_DH_anon_WITH_AES_128_CBC_SHA256:DH:NULL:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 006d:TLS_DH_anon_WITH_AES_256_CBC_SHA256:DH:NULL:AES:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5246:0:0300:ffff 0084:TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:RSA:RSA:CAMELLIA:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0085:TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:DH:DSS:CAMELLIA:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0086:TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:DH:RSA:CAMELLIA:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0087:TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:DHE:DSS:CAMELLIA:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0088:TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:DHE:RSA:CAMELLIA:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 0089:TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:DH:NULL:CAMELLIA:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5932:0:0300:ffff 008a:TLS_PSK_WITH_RC4_128_SHA:PSK:PSK:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc4279,rfc6347:0:0300:ffff 008b:TLS_PSK_WITH_3DES_EDE_CBC_SHA:PSK:PSK:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 008c:TLS_PSK_WITH_AES_128_CBC_SHA:PSK:PSK:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 008d:TLS_PSK_WITH_AES_256_CBC_SHA:PSK:PSK:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 008e:TLS_DHE_PSK_WITH_RC4_128_SHA:DHE:PSK:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc4279,rfc6347:0:0300:ffff 008f:TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:DHE:PSK:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 0090:TLS_DHE_PSK_WITH_AES_128_CBC_SHA:DHE:PSK:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 0091:TLS_DHE_PSK_WITH_AES_256_CBC_SHA:DHE:PSK:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 0092:TLS_RSA_PSK_WITH_RC4_128_SHA:RSA:PSK:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc4279,rfc6347:0:0300:ffff 0093:TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:RSA:PSK:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 0094:TLS_RSA_PSK_WITH_AES_128_CBC_SHA:RSA:PSK:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 0095:TLS_RSA_PSK_WITH_AES_256_CBC_SHA:RSA:PSK:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc4279:0:0300:ffff 0096:TLS_RSA_WITH_SEED_CBC_SHA:RSA:RSA:SEED:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4162:0:0300:ffff 0097:TLS_DH_DSS_WITH_SEED_CBC_SHA:DH:DSS:SEED:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4162:0:0300:ffff 0098:TLS_DH_RSA_WITH_SEED_CBC_SHA:DH:RSA:SEED:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4162:0:0300:ffff 0099:TLS_DHE_DSS_WITH_SEED_CBC_SHA:DHE:DSS:SEED:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4162:0:0300:ffff 009a:TLS_DHE_RSA_WITH_SEED_CBC_SHA:DHE:RSA:SEED:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4162:0:0300:ffff 009b:TLS_DH_anon_WITH_SEED_CBC_SHA:DH:NULL:SEED:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc4162:0:0300:ffff 009c:TLS_RSA_WITH_AES_128_GCM_SHA256:RSA:RSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5288:0:0300:ffff 009d:TLS_RSA_WITH_AES_256_GCM_SHA384:RSA:RSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5288:0:0300:ffff 009e:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:DHE:RSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5288:0:0300:ffff 009f:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:DHE:RSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5288:0:0300:ffff 00a0:TLS_DH_RSA_WITH_AES_128_GCM_SHA256:DH:RSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5288:0:0300:ffff 00a1:TLS_DH_RSA_WITH_AES_256_GCM_SHA384:DH:RSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5288:0:0300:ffff 00a2:TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:DHE:DSS:AES:GCM:128:AEAD:128:SHA256:256:rfc5288:0:0300:ffff 00a3:TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:DHE:DSS:AES:GCM:256:AEAD:256:SHA384:384:rfc5288:0:0300:ffff 00a4:TLS_DH_DSS_WITH_AES_128_GCM_SHA256:DH:DSS:AES:GCM:128:AEAD:128:SHA256:256:rfc5288:0:0300:ffff 00a5:TLS_DH_DSS_WITH_AES_256_GCM_SHA384:DH:DSS:AES:GCM:256:AEAD:256:SHA384:384:rfc5288:0:0300:ffff 00a6:TLS_DH_anon_WITH_AES_128_GCM_SHA256:DH:NULL:AES:GCM:128:AEAD:128:SHA256:256:rfc5288:0:0300:ffff 00a7:TLS_DH_anon_WITH_AES_256_GCM_SHA384:DH:NULL:AES:GCM:256:AEAD:256:SHA384:384:rfc5288:0:0300:ffff 00a8:TLS_PSK_WITH_AES_128_GCM_SHA256:PSK:PSK:AES:GCM:128:AEAD:128:SHA256:256:rfc5487:0:0300:ffff 00a9:TLS_PSK_WITH_AES_256_GCM_SHA384:PSK:PSK:AES:GCM:256:AEAD:256:SHA384:384:rfc5487:0:0300:ffff 00aa:TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:DHE:PSK:AES:GCM:128:AEAD:128:SHA256:256:rfc5487:0:0300:ffff 00ab:TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:DHE:PSK:AES:GCM:256:AEAD:256:SHA384:384:rfc5487:0:0300:ffff 00ac:TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:RSA:PSK:AES:GCM:128:AEAD:128:SHA256:256:rfc5487:0:0300:ffff 00ad:TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:RSA:PSK:AES:GCM:256:AEAD:256:SHA384:384:rfc5487:0:0300:ffff 00ae:TLS_PSK_WITH_AES_128_CBC_SHA256:PSK:PSK:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5487:0:0300:ffff 00af:TLS_PSK_WITH_AES_256_CBC_SHA384:PSK:PSK:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5487:0:0300:ffff 00b0:TLS_PSK_WITH_NULL_SHA256:PSK:PSK:NULL::0:HMAC-SHA256:256:SHA256:256:rfc5487:0:0300:ffff 00b1:TLS_PSK_WITH_NULL_SHA384:PSK:PSK:NULL::0:HMAC-SHA384:384:SHA384:384:rfc5487:0:0300:ffff 00b2:TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:DHE:PSK:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5487:0:0300:ffff 00b3:TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:DHE:PSK:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5487:0:0300:ffff 00b4:TLS_DHE_PSK_WITH_NULL_SHA256:DHE:PSK:NULL::0:HMAC-SHA256:256:SHA256:256:rfc5487:0:0300:ffff 00b5:TLS_DHE_PSK_WITH_NULL_SHA384:DHE:PSK:NULL::0:HMAC-SHA384:384:SHA384:384:rfc5487:0:0300:ffff 00b6:TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:RSA:PSK:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5487:0:0300:ffff 00b7:TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:RSA:PSK:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5487:0:0300:ffff 00b8:TLS_RSA_PSK_WITH_NULL_SHA256:RSA:PSK:NULL::0:HMAC-SHA256:256:SHA256:256:rfc5487:0:0300:ffff 00b9:TLS_RSA_PSK_WITH_NULL_SHA384:RSA:PSK:NULL::0:HMAC-SHA384:384:SHA384:384:rfc5487:0:0300:ffff 00ba:TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:RSA:RSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00bb:TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:DH:DSS:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00bc:TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:DH:RSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00bd:TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:DHE:DSS:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00be:TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:DHE:RSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00bf:TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:DH:NULL:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c0:TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:RSA:RSA:CAMELLIA:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c1:TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:DH:DSS:CAMELLIA:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c2:TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:DH:RSA:CAMELLIA:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c3:TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:DHE:DSS:CAMELLIA:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c4:TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:DHE:RSA:CAMELLIA:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c5:TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:DH:NULL:CAMELLIA:CBC:256:HMAC-SHA256:256:SHA256:256:rfc5932:0:0300:ffff 00c6:TLS_SM4_GCM_SM3:TLS13:TLS13:SM4:GCM:128:AEAD:128:SM3:256:rfc8998:0:0300:ffff 00c7:TLS_SM4_CCM_SM3:TLS13:TLS13:SM4:CCM:128:AEAD:128:SM3:256:rfc8998:0:0300:ffff 00ff:TLS_EMPTY_RENEGOTIATION_INFO_SCSV:NULL:NULL:NULL::0:NULL:0:NULL:0:rfc5746:0:0:0 1301:TLS_AES_128_GCM_SHA256:TLS13:TLS13:AES:GCM:128:AEAD:128:SHA256:256:rfc8446:0:0300:ffff 1302:TLS_AES_256_GCM_SHA384:TLS13:TLS13:AES:GCM:256:AEAD:256:SHA384:384:rfc8446:0:0300:ffff 1303:TLS_CHACHA20_POLY1305_SHA256:TLS13:TLS13:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc8446:0:0300:ffff 1304:TLS_AES_128_CCM_SHA256:TLS13:TLS13:AES:CCM:128:AEAD:128:SHA256:256:rfc8446:0:0300:ffff 1305:TLS_AES_128_CCM_8_SHA256:TLS13:TLS13:AES:CCM:128:AEAD:128:SHA256:256:rfc8446,iesg action 2018-08-16:0:0300:ffff 1306:TLS_AEGIS_256_SHA512:TLS13:TLS13:AEGIS:NULL:256:HMAC-SHA512:512:SHA512:512:draft-irtf-cfrg-aegis-aead-08:0:0300:ffff 1307:TLS_AEGIS_128L_SHA256:TLS13:TLS13:AEGIS:NULL:128:HMAC-SHA256:256:SHA256:256:draft-irtf-cfrg-aegis-aead-08:0:0300:ffff 5600:TLS_FALLBACK_SCSV:NULL:NULL:NULL::0:NULL:0:NULL:0:rfc7507:0:0:0 c001:TLS_ECDH_ECDSA_WITH_NULL_SHA:ECDH:ECDSA:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c002:TLS_ECDH_ECDSA_WITH_RC4_128_SHA:ECDH:ECDSA:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc8422,rfc6347:0:0300:ffff c003:TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:ECDH:ECDSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c004:TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:ECDH:ECDSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c005:TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:ECDH:ECDSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c006:TLS_ECDHE_ECDSA_WITH_NULL_SHA:ECDHE:ECDSA:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c007:TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:ECDHE:ECDSA:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc8422,rfc6347:0:0300:ffff c008:TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:ECDHE:ECDSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c009:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:ECDHE:ECDSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c00a:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:ECDHE:ECDSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c00b:TLS_ECDH_RSA_WITH_NULL_SHA:ECDH:RSA:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c00c:TLS_ECDH_RSA_WITH_RC4_128_SHA:ECDH:RSA:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc8422,rfc6347:0:0300:ffff c00d:TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:ECDH:RSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c00e:TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:ECDH:RSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c00f:TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:ECDH:RSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c010:TLS_ECDHE_RSA_WITH_NULL_SHA:ECDHE:RSA:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c011:TLS_ECDHE_RSA_WITH_RC4_128_SHA:ECDHE:RSA:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc8422,rfc6347:0:0300:ffff c012:TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:ECDHE:RSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c013:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:ECDHE:RSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c014:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:ECDHE:RSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c015:TLS_ECDH_anon_WITH_NULL_SHA:ECDH:NULL:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c016:TLS_ECDH_anon_WITH_RC4_128_SHA:ECDH:NULL:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc8422,rfc6347:0:0300:ffff c017:TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:ECDH:NULL:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c018:TLS_ECDH_anon_WITH_AES_128_CBC_SHA:ECDH:NULL:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c019:TLS_ECDH_anon_WITH_AES_256_CBC_SHA:ECDH:NULL:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc8422:0:0300:ffff c01a:TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:SRP:SRP:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c01b:TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:SRP:SRP+RSA:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c01c:TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:SRP:SRP+DSS:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c01d:TLS_SRP_SHA_WITH_AES_128_CBC_SHA:SRP:SRP:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c01e:TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:SRP:SRP+RSA:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c01f:TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:SRP:SRP+DSS:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c020:TLS_SRP_SHA_WITH_AES_256_CBC_SHA:SRP:SRP:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c021:TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:SRP:SRP+RSA:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c022:TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:SRP:SRP+DSS:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5054:0:0300:ffff c023:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:ECDHE:ECDSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5289:0:0300:ffff c024:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:ECDHE:ECDSA:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5289:0:0300:ffff c025:TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:ECDH:ECDSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5289:0:0300:ffff c026:TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:ECDH:ECDSA:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5289:0:0300:ffff c027:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:ECDHE:RSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5289:0:0300:ffff c028:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:ECDHE:RSA:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5289:0:0300:ffff c029:TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:ECDH:RSA:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5289:0:0300:ffff c02a:TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:ECDH:RSA:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5289:0:0300:ffff c02b:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:ECDHE:ECDSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5289:0:0300:ffff c02c:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:ECDHE:ECDSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5289:0:0300:ffff c02d:TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:ECDH:ECDSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5289:0:0300:ffff c02e:TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:ECDH:ECDSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5289:0:0300:ffff c02f:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:ECDHE:RSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5289:0:0300:ffff c030:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:ECDHE:RSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5289:0:0300:ffff c031:TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:ECDH:RSA:AES:GCM:128:AEAD:128:SHA256:256:rfc5289:0:0300:ffff c032:TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:ECDH:RSA:AES:GCM:256:AEAD:256:SHA384:384:rfc5289:0:0300:ffff c033:TLS_ECDHE_PSK_WITH_RC4_128_SHA:ECDHE:PSK:RC4::128:HMAC-SHA1:160:DEFAULT:0:rfc5489,rfc6347:0:0300:ffff c034:TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:ECDHE:PSK:3DES:CBC:168:HMAC-SHA1:160:DEFAULT:0:rfc5489:0:0300:ffff c035:TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:ECDHE:PSK:AES:CBC:128:HMAC-SHA1:160:DEFAULT:0:rfc5489:0:0300:ffff c036:TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:ECDHE:PSK:AES:CBC:256:HMAC-SHA1:160:DEFAULT:0:rfc5489:0:0300:ffff c037:TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:ECDHE:PSK:AES:CBC:128:HMAC-SHA256:256:SHA256:256:rfc5489:0:0300:ffff c038:TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:ECDHE:PSK:AES:CBC:256:HMAC-SHA384:384:SHA384:384:rfc5489:0:0300:ffff c039:TLS_ECDHE_PSK_WITH_NULL_SHA:ECDHE:PSK:NULL::0:HMAC-SHA1:160:DEFAULT:0:rfc5489:0:0300:ffff c03a:TLS_ECDHE_PSK_WITH_NULL_SHA256:ECDHE:PSK:NULL::0:HMAC-SHA256:256:SHA256:256:rfc5489:0:0300:ffff c03b:TLS_ECDHE_PSK_WITH_NULL_SHA384:ECDHE:PSK:NULL::0:HMAC-SHA384:384:SHA384:384:rfc5489:0:0300:ffff c03c:TLS_RSA_WITH_ARIA_128_CBC_SHA256:RSA:RSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c03d:TLS_RSA_WITH_ARIA_256_CBC_SHA384:RSA:RSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c03e:TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256:DH:DSS:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c03f:TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384:DH:DSS:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c040:TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256:DH:RSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c041:TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384:DH:RSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c042:TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256:DHE:DSS:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c043:TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384:DHE:DSS:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c044:TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256:DHE:RSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c045:TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384:DHE:RSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c046:TLS_DH_anon_WITH_ARIA_128_CBC_SHA256:DH:NULL:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c047:TLS_DH_anon_WITH_ARIA_256_CBC_SHA384:DH:NULL:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c048:TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256:ECDHE:ECDSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c049:TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384:ECDHE:ECDSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c04a:TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256:ECDH:ECDSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c04b:TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384:ECDH:ECDSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c04c:TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256:ECDHE:RSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c04d:TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384:ECDHE:RSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c04e:TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256:ECDH:RSA:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c04f:TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384:ECDH:RSA:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c050:TLS_RSA_WITH_ARIA_128_GCM_SHA256:RSA:RSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c051:TLS_RSA_WITH_ARIA_256_GCM_SHA384:RSA:RSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c052:TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256:DHE:RSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c053:TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384:DHE:RSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c054:TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256:DH:RSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c055:TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384:DH:RSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c056:TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256:DHE:DSS:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c057:TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384:DHE:DSS:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c058:TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256:DH:DSS:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c059:TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384:DH:DSS:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c05a:TLS_DH_anon_WITH_ARIA_128_GCM_SHA256:DH:NULL:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c05b:TLS_DH_anon_WITH_ARIA_256_GCM_SHA384:DH:NULL:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c05c:TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256:ECDHE:ECDSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c05d:TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384:ECDHE:ECDSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c05e:TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256:ECDH:ECDSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c05f:TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384:ECDH:ECDSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c060:TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256:ECDHE:RSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c061:TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384:ECDHE:RSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c062:TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256:ECDH:RSA:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c063:TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384:ECDH:RSA:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c064:TLS_PSK_WITH_ARIA_128_CBC_SHA256:PSK:PSK:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c065:TLS_PSK_WITH_ARIA_256_CBC_SHA384:PSK:PSK:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c066:TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256:DHE:PSK:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c067:TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384:DHE:PSK:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c068:TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256:RSA:PSK:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c069:TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384:RSA:PSK:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c06a:TLS_PSK_WITH_ARIA_128_GCM_SHA256:PSK:PSK:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c06b:TLS_PSK_WITH_ARIA_256_GCM_SHA384:PSK:PSK:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c06c:TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256:DHE:PSK:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c06d:TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384:DHE:PSK:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c06e:TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256:RSA:PSK:ARIA:GCM:128:AEAD:128:SHA256:256:rfc6209:0:0300:ffff c06f:TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384:RSA:PSK:ARIA:GCM:256:AEAD:256:SHA384:384:rfc6209:0:0300:ffff c070:TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256:ECDHE:PSK:ARIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6209:0:0300:ffff c071:TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384:ECDHE:PSK:ARIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6209:0:0300:ffff c072:TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:ECDHE:ECDSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c073:TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:ECDHE:ECDSA:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c074:TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:ECDH:ECDSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c075:TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:ECDH:ECDSA:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c076:TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:ECDHE:RSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c077:TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:ECDHE:RSA:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c078:TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:ECDH:RSA:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c079:TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:ECDH:RSA:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c07a:TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:RSA:RSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c07b:TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:RSA:RSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c07c:TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:DHE:RSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c07d:TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:DHE:RSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c07e:TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:DH:RSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c07f:TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:DH:RSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c080:TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:DHE:DSS:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c081:TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:DHE:DSS:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c082:TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:DH:DSS:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c083:TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:DH:DSS:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c084:TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:DH:NULL:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c085:TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:DH:NULL:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c086:TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:ECDHE:ECDSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c087:TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:ECDHE:ECDSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c088:TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:ECDH:ECDSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c089:TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:ECDH:ECDSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c08a:TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:ECDHE:RSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c08b:TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:ECDHE:RSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c08c:TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:ECDH:RSA:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c08d:TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:ECDH:RSA:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c08e:TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:PSK:PSK:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c08f:TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:PSK:PSK:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c090:TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:DHE:PSK:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c091:TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:DHE:PSK:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c092:TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:RSA:PSK:CAMELLIA:GCM:128:AEAD:128:SHA256:256:rfc6367:0:0300:ffff c093:TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:RSA:PSK:CAMELLIA:GCM:256:AEAD:256:SHA384:384:rfc6367:0:0300:ffff c094:TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:PSK:PSK:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c095:TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:PSK:PSK:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c096:TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:DHE:PSK:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c097:TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:DHE:PSK:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c098:TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:RSA:PSK:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c099:TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:RSA:PSK:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c09a:TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:ECDHE:PSK:CAMELLIA:CBC:128:HMAC-SHA256:256:SHA256:256:rfc6367:0:0300:ffff c09b:TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:ECDHE:PSK:CAMELLIA:CBC:256:HMAC-SHA384:384:SHA384:384:rfc6367:0:0300:ffff c09c:TLS_RSA_WITH_AES_128_CCM:RSA:RSA:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c09d:TLS_RSA_WITH_AES_256_CCM:RSA:RSA:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c09e:TLS_DHE_RSA_WITH_AES_128_CCM:DHE:RSA:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c09f:TLS_DHE_RSA_WITH_AES_256_CCM:DHE:RSA:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0a0:TLS_RSA_WITH_AES_128_CCM_8:RSA:RSA:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c0a1:TLS_RSA_WITH_AES_256_CCM_8:RSA:RSA:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0a2:TLS_DHE_RSA_WITH_AES_128_CCM_8:DHE:RSA:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c0a3:TLS_DHE_RSA_WITH_AES_256_CCM_8:DHE:RSA:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0a4:TLS_PSK_WITH_AES_128_CCM:PSK:PSK:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c0a5:TLS_PSK_WITH_AES_256_CCM:PSK:PSK:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0a6:TLS_DHE_PSK_WITH_AES_128_CCM:DHE:PSK:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c0a7:TLS_DHE_PSK_WITH_AES_256_CCM:DHE:PSK:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0a8:TLS_PSK_WITH_AES_128_CCM_8:PSK:PSK:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c0a9:TLS_PSK_WITH_AES_256_CCM_8:PSK:PSK:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0aa:TLS_PSK_DHE_WITH_AES_128_CCM_8:PSK:DHE:AES:CCM:128:AEAD:128:DEFAULT:0:rfc6655:0:0300:ffff c0ab:TLS_PSK_DHE_WITH_AES_256_CCM_8:PSK:DHE:AES:CCM:256:AEAD:256:DEFAULT:0:rfc6655:0:0300:ffff c0ac:TLS_ECDHE_ECDSA_WITH_AES_128_CCM:ECDHE:ECDSA:AES:CCM:128:AEAD:128:DEFAULT:0:rfc7251:0:0300:ffff c0ad:TLS_ECDHE_ECDSA_WITH_AES_256_CCM:ECDHE:ECDSA:AES:CCM:256:AEAD:256:DEFAULT:0:rfc7251:0:0300:ffff c0ae:TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:ECDHE:ECDSA:AES:CCM:128:AEAD:128:DEFAULT:0:rfc7251:0:0300:ffff c0af:TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:ECDHE:ECDSA:AES:CCM:256:AEAD:256:DEFAULT:0:rfc7251:0:0300:ffff c0b0:TLS_ECCPWD_WITH_AES_128_GCM_SHA256:ECCPWD:ECCPWD:AES:GCM:128:AEAD:128:SHA256:256:rfc8492:0:0300:ffff c0b1:TLS_ECCPWD_WITH_AES_256_GCM_SHA384:ECCPWD:ECCPWD:AES:GCM:256:AEAD:256:SHA384:384:rfc8492:0:0300:ffff c0b2:TLS_ECCPWD_WITH_AES_128_CCM_SHA256:ECCPWD:ECCPWD:AES:CCM:128:AEAD:128:SHA256:256:rfc8492:0:0300:ffff c0b3:TLS_ECCPWD_WITH_AES_256_CCM_SHA384:ECCPWD:ECCPWD:AES:CCM:256:AEAD:256:SHA384:384:rfc8492:0:0300:ffff c0b4:TLS_SHA256_SHA256:TLS13:TLS13:NULL::0:HMAC-SHA256:256:SHA256:256:rfc9150:0:0300:ffff c0b5:TLS_SHA384_SHA384:TLS13:TLS13:NULL::0:HMAC-SHA384:384:SHA384:384:rfc9150:0:0300:ffff cca8:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:ECDHE:RSA:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff cca9:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:ECDHE:ECDSA:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff ccaa:TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:DHE:RSA:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff ccab:TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:PSK:PSK:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff ccac:TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:ECDHE:PSK:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff ccad:TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:DHE:PSK:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff ccae:TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:RSA:PSK:CHACHA20_POLY1305::128:AEAD:128:SHA256:256:rfc7905:0:0300:ffff d001:TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256:ECDHE:PSK:AES:GCM:128:AEAD:128:SHA256:256:rfc8442:0:0300:ffff d002:TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384:ECDHE:PSK:AES:GCM:256:AEAD:256:SHA384:384:rfc8442:0:0300:ffff d003:TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256:ECDHE:PSK:AES:CCM:128:AEAD:128:SHA256:256:rfc8442:0:0300:ffff d005:TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256:ECDHE:PSK:AES:CCM:128:AEAD:128:SHA256:256:rfc8442:0:0300:ffff 0062:TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA:RSA:RSA:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:draft-ietf-tls-56-bit-ciphersuites-01:0:0300:ffff 0064:TLS_RSA_EXPORT1024_WITH_RC4_56_SHA:RSA:RSA:RC4::56:HMAC-SHA1:160:DEFAULT:0:draft-ietf-tls-56-bit-ciphersuites-01:0:0300:ffff 0063:TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA:DHE:DSS:DES:CBC:56:HMAC-SHA1:160:DEFAULT:0:draft-ietf-tls-56-bit-ciphersuites-01:0:0300:ffff 0065:TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA:DHE:DSS:RC4::56:HMAC-SHA1:160:DEFAULT:0:draft-ietf-tls-56-bit-ciphersuites-01:0:0300:ffff 0066:TLS_DHE_DSS_WITH_RC4_128_SHA:DHE:DSS:RC4::128:HMAC-SHA1:160:DEFAULT:0:draft-ietf-tls-56-bit-ciphersuites-01:0:0300:ffff 0060:TLS_RSA_EXPORT1024_WITH_RC4_56_MD5:RSA:RSA:RC4::56:HMAC-MD5:128:DEFAULT:0:unknown:0:0300:ffff 0061:TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5:RSA:RSA:RC2:CBC:56:HMAC-MD5:128:DEFAULT:0:unknown:0:0300:ffff tls-parser-0.12.2/src/certificate_transparency.rs000064400000000000000000000061351046102023000202170ustar 00000000000000// Certificate Trasparency structures are defined in // [RFC6962](https://datatracker.ietf.org/doc/html/rfc6962). use alloc::vec::Vec; use core::convert::TryInto; use nom::{ bytes::streaming::take, combinator::{complete, map_parser}, multi::{length_data, many0}, number::streaming::{be_u16, be_u64, be_u8}, IResult, }; use nom_derive::*; use rusticata_macros::newtype_enum; use crate::{parse_digitally_signed, DigitallySigned}; /// Certificate Transparency Version as defined in [RFC6962 Section 3.2](https://datatracker.ietf.org/doc/html/rfc6962#section-3.2) #[derive(Clone, Copy, Debug, PartialEq, Eq, Nom)] pub struct CtVersion(pub u8); newtype_enum! { impl display CtVersion { V1 = 0, } } /// LogID as defined in [RFC6962 Section 3.2](https://datatracker.ietf.org/doc/html/rfc6962#section-3.2) #[derive(Clone, Debug, PartialEq)] pub struct CtLogID<'a> { pub key_id: &'a [u8; 32], } /// CtExtensions as defined in [RFC6962 Section 3.2](https://datatracker.ietf.org/doc/html/rfc6962#section-3.2) #[derive(Clone, Debug, PartialEq)] pub struct CtExtensions<'a>(pub &'a [u8]); /// Signed Certificate Timestamp as defined in [RFC6962 Section 3.2](https://datatracker.ietf.org/doc/html/rfc6962#section-3.2) #[derive(Clone, Debug, PartialEq)] pub struct SignedCertificateTimestamp<'a> { pub version: CtVersion, pub id: CtLogID<'a>, pub timestamp: u64, pub extensions: CtExtensions<'a>, pub signature: DigitallySigned<'a>, } pub(crate) fn parse_log_id(i: &[u8]) -> IResult<&[u8], CtLogID> { let (i, key_id) = take(32usize)(i)?; Ok(( i, CtLogID { key_id: key_id .try_into() .expect("take(32) is in sync with key_id size"), }, )) } pub(crate) fn parse_ct_extensions(i: &[u8]) -> IResult<&[u8], CtExtensions> { let (i, ext_len) = be_u16(i)?; let (i, ext_data) = take(ext_len as usize)(i)?; Ok((i, CtExtensions(ext_data))) } pub(crate) fn parse_ct_signed_certificate_timestamp_content( i: &[u8], ) -> IResult<&[u8], SignedCertificateTimestamp> { let (i, version) = be_u8(i)?; let (i, id) = parse_log_id(i)?; let (i, timestamp) = be_u64(i)?; let (i, extensions) = parse_ct_extensions(i)?; let (i, signature) = parse_digitally_signed(i)?; Ok(( i, SignedCertificateTimestamp { version: CtVersion(version), id, timestamp, extensions, signature, }, )) } /// Parses as single Signed Certificate Timestamp entry pub fn parse_ct_signed_certificate_timestamp( i: &[u8], ) -> IResult<&[u8], SignedCertificateTimestamp> { map_parser( length_data(be_u16), parse_ct_signed_certificate_timestamp_content, )(i) } /// Parses a list of Signed Certificate Timestamp entries pub fn parse_ct_signed_certificate_timestamp_list( i: &[u8], ) -> IResult<&[u8], Vec> { let (i, sct_len) = be_u16(i)?; let (i, sct_list) = map_parser( take(sct_len as usize), many0(complete(parse_ct_signed_certificate_timestamp)), )(i)?; Ok((i, sct_list)) } tls-parser-0.12.2/src/dtls.rs000064400000000000000000000252751046102023000141200ustar 00000000000000//! Datagram Transport Layer Security Version 1.2 (RFC 6347) use alloc::vec::Vec; use nom::bytes::streaming::take; use nom::combinator::{complete, cond, map, map_parser, opt, verify}; use nom::error::{make_error, ErrorKind}; use nom::multi::{length_data, many1}; use nom::number::streaming::{be_u16, be_u24, be_u64, be_u8}; use nom::{Err, IResult}; use nom_derive::Parse; use crate::tls_handshake::*; use crate::tls_message::*; use crate::tls_record::{TlsRecordType, MAX_RECORD_LEN}; use crate::TlsMessageAlert; /// DTLS Plaintext record header #[derive(Debug, PartialEq)] pub struct DTLSRecordHeader { pub content_type: TlsRecordType, pub version: TlsVersion, /// A counter value that is incremented on every cipher state change. pub epoch: u16, /// The sequence number for this record. pub sequence_number: u64, // really an u48 pub length: u16, } /// DTLS Plaintext record /// /// Each DTLS record MUST fit within a single datagram. /// /// Multiple DTLS records may be placed in a single datagram. #[derive(Debug, PartialEq)] pub struct DTLSPlaintext<'a> { pub header: DTLSRecordHeader, pub messages: Vec>, } #[derive(Debug, PartialEq)] pub struct DTLSRawRecord<'a> { pub header: DTLSRecordHeader, pub fragment: &'a [u8], } #[derive(Debug, PartialEq)] pub struct DTLSClientHello<'a> { pub version: TlsVersion, pub random: &'a [u8], pub session_id: Option<&'a [u8]>, pub cookie: &'a [u8], /// A list of ciphers supported by client pub ciphers: Vec, /// A list of compression methods supported by client pub comp: Vec, pub ext: Option<&'a [u8]>, } impl<'a> ClientHello<'a> for DTLSClientHello<'a> { fn version(&self) -> TlsVersion { self.version } fn random(&self) -> &'a [u8] { self.random } fn session_id(&self) -> Option<&'a [u8]> { self.session_id } fn ciphers(&self) -> &Vec { &self.ciphers } fn comp(&self) -> &Vec { &self.comp } fn ext(&self) -> Option<&'a [u8]> { self.ext } } #[derive(Debug, PartialEq)] pub struct DTLSHelloVerifyRequest<'a> { pub server_version: TlsVersion, pub cookie: &'a [u8], } /// DTLS Generic handshake message #[derive(Debug, PartialEq)] pub struct DTLSMessageHandshake<'a> { pub msg_type: TlsHandshakeType, pub length: u32, pub message_seq: u16, pub fragment_offset: u32, pub fragment_length: u32, pub body: DTLSMessageHandshakeBody<'a>, } /// DTLS Generic handshake message #[derive(Debug, PartialEq)] pub enum DTLSMessageHandshakeBody<'a> { HelloRequest, ClientHello(DTLSClientHello<'a>), HelloVerifyRequest(DTLSHelloVerifyRequest<'a>), ServerHello(TlsServerHelloContents<'a>), NewSessionTicket(TlsNewSessionTicketContent<'a>), HelloRetryRequest(TlsHelloRetryRequestContents<'a>), Certificate(TlsCertificateContents<'a>), ServerKeyExchange(TlsServerKeyExchangeContents<'a>), CertificateRequest(TlsCertificateRequestContents<'a>), ServerDone(&'a [u8]), CertificateVerify(&'a [u8]), ClientKeyExchange(TlsClientKeyExchangeContents<'a>), Finished(&'a [u8]), CertificateStatus(TlsCertificateStatusContents<'a>), NextProtocol(TlsNextProtocolContent<'a>), Fragment(&'a [u8]), } /// DTLS plaintext message /// /// Plaintext records can only be found during the handshake. #[derive(Debug, PartialEq)] pub enum DTLSMessage<'a> { Handshake(DTLSMessageHandshake<'a>), ChangeCipherSpec, Alert(TlsMessageAlert), ApplicationData(TlsMessageApplicationData<'a>), Heartbeat(TlsMessageHeartbeat<'a>), } impl<'a> DTLSMessage<'a> { /// Tell if this DTLSMessage is a (handshake) fragment that needs combining with other /// fragments to be a complete message. pub fn is_fragment(&self) -> bool { match self { DTLSMessage::Handshake(h) => matches!(h.body, DTLSMessageHandshakeBody::Fragment(_)), _ => false, } } } // --------------------------- PARSERS --------------------------- /// DTLS record header // Section 4.1 of RFC6347 pub fn parse_dtls_record_header(i: &[u8]) -> IResult<&[u8], DTLSRecordHeader> { let (i, content_type) = TlsRecordType::parse(i)?; let (i, version) = TlsVersion::parse(i)?; let (i, int0) = be_u64(i)?; let epoch = (int0 >> 48) as u16; let sequence_number = int0 & 0xffff_ffff_ffff; let (i, length) = be_u16(i)?; let record = DTLSRecordHeader { content_type, version, epoch, sequence_number, length, }; Ok((i, record)) } /// Treat the entire input as an opaque fragment. fn parse_dtls_fragment(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> { Ok((&[], DTLSMessageHandshakeBody::Fragment(i))) } /// DTLS Client Hello // Section 4.2 of RFC6347 fn parse_dtls_client_hello(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> { let (i, version) = TlsVersion::parse(i)?; let (i, random) = take(32usize)(i)?; let (i, sidlen) = verify(be_u8, |&n| n <= 32)(i)?; let (i, session_id) = cond(sidlen > 0, take(sidlen as usize))(i)?; let (i, cookie) = length_data(be_u8)(i)?; let (i, ciphers_len) = be_u16(i)?; let (i, ciphers) = parse_cipher_suites(i, ciphers_len as usize)?; let (i, comp_len) = be_u8(i)?; let (i, comp) = parse_compressions_algs(i, comp_len as usize)?; let (i, ext) = opt(complete(length_data(be_u16)))(i)?; let content = DTLSClientHello { version, random, session_id, cookie, ciphers, comp, ext, }; Ok((i, DTLSMessageHandshakeBody::ClientHello(content))) } /// DTLS Client Hello // Section 4.2 of RFC6347 fn parse_dtls_hello_verify_request(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> { let (i, server_version) = TlsVersion::parse(i)?; let (i, cookie) = length_data(be_u8)(i)?; let content = DTLSHelloVerifyRequest { server_version, cookie, }; Ok((i, DTLSMessageHandshakeBody::HelloVerifyRequest(content))) } fn parse_dtls_handshake_msg_server_hello_tlsv12( i: &[u8], ) -> IResult<&[u8], DTLSMessageHandshakeBody> { map( parse_tls_server_hello_tlsv12::, DTLSMessageHandshakeBody::ServerHello, )(i) } fn parse_dtls_handshake_msg_serverdone( i: &[u8], len: usize, ) -> IResult<&[u8], DTLSMessageHandshakeBody> { map(take(len), DTLSMessageHandshakeBody::ServerDone)(i) } fn parse_dtls_handshake_msg_clientkeyexchange( i: &[u8], len: usize, ) -> IResult<&[u8], DTLSMessageHandshakeBody> { map( parse_tls_clientkeyexchange(len), DTLSMessageHandshakeBody::ClientKeyExchange, )(i) } fn parse_dtls_handshake_msg_certificate(i: &[u8]) -> IResult<&[u8], DTLSMessageHandshakeBody> { map(parse_tls_certificate, DTLSMessageHandshakeBody::Certificate)(i) } /// Parse a DTLS handshake message pub fn parse_dtls_message_handshake(i: &[u8]) -> IResult<&[u8], DTLSMessage> { let (i, msg_type) = map(be_u8, TlsHandshakeType)(i)?; let (i, length) = be_u24(i)?; let (i, message_seq) = be_u16(i)?; let (i, fragment_offset) = be_u24(i)?; let (i, fragment_length) = be_u24(i)?; // This packet contains fragment_length (which is less than length for fragmentation) let (i, raw_msg) = take(fragment_length)(i)?; // Handshake messages can be fragmented over multiple packets. When fragmented, the user // needs the fragment_offset, fragment_length and length to determine whether they received // all the fragments. The DTLS spec allows for overlapping and duplicated fragments. let is_fragment = fragment_offset > 0 || fragment_length < length; let (_, body) = match msg_type { _ if is_fragment => parse_dtls_fragment(raw_msg), TlsHandshakeType::ClientHello => parse_dtls_client_hello(raw_msg), TlsHandshakeType::HelloVerifyRequest => parse_dtls_hello_verify_request(raw_msg), TlsHandshakeType::ServerHello => parse_dtls_handshake_msg_server_hello_tlsv12(raw_msg), TlsHandshakeType::ServerDone => { parse_dtls_handshake_msg_serverdone(raw_msg, length as usize) } TlsHandshakeType::ClientKeyExchange => { parse_dtls_handshake_msg_clientkeyexchange(raw_msg, length as usize) } TlsHandshakeType::Certificate => parse_dtls_handshake_msg_certificate(raw_msg), _ => { // eprintln!("Unsupported message type {:?}", msg_type); Err(Err::Error(make_error(i, ErrorKind::Switch))) } }?; let msg = DTLSMessageHandshake { msg_type, length, message_seq, fragment_offset, fragment_length, body, }; Ok((i, DTLSMessage::Handshake(msg))) } /// Parse a DTLS changecipherspec message // XXX add extra verification hdr.len == 1 pub fn parse_dtls_message_changecipherspec(i: &[u8]) -> IResult<&[u8], DTLSMessage> { let (i, _) = verify(be_u8, |&tag| tag == 0x01)(i)?; Ok((i, DTLSMessage::ChangeCipherSpec)) } /// Parse a DTLS alert message // XXX add extra verification hdr.len == 2 pub fn parse_dtls_message_alert(i: &[u8]) -> IResult<&[u8], DTLSMessage> { let (i, alert) = TlsMessageAlert::parse(i)?; Ok((i, DTLSMessage::Alert(alert))) } pub fn parse_dtls_record_with_header<'i>( i: &'i [u8], hdr: &DTLSRecordHeader, ) -> IResult<&'i [u8], Vec>> { match hdr.content_type { TlsRecordType::ChangeCipherSpec => many1(complete(parse_dtls_message_changecipherspec))(i), TlsRecordType::Alert => many1(complete(parse_dtls_message_alert))(i), TlsRecordType::Handshake => many1(complete(parse_dtls_message_handshake))(i), // TlsRecordType::ApplicationData => many1(complete(parse_tls_message_applicationdata))(i), // TlsRecordType::Heartbeat => parse_tls_message_heartbeat(i, hdr.length), _ => { // eprintln!("Unsupported record type {:?}", hdr.content_type); Err(Err::Error(make_error(i, ErrorKind::Switch))) } } } /// Parse one DTLS plaintext record // Section 4.1 of RFC6347 pub fn parse_dtls_plaintext_record(i: &[u8]) -> IResult<&[u8], DTLSPlaintext> { let (i, header) = parse_dtls_record_header(i)?; // As in TLS 1.2, the length should not exceed 2^14. if header.length > MAX_RECORD_LEN { return Err(Err::Error(make_error(i, ErrorKind::TooLarge))); } let (i, messages) = map_parser(take(header.length as usize), |i| { parse_dtls_record_with_header(i, &header) })(i)?; Ok((i, DTLSPlaintext { header, messages })) } /// Parse multiple DTLS plaintext record // Section 4.1 of RFC6347 pub fn parse_dtls_plaintext_records(i: &[u8]) -> IResult<&[u8], Vec> { many1(complete(parse_dtls_plaintext_record))(i) } tls-parser-0.12.2/src/lib.rs000064400000000000000000000153331046102023000137120ustar 00000000000000//! [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT) //! [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE) //! [![Crates.io Version](https://img.shields.io/crates/v/tls-parser.svg)](https://crates.io/crates/tls-parser) //! [![GitHub CI](https://github.com/cpu/tls-parser/actions/workflows/rust.yml/badge.svg)](https://github.com/cpu/tls-parser/actions/workflows/rust.yml) //! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.70.0+-lightgray.svg)](#rust-version-requirements) //! //! # TLS Parser //! //! A TLS parser, implemented with the [nom](https://github.com/Geal/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](https://github.com/rusticata/rusticata/blob/master/src/tls.rs) //! 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](https://github.com/rusticata/tls-parser) //! and is part of the [Rusticata](https://github.com/rusticata) project. //! //! ## Parsing records //! //! The main parsing functions are located in the [tls.rs](src/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 //! //! ```rust //! 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: //! //! ```rust //! # use tls_parser::{parse_tls_raw_record, parse_tls_record_with_header}; //! # use tls_parser::nom::{Err, IResult}; //! //! # let bytes : &[u8]= include_bytes!("../assets/client_hello_dhe.bin"); //! // [ 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](https://github.com/rusticata/rusticata/blob/master/src/tls.rs) file of //! the [rusticata](https://github.com/rusticata/rusticata) crate. //! //! ## State machine //! //! A TLS state machine is provided in [tls_states.rs](src/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)`. //! //! ```rust //! # use tls_parser::{tls_state_transition, TlsMessage, TlsState}; //! # use tls_parser::nom::{Err, IResult}; //! //! struct ParseContext { //! state: TlsState, //! } //! //! # fn update_state_machine(msg: &TlsMessage, ctx: &mut ParseContext, to_server:bool) -> Result<(),&'static str> { //! 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). #![deny(/*missing_docs,*/ unstable_features, /*unused_import_braces,*/ unused_qualifications)] #![forbid(unsafe_code)] #![allow(clippy::upper_case_acronyms)] #![no_std] #[cfg(any(test, feature = "std"))] #[macro_use] extern crate std; extern crate alloc; mod certificate_transparency; mod dtls; mod tls_alert; mod tls_ciphers; mod tls_debug; mod tls_dh; mod tls_ec; mod tls_extensions; mod tls_handshake; mod tls_message; mod tls_record; mod tls_sign_hash; mod tls_states; pub use certificate_transparency::*; pub use dtls::*; pub use tls_alert::*; pub use tls_ciphers::*; pub use tls_dh::*; pub use tls_ec::*; pub use tls_extensions::*; pub use tls_handshake::*; pub use tls_message::*; pub use tls_record::*; pub use tls_sign_hash::*; pub use tls_states::*; #[cfg(all(feature = "serialize", not(feature = "std")))] compile_error!("features `serialize` cannot be enabled when using `no_std`"); #[cfg(all(feature = "serialize", feature = "std"))] mod tls_serialize; #[cfg(feature = "serialize")] pub use tls_serialize::*; pub use nom; pub use nom::{Err, IResult}; pub use rusticata_macros; tls-parser-0.12.2/src/tls_alert.rs000064400000000000000000000054751046102023000151430ustar 00000000000000use nom_derive::*; use rusticata_macros::newtype_enum; /// TLS alert severity #[derive(Clone, Copy, Debug, PartialEq, Eq, Nom)] pub struct TlsAlertSeverity(pub u8); newtype_enum! { impl display TlsAlertSeverity { Warning = 0x01, Fatal = 0x02 } } /// TLS alert description /// /// Alerts are defined in the [IANA TLS Alert /// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-6) #[derive(Clone, Copy, Debug, PartialEq, Eq, Nom)] pub struct TlsAlertDescription(pub u8); newtype_enum! { impl display TlsAlertDescription { CloseNotify = 0x00, UnexpectedMessage = 0x0A, BadRecordMac = 0x14, DecryptionFailed = 0x15, RecordOverflow = 0x16, DecompressionFailure = 0x1E, HandshakeFailure = 0x28, NoCertificate = 0x29, BadCertificate = 0x2A, UnsupportedCertificate = 0x2B, CertificateRevoked = 0x2C, CertificateExpired = 0x2D, CertificateUnknown = 0x2E, IllegalParameter = 0x2F, UnknownCa = 0x30, AccessDenied = 0x31, DecodeError = 0x32, DecryptError = 0x33, ExportRestriction = 0x3C, ProtocolVersion = 0x46, InsufficientSecurity = 0x47, InternalError = 0x50, InappropriateFallback = 0x56, UserCancelled = 0x5A, NoRenegotiation = 0x64, MissingExtension = 0x6d, UnsupportedExtension = 0x6e, CertUnobtainable = 0x6f, UnrecognizedName = 0x70, BadCertStatusResponse = 0x71, BadCertHashValue = 0x72, UnknownPskIdentity = 0x73, CertificateRequired = 0x74, NoApplicationProtocol = 0x78 // [RFC7301] } } /// TLS alert message #[derive(Clone, PartialEq, Nom)] pub struct TlsMessageAlert { /// Should match a [TlsAlertSeverity](enum.TlsAlertSeverity.html) value pub severity: TlsAlertSeverity, /// Should match a [TlsAlertDescription](enum.TlsAlertDescription.html) value pub code: TlsAlertDescription, } #[cfg(test)] mod tests { use crate::tls_alert::*; #[test] fn test_tlsalert_cast_severity() { let a = TlsAlertSeverity::Warning; let a_u8 = a.0; assert_eq!(a_u8, 0x01); let b = TlsAlertSeverity(a_u8); assert_eq!(b, TlsAlertSeverity::Warning); let s = format!("{}", b); assert_eq!(s, "Warning"); let s = format!("{}", TlsAlertSeverity(129)); assert_eq!(s, "TlsAlertSeverity(129 / 0x81)"); } #[test] fn test_tlsalert_cast_description() { let a = TlsAlertDescription::HandshakeFailure; let a_u8 = a.0; assert_eq!(a_u8, 0x28); let b = TlsAlertDescription(a_u8); assert_eq!(b, TlsAlertDescription::HandshakeFailure); } } // mod tests tls-parser-0.12.2/src/tls_ciphers.rs000064400000000000000000000141771046102023000154700ustar 00000000000000//! //! The [CIPHERS](static.CIPHERS.html) static hash map is built during the //! compilation of the crate, using `build.rs`. It parses a file derived from //! the [IANA TLS Cipher Suite //! Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4) //! to automatically extract parameters and add all known ciphersuites. #![allow(non_camel_case_types)] #![allow(clippy::unreadable_literal)] use core::convert::TryFrom; use num_enum::TryFromPrimitive; use crate::TlsCipherSuiteID; #[derive(Debug)] pub struct CipherSuiteNotFound(()); /// Key exchange methods #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum TlsCipherKx { Null, Psk, Krb5, Srp, Rsa, Dh, Dhe, Ecdh, Ecdhe, Aecdh, Eccpwd, Tls13, } /// Authentication methods #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum TlsCipherAu { Null, Psk, Krb5, Srp, Srp_Dss, Srp_Rsa, Dss, Rsa, Dhe, Ecdsa, Eccpwd, Tls13, } /// Encryption methods #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum TlsCipherEnc { Null, Des, TripleDes, Rc2, Rc4, Aria, Idea, Seed, Aes, Camellia, Chacha20_Poly1305, Sm4, Aegis, } /// Encryption modes #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum TlsCipherEncMode { Null, Cbc, Ccm, Gcm, } /// Message Authentication Code (MAC) methods #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum TlsCipherMac { Null, HmacMd5, HmacSha1, HmacSha256, HmacSha384, HmacSha512, Aead, } /// Pseudo-Random Function (PRF) Function #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum TlsPRF { Default, Null, Md5AndSha1, Sha1, Sha256, Sha384, Sha512, Sm3, } /// TLS Ciphersuite /// /// A CipherSuite is a set of algorithm and parameters used to secure /// a network connection. #[derive(Clone, Debug, PartialEq, Eq)] pub struct TlsCipherSuite { /// The IANA name of this ciphersuite pub name: &'static str, /// The 16-bit identifier, provided by IANA, for this ciphersuite pub id: TlsCipherSuiteID, /// The Key Exchange method for this ciphersuite pub kx: TlsCipherKx, /// The Authentication method for this ciphersuite pub au: TlsCipherAu, /// Encryption cipher pub enc: TlsCipherEnc, /// Encryption mode pub enc_mode: TlsCipherEncMode, /// Key size of the encryption, in bits pub enc_size: u16, /// Message Authentication Code (MAC) algorithm pub mac: TlsCipherMac, /// Message Authentication Code (MAC) length pub mac_size: u16, /// Pseudo-Random Function, if specific pub prf: TlsPRF, } include!(concat!(env!("OUT_DIR"), "/codegen.rs")); impl TlsCipherSuite { /// Attempt to get reference on `TlsCipherSuite` identified by `id`. pub fn from_id(id: u16) -> Option<&'static TlsCipherSuite> { CIPHERS.get(&id) } /// Attempt to get reference on `TlsCipherSuite` identified by `name`. pub fn from_name(name: &str) -> Option<&'static TlsCipherSuite> { CIPHERS.values().find(|&v| v.name == name) } /// Get the key of this ciphersuite encryption algorithm, in bytes pub const fn enc_key_size(&self) -> usize { (self.enc_size / 8) as usize } /// Get the block size of this ciphersuite encryption algorithm, in bytes pub const fn enc_block_size(&self) -> usize { match self.enc { TlsCipherEnc::Null => 0, TlsCipherEnc::Des | TlsCipherEnc::Idea | TlsCipherEnc::Rc2 | TlsCipherEnc::TripleDes => 8, TlsCipherEnc::Aes | TlsCipherEnc::Aria | TlsCipherEnc::Camellia | TlsCipherEnc::Seed | TlsCipherEnc::Sm4 => 16, // stream ciphers TlsCipherEnc::Chacha20_Poly1305 | TlsCipherEnc::Rc4 | TlsCipherEnc::Aegis => 0, } } /// Get the length of this ciphersuite MAC algorithm, in bytes pub const fn mac_length(&self) -> usize { match self.mac { TlsCipherMac::Null => 0, TlsCipherMac::Aead => 0, TlsCipherMac::HmacMd5 => 16, TlsCipherMac::HmacSha1 => 20, TlsCipherMac::HmacSha256 => 32, TlsCipherMac::HmacSha384 => 48, TlsCipherMac::HmacSha512 => 64, } } } impl TryFrom for &'static TlsCipherSuite { type Error = CipherSuiteNotFound; fn try_from(value: u16) -> Result { CIPHERS.get(&value).ok_or(CipherSuiteNotFound(())) } } impl TryFrom for &'static TlsCipherSuite { type Error = CipherSuiteNotFound; fn try_from(value: TlsCipherSuiteID) -> Result { CIPHERS.get(&value.0).ok_or(CipherSuiteNotFound(())) } } impl<'a> TryFrom<&'a str> for &'static TlsCipherSuite { type Error = CipherSuiteNotFound; fn try_from(value: &'a str) -> Result { CIPHERS .values() .find(|&v| v.name == value) .ok_or(CipherSuiteNotFound(())) } } #[cfg(test)] mod tests { use crate::tls_ciphers::{TlsCipherKx, TlsCipherSuite, CIPHERS}; use core::convert::TryFrom; #[test] fn test_cipher_count() { println!("loaded: {} cipher suites", CIPHERS.len()); assert!(!CIPHERS.is_empty()); } #[test] fn test_cipher_from_id() { let cipher = <&TlsCipherSuite>::try_from(0xc025).expect("could not get cipher"); println!("Found cipher: {:?}", cipher); } #[test] fn test_cipher_from_name() { let cipher = <&TlsCipherSuite>::try_from("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384") .expect("could not get cipher"); println!("Found cipher: {:?}", cipher); } #[test] fn test_cipher_filter() { let ecdhe_ciphers_count = CIPHERS .values() .filter(|c| c.kx == TlsCipherKx::Ecdhe) .count(); assert!(ecdhe_ciphers_count > 20); } } tls-parser-0.12.2/src/tls_debug.rs000064400000000000000000000261241046102023000151140ustar 00000000000000use alloc::format; use alloc::vec::Vec; use core::fmt; use core::str::from_utf8; use rusticata_macros::debug::HexSlice; use crate::tls_alert::*; use crate::tls_dh::*; use crate::tls_ec::*; use crate::tls_extensions::*; use crate::tls_handshake::*; use crate::tls_record::*; use crate::tls_sign_hash::*; // ------------------------- tls.rs ------------------------------ impl<'a> fmt::Debug for TlsClientHelloContents<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsClientHelloContents") .field("version", &self.version) .field("random", &HexSlice(self.random)) .field("session_id", &self.session_id.map(HexSlice)) .field("ciphers", &self.ciphers) .field("comp", &self.comp) .field("ext", &self.ext.map(HexSlice)) .finish() } } impl<'a> fmt::Debug for TlsServerHelloContents<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsServerHelloContents") .field("version", &self.version) .field("random", &HexSlice(self.random)) .field("session_id", &self.session_id.map(HexSlice)) .field("cipher", &self.cipher) .field("compression", &self.compression) .field("ext", &self.ext.map(HexSlice)) .finish() } } impl<'a> fmt::Debug for TlsServerHelloV13Draft18Contents<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsServerHelloV13Draft18Contents") .field("version", &self.version) .field("random", &HexSlice(self.random)) .field("cipher", &self.cipher) .field("ext", &self.ext.map(HexSlice)) .finish() } } impl<'a> fmt::Debug for TlsHelloRetryRequestContents<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsHelloRetryRequestContents") .field("version", &self.version) .field("ext", &self.ext.map(HexSlice)) .finish() } } impl<'a> fmt::Debug for RawCertificate<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("RawCertificate") .field("data", &HexSlice(self.data)) .finish() } } impl<'a> fmt::Debug for TlsServerKeyExchangeContents<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsServerKeyExchangeContents") .field("parameters", &HexSlice(self.parameters)) .finish() } } impl<'a> fmt::Debug for TlsClientKeyExchangeContents<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { TlsClientKeyExchangeContents::Dh(p) => fmt.write_fmt(format_args!("{:?}", HexSlice(p))), TlsClientKeyExchangeContents::Ecdh(ref p) => fmt.write_fmt(format_args!("{:?}", p)), TlsClientKeyExchangeContents::Unknown(p) => { fmt.write_fmt(format_args!("{:?}", HexSlice(p))) } } } } impl fmt::Debug for TlsRecordHeader { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsRecordHeader") .field("type", &self.record_type) .field("version", &self.version) .field("len", &self.len) .finish() } } // ------------------------- tls_alert.rs ------------------------------ impl fmt::Debug for TlsMessageAlert { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("TlsMessageAlert") .field("severity", &self.severity) .field("code", &self.code) .finish() } } // ------------------------- tls_dh.rs ------------------------------ impl<'a> fmt::Debug for ServerDHParams<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let gs = self.dh_g.len() * 8; fmt.debug_struct("ServerDHParams") .field("group size", &gs) .field("dh_p", &HexSlice(self.dh_p)) .field("dh_g", &HexSlice(self.dh_g)) .field("dh_ys", &HexSlice(self.dh_ys)) .finish() } } // ------------------------- tls_ec.rs ------------------------------ impl<'a> fmt::Debug for ECParametersContent<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { ECParametersContent::ExplicitPrime(ref p) => { fmt.write_fmt(format_args!("ExplicitPrime({:?})", p)) } // ECParametersContent::ExplicitChar2(ref p) => { // fmt.write_fmt(format_args!("ExplicitChar2({:?})", HexSlice(p))) // } ECParametersContent::NamedGroup(p) => write!(fmt, "{}", p), } } } impl<'a> fmt::Debug for ECParameters<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("ECParameters") .field("curve_type", &format!("{}", self.curve_type)) .field("params_content", &self.params_content) .finish() } } // ------------------------- tls_extensions.rs ------------------------------ impl<'a> fmt::Debug for TlsExtension<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { TlsExtension::SNI(ref v) => { let v: Vec<_> = v .iter() .map(|&(ty, n)| { let s = from_utf8(n).unwrap_or(""); format!("type={},name={}", ty, s) }) .collect(); write!(fmt, "TlsExtension::SNI({:?})", v) } TlsExtension::MaxFragmentLength(l) => { write!(fmt, "TlsExtension::MaxFragmentLength({})", l) } TlsExtension::StatusRequest(data) => { write!(fmt, "TlsExtension::StatusRequest({:?})", data) } TlsExtension::EllipticCurves(ref v) => { let v2: Vec<_> = v.iter().map(|&curve| format!("{}", curve)).collect(); write!(fmt, "TlsExtension::EllipticCurves({:?})", v2) } TlsExtension::EcPointFormats(v) => write!(fmt, "TlsExtension::EcPointFormats({:?})", v), TlsExtension::SignatureAlgorithms(ref v) => { let v2: Vec<_> = v .iter() .map(|&alg| { let s = format!("{}", SignatureScheme(alg)); if s.starts_with("SignatureScheme") { format!( "{}", SignatureAndHashAlgorithm { hash: HashAlgorithm((alg >> 8) as u8), sign: SignAlgorithm((alg & 0xff) as u8) } ) } else { s } }) .collect(); write!(fmt, "TlsExtension::SignatureAlgorithms({:?})", v2) } TlsExtension::SessionTicket(data) => { write!(fmt, "TlsExtension::SessionTicket(data={:?})", data) } TlsExtension::RecordSizeLimit(data) => { write!(fmt, "TlsExtension::RecordSizeLimit(data={})", data) } TlsExtension::KeyShareOld(data) => { write!(fmt, "TlsExtension::KeyShareOld(data={:?})", HexSlice(data)) } TlsExtension::KeyShare(data) => { write!(fmt, "TlsExtension::KeyShare(data={:?})", HexSlice(data)) } TlsExtension::PreSharedKey(data) => { write!(fmt, "TlsExtension::PreSharedKey(data={:?})", HexSlice(data)) } TlsExtension::EarlyData(o) => write!(fmt, "TlsExtension::EarlyData({:?})", o), TlsExtension::SupportedVersions(ref v) => { let v2: Vec<_> = v.iter().map(|c| format!("{}", c)).collect(); write!(fmt, "TlsExtension::SupportedVersions(v={:?})", v2) } TlsExtension::Cookie(data) => write!(fmt, "TlsExtension::Cookie(data={:?})", data), TlsExtension::PskExchangeModes(ref v) => { write!(fmt, "TlsExtension::PskExchangeModes({:?})", v) } TlsExtension::Heartbeat(mode) => write!(fmt, "TlsExtension::Heartbeat(mode={})", mode), TlsExtension::ALPN(ref v) => { let v: Vec<_> = v .iter() .map(|c| from_utf8(c).unwrap_or("")) .collect(); write!(fmt, "TlsExtension::ALPN({:?})", v) } TlsExtension::SignedCertificateTimestamp(data) => write!( fmt, "TlsExtension::SignedCertificateTimestamp(data={:?})", data ), TlsExtension::Padding(data) => write!(fmt, "TlsExtension::Padding(data={:?})", data), TlsExtension::EncryptThenMac => write!(fmt, "TlsExtension::EncryptThenMac"), TlsExtension::ExtendedMasterSecret => write!(fmt, "TlsExtension::ExtendedMasterSecret"), TlsExtension::OidFilters(ref v) => { let v: Vec<_> = v.iter().map(|c| format!("{:?}", c)).collect(); write!(fmt, "TlsExtension::OidFilters({:?})", v) } TlsExtension::PostHandshakeAuth => write!(fmt, "TlsExtension::PostHandshakeAuth"), TlsExtension::NextProtocolNegotiation => { write!(fmt, "TlsExtension::NextProtocolNegotiation") } TlsExtension::RenegotiationInfo(data) => { write!(fmt, "TlsExtension::RenegotiationInfo(data={:?})", data) } TlsExtension::EncryptedServerName { ciphersuite, group, .. } => write!( fmt, "TlsExtension::EncryptedServerName{{cipher: {:?}, group: {:?} ..}}", ciphersuite, group ), TlsExtension::Grease(t, data) => write!( fmt, "TlsExtension::Grease(0x{:x},data={:?})", t, HexSlice(data) ), TlsExtension::Unknown(t, data) => write!( fmt, "TlsExtension::Unknown(type=0x{:x},data={:?})", t.0, data ), } } } // ------------------------- tls_sign_hash.rs ------------------------------ impl fmt::Display for SignatureAndHashAlgorithm { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "HashSign({},{})", self.hash, self.sign) } } impl fmt::Debug for SignatureAndHashAlgorithm { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "SignatureAndHashAlgorithm({},{})", self.hash, self.sign ) } } impl<'a> fmt::Debug for DigitallySigned<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("DigitallySigned") .field("alg", &self.alg) .field("data", &HexSlice(self.data)) .finish() } } tls-parser-0.12.2/src/tls_dh.rs000064400000000000000000000013331046102023000144140ustar 00000000000000use nom::multi::length_data; use nom::number::streaming::be_u16; use nom::IResult; use nom_derive::*; /// Diffie-Hellman parameters, defined in \[RFC5246\] section 7.4.3 #[derive(PartialEq, NomBE)] pub struct ServerDHParams<'a> { /// The prime modulus used for the Diffie-Hellman operation. #[nom(Parse = "length_data(be_u16)")] pub dh_p: &'a [u8], /// The generator used for the Diffie-Hellman operation. #[nom(Parse = "length_data(be_u16)")] pub dh_g: &'a [u8], /// The server's Diffie-Hellman public value (g^X mod p). #[nom(Parse = "length_data(be_u16)")] pub dh_ys: &'a [u8], } #[inline] pub fn parse_dh_params(i: &[u8]) -> IResult<&[u8], ServerDHParams> { ServerDHParams::parse(i) } tls-parser-0.12.2/src/tls_ec.rs000064400000000000000000000142011046102023000144060ustar 00000000000000use alloc::vec::Vec; use nom::error::{make_error, ErrorKind}; use nom::multi::length_data; use nom::number::streaming::be_u8; use nom::{Err, IResult}; use nom_derive::*; use rusticata_macros::newtype_enum; /// Named elliptic curves /// /// Named curves, as defined in [RFC4492](https://tools.ietf.org/html/rfc4492), [RFC7027](https://tools.ietf.org/html/rfc7027), [RFC7919](https://tools.ietf.org/html/rfc7919) and /// [IANA Supported Groups /// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8) #[derive(Clone, Copy, PartialEq, Eq, NomBE)] pub struct NamedGroup(pub u16); newtype_enum! { impl debug NamedGroup { Sect163k1 = 1, Sect163r1 = 2, Sect163r2 = 3, Sect193r1 = 4, Sect193r2 = 5, Sect233k1 = 6, Sect233r1 = 7, Sect239k1 = 8, Sect283k1 = 9, Sect283r1 = 10, Sect409k1 = 11, Sect409r1 = 12, Sect571k1 = 13, Sect571r1 = 14, Secp160k1 = 15, Secp160r1 = 16, Secp160r2 = 17, Secp192k1 = 18, Secp192r1 = 19, Secp224k1 = 20, Secp224r1 = 21, Secp256k1 = 22, Secp256r1 = 23, Secp384r1 = 24, Secp521r1 = 25, BrainpoolP256r1 = 26, BrainpoolP384r1 = 27, BrainpoolP512r1 = 28, EcdhX25519 = 29, EcdhX448 = 30, BrainpoolP256r1tls13 = 31, BrainpoolP384r1tls13 = 32, BrainpoolP512r1tls13 = 33, Sm2 = 41, Ffdhe2048 = 0x100, Ffdhe3072 = 0x101, Ffdhe4096 = 0x102, Ffdhe6144 = 0x103, Ffdhe8192 = 0x104, ArbitraryExplicitPrimeCurves = 0xFF01, ArbitraryExplicitChar2Curves = 0xFF02, } } impl NamedGroup { /// Return key size of curve in bits, or None if unknown pub fn key_bits(self: NamedGroup) -> Option { match self { NamedGroup::Sect163k1 => Some(163), NamedGroup::Sect163r1 => Some(163), NamedGroup::Sect163r2 => Some(163), NamedGroup::Sect193r1 => Some(193), NamedGroup::Sect193r2 => Some(193), NamedGroup::Sect233k1 => Some(233), NamedGroup::Sect233r1 => Some(233), NamedGroup::Sect239k1 => Some(239), NamedGroup::Sect283k1 => Some(283), NamedGroup::Sect283r1 => Some(283), NamedGroup::Sect409k1 => Some(409), NamedGroup::Sect409r1 => Some(409), NamedGroup::Sect571k1 => Some(571), NamedGroup::Sect571r1 => Some(571), NamedGroup::Secp160k1 => Some(160), NamedGroup::Secp160r1 => Some(160), NamedGroup::Secp160r2 => Some(160), NamedGroup::Secp192k1 => Some(192), NamedGroup::Secp192r1 => Some(192), NamedGroup::Secp224k1 => Some(224), NamedGroup::Secp224r1 => Some(224), NamedGroup::Secp256k1 => Some(256), NamedGroup::Secp256r1 => Some(256), NamedGroup::Secp384r1 => Some(384), NamedGroup::Secp521r1 => Some(521), NamedGroup::BrainpoolP256r1 => Some(256), NamedGroup::BrainpoolP384r1 => Some(384), NamedGroup::BrainpoolP512r1 => Some(521), NamedGroup::EcdhX25519 => Some(253), _ => None, } } } /// Elliptic curve /// /// a and b specify the coefficients of the curve #[derive(Debug, PartialEq, NomBE)] pub struct ECCurve<'a> { #[nom(Parse = "length_data(be_u8)")] pub a: &'a [u8], #[nom(Parse = "length_data(be_u8)")] pub b: &'a [u8], } /// Elliptic curve types, as defined in the /// [IANA EC Curve Type Registry /// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10) #[derive(Clone, Copy, PartialEq, Eq, NomBE)] pub struct ECCurveType(pub u8); newtype_enum! { impl display ECCurveType { ExplicitPrime = 1, ExplicitChar2 = 2, NamedGroup = 3, } } /// EC Point #[derive(Clone, Debug, PartialEq, NomBE)] pub struct ECPoint<'a> { #[nom(Parse = "length_data(be_u8)")] pub point: &'a [u8], } /// Elliptic curve parameters, conveyed verbosely as a prime field, as /// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4 #[derive(Debug, PartialEq, NomBE)] pub struct ExplicitPrimeContent<'a> { #[nom(Parse = "length_data(be_u8)")] pub prime_p: &'a [u8], pub curve: ECCurve<'a>, pub base: ECPoint<'a>, #[nom(Parse = "length_data(be_u8)")] pub order: &'a [u8], #[nom(Parse = "length_data(be_u8)")] pub cofactor: &'a [u8], } /// Elliptic curve parameters content (depending on EC type) #[derive(PartialEq, Nom)] #[nom(Selector = "ECCurveType")] pub enum ECParametersContent<'a> { #[nom(Selector = "ECCurveType::ExplicitPrime")] ExplicitPrime(ExplicitPrimeContent<'a>), // TODO ExplicitChar2 is defined in [RFC4492] section 5.4 // #[nom(Selector="ECCurveType::ExplicitChar2")] // ExplicitChar2(&'a [u8]), #[nom(Selector = "ECCurveType::NamedGroup")] NamedGroup(NamedGroup), } /// Elliptic curve parameters, /// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4 #[derive(PartialEq, NomBE)] pub struct ECParameters<'a> { /// Should match a [ECCurveType](enum.ECCurveType.html) value pub curve_type: ECCurveType, #[nom(Parse = "{|i| ECParametersContent::parse(i, curve_type)}")] pub params_content: ECParametersContent<'a>, } /// ECDH parameters /// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4 #[derive(Debug, PartialEq, NomBE)] pub struct ServerECDHParams<'a> { pub curve_params: ECParameters<'a>, pub public: ECPoint<'a>, } /// Parse the entire input as a list of named groups (curves) pub fn parse_named_groups(i: &[u8]) -> IResult<&[u8], Vec> { let len = i.len(); if len == 0 { return Ok((i, Vec::new())); } if len % 2 == 1 || len > i.len() { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } let v = (i[..len]) .chunks(2) .map(|chunk| NamedGroup((chunk[0] as u16) << 8 | chunk[1] as u16)) .collect(); Ok((&i[len..], v)) } #[inline] pub fn parse_ec_parameters(i: &[u8]) -> IResult<&[u8], ECParameters> { ECParameters::parse(i) } #[inline] pub fn parse_ecdh_params(i: &[u8]) -> IResult<&[u8], ServerECDHParams> { ServerECDHParams::parse(i) } tls-parser-0.12.2/src/tls_extensions.rs000064400000000000000000000700401046102023000162210ustar 00000000000000//! //! TLS extensions are defined in: //! //! - [RFC4492](https://tools.ietf.org/html/rfc4492) //! - [RFC6066](https://tools.ietf.org/html/rfc6066) //! - [RFC7366](https://tools.ietf.org/html/rfc7366) //! - [RFC7627](https://tools.ietf.org/html/rfc7627) use crate::tls_ec::{parse_named_groups, NamedGroup}; use crate::tls_handshake::{parse_tls_versions, TlsCipherSuiteID, TlsVersion}; use alloc::{vec, vec::Vec}; use nom::bytes::streaming::{tag, take}; use nom::combinator::{complete, cond, map, map_parser, opt, verify}; use nom::error::{make_error, ErrorKind}; use nom::multi::{length_data, many0}; use nom::number::streaming::{be_u16, be_u32, be_u8}; use nom::{Err, IResult}; use nom_derive::{NomBE, Parse}; use rusticata_macros::newtype_enum; /// TLS extension types, /// defined in the [IANA Transport Layer Security (TLS) /// Extensions](http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml) /// registry #[derive(Clone, Copy, Debug, PartialEq, Eq, NomBE)] pub struct TlsExtensionType(pub u16); newtype_enum! { impl display TlsExtensionType { ServerName = 0, // [RFC6066] MaxFragmentLength = 1, ClientCertificate = 2, TrustedCaKeys = 3, TruncatedHMac = 4, StatusRequest = 5, // [RFC6066] UserMapping = 6, ClientAuthz = 7, ServerAuthz = 8, CertType = 9, SupportedGroups = 10, // [RFC4492][RFC7919] EcPointFormats = 11, // [RFC4492] Srp = 12, // [RFC5054] SignatureAlgorithms = 13, // [RFC8446] UseSrtp = 14, Heartbeat = 15, // [RFC6520] ApplicationLayerProtocolNegotiation = 16, // [RFC7301] StatusRequestv2 = 17, SignedCertificateTimestamp = 18, ClientCertificateType = 19, ServerCertificateType = 20, Padding = 21, // [RFC7685] EncryptThenMac = 22, // [RFC7366] ExtendedMasterSecret = 23, // [RFC7627] TokenBinding = 24, CachedInfo = 25, RecordSizeLimit = 28, // [RFC8449] SessionTicketTLS = 35, KeyShareOld = 40, // moved to 51 in TLS 1.3 draft 23 PreSharedKey = 41, // [RFC8446] EarlyData = 42, // [RFC8446] SupportedVersions = 43, // [RFC8446] Cookie = 44, // [RFC8446] PskExchangeModes = 45, // [RFC8446] TicketEarlyDataInfo = 46, // TLS 1.3 draft 18, removed in draft 19 CertificateAuthorities = 47, OidFilters = 48, // [RFC8446] PostHandshakeAuth = 49, // TLS 1.3 draft 20 SigAlgorithmsCert = 50, // TLS 1.3 draft 23 KeyShare = 51, // TLS 1.3 draft 23 NextProtocolNegotiation = 13172, Grease = 0xfafa, RenegotiationInfo = 0xff01, // [RFC5746] EncryptedServerName = 0xffce, // draft-ietf-tls-esni } } impl TlsExtensionType { pub fn from_u16(t: u16) -> TlsExtensionType { TlsExtensionType(t) } } impl From for u16 { fn from(ext: TlsExtensionType) -> u16 { ext.0 } } /// TLS extensions /// #[derive(Clone, PartialEq)] pub enum TlsExtension<'a> { SNI(Vec<(SNIType, &'a [u8])>), MaxFragmentLength(u8), StatusRequest(Option<(CertificateStatusType, &'a [u8])>), EllipticCurves(Vec), EcPointFormats(&'a [u8]), SignatureAlgorithms(Vec), RecordSizeLimit(u16), SessionTicket(&'a [u8]), KeyShareOld(&'a [u8]), KeyShare(&'a [u8]), PreSharedKey(&'a [u8]), EarlyData(Option), SupportedVersions(Vec), Cookie(&'a [u8]), PskExchangeModes(Vec), Heartbeat(u8), ALPN(Vec<&'a [u8]>), SignedCertificateTimestamp(Option<&'a [u8]>), Padding(&'a [u8]), EncryptThenMac, ExtendedMasterSecret, OidFilters(Vec>), PostHandshakeAuth, NextProtocolNegotiation, RenegotiationInfo(&'a [u8]), EncryptedServerName { ciphersuite: TlsCipherSuiteID, group: NamedGroup, key_share: &'a [u8], record_digest: &'a [u8], encrypted_sni: &'a [u8], }, Grease(u16, &'a [u8]), Unknown(TlsExtensionType, &'a [u8]), } impl<'a> From<&'a TlsExtension<'a>> for TlsExtensionType { #[rustfmt::skip] fn from(ext: &TlsExtension) -> TlsExtensionType { match *ext { TlsExtension::SNI(_) => TlsExtensionType::ServerName, TlsExtension::MaxFragmentLength(_) => TlsExtensionType::MaxFragmentLength, TlsExtension::StatusRequest(_) => TlsExtensionType::StatusRequest, TlsExtension::EllipticCurves(_) => TlsExtensionType::SupportedGroups, TlsExtension::EcPointFormats(_) => TlsExtensionType::EcPointFormats, TlsExtension::SignatureAlgorithms(_) => TlsExtensionType::SignatureAlgorithms, TlsExtension::SessionTicket(_) => TlsExtensionType::SessionTicketTLS, TlsExtension::RecordSizeLimit(_) => TlsExtensionType::RecordSizeLimit, TlsExtension::KeyShareOld(_) => TlsExtensionType::KeyShareOld, TlsExtension::KeyShare(_) => TlsExtensionType::KeyShare, TlsExtension::PreSharedKey(_) => TlsExtensionType::PreSharedKey, TlsExtension::EarlyData(_) => TlsExtensionType::EarlyData, TlsExtension::SupportedVersions(_) => TlsExtensionType::SupportedVersions, TlsExtension::Cookie(_) => TlsExtensionType::Cookie, TlsExtension::PskExchangeModes(_) => TlsExtensionType::PskExchangeModes, TlsExtension::Heartbeat(_) => TlsExtensionType::Heartbeat, TlsExtension::ALPN(_) => TlsExtensionType::ApplicationLayerProtocolNegotiation, TlsExtension::SignedCertificateTimestamp(_) => TlsExtensionType::SignedCertificateTimestamp, TlsExtension::Padding(_) => TlsExtensionType::Padding, TlsExtension::EncryptThenMac => TlsExtensionType::EncryptThenMac, TlsExtension::ExtendedMasterSecret => TlsExtensionType::ExtendedMasterSecret, TlsExtension::OidFilters(_) => TlsExtensionType::OidFilters, TlsExtension::PostHandshakeAuth => TlsExtensionType::PostHandshakeAuth, TlsExtension::NextProtocolNegotiation => TlsExtensionType::NextProtocolNegotiation, TlsExtension::RenegotiationInfo(_) => TlsExtensionType::RenegotiationInfo, TlsExtension::EncryptedServerName{..} => TlsExtensionType::EncryptedServerName, TlsExtension::Grease(_,_) => TlsExtensionType::Grease, TlsExtension::Unknown(x,_) => x } } } #[derive(Clone, Debug, PartialEq)] pub struct KeyShareEntry<'a> { pub group: NamedGroup, // NamedGroup pub kx: &'a [u8], // Key Exchange Data } #[derive(Clone, Copy, Debug, PartialEq, Eq, NomBE)] pub struct PskKeyExchangeMode(pub u8); newtype_enum! { impl PskKeyExchangeMode { Psk = 0, PskDhe = 1, } } #[derive(Clone, Copy, Debug, PartialEq, Eq, NomBE)] pub struct SNIType(pub u8); newtype_enum! { impl display SNIType { HostName = 0, } } #[derive(Clone, Copy, PartialEq, Eq, NomBE)] pub struct CertificateStatusType(pub u8); newtype_enum! { impl debug CertificateStatusType { OCSP = 1, } } #[derive(Clone, Debug, PartialEq)] pub struct OidFilter<'a> { pub cert_ext_oid: &'a [u8], pub cert_ext_val: &'a [u8], } // struct { // NameType name_type; // select (name_type) { // case host_name: HostName; // } name; // } ServerName; // // enum { // host_name(0), (255) // } NameType; // // opaque HostName<1..2^16-1>; pub fn parse_tls_extension_sni_hostname(i: &[u8]) -> IResult<&[u8], (SNIType, &[u8])> { let (i, t) = SNIType::parse(i)?; let (i, v) = length_data(be_u16)(i)?; Ok((i, (t, v))) } // struct { // ServerName server_name_list<1..2^16-1> // } ServerNameList; pub fn parse_tls_extension_sni_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { if i.is_empty() { // special case: SNI extension in server can be empty return Ok((i, TlsExtension::SNI(Vec::new()))); } let (i, list_len) = be_u16(i)?; let (i, v) = map_parser( take(list_len), many0(complete(parse_tls_extension_sni_hostname)), )(i)?; Ok((i, TlsExtension::SNI(v))) } pub fn parse_tls_extension_sni(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x00])(i)?; map_parser(length_data(be_u16), parse_tls_extension_sni_content)(i) } /// Max fragment length \[RFC6066\] pub fn parse_tls_extension_max_fragment_length_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { map(be_u8, TlsExtension::MaxFragmentLength)(i) } /// Max fragment length \[RFC6066\] pub fn parse_tls_extension_max_fragment_length(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x01])(i)?; map_parser( length_data(be_u16), parse_tls_extension_max_fragment_length_content, )(i) } /// Status Request \[RFC6066\] fn parse_tls_extension_status_request_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { match ext_len { 0 => Ok((i, TlsExtension::StatusRequest(None))), _ => { let (i, status_type) = be_u8(i)?; let (i, request) = take(ext_len - 1)(i)?; Ok(( i, TlsExtension::StatusRequest(Some((CertificateStatusType(status_type), request))), )) } } } pub fn parse_tls_extension_status_request(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x05])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_status_request_content(d, ext_len) })(i) } // defined in rfc8422 pub fn parse_tls_extension_elliptic_curves_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { map_parser( length_data(be_u16), map(parse_named_groups, TlsExtension::EllipticCurves), )(i) } pub fn parse_tls_extension_elliptic_curves(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x0a])(i)?; map_parser( length_data(be_u16), parse_tls_extension_elliptic_curves_content, )(i) } pub fn parse_tls_extension_ec_point_formats_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { map(length_data(be_u8), TlsExtension::EcPointFormats)(i) } pub fn parse_tls_extension_ec_point_formats(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x0a])(i)?; map_parser( length_data(be_u16), parse_tls_extension_ec_point_formats_content, )(i) } /// Parse 'Signature Algorithms' extension (rfc8446, TLS 1.3 only) pub fn parse_tls_extension_signature_algorithms_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, l) = map_parser(length_data(be_u16), many0(complete(be_u16)))(i)?; Ok((i, TlsExtension::SignatureAlgorithms(l))) // XXX SignatureAlgorithms or SignatureScheme } pub fn parse_tls_extension_signature_algorithms(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 13])(i)?; map_parser( length_data(be_u16), parse_tls_extension_signature_algorithms_content, )(i) } // rfc6520 pub fn parse_tls_extension_heartbeat_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { map(be_u8, TlsExtension::Heartbeat)(i) } pub fn parse_tls_extension_heartbeat(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x0d])(i)?; let (i, ext_len) = verify(be_u16, |&n| n == 1)(i)?; map_parser(take(ext_len), parse_tls_extension_heartbeat_content)(i) } fn parse_protocol_name(i: &[u8]) -> IResult<&[u8], &[u8]> { length_data(be_u8)(i) } /// Defined in \[RFC7301\] pub fn parse_tls_extension_alpn_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, v) = map_parser(length_data(be_u16), many0(complete(parse_protocol_name)))(i)?; Ok((i, TlsExtension::ALPN(v))) } /// Defined in \[RFC7685\] fn parse_tls_extension_padding_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> { map(take(ext_len), TlsExtension::Padding)(i) } /// Defined in \[RFC6962\] pub fn parse_tls_extension_signed_certificate_timestamp_content( i: &[u8], ) -> IResult<&[u8], TlsExtension> { map( opt(complete(length_data(be_u16))), TlsExtension::SignedCertificateTimestamp, )(i) } /// Encrypt-then-MAC is defined in \[RFC7366\] fn parse_tls_extension_encrypt_then_mac_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { if ext_len != 0 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } Ok((i, TlsExtension::EncryptThenMac)) } /// Encrypt-then-MAC is defined in \[RFC7366\] pub fn parse_tls_extension_encrypt_then_mac(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x16])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_encrypt_then_mac_content(d, ext_len) })(i) } /// Extended Master Secret is defined in \[RFC7627\] fn parse_tls_extension_extended_master_secret_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { if ext_len != 0 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } Ok((i, TlsExtension::ExtendedMasterSecret)) } /// Extended Master Secret is defined in \[RFC7627\] pub fn parse_tls_extension_extended_master_secret(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x17])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_extended_master_secret_content(d, ext_len) })(i) } /// Extended Record Size Limit is defined in \[RFC7627\] fn parse_tls_extension_record_size_limit(i: &[u8]) -> IResult<&[u8], TlsExtension> { map(be_u16, TlsExtension::RecordSizeLimit)(i) } fn parse_tls_extension_session_ticket_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { map(take(ext_len), TlsExtension::SessionTicket)(i) } pub fn parse_tls_extension_session_ticket(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x23])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_session_ticket_content(d, ext_len) })(i) } fn parse_tls_extension_key_share_old_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { map(take(ext_len), TlsExtension::KeyShareOld)(i) } fn parse_tls_extension_key_share_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> { map(take(ext_len), TlsExtension::KeyShare)(i) } pub fn parse_tls_extension_key_share(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x33])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_key_share_content(d, ext_len) })(i) } fn parse_tls_extension_pre_shared_key_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { map(take(ext_len), TlsExtension::PreSharedKey)(i) } pub fn parse_tls_extension_pre_shared_key(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x28])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_pre_shared_key_content(d, ext_len) })(i) } fn parse_tls_extension_early_data_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> { map(cond(ext_len > 0, be_u32), TlsExtension::EarlyData)(i) } pub fn parse_tls_extension_early_data(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x2a])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_early_data_content(d, ext_len) })(i) } // TLS 1.3 draft 23 // struct { // select (Handshake.msg_type) { // case client_hello: // ProtocolVersion versions<2..254>; // // case server_hello: /* and HelloRetryRequest */ // ProtocolVersion selected_version; // }; // } SupportedVersions; // XXX the content depends on the current message type // XXX first case has length 1 + 2*n, while the second case has length 2 fn parse_tls_extension_supported_versions_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { if ext_len == 2 { map(be_u16, |x| { TlsExtension::SupportedVersions(vec![TlsVersion(x)]) })(i) } else { let (i, _) = be_u8(i)?; if ext_len == 0 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } let (i, l) = map_parser(take(ext_len - 1), parse_tls_versions)(i)?; Ok((i, TlsExtension::SupportedVersions(l))) } } pub fn parse_tls_extension_supported_versions(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x2b])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_supported_versions_content(d, ext_len) })(i) } fn parse_tls_extension_cookie_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> { map(take(ext_len), TlsExtension::Cookie)(i) } pub fn parse_tls_extension_cookie(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x2c])(i)?; let (i, ext_len) = be_u16(i)?; map_parser(take(ext_len), move |d| { parse_tls_extension_cookie_content(d, ext_len) })(i) } pub fn parse_tls_extension_psk_key_exchange_modes_content( i: &[u8], ) -> IResult<&[u8], TlsExtension> { let (i, v) = length_data(be_u8)(i)?; Ok((i, TlsExtension::PskExchangeModes(v.to_vec()))) } pub fn parse_tls_extension_psk_key_exchange_modes(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, _) = tag([0x00, 0x2d])(i)?; let (i, ext_len) = be_u16(i)?; map_parser( take(ext_len), parse_tls_extension_psk_key_exchange_modes_content, )(i) } /// Defined in RFC-draft-agl-tls-nextprotoneg-03. Deprecated in favour of ALPN. fn parse_tls_extension_npn_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> { if ext_len != 0 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } Ok((i, TlsExtension::NextProtocolNegotiation)) } /// Renegotiation Info, defined in \[RFC5746\] pub fn parse_tls_extension_renegotiation_info_content(i: &[u8]) -> IResult<&[u8], TlsExtension> { map(length_data(be_u8), TlsExtension::RenegotiationInfo)(i) } /// Encrypted Server Name, defined in \[draft-ietf-tls-esni\] pub fn parse_tls_extension_encrypted_server_name(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, ciphersuite) = map(be_u16, TlsCipherSuiteID)(i)?; let (i, group) = NamedGroup::parse(i)?; let (i, key_share) = length_data(be_u16)(i)?; let (i, record_digest) = length_data(be_u16)(i)?; let (i, encrypted_sni) = length_data(be_u16)(i)?; let esn = TlsExtension::EncryptedServerName { ciphersuite, group, key_share, record_digest, encrypted_sni, }; Ok((i, esn)) } fn parse_tls_oid_filter(i: &[u8]) -> IResult<&[u8], OidFilter> { let (i, cert_ext_oid) = length_data(be_u8)(i)?; let (i, cert_ext_val) = length_data(be_u16)(i)?; let filter = OidFilter { cert_ext_oid, cert_ext_val, }; Ok((i, filter)) } /// Defined in TLS 1.3 draft 19 fn parse_tls_extension_oid_filters(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, v) = map_parser(length_data(be_u16), many0(complete(parse_tls_oid_filter)))(i)?; Ok((i, TlsExtension::OidFilters(v))) } /// Defined in TLS 1.3 draft 20 fn parse_tls_extension_post_handshake_auth_content( i: &[u8], ext_len: u16, ) -> IResult<&[u8], TlsExtension> { if ext_len != 0 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } Ok((i, TlsExtension::PostHandshakeAuth)) } pub fn parse_tls_extension_unknown(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, ext_type) = be_u16(i)?; let (i, ext_data) = length_data(be_u16)(i)?; Ok(( i, TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data), )) } /// Parse a single TLS Client Hello extension pub fn parse_tls_client_hello_extension(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, ext_type) = be_u16(i)?; let (i, ext_data) = length_data(be_u16)(i)?; if ext_type & 0x0f0f == 0x0a0a { return Ok((i, TlsExtension::Grease(ext_type, ext_data))); } let ext_len = ext_data.len() as u16; let (_, ext) = match ext_type { 0 => parse_tls_extension_sni_content(ext_data), 1 => parse_tls_extension_max_fragment_length_content(ext_data), 5 => parse_tls_extension_status_request_content(ext_data, ext_len), 10 => parse_tls_extension_elliptic_curves_content(ext_data), 11 => parse_tls_extension_ec_point_formats_content(ext_data), 13 => parse_tls_extension_signature_algorithms_content(ext_data), 15 => parse_tls_extension_heartbeat_content(ext_data), 16 => parse_tls_extension_alpn_content(ext_data), 18 => parse_tls_extension_signed_certificate_timestamp_content(ext_data), // ok XXX should be empty 21 => parse_tls_extension_padding_content(ext_data, ext_len), 22 => parse_tls_extension_encrypt_then_mac_content(ext_data, ext_len), 23 => parse_tls_extension_extended_master_secret_content(ext_data, ext_len), 28 => parse_tls_extension_record_size_limit(ext_data), 35 => parse_tls_extension_session_ticket_content(ext_data, ext_len), 41 => parse_tls_extension_pre_shared_key_content(ext_data, ext_len), 42 => parse_tls_extension_early_data_content(ext_data, ext_len), 43 => parse_tls_extension_supported_versions_content(ext_data, ext_len), 44 => parse_tls_extension_cookie_content(ext_data, ext_len), 45 => parse_tls_extension_psk_key_exchange_modes_content(ext_data), 48 => parse_tls_extension_oid_filters(ext_data), 49 => parse_tls_extension_post_handshake_auth_content(ext_data, ext_len), 51 => parse_tls_extension_key_share_content(ext_data, ext_len), // XXX request 13172 => parse_tls_extension_npn_content(ext_data, ext_len), // XXX must be empty 0xff01 => parse_tls_extension_renegotiation_info_content(ext_data), 0xffce => parse_tls_extension_encrypted_server_name(ext_data), _ => Ok(( i, TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data), )), }?; Ok((i, ext)) } /// Parse a single TLS Server Hello extension pub fn parse_tls_server_hello_extension(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, ext_type) = be_u16(i)?; let (i, ext_data) = length_data(be_u16)(i)?; if ext_type & 0x0f0f == 0x0a0a { return Ok((i, TlsExtension::Grease(ext_type, ext_data))); } let ext_len = ext_data.len() as u16; let (_, ext) = match ext_type { 0 => parse_tls_extension_sni_content(ext_data), // XXX SHALL be empty (RFC6066 section 3) 1 => parse_tls_extension_max_fragment_length_content(ext_data), 5 => parse_tls_extension_status_request_content(ext_data, ext_len), // SHALL be empty 11 => parse_tls_extension_ec_point_formats_content(ext_data), // ok XXX only one 13 => parse_tls_extension_signature_algorithms_content(ext_data), // XXX allowed? 15 => parse_tls_extension_heartbeat_content(ext_data), 16 => parse_tls_extension_alpn_content(ext_data), // ok XXX MUST contain one protocol name 18 => parse_tls_extension_signed_certificate_timestamp_content(ext_data), 21 => parse_tls_extension_encrypt_then_mac_content(ext_data, ext_len), 23 => parse_tls_extension_extended_master_secret_content(ext_data, ext_len), 28 => parse_tls_extension_record_size_limit(ext_data), 35 => parse_tls_extension_session_ticket_content(ext_data, ext_len), 41 => parse_tls_extension_pre_shared_key_content(ext_data, ext_len), 42 => parse_tls_extension_early_data_content(ext_data, ext_len), 43 => parse_tls_extension_supported_versions_content(ext_data, ext_len), // ok XXX only one 44 => parse_tls_extension_cookie_content(ext_data, ext_len), 51 => parse_tls_extension_key_share_content(ext_data, ext_len), // XXX selected entry 13172 => parse_tls_extension_npn_content(ext_data, ext_len), 0xff01 => parse_tls_extension_renegotiation_info_content(ext_data), _ => Ok(( i, TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data), )), }?; Ok((i, ext)) } /// Parse a single TLS extension (of any type) pub fn parse_tls_extension(i: &[u8]) -> IResult<&[u8], TlsExtension> { let (i, ext_type) = be_u16(i)?; let (i, ext_data) = length_data(be_u16)(i)?; if ext_type & 0x0f0f == 0x0a0a { return Ok((i, TlsExtension::Grease(ext_type, ext_data))); } let ext_len = ext_data.len() as u16; let (_, ext) = match ext_type { 0 => parse_tls_extension_sni_content(ext_data), 1 => parse_tls_extension_max_fragment_length_content(ext_data), 5 => parse_tls_extension_status_request_content(ext_data, ext_len), 10 => parse_tls_extension_elliptic_curves_content(ext_data), 11 => parse_tls_extension_ec_point_formats_content(ext_data), 13 => parse_tls_extension_signature_algorithms_content(ext_data), 15 => parse_tls_extension_heartbeat_content(ext_data), 16 => parse_tls_extension_alpn_content(ext_data), 18 => parse_tls_extension_signed_certificate_timestamp_content(ext_data), 21 => parse_tls_extension_padding_content(ext_data, ext_len), 22 => parse_tls_extension_encrypt_then_mac_content(ext_data, ext_len), 23 => parse_tls_extension_extended_master_secret_content(ext_data, ext_len), 28 => parse_tls_extension_record_size_limit(ext_data), 35 => parse_tls_extension_session_ticket_content(ext_data, ext_len), 40 => parse_tls_extension_key_share_old_content(ext_data, ext_len), 41 => parse_tls_extension_pre_shared_key_content(ext_data, ext_len), 42 => parse_tls_extension_early_data_content(ext_data, ext_len), 43 => parse_tls_extension_supported_versions_content(ext_data, ext_len), 44 => parse_tls_extension_cookie_content(ext_data, ext_len), 45 => parse_tls_extension_psk_key_exchange_modes_content(ext_data), 48 => parse_tls_extension_oid_filters(ext_data), 49 => parse_tls_extension_post_handshake_auth_content(ext_data, ext_len), 51 => parse_tls_extension_key_share_content(ext_data, ext_len), 13172 => parse_tls_extension_npn_content(ext_data, ext_len), 0xff01 => parse_tls_extension_renegotiation_info_content(ext_data), 0xffce => parse_tls_extension_encrypted_server_name(ext_data), _ => Ok(( i, TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data), )), }?; Ok((i, ext)) } /// Parse zero or more TLS Client Hello extensions pub fn parse_tls_client_hello_extensions(i: &[u8]) -> IResult<&[u8], Vec> { many0(complete(parse_tls_client_hello_extension))(i) } /// Parse zero or more TLS Server Hello extensions pub fn parse_tls_server_hello_extensions(i: &[u8]) -> IResult<&[u8], Vec> { many0(complete(parse_tls_server_hello_extension))(i) } /// Parse zero or more TLS extensions (of any type) pub fn parse_tls_extensions(i: &[u8]) -> IResult<&[u8], Vec> { many0(complete(parse_tls_extension))(i) } tls-parser-0.12.2/src/tls_handshake.rs000064400000000000000000000670751046102023000157660ustar 00000000000000use alloc::vec::Vec; use core::convert::TryInto; use core::fmt; use core::ops::Deref; use nom::branch::alt; use nom::bytes::streaming::take; use nom::combinator::{complete, cond, map, map_parser, opt, verify}; use nom::error::{make_error, ErrorKind}; use nom::multi::{length_count, length_data, many0}; use nom::number::streaming::{be_u16, be_u24, be_u32, be_u8}; use nom::{Err, IResult}; use nom_derive::{NomBE, Parse}; use rusticata_macros::newtype_enum; use crate::tls_ciphers::*; // use crate::tls_debug::*; use crate::tls_ec::*; use crate::tls_message::TlsMessage; /// Handshake type /// /// Handshake types are defined in [RFC5246](https://tools.ietf.org/html/rfc5246) and /// the [IANA HandshakeType /// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-7) #[derive(Clone, Copy, PartialEq, Eq, NomBE)] pub struct TlsHandshakeType(pub u8); newtype_enum! { impl debug TlsHandshakeType { HelloRequest = 0x00, ClientHello = 0x01, ServerHello = 0x02, HelloVerifyRequest = 0x03, NewSessionTicket = 0x04, EndOfEarlyData = 0x05, HelloRetryRequest = 0x06, EncryptedExtensions = 0x08, Certificate = 0x0b, ServerKeyExchange = 0x0c, CertificateRequest = 0x0d, ServerDone = 0x0e, CertificateVerify = 0x0f, ClientKeyExchange = 0x10, Finished = 0x14, CertificateURL = 0x15, CertificateStatus = 0x16, KeyUpdate = 0x18, NextProtocol = 0x43, } } impl From for u8 { fn from(v: TlsHandshakeType) -> u8 { v.0 } } /// TLS version /// /// Only the TLS version defined in the TLS message header is meaningful, the /// version defined in the record should be ignored or set to TLS 1.0 #[derive(Clone, Copy, Default, PartialEq, Eq, NomBE)] pub struct TlsVersion(pub u16); impl TlsVersion { pub const fn to_be_bytes(&self) -> [u8; 2] { self.0.to_be_bytes() } } newtype_enum! { impl debug TlsVersion { Ssl30 = 0x0300, Tls10 = 0x0301, Tls11 = 0x0302, Tls12 = 0x0303, Tls13 = 0x0304, Tls13Draft18 = 0x7f12, Tls13Draft19 = 0x7f13, Tls13Draft20 = 0x7f14, Tls13Draft21 = 0x7f15, Tls13Draft22 = 0x7f16, Tls13Draft23 = 0x7f17, DTls10 = 0xfeff, DTls11 = 0xfefe, DTls12 = 0xfefd, } } impl From for u16 { fn from(v: TlsVersion) -> u16 { v.0 } } impl fmt::LowerHex for TlsVersion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:x}", self.0) } } /// Heartbeat type, as defined in [RFC6520](https://tools.ietf.org/html/rfc6520) section 3 #[derive(Clone, Copy, PartialEq, Eq, NomBE)] pub struct TlsHeartbeatMessageType(pub u8); newtype_enum! { impl debug TlsHeartbeatMessageType { HeartBeatRequest = 0x1, HeartBeatResponse = 0x2, } } impl From for u8 { fn from(v: TlsHeartbeatMessageType) -> u8 { v.0 } } #[derive(Clone, Copy, Default, PartialEq, Eq, NomBE)] pub struct TlsCompressionID(pub u8); newtype_enum! { impl debug TlsCompressionID { Null = 0x00, Deflate = 0x01, } } impl From for u8 { fn from(c: TlsCompressionID) -> u8 { c.0 } } impl Deref for TlsCompressionID { type Target = u8; fn deref(&self) -> &Self::Target { &self.0 } } impl AsRef for TlsCompressionID { fn as_ref(&self) -> &u8 { &self.0 } } #[derive(Clone, Copy, Default, PartialEq, Eq, NomBE)] pub struct TlsCipherSuiteID(pub u16); impl TlsCipherSuiteID { pub fn get_ciphersuite(self) -> Option<&'static TlsCipherSuite> { TlsCipherSuite::from_id(self.0) } } impl From for u16 { fn from(c: TlsCipherSuiteID) -> u16 { c.0 } } impl Deref for TlsCipherSuiteID { type Target = u16; fn deref(&self) -> &Self::Target { &self.0 } } impl AsRef for TlsCipherSuiteID { fn as_ref(&self) -> &u16 { &self.0 } } impl fmt::Display for TlsCipherSuiteID { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } } impl fmt::Debug for TlsCipherSuiteID { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match TlsCipherSuite::from_id(self.0) { Some(c) => write!(f, "0x{:04x}({})", self.0, c.name), None => write!(f, "0x{:04x}(Unknown cipher)", self.0), } } } impl fmt::LowerHex for TlsCipherSuiteID { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:x}", self.0) } } /// A trait that both TLS & DTLS satisfy pub trait ClientHello<'a> { /// TLS version of message fn version(&self) -> TlsVersion; fn random(&self) -> &'a [u8]; // Get the first part (4 bytes) of random fn rand_time(&self) -> u32 { self.random() .try_into() .map(u32::from_be_bytes) .unwrap_or(0) } // Get the second part (28 bytes) of random fn rand_bytes(&self) -> &'a [u8] { self.random().get(4..).unwrap_or(&[]) } fn session_id(&self) -> Option<&'a [u8]>; /// A list of ciphers supported by client fn ciphers(&self) -> &Vec; fn cipher_suites(&self) -> Vec> { self.ciphers() .iter() .map(|&x| x.get_ciphersuite()) .collect() } /// A list of compression methods supported by client fn comp(&self) -> &Vec; fn ext(&self) -> Option<&'a [u8]>; } /// TLS Client Hello (from TLS 1.0 to TLS 1.2) /// /// Some fields are unparsed (for performance reasons), for ex to parse `ext`, /// call the [parse_tls_client_hello_extension](crate::parse_tls_client_hello_extension) function. #[derive(Clone, PartialEq)] pub struct TlsClientHelloContents<'a> { /// TLS version of message pub version: TlsVersion, pub random: &'a [u8], pub session_id: Option<&'a [u8]>, /// A list of ciphers supported by client pub ciphers: Vec, /// A list of compression methods supported by client pub comp: Vec, pub ext: Option<&'a [u8]>, } impl<'a> TlsClientHelloContents<'a> { pub fn new( v: u16, random: &'a [u8], sid: Option<&'a [u8]>, c: Vec, co: Vec, e: Option<&'a [u8]>, ) -> Self { TlsClientHelloContents { version: TlsVersion(v), random, session_id: sid, ciphers: c, comp: co, ext: e, } } pub fn get_version(&self) -> TlsVersion { self.version } pub fn get_ciphers(&self) -> Vec> { self.ciphers.iter().map(|&x| x.get_ciphersuite()).collect() } } impl<'a> ClientHello<'a> for TlsClientHelloContents<'a> { fn version(&self) -> TlsVersion { self.version } fn random(&self) -> &'a [u8] { self.random } fn session_id(&self) -> Option<&'a [u8]> { self.session_id } fn ciphers(&self) -> &Vec { &self.ciphers } fn comp(&self) -> &Vec { &self.comp } fn ext(&self) -> Option<&'a [u8]> { self.ext } } /// TLS Server Hello (from TLS 1.0 to TLS 1.2) #[derive(Clone, PartialEq)] pub struct TlsServerHelloContents<'a> { pub version: TlsVersion, pub random: &'a [u8], pub session_id: Option<&'a [u8]>, pub cipher: TlsCipherSuiteID, pub compression: TlsCompressionID, pub ext: Option<&'a [u8]>, } /// TLS Server Hello (TLS 1.3 draft 18) #[derive(Clone, PartialEq)] pub struct TlsServerHelloV13Draft18Contents<'a> { pub version: TlsVersion, pub random: &'a [u8], pub cipher: TlsCipherSuiteID, pub ext: Option<&'a [u8]>, } /// TLS Hello Retry Request (TLS 1.3) #[derive(Clone, PartialEq)] pub struct TlsHelloRetryRequestContents<'a> { pub version: TlsVersion, pub cipher: TlsCipherSuiteID, pub ext: Option<&'a [u8]>, } impl<'a> TlsServerHelloContents<'a> { pub fn new( v: u16, random: &'a [u8], sid: Option<&'a [u8]>, c: u16, co: u8, e: Option<&'a [u8]>, ) -> Self { TlsServerHelloContents { version: TlsVersion(v), random, session_id: sid, cipher: TlsCipherSuiteID(c), compression: TlsCompressionID(co), ext: e, } } pub fn get_version(&self) -> TlsVersion { self.version } pub fn get_cipher(&self) -> Option<&'static TlsCipherSuite> { self.cipher.get_ciphersuite() } } /// Session ticket, as defined in [RFC5077](https://tools.ietf.org/html/rfc5077) #[derive(Clone, Debug, PartialEq)] pub struct TlsNewSessionTicketContent<'a> { pub ticket_lifetime_hint: u32, pub ticket: &'a [u8], } /// A raw certificate, which should be a DER-encoded X.509 certificate. /// /// See [RFC5280](https://tools.ietf.org/html/rfc5280) for X509v3 certificate format. #[derive(Clone, PartialEq)] pub struct RawCertificate<'a> { pub data: &'a [u8], } /// The certificate chain, usually composed of the certificate, and all /// required certificate authorities. #[derive(Clone, Debug, PartialEq)] pub struct TlsCertificateContents<'a> { pub cert_chain: Vec>, } /// Certificate request, as defined in [RFC5246](https://tools.ietf.org/html/rfc5246) section 7.4.4 /// /// Note: TLS 1.2 adds SignatureAndHashAlgorithm (chapter 7.4.4) but do not declare it in A.4.2 #[derive(Clone, Debug, PartialEq)] pub struct TlsCertificateRequestContents<'a> { pub cert_types: Vec, pub sig_hash_algs: Option>, /// A list of DER-encoded distinguished names. See /// [X.501](http://www.itu.int/rec/T-REC-X.501/en) pub unparsed_ca: Vec<&'a [u8]>, } /// Server key exchange parameters /// /// This is an opaque struct, since the content depends on the selected /// key exchange method. #[derive(Clone, PartialEq)] pub struct TlsServerKeyExchangeContents<'a> { pub parameters: &'a [u8], } /// Client key exchange parameters /// /// Content depends on the selected key exchange method. #[derive(Clone, PartialEq)] pub enum TlsClientKeyExchangeContents<'a> { Dh(&'a [u8]), Ecdh(ECPoint<'a>), Unknown(&'a [u8]), } /// Certificate status response, as defined in [RFC6066](https://tools.ietf.org/html/rfc6066) section 8 #[derive(Clone, Debug, PartialEq)] pub struct TlsCertificateStatusContents<'a> { pub status_type: u8, pub blob: &'a [u8], } /// Next protocol response, defined in /// [draft-agl-tls-nextprotoneg-03](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03) #[derive(Clone, Debug, PartialEq)] pub struct TlsNextProtocolContent<'a> { pub selected_protocol: &'a [u8], pub padding: &'a [u8], } /// Key update request (TLS 1.3) #[derive(Copy, Clone, PartialEq, Eq)] pub struct KeyUpdateRequest(pub u8); newtype_enum! { impl KeyUpdateRequest { NotRequested = 0x0, Requested = 0x1, } } /// Generic handshake message #[derive(Clone, Debug, PartialEq)] pub enum TlsMessageHandshake<'a> { HelloRequest, ClientHello(TlsClientHelloContents<'a>), ServerHello(TlsServerHelloContents<'a>), ServerHelloV13Draft18(TlsServerHelloV13Draft18Contents<'a>), NewSessionTicket(TlsNewSessionTicketContent<'a>), EndOfEarlyData, HelloRetryRequest(TlsHelloRetryRequestContents<'a>), Certificate(TlsCertificateContents<'a>), ServerKeyExchange(TlsServerKeyExchangeContents<'a>), CertificateRequest(TlsCertificateRequestContents<'a>), ServerDone(&'a [u8]), CertificateVerify(&'a [u8]), ClientKeyExchange(TlsClientKeyExchangeContents<'a>), Finished(&'a [u8]), CertificateStatus(TlsCertificateStatusContents<'a>), NextProtocol(TlsNextProtocolContent<'a>), KeyUpdate(u8), } /// Parse a HelloRequest handshake message pub fn parse_tls_handshake_msg_hello_request(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { Ok((i, TlsMessageHandshake::HelloRequest)) } /// Parse handshake message contents for ClientHello /// /// ```rust /// use tls_parser::*; /// /// # pub fn do_stuff(bytes: &[u8]) { /// if let Ok((_, ch)) = parse_tls_handshake_client_hello(bytes) { /// println!("ClientHello TLS version: {}", ch.version); /// println!(" number of proposed ciphersuites: {}", ch.ciphers.len()); /// } /// # } /// ``` pub fn parse_tls_handshake_client_hello(i: &[u8]) -> IResult<&[u8], TlsClientHelloContents> { let (i, version) = be_u16(i)?; let (i, random) = take(32usize)(i)?; let (i, sidlen) = verify(be_u8, |&n| n <= 32)(i)?; let (i, sid) = cond(sidlen > 0, take(sidlen as usize))(i)?; let (i, ciphers_len) = be_u16(i)?; let (i, ciphers) = parse_cipher_suites(i, ciphers_len as usize)?; let (i, comp_len) = be_u8(i)?; let (i, comp) = parse_compressions_algs(i, comp_len as usize)?; let (i, ext) = opt(complete(length_data(be_u16)))(i)?; let content = TlsClientHelloContents::new(version, random, sid, ciphers, comp, ext); Ok((i, content)) } /// Parse a ClientHello handshake message /// /// This function returns a [TlsMessageHandshake]. To get only the `ClientHello` contents, use the /// [parse_tls_handshake_client_hello] function. /// /// ```rust /// use tls_parser::*; /// /// # pub fn do_stuff(bytes: &[u8]) { /// if let Ok((_, TlsMessageHandshake::ClientHello(ch))) = /// parse_tls_handshake_msg_client_hello(bytes) { /// println!("ClientHello TLS version: {}", ch.version); /// println!(" number of proposed ciphersuites: {}", ch.ciphers.len()); /// } /// # } /// ``` pub fn parse_tls_handshake_msg_client_hello(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { map( parse_tls_handshake_client_hello, TlsMessageHandshake::ClientHello, )(i) } pub(crate) fn parse_cipher_suites(i: &[u8], len: usize) -> IResult<&[u8], Vec> { if len == 0 { return Ok((i, Vec::new())); } if len % 2 == 1 || len > i.len() { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } let v = (i[..len]) .chunks(2) .map(|chunk| TlsCipherSuiteID((chunk[0] as u16) << 8 | chunk[1] as u16)) .collect(); Ok((&i[len..], v)) } pub(crate) fn parse_compressions_algs( i: &[u8], len: usize, ) -> IResult<&[u8], Vec> { if len == 0 { return Ok((i, Vec::new())); } if len > i.len() { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } let v = (i[..len]).iter().map(|&it| TlsCompressionID(it)).collect(); Ok((&i[len..], v)) } pub(crate) fn parse_tls_versions(i: &[u8]) -> IResult<&[u8], Vec> { let len = i.len(); if len == 0 { return Ok((i, Vec::new())); } if len % 2 == 1 || len > i.len() { return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); } let v = (i[..len]) .chunks(2) .map(|chunk| TlsVersion((chunk[0] as u16) << 8 | chunk[1] as u16)) .collect(); Ok((&i[len..], v)) } fn parse_certs(i: &[u8]) -> IResult<&[u8], Vec> { many0(complete(map(length_data(be_u24), |data| RawCertificate { data, })))(i) } fn parse_tls_handshake_msg_server_hello_tlsv12( i: &[u8], ) -> IResult<&[u8], TlsMessageHandshake> { map( parse_tls_server_hello_tlsv12::, TlsMessageHandshake::ServerHello, )(i) } pub(crate) fn parse_tls_server_hello_tlsv12( i: &[u8], ) -> IResult<&[u8], TlsServerHelloContents> { let (i, version) = be_u16(i)?; let (i, random) = take(32usize)(i)?; let (i, sidlen) = verify(be_u8, |&n| n <= 32)(i)?; let (i, sid) = cond(sidlen > 0, take(sidlen as usize))(i)?; let (i, cipher) = be_u16(i)?; let (i, comp) = be_u8(i)?; let (i, ext) = if HAS_EXT { opt(complete(length_data(be_u16)))(i)? } else { (i, None) }; let content = TlsServerHelloContents::new(version, random, sid, cipher, comp, ext); Ok((i, content)) } fn parse_tls_handshake_msg_server_hello_tlsv13draft18( i: &[u8], ) -> IResult<&[u8], TlsMessageHandshake> { let (i, version) = TlsVersion::parse(i)?; let (i, random) = take(32usize)(i)?; let (i, cipher) = map(be_u16, TlsCipherSuiteID)(i)?; let (i, ext) = opt(complete(length_data(be_u16)))(i)?; let content = TlsServerHelloV13Draft18Contents { version, random, cipher, ext, }; Ok((i, TlsMessageHandshake::ServerHelloV13Draft18(content))) } /// Parse handshake message contents for ServerHello (all TLS versions except 1.3 draft 18) /// /// ```rust /// use tls_parser::*; /// /// # pub fn do_stuff(bytes: &[u8]) { /// if let Ok((_, sh)) = parse_tls_handshake_server_hello(bytes) { /// println!("ServerHello TLS version: {}", sh.version); /// println!(" server chosen ciphersuites: {}", sh.cipher); /// } /// # } /// ``` pub fn parse_tls_handshake_server_hello(i: &[u8]) -> IResult<&[u8], TlsServerHelloContents> { let (_, version) = be_u16(i)?; match version { 0x0303 => parse_tls_server_hello_tlsv12::(i), 0x0302 => parse_tls_server_hello_tlsv12::(i), 0x0301 => parse_tls_server_hello_tlsv12::(i), 0x0300 => parse_tls_server_hello_tlsv12::(i), _ => Err(Err::Error(make_error(i, ErrorKind::Tag))), } } /// Parse a ServerHello handshake message (all TLS versions) /// /// This function returns a [TlsMessageHandshake]. To get only the `ServerHello` contents, use the /// [parse_tls_handshake_server_hello] function. /// /// ```rust /// use tls_parser::*; /// /// # pub fn do_stuff(bytes: &[u8]) { /// if let Ok((_, msg)) = parse_tls_handshake_msg_server_hello(bytes) { /// match msg { /// TlsMessageHandshake::ServerHello(sh) => { /// println!("ServerHello TLS version: {}", sh.version); /// println!(" server chosen ciphersuites: {}", sh.cipher); /// } /// TlsMessageHandshake::ServerHelloV13Draft18(sh) => { /// println!("ServerHello v1.3 draft 18 TLS version: {}", sh.version); /// } /// _ => { /// println!("Not a ServerHello"); /// } /// } /// } /// # } /// ``` pub fn parse_tls_handshake_msg_server_hello(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { let (_, version) = be_u16(i)?; match version { 0x7f12 => parse_tls_handshake_msg_server_hello_tlsv13draft18(i), 0x0303 => parse_tls_handshake_msg_server_hello_tlsv12::(i), 0x0302 => parse_tls_handshake_msg_server_hello_tlsv12::(i), 0x0301 => parse_tls_handshake_msg_server_hello_tlsv12::(i), 0x0300 => parse_tls_handshake_msg_server_hello_tlsv12::(i), _ => Err(Err::Error(make_error(i, ErrorKind::Tag))), } } /// Parse a NewSessionTicket handshake message // RFC 5077 Stateless TLS Session Resumption pub fn parse_tls_handshake_msg_newsessionticket( i: &[u8], len: usize, ) -> IResult<&[u8], TlsMessageHandshake> { if len < 4 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } let (i, ticket_lifetime_hint) = be_u32(i)?; let (i, ticket) = take(len - 4)(i)?; let content = TlsNewSessionTicketContent { ticket_lifetime_hint, ticket, }; Ok((i, TlsMessageHandshake::NewSessionTicket(content))) } /// Parse a HelloRetryRequest handshake message pub fn parse_tls_handshake_msg_hello_retry_request( i: &[u8], ) -> IResult<&[u8], TlsMessageHandshake> { let (i, version) = TlsVersion::parse(i)?; let (i, cipher) = map(be_u16, TlsCipherSuiteID)(i)?; let (i, ext) = opt(complete(length_data(be_u16)))(i)?; let content = TlsHelloRetryRequestContents { version, cipher, ext, }; Ok((i, TlsMessageHandshake::HelloRetryRequest(content))) } pub(crate) fn parse_tls_certificate(i: &[u8]) -> IResult<&[u8], TlsCertificateContents> { let (i, cert_len) = be_u24(i)?; let (i, cert_chain) = map_parser(take(cert_len as usize), parse_certs)(i)?; let content = TlsCertificateContents { cert_chain }; Ok((i, content)) } /// Parse a Certificate handshake message pub fn parse_tls_handshake_msg_certificate(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { map(parse_tls_certificate, TlsMessageHandshake::Certificate)(i) } /// Parse a ServerKeyExchange handshake message pub fn parse_tls_handshake_msg_serverkeyexchange( i: &[u8], len: usize, ) -> IResult<&[u8], TlsMessageHandshake> { map(take(len), |ext| { TlsMessageHandshake::ServerKeyExchange(TlsServerKeyExchangeContents { parameters: ext }) })(i) } /// Parse a ServerDone handshake message pub fn parse_tls_handshake_msg_serverdone( i: &[u8], len: usize, ) -> IResult<&[u8], TlsMessageHandshake> { map(take(len), TlsMessageHandshake::ServerDone)(i) } /// Parse a CertificateVerify handshake message pub fn parse_tls_handshake_msg_certificateverify( i: &[u8], len: usize, ) -> IResult<&[u8], TlsMessageHandshake> { map(take(len), TlsMessageHandshake::CertificateVerify)(i) } pub(crate) fn parse_tls_clientkeyexchange( len: usize, ) -> impl FnMut(&[u8]) -> IResult<&[u8], TlsClientKeyExchangeContents> { move |i| map(take(len), TlsClientKeyExchangeContents::Unknown)(i) } /// Parse a ClientKeyExchange handshake message /// /// This function does not known the data structure, so it will always return /// [TlsClientKeyExchangeContents::Unknown] with the raw data pub fn parse_tls_handshake_msg_clientkeyexchange( i: &[u8], len: usize, ) -> IResult<&[u8], TlsMessageHandshake> { map( parse_tls_clientkeyexchange(len), TlsMessageHandshake::ClientKeyExchange, )(i) } fn parse_certrequest_nosigalg(i: &[u8]) -> IResult<&[u8], TlsCertificateRequestContents> { let (i, cert_types) = length_count(be_u8, be_u8)(i)?; let (i, ca_len) = be_u16(i)?; let (i, unparsed_ca) = map_parser(take(ca_len as usize), many0(complete(length_data(be_u16))))(i)?; let content = TlsCertificateRequestContents { cert_types, // sig_hash_algs: Some(sig_hash_algs), sig_hash_algs: None, unparsed_ca, }; Ok((i, content)) } fn parse_certrequest_full(i: &[u8]) -> IResult<&[u8], TlsCertificateRequestContents> { let (i, cert_types) = length_count(be_u8, be_u8)(i)?; let (i, sig_hash_algs_len) = be_u16(i)?; let (i, sig_hash_algs) = map_parser(take(sig_hash_algs_len as usize), many0(complete(be_u16)))(i)?; let (i, ca_len) = be_u16(i)?; let (i, unparsed_ca) = map_parser(take(ca_len as usize), many0(complete(length_data(be_u16))))(i)?; let content = TlsCertificateRequestContents { cert_types, sig_hash_algs: Some(sig_hash_algs), unparsed_ca, }; Ok((i, content)) } /// Parse a CertificateRequest handshake message pub fn parse_tls_handshake_certificaterequest( i: &[u8], ) -> IResult<&[u8], TlsCertificateRequestContents> { alt(( complete(parse_certrequest_full), complete(parse_certrequest_nosigalg), ))(i) } /// Parse a CertificateRequest handshake message pub fn parse_tls_handshake_msg_certificaterequest(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { map( parse_tls_handshake_certificaterequest, TlsMessageHandshake::CertificateRequest, )(i) } /// Parse a Finished handshake message pub fn parse_tls_handshake_msg_finished( i: &[u8], len: usize, ) -> IResult<&[u8], TlsMessageHandshake> { map(take(len), TlsMessageHandshake::Finished)(i) } /// Parse handshake message contents for CertificateStatus (\[RFC6066\]) /// /// If status_type == 0, blob is a OCSPResponse, as defined in [RFC2560](https://tools.ietf.org/html/rfc2560) /// /// Note that the OCSPResponse object is DER-encoded. pub fn parse_tls_handshake_certificatestatus( i: &[u8], ) -> IResult<&[u8], TlsCertificateStatusContents> { let (i, status_type) = be_u8(i)?; let (i, blob) = length_data(be_u24)(i)?; let content = TlsCertificateStatusContents { status_type, blob }; Ok((i, content)) } /// Parse a CertificateStatus handshake message (\[RFC6066\]) /// /// If status_type == 0, blob is a OCSPResponse, as defined in [RFC2560](https://tools.ietf.org/html/rfc2560) /// /// Note that the OCSPResponse object is DER-encoded. pub fn parse_tls_handshake_msg_certificatestatus(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { map( parse_tls_handshake_certificatestatus, TlsMessageHandshake::CertificateStatus, )(i) } /// Parse handshake message contents for NextProtocol /// /// NextProtocol handshake message, as defined in /// [draft-agl-tls-nextprotoneg-03](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03) /// Deprecated in favour of ALPN. pub fn parse_tls_handshake_next_protocol(i: &[u8]) -> IResult<&[u8], TlsNextProtocolContent> { let (i, selected_protocol) = length_data(be_u8)(i)?; let (i, padding) = length_data(be_u8)(i)?; let next_proto = TlsNextProtocolContent { selected_protocol, padding, }; Ok((i, next_proto)) } /// Parse a NextProtocol handshake message /// /// NextProtocol handshake message, as defined in /// [draft-agl-tls-nextprotoneg-03](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-03) /// Deprecated in favour of ALPN. pub fn parse_tls_handshake_msg_next_protocol(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { map( parse_tls_handshake_next_protocol, TlsMessageHandshake::NextProtocol, )(i) } /// Parse a KeyUpdate handshake message pub fn parse_tls_handshake_msg_key_update(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> { map(be_u8, TlsMessageHandshake::KeyUpdate)(i) } /// Parse a TLS handshake message pub fn parse_tls_message_handshake(i: &[u8]) -> IResult<&[u8], TlsMessage> { let (i, ht) = be_u8(i)?; let (i, hl) = be_u24(i)?; let (i, raw_msg) = take(hl)(i)?; let (_, msg) = match TlsHandshakeType(ht) { TlsHandshakeType::HelloRequest => parse_tls_handshake_msg_hello_request(raw_msg), TlsHandshakeType::ClientHello => parse_tls_handshake_msg_client_hello(raw_msg), TlsHandshakeType::ServerHello => parse_tls_handshake_msg_server_hello(raw_msg), TlsHandshakeType::NewSessionTicket => { parse_tls_handshake_msg_newsessionticket(raw_msg, hl as usize) } TlsHandshakeType::EndOfEarlyData => Ok((raw_msg, TlsMessageHandshake::EndOfEarlyData)), TlsHandshakeType::HelloRetryRequest => parse_tls_handshake_msg_hello_retry_request(raw_msg), TlsHandshakeType::Certificate => parse_tls_handshake_msg_certificate(raw_msg), TlsHandshakeType::ServerKeyExchange => { parse_tls_handshake_msg_serverkeyexchange(raw_msg, hl as usize) } TlsHandshakeType::CertificateRequest => parse_tls_handshake_msg_certificaterequest(raw_msg), TlsHandshakeType::ServerDone => parse_tls_handshake_msg_serverdone(raw_msg, hl as usize), TlsHandshakeType::CertificateVerify => { parse_tls_handshake_msg_certificateverify(raw_msg, hl as usize) } TlsHandshakeType::ClientKeyExchange => { parse_tls_handshake_msg_clientkeyexchange(raw_msg, hl as usize) } TlsHandshakeType::Finished => parse_tls_handshake_msg_finished(raw_msg, hl as usize), // TlsHandshakeType::CertificateURL => parse_tls_handshake_msg_certificateurl(raw_msg), TlsHandshakeType::CertificateStatus => parse_tls_handshake_msg_certificatestatus(raw_msg), TlsHandshakeType::KeyUpdate => parse_tls_handshake_msg_key_update(raw_msg), TlsHandshakeType::NextProtocol => parse_tls_handshake_msg_next_protocol(raw_msg), _ => Err(Err::Error(make_error(i, ErrorKind::Switch))), }?; Ok((i, TlsMessage::Handshake(msg))) } tls-parser-0.12.2/src/tls_message.rs000064400000000000000000000050171046102023000154500ustar 00000000000000use alloc::{vec, vec::Vec}; use nom::bytes::streaming::take; use nom::combinator::verify; use nom::error::{make_error, ErrorKind}; use nom::number::streaming::{be_u16, be_u8}; use nom::{Err, IResult}; use nom_derive::Parse; use crate::tls_alert::*; use crate::tls_handshake::*; /// TLS plaintext message /// /// Plaintext records can only be found during the handshake. #[derive(Clone, Debug, PartialEq)] pub enum TlsMessage<'a> { Handshake(TlsMessageHandshake<'a>), ChangeCipherSpec, Alert(TlsMessageAlert), ApplicationData(TlsMessageApplicationData<'a>), Heartbeat(TlsMessageHeartbeat<'a>), } /// TLS application data /// /// Since this message can only be sent after the handshake, data is /// stored as opaque. #[derive(Clone, Debug, PartialEq)] pub struct TlsMessageApplicationData<'a> { pub blob: &'a [u8], } /// TLS heartbeat message, as defined in [RFC6520](https://tools.ietf.org/html/rfc6520) /// /// Heartbeat messages should not be sent during handshake, but in practise /// they can (and this caused heartbleed). #[derive(Clone, Debug, PartialEq)] pub struct TlsMessageHeartbeat<'a> { pub heartbeat_type: TlsHeartbeatMessageType, pub payload_len: u16, pub payload: &'a [u8], } /// Parse a TLS changecipherspec message // XXX add extra verification hdr.len == 1 pub fn parse_tls_message_changecipherspec(i: &[u8]) -> IResult<&[u8], TlsMessage> { let (i, _) = verify(be_u8, |&tag| tag == 0x01)(i)?; Ok((i, TlsMessage::ChangeCipherSpec)) } /// Parse a TLS alert message // XXX add extra verification hdr.len == 2 pub fn parse_tls_message_alert(i: &[u8]) -> IResult<&[u8], TlsMessage> { let (i, alert) = TlsMessageAlert::parse(i)?; Ok((i, TlsMessage::Alert(alert))) } /// Parse a TLS applicationdata message /// /// Read the entire input as applicationdata pub fn parse_tls_message_applicationdata(i: &[u8]) -> IResult<&[u8], TlsMessage> { let msg = TlsMessage::ApplicationData(TlsMessageApplicationData { blob: i }); Ok((&[], msg)) } /// Parse a TLS heartbeat message pub fn parse_tls_message_heartbeat( i: &[u8], tls_plaintext_len: u16, ) -> IResult<&[u8], Vec> { let (i, heartbeat_type) = TlsHeartbeatMessageType::parse(i)?; let (i, payload_len) = be_u16(i)?; if tls_plaintext_len < 3 { return Err(Err::Error(make_error(i, ErrorKind::Verify))); } let (i, payload) = take(payload_len as usize)(i)?; let v = vec![TlsMessage::Heartbeat(TlsMessageHeartbeat { heartbeat_type, payload_len, payload, })]; Ok((i, v)) } tls-parser-0.12.2/src/tls_record.rs000064400000000000000000000132471046102023000153060ustar 00000000000000use alloc::vec::Vec; use nom::bytes::streaming::take; use nom::combinator::{complete, map_parser}; use nom::error::{make_error, ErrorKind}; use nom::multi::many1; use nom::{Err, IResult}; use nom_derive::{NomBE, Parse}; use rusticata_macros::newtype_enum; use crate::tls_handshake::*; use crate::tls_message::*; use crate::TlsVersion; /// Max record size for TLSCipherText (RFC8446 5.2) pub const MAX_RECORD_LEN: u16 = (1 << 14) + 256; /// Content type, as defined in IANA TLS ContentType registry #[derive(Clone, Copy, PartialEq, Eq, NomBE)] pub struct TlsRecordType(pub u8); newtype_enum! { impl debug TlsRecordType { ChangeCipherSpec = 0x14, Alert = 0x15, Handshake = 0x16, ApplicationData = 0x17, Heartbeat = 0x18, } } impl From for u8 { fn from(v: TlsRecordType) -> u8 { v.0 } } /// TLS record header #[derive(Clone, Copy, PartialEq, NomBE)] pub struct TlsRecordHeader { pub record_type: TlsRecordType, pub version: TlsVersion, pub len: u16, } /// TLS plaintext record /// /// A TLS record can contain multiple messages (sharing the same record type). /// Plaintext records can only be found during the handshake. #[derive(Clone, Debug, PartialEq)] pub struct TlsPlaintext<'a> { pub hdr: TlsRecordHeader, pub msg: Vec>, } /// TLS encrypted data /// /// This struct only contains an opaque pointer (data are encrypted). #[derive(Clone, Debug, PartialEq)] pub struct TlsEncryptedContent<'a> { pub blob: &'a [u8], } /// Encrypted TLS record (containing opaque data) #[derive(Clone, Debug, PartialEq)] pub struct TlsEncrypted<'a> { pub hdr: TlsRecordHeader, pub msg: TlsEncryptedContent<'a>, } /// Tls Record with raw (unparsed) data /// /// Use [`parse_tls_raw_record`] to parse content #[derive(Clone, Debug, PartialEq)] pub struct TlsRawRecord<'a> { pub hdr: TlsRecordHeader, pub data: &'a [u8], } /// Read TLS record header /// /// This function is used to get the record header. /// After calling this function, caller can read the expected number of bytes and use /// [`parse_tls_record_with_header`] to parse content. #[inline] pub fn parse_tls_record_header(i: &[u8]) -> IResult<&[u8], TlsRecordHeader> { TlsRecordHeader::parse(i) } /// Given data and a TLS record header, parse content. /// /// A record can contain multiple messages (with the same type). /// /// Note that message length is checked (not required for parser safety, but for /// strict protocol conformance). #[rustfmt::skip] #[allow(clippy::trivially_copy_pass_by_ref)] // TlsRecordHeader is only 6 bytes, but we prefer not breaking current API pub fn parse_tls_record_with_header<'i>(i:&'i [u8], hdr:&TlsRecordHeader ) -> IResult<&'i [u8], Vec>> { match hdr.record_type { TlsRecordType::ChangeCipherSpec => many1(complete(parse_tls_message_changecipherspec))(i), TlsRecordType::Alert => many1(complete(parse_tls_message_alert))(i), TlsRecordType::Handshake => many1(complete(parse_tls_message_handshake))(i), TlsRecordType::ApplicationData => many1(complete(parse_tls_message_applicationdata))(i), TlsRecordType::Heartbeat => parse_tls_message_heartbeat(i, hdr.len), _ => Err(Err::Error(make_error(i, ErrorKind::Switch))) } } /// Parse one packet only, as plaintext /// A single record can contain multiple messages, they must share the same record type pub fn parse_tls_plaintext(i: &[u8]) -> IResult<&[u8], TlsPlaintext> { let (i, hdr) = parse_tls_record_header(i)?; if hdr.len > MAX_RECORD_LEN { return Err(Err::Error(make_error(i, ErrorKind::TooLarge))); } let (i, msg) = map_parser(take(hdr.len as usize), |i| { parse_tls_record_with_header(i, &hdr) })(i)?; Ok((i, TlsPlaintext { hdr, msg })) } /// Parse one packet only, as encrypted content pub fn parse_tls_encrypted(i: &[u8]) -> IResult<&[u8], TlsEncrypted> { let (i, hdr) = parse_tls_record_header(i)?; if hdr.len > MAX_RECORD_LEN { return Err(Err::Error(make_error(i, ErrorKind::TooLarge))); } let (i, blob) = take(hdr.len as usize)(i)?; let msg = TlsEncryptedContent { blob }; Ok((i, TlsEncrypted { hdr, msg })) } /// Read TLS record envelope, but do not decode data /// /// This function is used to get the record type, and to make sure the record is /// complete (not fragmented). /// After calling this function, use [`parse_tls_record_with_header`] to parse content. pub fn parse_tls_raw_record(i: &[u8]) -> IResult<&[u8], TlsRawRecord> { let (i, hdr) = parse_tls_record_header(i)?; if hdr.len > MAX_RECORD_LEN { return Err(Err::Error(make_error(i, ErrorKind::TooLarge))); } let (i, data) = take(hdr.len as usize)(i)?; Ok((i, TlsRawRecord { hdr, data })) } /// Parse one packet only, as plaintext /// /// This function is deprecated. Use [`parse_tls_plaintext`] instead. /// /// This function will be removed from API, as the name is not correct: it is /// not possible to parse TLS packets without knowing the TLS state. #[deprecated(since = "0.5.0", note = "Use parse_tls_plaintext")] #[inline] pub fn tls_parser(i: &[u8]) -> IResult<&[u8], TlsPlaintext> { parse_tls_plaintext(i) } /// 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. /// /// This function will be removed from API, as it should be replaced by a more /// useful one to handle fragmentation. pub fn tls_parser_many(i: &[u8]) -> IResult<&[u8], Vec> { many1(complete(parse_tls_plaintext))(i) } tls-parser-0.12.2/src/tls_serialize.rs000064400000000000000000000427261046102023000160230ustar 00000000000000use crate::tls_ec::{ECPoint, NamedGroup}; use crate::tls_extensions::{SNIType, TlsExtension, TlsExtensionType}; use crate::tls_handshake::*; use crate::tls_message::*; use crate::tls_record::*; use alloc::vec::Vec; use cookie_factory::bytes::{be_u16, be_u24, be_u8}; use cookie_factory::combinator::slice; use cookie_factory::multi::{all, many_ref}; use cookie_factory::sequence::tuple; use cookie_factory::*; use std::io::Write; pub use cookie_factory::GenError; pub use rusticata_macros::Serialize; fn gen_tls_ext_sni_hostname<'a, 'b: 'a, W: Write + 'a>( i: &(SNIType, &'b [u8]), ) -> impl SerializeFn + 'a { tuple((be_u8((i.0).0), be_u16(i.1.len() as u16), slice(i.1))) } fn length_be_u16(f: F) -> impl SerializeFn where W: Write, F: SerializeFn>, { move |out| { // use a temporary buffer let (buf, len) = gen(&f, Vec::new())?; tuple((be_u16(len as u16), slice(buf)))(out) } } fn length_be_u24(f: F) -> impl SerializeFn where W: Write, F: SerializeFn>, { move |out| { // use a temporary buffer let (buf, len) = gen(&f, Vec::new())?; tuple((be_u24(len as u32), slice(buf)))(out) } } fn tagged_extension(tag: u16, f: F) -> impl SerializeFn where W: Write, F: SerializeFn>, { move |out| tuple((be_u16(tag), length_be_u16(&f)))(out) } fn gen_tls_ext_sni<'a, W>(m: &'a [(SNIType, &[u8])]) -> impl SerializeFn + 'a where W: Write + 'a, { tagged_extension( u16::from(TlsExtensionType::ServerName), length_be_u16(many_ref(m, gen_tls_ext_sni_hostname)), ) } fn gen_tls_ext_max_fragment_length(l: u8) -> impl SerializeFn where W: Write, { tagged_extension(u16::from(TlsExtensionType::MaxFragmentLength), be_u8(l)) } fn gen_tls_named_group(g: NamedGroup) -> impl SerializeFn where W: Write, { be_u16(g.0) } fn gen_tls_ext_elliptic_curves<'a, W>(v: &'a [NamedGroup]) -> impl SerializeFn + 'a where W: Write + 'a, { tagged_extension( u16::from(TlsExtensionType::SupportedGroups), length_be_u16(all(v.iter().map(|&g| gen_tls_named_group(g)))), ) } /// Serialize a single TLS extension /// /// # Example /// /// ```rust /// use cookie_factory::{gen_simple, GenError}; /// use tls_parser::TlsExtension; /// use tls_parser::gen_tls_extensions; /// /// fn extensions_to_vec(ext: &[TlsExtension]) -> Result, GenError> { /// gen_simple(gen_tls_extensions(&ext), Vec::new()) /// } /// ``` /// /// # Note /// /// **Implementation is incomplete: /// only a few extensions are supported** (*Work in progress*) pub fn gen_tls_extension<'a, W>(m: &'a TlsExtension) -> impl SerializeFn + 'a where W: Write + 'a, { move |out| match m { TlsExtension::SNI(ref v) => gen_tls_ext_sni(v)(out), TlsExtension::MaxFragmentLength(l) => gen_tls_ext_max_fragment_length(*l)(out), TlsExtension::EllipticCurves(ref v) => gen_tls_ext_elliptic_curves(v)(out), _ => Err(GenError::NotYetImplemented), } } /// Serialize a list of TLS extensions pub fn gen_tls_extensions<'a, W>(m: &'a [TlsExtension]) -> impl SerializeFn + 'a where W: Write + 'a, { length_be_u16(many_ref(m, gen_tls_extension)) } fn gen_tls_sessionid<'a, W>(m: &'a Option<&[u8]>) -> impl SerializeFn + 'a where W: Write + 'a, { move |out| match m { None => be_u8(0)(out), Some(o) => be_u8(o.len() as u8)(out).and_then(slice(o)), } } fn maybe_extensions<'a, W>(m: &'a Option<&[u8]>) -> impl SerializeFn + 'a where W: Write + 'a, { move |out| match m { Some(o) => be_u16(o.len() as u16)(out).and_then(slice(o)), None => be_u16(0)(out), } } /// Serialize a ClientHello message pub fn gen_tls_clienthello<'a, W>(m: &'a TlsClientHelloContents) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::ClientHello)), length_be_u24(tuple(( be_u16(m.version.0), slice(m.random), // check that length is 32 gen_tls_sessionid(&m.session_id), be_u16(m.ciphers.len() as u16 * 2), all(m.ciphers.iter().map(|cipher| be_u16(cipher.0))), be_u8(m.comp.len() as u8), all(m.comp.iter().map(|comp| be_u8(comp.0))), maybe_extensions(&m.ext), ))), )) } /// Serialize a ServerHello message pub fn gen_tls_serverhello<'a, W>(m: &'a TlsServerHelloContents) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::ServerHello)), length_be_u24(tuple(( be_u16(m.version.0), slice(m.random), // check that length is 32 gen_tls_sessionid(&m.session_id), be_u16(m.cipher.0), be_u8(m.compression.0), maybe_extensions(&m.ext), ))), )) } /// Serialize a ServerHello (TLS 1.3 draft 18) message pub fn gen_tls_serverhellodraft18<'a, W>( m: &'a TlsServerHelloV13Draft18Contents, ) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::ServerHello)), length_be_u24(tuple(( be_u16(m.version.0), slice(m.random), // check that length is 32 be_u16(m.cipher.0), maybe_extensions(&m.ext), ))), )) } /// Serialize a ClientKeyExchange message, from raw contents fn gen_tls_clientkeyexchange_unknown<'a, W>(m: &'a [u8]) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::ClientKeyExchange)), length_be_u24(slice(m)), )) } /// Serialize a ClientKeyExchange message, for DH parameters fn gen_tls_clientkeyexchange_dh<'a, W>(m: &'a [u8]) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::ClientKeyExchange)), length_be_u24(length_be_u16(slice(m))), )) } /// Serialize a ClientKeyExchange message, for ECDH parameters fn gen_tls_clientkeyexchange_ecdh<'a, W>(m: &'a ECPoint) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::ClientKeyExchange)), length_be_u24(tuple(( // for ECDH, length is only 1 byte be_u8(m.point.len() as u8), slice(m.point), ))), )) } /// Serialize a ClientKeyExchange message pub fn gen_tls_clientkeyexchange<'a, W>( m: &'a TlsClientKeyExchangeContents, ) -> impl SerializeFn + 'a where W: Write + 'a, { move |out| match m { TlsClientKeyExchangeContents::Unknown(b) => gen_tls_clientkeyexchange_unknown(b)(out), TlsClientKeyExchangeContents::Dh(b) => gen_tls_clientkeyexchange_dh(b)(out), TlsClientKeyExchangeContents::Ecdh(ref b) => gen_tls_clientkeyexchange_ecdh(b)(out), } } /// Serialize a HelloRequest message pub fn gen_tls_hellorequest() -> impl SerializeFn where W: Write, { tuple((be_u8(u8::from(TlsHandshakeType::HelloRequest)), be_u24(0))) } /// Serialize a Finished message pub fn gen_tls_finished<'a, W>(m: &'a [u8]) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(u8::from(TlsHandshakeType::Finished)), length_be_u24(slice(m)), )) } /// Serialize a TLS handshake message fn gen_tls_messagehandshake<'a, W>(m: &'a TlsMessageHandshake<'a>) -> impl SerializeFn + 'a where W: Write + 'a, { move |out| match m { TlsMessageHandshake::HelloRequest => gen_tls_hellorequest()(out), TlsMessageHandshake::ClientHello(ref m) => gen_tls_clienthello(m)(out), TlsMessageHandshake::ServerHello(ref m) => gen_tls_serverhello(m)(out), TlsMessageHandshake::ServerHelloV13Draft18(ref m) => gen_tls_serverhellodraft18(m)(out), TlsMessageHandshake::ClientKeyExchange(ref m) => gen_tls_clientkeyexchange(m)(out), TlsMessageHandshake::Finished(m) => gen_tls_finished(m)(out), _ => Err(GenError::NotYetImplemented), } } impl<'a> Serialize> for TlsMessageHandshake<'a> { type Error = GenError; fn serialize(&self) -> Result, Self::Error> { gen_simple(gen_tls_messagehandshake(self), Vec::new()) } } /// Serialize a ChangeCipherSpec message pub fn gen_tls_changecipherspec() -> impl SerializeFn where W: Write, { be_u8(u8::from(TlsRecordType::ChangeCipherSpec)) } /// Serialize a TLS message /// /// # Example /// /// ```rust /// use cookie_factory::{gen_simple, GenError}; /// use tls_parser::TlsMessage; /// use tls_parser::gen_tls_message; /// /// fn tls_message_to_vec(msg: &TlsMessage) -> Result, GenError> { /// gen_simple(gen_tls_message(&msg), Vec::new()) /// } /// ``` pub fn gen_tls_message<'a, W>(m: &'a TlsMessage<'a>) -> impl SerializeFn + 'a where W: Write + 'a, { move |out| match m { TlsMessage::Handshake(ref m) => gen_tls_messagehandshake(m)(out), TlsMessage::ChangeCipherSpec => gen_tls_changecipherspec()(out), _ => Err(GenError::NotYetImplemented), } } impl<'a> Serialize> for TlsMessage<'a> { type Error = GenError; fn serialize(&self) -> Result, Self::Error> { gen_simple(gen_tls_message(self), Vec::new()) } } /// Serialize a TLS plaintext record /// /// # Example /// /// ```rust /// use cookie_factory::{gen_simple, GenError}; /// use tls_parser::TlsPlaintext; /// use tls_parser::gen_tls_plaintext; /// /// fn tls_message_to_vec(rec: &TlsPlaintext) -> Result, GenError> { /// gen_simple(gen_tls_plaintext(&rec), Vec::new()) /// } /// ``` pub fn gen_tls_plaintext<'a, W>(p: &'a TlsPlaintext) -> impl SerializeFn + 'a where W: Write + 'a, { tuple(( be_u8(p.hdr.record_type.0), be_u16(p.hdr.version.0), length_be_u16(all(p.msg.iter().map(gen_tls_message))), )) } impl<'a> Serialize> for TlsPlaintext<'a> { type Error = GenError; fn serialize(&self) -> Result, Self::Error> { gen_simple(gen_tls_plaintext(self), Vec::new()) } } #[cfg(test)] mod tests { use super::*; use crate::tls_extensions::parse_tls_extension; use hex_literal::hex; const CH_DHE: &[u8] = include_bytes!("../assets/client_hello_dhe.bin"); #[test] fn serialize_tagged_extension() { let expected = &hex!("12 34 00 02 00 01"); let res = gen_simple(tagged_extension(0x1234, be_u16(1)), Vec::new()).expect("serialize failed"); assert_eq!(&res, expected); } #[test] fn serialize_extension_sni() { let raw_sni = &hex!( " 00 00 00 14 00 12 00 00 0f 63 2e 64 69 73 71 75 73 63 64 6e 2e 63 6f 6d " ); let (_, ext) = parse_tls_extension(raw_sni).expect("could not parse sni extension"); if let TlsExtension::SNI(sni) = ext { let res = gen_simple(gen_tls_ext_sni(&sni), Vec::new()) .expect("could not serialize sni extension"); assert_eq!(&res, raw_sni); } else { panic!("parsed extension has wrong type"); } } #[test] fn serialize_tls_extensions() { let ext = vec![TlsExtension::SNI(vec![( SNIType::HostName, b"www.google.com", )])]; let res = gen_simple(gen_tls_extensions(&ext), Vec::new()) .expect("could not serialize extensions"); let v = [ 0x00, 0x17, // Extensions length (total) 0x00, 0x00, // SNI tag 0x00, 0x13, // SNI ext length 0x00, 0x11, // SNI list length // element 0: 0x00, // type 0x00, 0x0e, // length 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, ]; assert_eq!(&res, &v); } #[test] fn serialize_plaintext() { let random: &[u8] = &[ 0x87, 0xd7, 0x9d, 0xb2, 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, ]; let ciphers = [ 0xc030, 0xc02c, 0xc028, 0xc024, 0xc014, 0xc00a, 0x00a5, 0x00a3, 0x00a1, 0x009f, 0x006b, 0x006a, 0x0069, 0x0068, 0x0039, 0x0038, 0x0037, 0x0036, 0x0088, 0x0087, 0x0086, 0x0085, 0xc032, 0xc02e, 0xc02a, 0xc026, 0xc00f, 0xc005, 0x009d, 0x003d, 0x0035, 0x0084, 0xc02f, 0xc02b, 0xc027, 0xc023, 0xc013, 0xc009, 0x00a4, 0x00a2, 0x00a0, 0x009e, 0x0067, 0x0040, 0x003f, 0x003e, 0x0033, 0x0032, 0x0031, 0x0030, 0x009a, 0x0099, 0x0098, 0x0097, 0x0045, 0x0044, 0x0043, 0x0042, 0xc031, 0xc02d, 0xc029, 0xc025, 0xc00e, 0xc004, 0x009c, 0x003c, 0x002f, 0x0096, 0x0041, 0xc011, 0xc007, 0xc00c, 0xc002, 0x0005, 0x0004, 0xc012, 0xc008, 0x0016, 0x0013, 0x0010, 0x000d, 0xc00d, 0xc003, 0x000a, 0x00ff, ]; let comp = vec![TlsCompressionID(0x00)]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls10, len: 215, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::ClientHello( TlsClientHelloContents { version: TlsVersion::Tls12, random, session_id: None, ciphers: ciphers.iter().map(|&x| TlsCipherSuiteID(x)).collect(), comp, ext: Some(&[]), }, ))], }; let res = expected .serialize() .expect("Could not serialize plaintext message"); let (_, res_reparse) = parse_tls_plaintext(&res).expect("Could not parse gen_tls_plaintext output"); assert_eq!(res_reparse, expected); } #[test] fn serialize_hellorequest() { let m = TlsMessageHandshake::HelloRequest; let res = m.serialize().expect("Could not serialize messages"); let v = [0, 0, 0, 0]; assert_eq!(&v[..], &res[..]); } #[test] fn serialize_tls_ext() { let ext = TlsExtension::SNI(vec![(SNIType::HostName, b"www.google.com")]); let res = gen_simple(gen_tls_extension(&ext), Vec::new()).expect("Could not serialize messages"); let v = [ 0x00, 0x00, // SNI tag 0x00, 0x13, // SNI ext length 0x00, 0x11, // SNI list length // element 0: 0x00, // type 0x00, 0x0e, // length 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, ]; assert_eq!(&v[..], &res[..]); } #[test] fn serialize_clienthello() { let random: &[u8] = &[ 0xb2, 0x9d, 0xd7, 0x87, 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, ]; let ciphers = &[0xc030, 0xc02c]; let comp = vec![TlsCompressionID(0x00)]; let m = TlsMessageHandshake::ClientHello(TlsClientHelloContents { version: TlsVersion::Tls12, random, session_id: None, ciphers: ciphers.iter().map(|&x| TlsCipherSuiteID(x)).collect(), comp, ext: None, }); let res = m.serialize().expect("Could not serialize messages"); let v = [ 0x01, 0x00, 0x00, 0x2d, 0x03, 0x03, // type, length, version 0xb2, 0x9d, 0xd7, 0x87, // random time 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, // random data 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, 0x00, // session ID 0x00, 0x04, 0xc0, 0x30, 0xc0, 0x2c, // ciphers 0x01, 0x00, // compression 0x00, 0x00, // extensions length ]; assert_eq!(&v[..], &res[..]); } #[test] fn serialize_serverhello() { let random: &[u8] = &[ 0xb2, 0x9d, 0xd7, 0x87, 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, ]; let m = TlsMessageHandshake::ServerHello(TlsServerHelloContents { version: TlsVersion::Tls12, random, session_id: None, cipher: TlsCipherSuiteID(0xc030), compression: TlsCompressionID(0), ext: None, }); let res = gen_simple(gen_tls_messagehandshake(&m), Vec::new()) .expect("Could not serialize message"); let v = [ 0x02, 0x00, 0x00, 0x28, 0x03, 0x03, // type, length, version 0xb2, 0x9d, 0xd7, 0x87, // random time 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, // random data 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, 0x00, // session ID 0xc0, 0x30, // cipher 0x00, // compression 0x00, 0x00, // extensions length ]; assert_eq!(&v[..], &res[..]); } #[test] fn read_serialize_clienthello_dhe() { let (_, record) = parse_tls_plaintext(CH_DHE).expect("parsing failed"); let res = gen_simple(gen_tls_plaintext(&record), Vec::new()) .expect("Could not serialize message"); let (_, record2) = parse_tls_plaintext(&res).expect("re-parsing failed"); assert_eq!(record, record2); } } tls-parser-0.12.2/src/tls_sign_hash.rs000064400000000000000000000075601046102023000157740ustar 00000000000000use nom::combinator::map; use nom::multi::length_data; use nom::number::streaming::be_u16; use nom::sequence::pair; use nom::IResult; use nom_derive::*; use rusticata_macros::newtype_enum; /// Hash algorithms, as defined in \[RFC5246\] #[derive(Clone, Debug, PartialEq, Eq, Nom)] pub struct HashAlgorithm(pub u8); newtype_enum! { impl display HashAlgorithm { None = 0, Md5 = 1, Sha1 = 2, Sha224 = 3, Sha256 = 4, Sha384 = 5, Sha512 = 6, Intrinsic = 8, // [RFC8422] } } /// Signature algorithms, as defined in \[RFC5246\] #[derive(Clone, Debug, PartialEq, Eq, Nom)] pub struct SignAlgorithm(pub u8); newtype_enum! { impl display SignAlgorithm { Anonymous = 0, Rsa = 1, Dsa = 2, Ecdsa = 3, Ed25519 = 7, // [RFC8422] Ed448 = 8, // [RFC8422] } } #[derive(Clone, PartialEq, Nom)] pub struct SignatureAndHashAlgorithm { pub hash: HashAlgorithm, pub sign: SignAlgorithm, } /// Signature algorithms, as defined in \[RFC8446\] 4.2.3 #[derive(Debug, PartialEq, Eq, Nom)] pub struct SignatureScheme(pub u16); newtype_enum! { impl display SignatureScheme { /* RSASSA-PKCS1-v1_5 algorithms */ rsa_pkcs1_sha256 = 0x0401, rsa_pkcs1_sha384 = 0x0501, rsa_pkcs1_sha512 = 0x0601, /* ECDSA algorithms */ ecdsa_secp256r1_sha256 = 0x0403, ecdsa_secp384r1_sha384 = 0x0503, ecdsa_secp521r1_sha512 = 0x0603, /* ShangMi (SM) Cipher Suites */ sm2sig_sm3 = 0x0708, /* RSASSA-PSS algorithms with public key OID rsaEncryption */ rsa_pss_rsae_sha256 = 0x0804, rsa_pss_rsae_sha384 = 0x0805, rsa_pss_rsae_sha512 = 0x0806, /* EdDSA algorithms */ ed25519 = 0x0807, ed448 = 0x0808, /* RSASSA-PSS algorithms with public key OID RSASSA-PSS */ rsa_pss_pss_sha256 = 0x0809, rsa_pss_pss_sha384 = 0x080a, rsa_pss_pss_sha512 = 0x080b, /* Brainpool SignatureScheme Types for TLS 1.3 (RFC8734) */ ecdsa_brainpoolP256r1tls13_sha256 = 0x081a, ecdsa_brainpoolP384r1tls13_sha384 = 0x081b, ecdsa_brainpoolP512r1tls13_sha512 = 0x081c, /* Legacy algorithms */ rsa_pkcs1_sha1 = 0x0201, ecdsa_sha1 = 0x0203, } } impl SignatureScheme { pub fn is_reserved(&self) -> bool { self.0 >= 0xfe00 && self.0 < 0xff00 } /// Get Hash algorithm (for tls <= 1.2) for legacy extension format pub fn hash_alg(&self) -> u8 { ((self.0 >> 8) & 0xff) as u8 } /// Get Signature algorithm (for tls <= 1.2) for legacy extension format pub fn sign_alg(&self) -> u8 { (self.0 & 0xff) as u8 } } /// DigitallySigned structure from \[RFC2246\] section 4.7 /// has no algorithm definition. /// This should be deprecated in favor of /// DigitallySigned structure from \[RFC5246\] section 4.7 #[derive(Clone, PartialEq)] pub struct DigitallySigned<'a> { pub alg: Option, // pub alg: Option, // SignatureScheme pub data: &'a [u8], } pub fn parse_digitally_signed_old(i: &[u8]) -> IResult<&[u8], DigitallySigned> { map(length_data(be_u16), |data| DigitallySigned { alg: None, data, })(i) } pub fn parse_digitally_signed(i: &[u8]) -> IResult<&[u8], DigitallySigned> { let (i, hash) = HashAlgorithm::parse(i)?; let (i, sign) = SignAlgorithm::parse(i)?; let (i, data) = length_data(be_u16)(i)?; let signed = DigitallySigned { alg: Some(SignatureAndHashAlgorithm { hash, sign }), data, }; Ok((i, signed)) } /// Parse DigitallySigned object, depending on the `ext` parameter which should /// be true if the TLS client has sent the `signature_algorithms` extension pub fn parse_content_and_signature<'a, F, T>( i: &'a [u8], fun: F, ext: bool, ) -> IResult<&'a [u8], (T, DigitallySigned<'a>)> where F: Fn(&'a [u8]) -> IResult<&'a [u8], T>, { if ext { pair(fun, parse_digitally_signed)(i) } else { pair(fun, parse_digitally_signed_old)(i) } } tls-parser-0.12.2/src/tls_states.rs000064400000000000000000000161441046102023000153320ustar 00000000000000use crate::tls_alert::TlsAlertSeverity; use crate::tls_handshake::*; use crate::tls_message::*; #[derive(Debug, PartialEq, Eq)] /// Error types for the state machine pub enum StateChangeError { InvalidTransition, ParseError, } /// TLS machine possible states #[derive(Copy, Clone, Debug, PartialEq)] pub enum TlsState { None, ClientHello, AskResumeSession, ResumeSession, ServerHello, Certificate, CertificateSt, ServerKeyExchange, ServerHelloDone, ClientKeyExchange, ClientChangeCipherSpec, CRCertRequest, CRHelloDone, CRCert, CRClientKeyExchange, CRCertVerify, NoCertSKE, NoCertHelloDone, NoCertCKE, PskHelloDone, PskCKE, SessionEncrypted, Alert, Finished, Invalid, } #[rustfmt::skip] fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake, to_server:bool) -> Result { match (state,msg,to_server) { (TlsState::None, TlsMessageHandshake::ClientHello(msg), true) => { match msg.session_id { Some(_) => Ok(TlsState::AskResumeSession), _ => Ok(TlsState::ClientHello) } }, // Server certificate (TlsState::ClientHello, &TlsMessageHandshake::ServerHello(_), false) => Ok(TlsState::ServerHello), (TlsState::ServerHello, &TlsMessageHandshake::Certificate(_), false) => Ok(TlsState::Certificate), // Server certificate, no client certificate requested (TlsState::Certificate, &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::ServerKeyExchange), (TlsState::Certificate, &TlsMessageHandshake::CertificateStatus(_), false) => Ok(TlsState::CertificateSt), (TlsState::CertificateSt, &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::ServerKeyExchange), (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_), false) => Ok(TlsState::ServerHelloDone), (TlsState::ServerHelloDone ,&TlsMessageHandshake::ClientKeyExchange(_), true) => Ok(TlsState::ClientKeyExchange), // Server certificate, client certificate requested (TlsState::Certificate, &TlsMessageHandshake::CertificateRequest(_), false)=> Ok(TlsState::CRCertRequest), (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_), false)=> Ok(TlsState::CRCertRequest), (TlsState::CRCertRequest, &TlsMessageHandshake::ServerDone(_), false) => Ok(TlsState::CRHelloDone), (TlsState::CRHelloDone, &TlsMessageHandshake::Certificate(_), true) => Ok(TlsState::CRCert), (TlsState::CRCert, &TlsMessageHandshake::ClientKeyExchange(_), true) => Ok(TlsState::CRClientKeyExchange), (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_), _) => Ok(TlsState::CRCertVerify), // Server has no certificate (but accepts anonymous) (TlsState::ServerHello, &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::NoCertSKE), (TlsState::NoCertSKE, &TlsMessageHandshake::ServerDone(_), false) => Ok(TlsState::NoCertHelloDone), (TlsState::NoCertHelloDone, &TlsMessageHandshake::ClientKeyExchange(_), true) => Ok(TlsState::NoCertCKE), // PSK (TlsState::Certificate, &TlsMessageHandshake::ServerDone(_), false) => Ok(TlsState::PskHelloDone), (TlsState::PskHelloDone, &TlsMessageHandshake::ClientKeyExchange(_), true) => Ok(TlsState::PskCKE), // Resuming session (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_), false) => Ok(TlsState::ResumeSession), // Resume session failed (TlsState::ResumeSession, &TlsMessageHandshake::Certificate(_), false) => Ok(TlsState::Certificate), // TLS 1.3 Draft 18 1-RTT // Re-use the ClientChangeCipherSpec state to indicate the next message will be encrypted (TlsState::ClientHello, &TlsMessageHandshake::ServerHelloV13Draft18(_), false) => Ok(TlsState::ClientChangeCipherSpec), // Hello requests must be accepted at any time (except start), but ignored [RFC5246] 7.4.1.1 (TlsState::None, &TlsMessageHandshake::HelloRequest, _) => Err(StateChangeError::InvalidTransition), (s, &TlsMessageHandshake::HelloRequest, _) => Ok(s), // NewSessionTicket message (after CCS) (TlsState::ClientChangeCipherSpec, &TlsMessageHandshake::NewSessionTicket(_), false) => Ok(TlsState::ClientChangeCipherSpec), // All other transitions are considered invalid _ => Err(StateChangeError::InvalidTransition), } } /// Update the TLS state machine, doing one transition /// /// Given the previous state and the parsed message, return the new state or a state machine error. /// /// This state machine only implements the TLS handshake. /// /// Some transitions only check the new message type, while some others must match the content /// (for example, to check if the client asked to resume a session). /// /// If the previous state is `Invalid`, the state machine will not return an error, but keep the /// same `Invalid` state. This is used to raise error only once if the state machine keeps being /// updated by new messages. #[rustfmt::skip] pub fn tls_state_transition(state: TlsState, msg: &TlsMessage, to_server:bool) -> Result { match (state,msg,to_server) { (TlsState::Invalid,_,_) => Ok(TlsState::Invalid), (TlsState::SessionEncrypted,_, _) => Ok(TlsState::SessionEncrypted), (TlsState::Finished,_,_) => Ok(TlsState::Invalid), (_,TlsMessage::Handshake(m),_) => tls_state_transition_handshake(state,m,to_server), // Server certificate (TlsState::ClientKeyExchange, &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec), (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec, false) => Ok(TlsState::SessionEncrypted), // Server certificate, client certificate requested (TlsState::CRClientKeyExchange, &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec), (TlsState::CRCertVerify, &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec), // No server certificate (TlsState::NoCertCKE, &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec), // PSK (TlsState::PskCKE, &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec), // Resume session (TlsState::ResumeSession, &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec), // 0-rtt (TlsState::AskResumeSession, &TlsMessage::ChangeCipherSpec, true) => Ok(TlsState::AskResumeSession), // non-fatal alerts (s, TlsMessage::Alert(a), _) => { if a.severity == TlsAlertSeverity::Warning { Ok(s) } else { Ok(TlsState::Finished) } }, (_,_,_) => Err(StateChangeError::InvalidTransition), } } tls-parser-0.12.2/tests/certificate_transparency.rs000064400000000000000000000113071046102023000205670ustar 00000000000000#[macro_use] extern crate pretty_assertions; extern crate nom; extern crate tls_parser; mod certificate_transparency { use tls_parser::*; static SCT_LIST: &[u8] = &[ 0x00, 0xf0, 0x00, 0x76, 0x00, 0xf6, 0x5c, 0x94, 0x2f, 0xd1, 0x77, 0x30, 0x22, 0x14, 0x54, 0x18, 0x08, 0x30, 0x94, 0x56, 0x8e, 0xe3, 0x4d, 0x13, 0x19, 0x33, 0xbf, 0xdf, 0x0c, 0x2f, 0x20, 0x0b, 0xcc, 0x4e, 0xf1, 0x64, 0xe3, 0x00, 0x00, 0x01, 0x72, 0x53, 0x4b, 0x97, 0xa5, 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xc6, 0x2d, 0xa9, 0x45, 0xd2, 0x81, 0xfd, 0xda, 0x9f, 0xf3, 0xf8, 0xa4, 0x18, 0xb4, 0x4d, 0x2f, 0x7c, 0x23, 0x60, 0xb5, 0x6a, 0xb9, 0x51, 0x88, 0x9c, 0x38, 0x1b, 0x36, 0xf8, 0xa9, 0xf2, 0x1d, 0x02, 0x20, 0x00, 0xe2, 0xfc, 0xde, 0xbc, 0x91, 0x08, 0x29, 0x46, 0x86, 0x08, 0x89, 0x5b, 0x62, 0xd4, 0x45, 0x3e, 0x91, 0xdd, 0x39, 0x76, 0xb7, 0xa6, 0xe4, 0xae, 0xd4, 0xd2, 0x38, 0x50, 0xe9, 0xc7, 0xd0, 0x00, 0x76, 0x00, 0x5c, 0xdc, 0x43, 0x92, 0xfe, 0xe6, 0xab, 0x45, 0x44, 0xb1, 0x5e, 0x9a, 0xd4, 0x56, 0xe6, 0x10, 0x37, 0xfb, 0xd5, 0xfa, 0x47, 0xdc, 0xa1, 0x73, 0x94, 0xb2, 0x5e, 0xe6, 0xf6, 0xc7, 0x0e, 0xca, 0x00, 0x00, 0x01, 0x72, 0x53, 0x4b, 0x97, 0xa0, 0x00, 0x00, 0x04, 0x03, 0x00, 0x47, 0x30, 0x45, 0x02, 0x20, 0x35, 0x6c, 0x91, 0x1f, 0xb3, 0x22, 0x79, 0xf2, 0x65, 0x95, 0x53, 0xcf, 0x3a, 0x36, 0xd7, 0xac, 0xde, 0xa1, 0xf4, 0xb1, 0xa9, 0x2e, 0xdd, 0x46, 0x0d, 0x96, 0xff, 0x1b, 0xda, 0x93, 0x4e, 0xe8, 0x02, 0x21, 0x00, 0xee, 0xed, 0x93, 0x37, 0xba, 0x12, 0xdb, 0x44, 0x67, 0x7e, 0x09, 0xa4, 0x5f, 0xd6, 0x66, 0x6c, 0x7b, 0x02, 0xb8, 0x63, 0x1f, 0xb6, 0xbf, 0x91, 0x53, 0x95, 0xb6, 0xf9, 0xd6, 0xfd, 0x45, 0x2d, ]; #[test] fn test_ct_parse_signed_certificate_timestamp_list() { let empty = &b""[..]; let res = parse_ct_signed_certificate_timestamp_list(SCT_LIST).unwrap(); let id1 = &[ 0xf6, 0x5c, 0x94, 0x2f, 0xd1, 0x77, 0x30, 0x22, 0x14, 0x54, 0x18, 0x08, 0x30, 0x94, 0x56, 0x8e, 0xe3, 0x4d, 0x13, 0x19, 0x33, 0xbf, 0xdf, 0x0c, 0x2f, 0x20, 0x0b, 0xcc, 0x4e, 0xf1, 0x64, 0xe3, ]; let id2 = &[ 0x5c, 0xdc, 0x43, 0x92, 0xfe, 0xe6, 0xab, 0x45, 0x44, 0xb1, 0x5e, 0x9a, 0xd4, 0x56, 0xe6, 0x10, 0x37, 0xfb, 0xd5, 0xfa, 0x47, 0xdc, 0xa1, 0x73, 0x94, 0xb2, 0x5e, 0xe6, 0xf6, 0xc7, 0x0e, 0xca, ]; let signature1 = DigitallySigned { alg: Some(SignatureAndHashAlgorithm { hash: HashAlgorithm::Sha256, sign: SignAlgorithm::Ecdsa, }), data: &[ 0x30, 0x45, 0x02, 0x21, 0x00, 0xc6, 0x2d, 0xa9, 0x45, 0xd2, 0x81, 0xfd, 0xda, 0x9f, 0xf3, 0xf8, 0xa4, 0x18, 0xb4, 0x4d, 0x2f, 0x7c, 0x23, 0x60, 0xb5, 0x6a, 0xb9, 0x51, 0x88, 0x9c, 0x38, 0x1b, 0x36, 0xf8, 0xa9, 0xf2, 0x1d, 0x02, 0x20, 0x00, 0xe2, 0xfc, 0xde, 0xbc, 0x91, 0x08, 0x29, 0x46, 0x86, 0x08, 0x89, 0x5b, 0x62, 0xd4, 0x45, 0x3e, 0x91, 0xdd, 0x39, 0x76, 0xb7, 0xa6, 0xe4, 0xae, 0xd4, 0xd2, 0x38, 0x50, 0xe9, 0xc7, 0xd0, ], }; let signature2 = DigitallySigned { alg: Some(SignatureAndHashAlgorithm { hash: HashAlgorithm::Sha256, sign: SignAlgorithm::Ecdsa, }), data: &[ 0x30, 0x45, 0x02, 0x20, 0x35, 0x6c, 0x91, 0x1f, 0xb3, 0x22, 0x79, 0xf2, 0x65, 0x95, 0x53, 0xcf, 0x3a, 0x36, 0xd7, 0xac, 0xde, 0xa1, 0xf4, 0xb1, 0xa9, 0x2e, 0xdd, 0x46, 0x0d, 0x96, 0xff, 0x1b, 0xda, 0x93, 0x4e, 0xe8, 0x02, 0x21, 0x00, 0xee, 0xed, 0x93, 0x37, 0xba, 0x12, 0xdb, 0x44, 0x67, 0x7e, 0x09, 0xa4, 0x5f, 0xd6, 0x66, 0x6c, 0x7b, 0x02, 0xb8, 0x63, 0x1f, 0xb6, 0xbf, 0x91, 0x53, 0x95, 0xb6, 0xf9, 0xd6, 0xfd, 0x45, 0x2d, ], }; assert_eq!( res, ( empty, vec![ SignedCertificateTimestamp { version: CtVersion::V1, id: CtLogID { key_id: id1 }, timestamp: 1590535362469, extensions: CtExtensions(empty), signature: signature1 }, SignedCertificateTimestamp { version: CtVersion::V1, id: CtLogID { key_id: id2 }, timestamp: 1590535362464, extensions: CtExtensions(empty), signature: signature2 } ] ) ); } } tls-parser-0.12.2/tests/tls_dh.rs000064400000000000000000000245651046102023000150030ustar 00000000000000mod tls_dh { use nom::sequence::pair; use tls_parser::*; #[rustfmt::skip] static ECDHE_PARAMS: &[u8] = &[ 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0xd1, 0x50, 0x12, 0xf4, 0xc4, 0xcf, 0xd4, 0xc2, 0x1f, 0xe8, 0xf6, 0x85, 0xdc, 0xde, 0x0b, 0xeb, 0x3c, 0x0d, 0x0f, 0x97, 0x29, 0x36, 0x63, 0xc6, 0xc1, 0x3b, 0xfd, 0x38, 0xce, 0xde, 0x43, 0x7f, 0x7d, 0x57, 0x64, 0x54, 0x6f, 0x89, 0x3c, 0xe7, 0x5e, 0x28, 0x9e, 0x9d, 0x24, 0xca, 0x07, 0x63, 0xd5, 0x03, 0x30, 0x8b, 0xd8, 0x1a, 0xae, 0xb6, 0xa8, 0x5f, 0x10, 0x87, 0x81, 0x29, 0x1b, 0xef, 0xbd, 0x00, 0xeb, 0x29, 0x37, 0xb3, 0xc3, 0xda, 0x8e, 0xad, 0xf3, 0x9c, 0x10, 0xe3, 0x93, 0xeb, 0x0a, 0x53, 0x14, 0xea, 0x3c, 0x05, 0xb7, 0xc1, 0x6b, 0x79, 0xca, 0xfc, 0x9a, 0x5b, 0xc3, 0xaf, 0xf2, 0xdd, 0x9f, 0xdd, 0x07, 0xf5, 0x07, 0xef, 0xb4, 0x24, 0xac, 0xdb, 0xd2, 0x0d, 0x65, 0x37, 0x96, 0xa0, 0x15, 0xef, 0x7c, 0x6d, 0x66, 0x63, 0x0d, 0x41, 0x1d, 0xd7, 0x90, 0x05, 0x66, 0xcf, 0x79, 0x0c, 0x03, 0x02, 0x01, 0x01, 0x00, 0x7c, 0xa7, 0x5f, 0x73, 0x77, 0x2c, 0x92, 0x4c, 0xe4, 0xa7, 0x67, 0x86, 0x76, 0xf2, 0xa3, 0xf8, 0xd1, 0x9d, 0xca, 0x4f, 0x71, 0xd1, 0x67, 0xf4, 0xbe, 0x7e, 0xb3, 0x60, 0xc4, 0xf1, 0x6e, 0x90, 0x22, 0x97, 0xe9, 0xc2, 0x43, 0xc9, 0xfb, 0x46, 0x21, 0xd4, 0xe9, 0xed, 0xdc, 0x46, 0x5b, 0x3e, 0x4c, 0xfb, 0xf2, 0xeb, 0x3f, 0x09, 0x4e, 0x59, 0x5f, 0x6f, 0x60, 0x50, 0x8a, 0x80, 0x50, 0xa7, 0xc3, 0xb9, 0xf0, 0xd1, 0x80, 0xb0, 0x1b, 0x11, 0x53, 0xe4, 0xac, 0x45, 0xa8, 0x75, 0x59, 0x55, 0x1a, 0x20, 0xa5, 0xbb, 0x23, 0xb6, 0x1c, 0x39, 0xa8, 0x4e, 0x62, 0x57, 0xef, 0x4f, 0x11, 0xce, 0x64, 0x87, 0x9b, 0x5a, 0xb8, 0x06, 0xf1, 0x62, 0x63, 0x3d, 0x13, 0x46, 0x72, 0x79, 0x7e, 0x65, 0x5c, 0xb4, 0x0a, 0xe3, 0x63, 0x13, 0x05, 0xc9, 0xaa, 0xc3, 0x93, 0x9b, 0x69, 0x37, 0x04, 0xa6, 0x7b, 0x69, 0xa9, 0x72, 0x67, 0x32, 0x9d, 0xc9, 0x53, 0x05, 0xe5, 0x18, 0x00, 0x73, 0xcb, 0x40, 0xd8, 0x86, 0x81, 0x01, 0x78, 0x36, 0x8f, 0x62, 0x94, 0xb4, 0x88, 0x27, 0xdb, 0x8e, 0xe4, 0x76, 0x56, 0x1d, 0xac, 0x7d, 0x36, 0x4c, 0xb4, 0xad, 0x4c, 0xe0, 0x21, 0x1f, 0xd5, 0x2d, 0x30, 0xa0, 0x78, 0xba, 0x28, 0x0b, 0xb4, 0x6d, 0xf1, 0x95, 0x41, 0x11, 0xdb, 0x64, 0xaf, 0x11, 0xa2, 0x9b, 0x45, 0x07, 0x42, 0x95, 0xf1, 0xe4, 0x0a, 0x16, 0x0c, 0x7f, 0xa7, 0x96, 0xc1, 0x91, 0xf0, 0x7c, 0xf7, 0x67, 0xe6, 0x1c, 0xbd, 0x1d, 0xcb, 0xbc, 0x42, 0x2a, 0x47, 0x35, 0x28, 0x96, 0xc3, 0x08, 0x48, 0x7d, 0xe9, 0xf1, 0x42, 0x00, 0xee, 0xd5, 0x0e, 0xd4, 0x08, 0xd6, 0x34, 0x15, 0xd6, 0x7c, 0x4b, 0xc5, 0x23, 0xf4, 0x8c, 0xfa, 0x70, 0xd8, 0x60, 0x46, 0xd2, 0xa3, 0xba, 0x75, 0xa4, 0x8f ]; #[test] fn test_tls_ecdhe_params() { let empty = &b""[..]; let bytes = ECDHE_PARAMS; let point_data = &bytes[4..137]; let expected1 = ServerECDHParams { curve_params: ECParameters { curve_type: ECCurveType::NamedGroup, params_content: ECParametersContent::NamedGroup(NamedGroup::Secp521r1), }, public: ECPoint { point: point_data }, }; let expected2 = DigitallySigned { alg: Some(SignatureAndHashAlgorithm { hash: HashAlgorithm::Sha1, sign: SignAlgorithm::Rsa, }), data: &bytes[141..], }; let res = pair(parse_ecdh_params, parse_digitally_signed)(bytes); assert_eq!(res, Ok((empty, (expected1, expected2)))); } #[rustfmt::skip] static DHE_PARAMS: &[u8] = &[ 0x01, 0x00, 0xad, 0x10, 0x7e, 0x1e, 0x91, 0x23, 0xa9, 0xd0, 0xd6, 0x60, 0xfa, 0xa7, 0x95, 0x59, 0xc5, 0x1f, 0xa2, 0x0d, 0x64, 0xe5, 0x68, 0x3b, 0x9f, 0xd1, 0xb5, 0x4b, 0x15, 0x97, 0xb6, 0x1d, 0x0a, 0x75, 0xe6, 0xfa, 0x14, 0x1d, 0xf9, 0x5a, 0x56, 0xdb, 0xaf, 0x9a, 0x3c, 0x40, 0x7b, 0xa1, 0xdf, 0x15, 0xeb, 0x3d, 0x68, 0x8a, 0x30, 0x9c, 0x18, 0x0e, 0x1d, 0xe6, 0xb8, 0x5a, 0x12, 0x74, 0xa0, 0xa6, 0x6d, 0x3f, 0x81, 0x52, 0xad, 0x6a, 0xc2, 0x12, 0x90, 0x37, 0xc9, 0xed, 0xef, 0xda, 0x4d, 0xf8, 0xd9, 0x1e, 0x8f, 0xef, 0x55, 0xb7, 0x39, 0x4b, 0x7a, 0xd5, 0xb7, 0xd0, 0xb6, 0xc1, 0x22, 0x07, 0xc9, 0xf9, 0x8d, 0x11, 0xed, 0x34, 0xdb, 0xf6, 0xc6, 0xba, 0x0b, 0x2c, 0x8b, 0xbc, 0x27, 0xbe, 0x6a, 0x00, 0xe0, 0xa0, 0xb9, 0xc4, 0x97, 0x08, 0xb3, 0xbf, 0x8a, 0x31, 0x70, 0x91, 0x88, 0x36, 0x81, 0x28, 0x61, 0x30, 0xbc, 0x89, 0x85, 0xdb, 0x16, 0x02, 0xe7, 0x14, 0x41, 0x5d, 0x93, 0x30, 0x27, 0x82, 0x73, 0xc7, 0xde, 0x31, 0xef, 0xdc, 0x73, 0x10, 0xf7, 0x12, 0x1f, 0xd5, 0xa0, 0x74, 0x15, 0x98, 0x7d, 0x9a, 0xdc, 0x0a, 0x48, 0x6d, 0xcd, 0xf9, 0x3a, 0xcc, 0x44, 0x32, 0x83, 0x87, 0x31, 0x5d, 0x75, 0xe1, 0x98, 0xc6, 0x41, 0xa4, 0x80, 0xcd, 0x86, 0xa1, 0xb9, 0xe5, 0x87, 0xe8, 0xbe, 0x60, 0xe6, 0x9c, 0xc9, 0x28, 0xb2, 0xb9, 0xc5, 0x21, 0x72, 0xe4, 0x13, 0x04, 0x2e, 0x9b, 0x23, 0xf1, 0x0b, 0x0e, 0x16, 0xe7, 0x97, 0x63, 0xc9, 0xb5, 0x3d, 0xcf, 0x4b, 0xa8, 0x0a, 0x29, 0xe3, 0xfb, 0x73, 0xc1, 0x6b, 0x8e, 0x75, 0xb9, 0x7e, 0xf3, 0x63, 0xe2, 0xff, 0xa3, 0x1f, 0x71, 0xcf, 0x9d, 0xe5, 0x38, 0x4e, 0x71, 0xb8, 0x1c, 0x0a, 0xc4, 0xdf, 0xfe, 0x0c, 0x10, 0xe6, 0x4f, 0x01, 0x00, 0xac, 0x40, 0x32, 0xef, 0x4f, 0x2d, 0x9a, 0xe3, 0x9d, 0xf3, 0x0b, 0x5c, 0x8f, 0xfd, 0xac, 0x50, 0x6c, 0xde, 0xbe, 0x7b, 0x89, 0x99, 0x8c, 0xaf, 0x74, 0x86, 0x6a, 0x08, 0xcf, 0xe4, 0xff, 0xe3, 0xa6, 0x82, 0x4a, 0x4e, 0x10, 0xb9, 0xa6, 0xf0, 0xdd, 0x92, 0x1f, 0x01, 0xa7, 0x0c, 0x4a, 0xfa, 0xab, 0x73, 0x9d, 0x77, 0x00, 0xc2, 0x9f, 0x52, 0xc5, 0x7d, 0xb1, 0x7c, 0x62, 0x0a, 0x86, 0x52, 0xbe, 0x5e, 0x90, 0x01, 0xa8, 0xd6, 0x6a, 0xd7, 0xc1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4a, 0xf4, 0xd0, 0x27, 0x27, 0x5a, 0xc1, 0x34, 0x8b, 0xb8, 0xa7, 0x62, 0xd0, 0x52, 0x1b, 0xc9, 0x8a, 0xe2, 0x47, 0x15, 0x04, 0x22, 0xea, 0x1e, 0xd4, 0x09, 0x93, 0x9d, 0x54, 0xda, 0x74, 0x60, 0xcd, 0xb5, 0xf6, 0xc6, 0xb2, 0x50, 0x71, 0x7c, 0xbe, 0xf1, 0x80, 0xeb, 0x34, 0x11, 0x8e, 0x98, 0xd1, 0x19, 0x52, 0x9a, 0x45, 0xd6, 0xf8, 0x34, 0x56, 0x6e, 0x30, 0x25, 0xe3, 0x16, 0xa3, 0x30, 0xef, 0xbb, 0x77, 0xa8, 0x6f, 0x0c, 0x1a, 0xb1, 0x5b, 0x05, 0x1a, 0xe3, 0xd4, 0x28, 0xc8, 0xf8, 0xac, 0xb7, 0x0a, 0x81, 0x37, 0x15, 0x0b, 0x8e, 0xeb, 0x10, 0xe1, 0x83, 0xed, 0xd1, 0x99, 0x63, 0xdd, 0xd9, 0xe2, 0x63, 0xe4, 0x77, 0x05, 0x89, 0xef, 0x6a, 0xa2, 0x1e, 0x7f, 0x5f, 0x2f, 0xf3, 0x81, 0xb5, 0x39, 0xcc, 0xe3, 0x40, 0x9d, 0x13, 0xcd, 0x56, 0x6a, 0xfb, 0xb4, 0x8d, 0x6c, 0x01, 0x91, 0x81, 0xe1, 0xbc, 0xfe, 0x94, 0xb3, 0x02, 0x69, 0xed, 0xfe, 0x72, 0xfe, 0x9b, 0x6a, 0xa4, 0xbd, 0x7b, 0x5a, 0x0f, 0x1c, 0x71, 0xcf, 0xff, 0x4c, 0x19, 0xc4, 0x18, 0xe1, 0xf6, 0xec, 0x01, 0x79, 0x81, 0xbc, 0x08, 0x7f, 0x2a, 0x70, 0x65, 0xb3, 0x84, 0xb8, 0x90, 0xd3, 0x19, 0x1f, 0x2b, 0xfa, 0x01, 0x00, 0x6f, 0x45, 0x37, 0xd8, 0xe5, 0x74, 0x44, 0xa4, 0xd0, 0xea, 0xa7, 0x37, 0x49, 0xb3, 0x06, 0xfa, 0xe6, 0x2e, 0x97, 0x18, 0x84, 0x13, 0x57, 0xd5, 0x5f, 0x87, 0xab, 0xc1, 0x4b, 0xc7, 0xac, 0x14, 0x52, 0x23, 0x1b, 0xb0, 0x64, 0xef, 0x0b, 0x52, 0x6d, 0x8f, 0xf3, 0x79, 0x1f, 0x91, 0xc0, 0x44, 0xd6, 0x07, 0xeb, 0x0a, 0xf2, 0x10, 0x96, 0xf1, 0x54, 0xa3, 0x11, 0x89, 0xb7, 0xdc, 0x87, 0xf1, 0x8f, 0x24, 0xb7, 0x08, 0xc5, 0xf4, 0x19, 0x67, 0x2c, 0x63, 0xde, 0xc3, 0x2d, 0x4e, 0xea, 0xbc, 0x4a, 0x55, 0x8a, 0x45, 0x7b, 0x57, 0xe2, 0x8a, 0xb1, 0x29, 0x0c, 0xcb, 0x41, 0xc3, 0xf0, 0x07, 0x85, 0x14, 0x35, 0x54, 0x35, 0x04, 0x69, 0xa4, 0x87, 0x9a, 0x97, 0x0f, 0x4f, 0xb8, 0x7c, 0x36, 0xa5, 0xd8, 0x89, 0xc8, 0x41, 0x62, 0xd8, 0x27, 0x30, 0xf5, 0x1b, 0x86, 0x46, 0xb6, 0x14, 0xa2, 0xea, 0x7c, 0xac, 0x62, 0xc1, 0xf8, 0x26, 0xf0, 0x63, 0x1e, 0x73, 0x74, 0xb2, 0xa0, 0x77, 0xd1, 0x2b, 0xeb, 0x79, 0x77, 0x65, 0xd9, 0x60, 0x50, 0x5d, 0x2b, 0x3b, 0x3c, 0xa2, 0xb5, 0x6a, 0x89, 0x2b, 0xb6, 0x92, 0xb0, 0x7e, 0x22, 0x03, 0xfe, 0xf5, 0x53, 0x90, 0x1f, 0x7d, 0xe9, 0x42, 0x82, 0xfa, 0x92, 0xb9, 0x7b, 0x15, 0xd4, 0xa6, 0x98, 0xe4, 0xf3, 0xee, 0xb6, 0xcc, 0xaa, 0xb2, 0xa6, 0xdf, 0x9a, 0xb9, 0x72, 0xcf, 0x5b, 0x76, 0x6b, 0xd5, 0x04, 0x98, 0x23, 0xa8, 0x29, 0xdf, 0x2a, 0xd9, 0xb7, 0x1e, 0xbc, 0xe3, 0x4a, 0x93, 0x08, 0x3a, 0xc4, 0x66, 0x1f, 0x2c, 0x94, 0x4d, 0x7a, 0xe6, 0xa9, 0x26, 0x40, 0x64, 0x2b, 0x31, 0xd7, 0xb5, 0x3b, 0x4e, 0xc5, 0x78, 0xe0, 0x90, 0x15, 0xaa, 0x95, 0x80, 0xc3, 0x22, 0x67, 0x5c, 0x21, 0x4c, 0xb7, 0xe3, 0x9f, 0xf2, 0xdb, 0x66, 0x97, 0x06, 0x01, 0x01, 0x00, 0x4e, 0x76, 0x32, 0x0e, 0xa2, 0xb2, 0x9f, 0x1c, 0xe0, 0x54, 0xff, 0x5c, 0xc7, 0xc4, 0x1b, 0xbc, 0x82, 0x8c, 0xfa, 0x05, 0xb7, 0xf3, 0x58, 0x0a, 0xa9, 0x12, 0x41, 0xb2, 0x4a, 0xfa, 0x3f, 0x0a, 0xc2, 0x30, 0xf3, 0xd7, 0x23, 0x28, 0xdf, 0x67, 0x51, 0x2f, 0x74, 0xef, 0x73, 0xe6, 0x9b, 0xf1, 0x2f, 0xe8, 0xda, 0x56, 0xba, 0x2a, 0x3f, 0xfe, 0x4c, 0xfb, 0x1c, 0xe5, 0xdd, 0x41, 0x1d, 0x5d, 0x20, 0xc1, 0x75, 0xc3, 0x62, 0x14, 0xa5, 0x32, 0x55, 0x2f, 0xfa, 0xf0, 0x8e, 0x9f, 0x95, 0x02, 0xfe, 0x15, 0x6f, 0x97, 0x18, 0xa1, 0x2f, 0xaf, 0xb0, 0x03, 0xcb, 0xac, 0x91, 0x36, 0x12, 0xd9, 0xea, 0x39, 0x9c, 0x40, 0xf5, 0xbd, 0x69, 0x9e, 0x2d, 0x12, 0xf7, 0x28, 0x18, 0x6e, 0x1b, 0x8d, 0x4c, 0x75, 0x40, 0x3e, 0xce, 0x5a, 0x8c, 0x24, 0x35, 0x34, 0x13, 0xa8, 0x7b, 0x12, 0x2f, 0x3f, 0x73, 0x48, 0x4f, 0x2a, 0xf0, 0x3b, 0xf5, 0xb0, 0x48, 0x39, 0x84, 0xd1, 0xc9, 0x78, 0x86, 0x78, 0xaf, 0x17, 0xf1, 0xc3, 0x08, 0x00, 0x1a, 0x16, 0x10, 0x85, 0xa3, 0x35, 0x58, 0xde, 0xae, 0xd3, 0x94, 0xb0, 0x66, 0x48, 0xbb, 0x4f, 0x58, 0x85, 0x55, 0x42, 0xee, 0xe3, 0x44, 0x97, 0x23, 0xb6, 0x70, 0xf6, 0xb1, 0x45, 0x1d, 0xe6, 0x0e, 0x63, 0x68, 0x37, 0x90, 0x42, 0xbe, 0x1c, 0xd3, 0x6d, 0x02, 0xc7, 0x47, 0x92, 0x5e, 0xd3, 0x62, 0xed, 0x3a, 0xa2, 0xdf, 0x98, 0xa6, 0x24, 0xb5, 0x17, 0x43, 0xb6, 0x6f, 0xcf, 0x70, 0x00, 0xb0, 0xf2, 0x18, 0xf6, 0xec, 0x7c, 0xed, 0x64, 0x36, 0x9b, 0x3a, 0xe2, 0x84, 0x74, 0xf8, 0xfa, 0x92, 0x40, 0xa0, 0xcd, 0x05, 0xc7, 0xd4, 0x80, 0x1d, 0x41, 0x03, 0xdb, 0x4d, 0x0e, 0xb7, 0x06, 0x7a, 0x52, 0xf7, 0x02, 0xa2, 0xb1, 0xbe, 0x76, 0xd7, 0x26 ]; #[test] fn test_tls_dhe_params() { let empty = &b""[..]; let bytes = DHE_PARAMS; let expected1 = ServerDHParams { dh_p: &bytes[2..258], dh_g: &bytes[260..516], dh_ys: &bytes[518..774], }; let expected2 = DigitallySigned { alg: Some(SignatureAndHashAlgorithm { hash: HashAlgorithm::Sha512, sign: SignAlgorithm::Rsa, }), data: &bytes[778..], }; let res = pair(parse_dh_params, parse_digitally_signed)(bytes); assert_eq!(res, Ok((empty, (expected1, expected2)))); } } // mod tls_dh tls-parser-0.12.2/tests/tls_extensions.rs000064400000000000000000000152151046102023000165770ustar 00000000000000#[macro_use] extern crate pretty_assertions; extern crate nom; extern crate tls_parser; mod tls_extensions { use tls_parser::*; #[rustfmt::skip] static CLIENT_EXTENSIONS1: &[u8] = &[ 0x00, 0x00, 0x00, 0x13, 0x00, 0x11, 0x00, 0x00, 0x0e, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x01 ]; #[test] fn test_tls_extensions() { let empty = &b""[..]; let bytes = CLIENT_EXTENSIONS1; let ec_point_formats = &[0, 1, 2]; let ext1 = &[0, 0, 0, 0]; let ecc: Vec<_> = [23, 25, 28, 27, 24, 26, 22, 14, 13, 11, 12, 9, 10] .iter() .map(|&x| NamedGroup(x)) .collect(); let expected = Ok(( empty, vec![ TlsExtension::SNI(vec![(SNIType::HostName, b"www.google.com")]), TlsExtension::EcPointFormats(ec_point_formats), TlsExtension::EllipticCurves(ecc), TlsExtension::SessionTicket(empty), TlsExtension::SignatureAlgorithms(vec![ 0x0601, 0x0602, 0x0603, 0x0501, 0x0502, 0x0503, 0x0401, 0x0402, 0x0403, 0x0301, 0x0302, 0x0303, 0x0201, 0x0202, 0x0203, ]), TlsExtension::StatusRequest(Some((CertificateStatusType::OCSP, ext1))), TlsExtension::Heartbeat(1), ], )); let res = parse_tls_extensions(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_max_fragment_length() { let empty = &b""[..]; let bytes = &[0x00, 0x01, 0x00, 0x01, 0x04]; let expected = Ok((empty, TlsExtension::MaxFragmentLength(4))); let res = parse_tls_extension(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_alpn() { let empty = &b""[..]; let bytes = &[ 0x00, 0x10, 0x00, 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, ]; let expected = Ok(( empty, TlsExtension::ALPN(vec![ b"h2-16", b"h2-15", b"h2-14", b"h2", b"spdy/3.1", b"http/1.1", ]), )); let res = parse_tls_extension(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_encrypt_then_mac() { let empty = &b""[..]; let bytes = &[0x00, 0x16, 0x00, 0x00]; let expected = Ok((empty, TlsExtension::EncryptThenMac)); let res = parse_tls_extension(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_extended_master_secret() { let empty = &b""[..]; let bytes = &[0x00, 0x17, 0x00, 0x00]; let expected = Ok((empty, TlsExtension::ExtendedMasterSecret)); let res = parse_tls_extension(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_npn() { let empty = &b""[..]; let bytes = &[0x33, 0x74, 0x00, 0x00]; let expected = Ok((empty, TlsExtension::NextProtocolNegotiation)); let res = parse_tls_extension(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_list() { let empty = &b""[..]; let bytes = &[0, 5, 0, 0, 0, 23, 0, 0, 255, 1, 0, 1, 0]; let expected = Ok(( empty, vec![ TlsExtension::StatusRequest(None), TlsExtension::ExtendedMasterSecret, TlsExtension::RenegotiationInfo(&[]), ], )); let res = parse_tls_extensions(bytes); println!("{:?}", res); assert_eq!(res, expected); } #[test] fn test_tls_extension_keyshare_helloretryrequest() { let empty = &b""[..]; let bytes = &[ 0x00, 0x33, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xa2, 0x4e, 0x84, 0xfa, 0x82, 0x63, 0xf8, 0xff, 0x20, 0x7a, 0x79, 0x82, 0xfd, 0x34, 0x12, 0xfc, 0xae, 0x8d, 0xd8, 0xe3, 0x1e, 0xf4, 0x5d, 0xe6, 0x61, 0x09, 0x3b, 0x7f, 0xa5, 0x81, 0x12, 0x63, 0x00, 0x2b, 0x00, 0x02, 0x7f, 0x17, ]; let expected = Ok(( empty, vec![ TlsExtension::KeyShare(&bytes[4..40]), TlsExtension::SupportedVersions(vec![TlsVersion(0x7f17)]), ], )); let res = parse_tls_extensions(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_signed_certificate_timestamp() { let empty = &b""[..]; let bytes = &[0x00, 0x12, 0x00, 0x00]; let expected = Ok((empty, TlsExtension::SignedCertificateTimestamp(None))); let res = parse_tls_extension(bytes); assert_eq!(res, expected); } #[test] fn test_tls_extension_grease() { let empty = &b""[..]; let bytes = &[0x3a, 0x3a, 0x00, 0x01, 0x00]; let expected = TlsExtension::Grease(0x3a3a, &[0x00]); let res = parse_tls_extension(bytes); assert_eq!(res, Ok((empty, expected))); } const ESNI: &[u8] = include_bytes!("../assets/esni.bin"); #[test] fn test_tls_extension_esni() { let res = parse_tls_extension(ESNI).expect("Parsing eSNI failed"); match res.1 { TlsExtension::EncryptedServerName { ciphersuite, group, .. } => { assert_eq!(ciphersuite.0, 0x1301); assert_eq!(group.0, 0x1d); } _ => panic!("Wrong extension type (expected eSNI"), } } #[test] fn test_tls_extension_record_size_limit() { let empty = &b""[..]; let bytes = &[0x00, 0x1c, 0x00, 0x02, 0x40, 0x01]; let expected = TlsExtension::RecordSizeLimit(16385); let res = parse_tls_extension(bytes); assert_eq!(res, Ok((empty, expected))); } } // mod tls_extensions tls-parser-0.12.2/tests/tls_handshake.rs000064400000000000000000001407231046102023000163310ustar 00000000000000#[macro_use] extern crate pretty_assertions; extern crate nom; extern crate tls_parser; mod tls_handshake { use nom::{Err, Needed}; use tls_parser::*; #[rustfmt::skip] static CH : &[u8] = &[ 0x16, 0x03, 0x01, 0x01, 0x2c, 0x01, 0x00, 0x01, 0x28, 0x03, 0x03, 0xb2, 0x9d, 0xd7, 0x87, 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, 0x00, 0x00, 0xaa, 0xc0, 0x30, 0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x0a, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39, 0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88, 0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32, 0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f, 0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x84, 0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x09, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e, 0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30, 0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97, 0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42, 0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0x00, 0xff, 0x01, 0x00, 0x00, 0x55, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x0f, 0x00, 0x01, 0x01 ]; #[test] fn test_tls_record_clienthello() { let empty = &b""[..]; let rand_data = [ 0xb2, 0x9d, 0xd7, 0x87, 0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4, ]; let ciphers = &[ 0xc030, 0xc02c, 0xc028, 0xc024, 0xc014, 0xc00a, 0x00a5, 0x00a3, 0x00a1, 0x009f, 0x006b, 0x006a, 0x0069, 0x0068, 0x0039, 0x0038, 0x0037, 0x0036, 0x0088, 0x0087, 0x0086, 0x0085, 0xc032, 0xc02e, 0xc02a, 0xc026, 0xc00f, 0xc005, 0x009d, 0x003d, 0x0035, 0x0084, 0xc02f, 0xc02b, 0xc027, 0xc023, 0xc013, 0xc009, 0x00a4, 0x00a2, 0x00a0, 0x009e, 0x0067, 0x0040, 0x003f, 0x003e, 0x0033, 0x0032, 0x0031, 0x0030, 0x009a, 0x0099, 0x0098, 0x0097, 0x0045, 0x0044, 0x0043, 0x0042, 0xc031, 0xc02d, 0xc029, 0xc025, 0xc00e, 0xc004, 0x009c, 0x003c, 0x002f, 0x0096, 0x0041, 0xc011, 0xc007, 0xc00c, 0xc002, 0x0005, 0x0004, 0xc012, 0xc008, 0x0016, 0x0013, 0x0010, 0x000d, 0xc00d, 0xc003, 0x000a, 0x00ff, ]; let comp = vec![TlsCompressionID(0x00)]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls10, len: 300, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::ClientHello( TlsClientHelloContents { version: TlsVersion::Tls12, random: &rand_data, session_id: None, ciphers: ciphers.iter().map(|&x| TlsCipherSuiteID(x)).collect(), comp, ext: Some(&CH[220..]), }, ))], }; let res = parse_tls_plaintext(CH); assert_eq!(res, Ok((empty, expected))); } // tls response, composed of 4 records: // - Server Hello // - Server Certificate // - Server Key Exchange // - Server Hello Done #[rustfmt::skip] static SERVER_REPLY1: &[u8] = &[ 0x16, 0x03, 0x03, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x37, 0x03, 0x03, 0x57, 0xc4, 0x57, 0xda, 0x9c, 0xd3, 0x24, 0x6d, 0x9d, 0x02, 0x26, 0xa2, 0xe5, 0x9a, 0xe8, 0xa5, 0x6f, 0x40, 0xad, 0x94, 0x30, 0xba, 0x49, 0x05, 0x3a, 0x1e, 0x1b, 0xe1, 0x94, 0xa1, 0xba, 0x41, 0x00, 0xc0, 0x2f, 0x00, 0x00, 0x0f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16, 0x03, 0x03, 0x0c, 0x09, 0x0b, 0x00, 0x0c, 0x05, 0x00, 0x0c, 0x02, 0x00, 0x04, 0x84, 0x30, 0x82, 0x04, 0x80, 0x30, 0x82, 0x03, 0x68, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x52, 0x1a, 0x61, 0xda, 0x68, 0xb6, 0xe6, 0x35, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x31, 0x37, 0x31, 0x38, 0x34, 0x39, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x30, 0x39, 0x31, 0x38, 0x32, 0x39, 0x30, 0x30, 0x5a, 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9b, 0x5b, 0x36, 0xcc, 0xce, 0x8c, 0x39, 0x86, 0xbd, 0x05, 0x2f, 0xc3, 0xff, 0x4c, 0x59, 0xa8, 0xfc, 0xe4, 0x6e, 0x0f, 0xc6, 0xbf, 0x23, 0xf6, 0x35, 0xc5, 0x3b, 0xcc, 0xc9, 0x61, 0x2f, 0x60, 0x11, 0x9b, 0x7a, 0x44, 0xd2, 0xd0, 0xd9, 0x62, 0x11, 0x09, 0xbe, 0x08, 0x53, 0x24, 0x73, 0xd9, 0x5f, 0x5e, 0xb0, 0x6f, 0x05, 0x3f, 0x53, 0xa3, 0x2d, 0x98, 0xa4, 0xf4, 0xaf, 0x23, 0x25, 0xb8, 0x80, 0xbc, 0xcc, 0xde, 0xa2, 0x56, 0xcb, 0x6f, 0x9d, 0x1a, 0xda, 0xa5, 0xbe, 0xb0, 0x8a, 0xdc, 0xcf, 0x30, 0xef, 0xe0, 0x68, 0x97, 0xc5, 0x70, 0xad, 0xcf, 0x10, 0x5b, 0xb6, 0x92, 0x98, 0x61, 0x57, 0x3d, 0xbf, 0x3f, 0xd0, 0x5d, 0xbc, 0x76, 0x23, 0xc8, 0xce, 0x35, 0x6d, 0x25, 0x1f, 0x11, 0x5a, 0x4b, 0x76, 0x36, 0xca, 0xd4, 0x57, 0x7e, 0x95, 0x7f, 0x78, 0xfb, 0x2c, 0xe0, 0x9a, 0xbf, 0x64, 0xc6, 0x43, 0x7b, 0xcd, 0xfa, 0x0e, 0xaa, 0x4f, 0x6a, 0xda, 0x04, 0xa4, 0xf5, 0xfa, 0x2d, 0xea, 0xac, 0xc3, 0xa7, 0xf4, 0xd3, 0x7c, 0x57, 0xd4, 0xb8, 0x2c, 0xcb, 0xe0, 0xd5, 0x26, 0x3b, 0x2d, 0x64, 0x0d, 0x20, 0x5a, 0xd5, 0xe4, 0x1a, 0x6e, 0x3a, 0x6a, 0x23, 0xb1, 0x0a, 0xc6, 0x33, 0xee, 0x49, 0x66, 0x13, 0x38, 0x58, 0x76, 0x53, 0x84, 0x4a, 0x8a, 0xaa, 0x77, 0x8e, 0xa8, 0x38, 0xfb, 0xe9, 0x4d, 0xd0, 0x02, 0xf9, 0x7b, 0xf3, 0x67, 0x94, 0xe0, 0x58, 0x9e, 0x04, 0xc1, 0x3b, 0xd8, 0x2b, 0x89, 0x5f, 0x57, 0xf3, 0xb5, 0xf3, 0x41, 0x63, 0x7a, 0x32, 0x98, 0x5e, 0x18, 0x29, 0x04, 0xb7, 0x64, 0xbe, 0x91, 0xf9, 0x15, 0xf7, 0x34, 0x23, 0x0f, 0x4d, 0xd1, 0xeb, 0x80, 0xe9, 0xad, 0xb3, 0x65, 0xc1, 0xcd, 0x7e, 0x68, 0x3f, 0x9b, 0x0c, 0x6d, 0xb2, 0xbf, 0x16, 0x11, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x4b, 0x30, 0x82, 0x01, 0x47, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x19, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x12, 0x30, 0x10, 0x82, 0x0e, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2e, 0x67, 0x92, 0x22, 0x0f, 0xd3, 0xd5, 0xd1, 0xd6, 0x0a, 0x21, 0xf5, 0x3e, 0x2b, 0xe7, 0x87, 0xbe, 0xaf, 0x37, 0x9b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7d, 0x0e, 0x9e, 0x7b, 0xf0, 0x81, 0xd6, 0x19, 0xa5, 0xc1, 0xe3, 0xd4, 0x16, 0xad, 0x17, 0x74, 0x76, 0x80, 0x97, 0x9c, 0x96, 0x7b, 0xfb, 0x8e, 0x3a, 0x12, 0x14, 0x25, 0x48, 0xb9, 0xed, 0x46, 0xc9, 0x07, 0xc6, 0xd9, 0xfd, 0x06, 0xba, 0x9f, 0x66, 0xd6, 0x1c, 0xe4, 0xbb, 0xcb, 0x76, 0x44, 0x95, 0x31, 0x76, 0x4c, 0xfb, 0xb5, 0xad, 0xc7, 0xf0, 0x6a, 0xfa, 0x30, 0xc3, 0x58, 0xa1, 0x8b, 0xcc, 0xe2, 0x70, 0xbb, 0x8a, 0x78, 0x5e, 0x41, 0x60, 0x1e, 0xda, 0x69, 0xc3, 0xcb, 0x9f, 0xa2, 0x10, 0xff, 0x20, 0xfc, 0xa4, 0x35, 0xdb, 0x32, 0xcb, 0x26, 0xba, 0xc0, 0xcf, 0x3f, 0x5c, 0x86, 0x78, 0x2c, 0xaa, 0x73, 0x39, 0xf9, 0x8c, 0xfd, 0xa6, 0x9a, 0x8e, 0x3f, 0x5d, 0x7d, 0x8c, 0x7c, 0x3a, 0xe7, 0xbe, 0x69, 0x73, 0xa8, 0x06, 0x5d, 0x56, 0xe3, 0xe2, 0x80, 0x0d, 0x99, 0xcc, 0x4d, 0x5f, 0x7e, 0xfb, 0x62, 0xd8, 0xcf, 0x55, 0x2d, 0xbc, 0x9f, 0xef, 0xa7, 0xe6, 0x46, 0xda, 0xc9, 0x66, 0x07, 0x0e, 0x13, 0x4d, 0x61, 0xb3, 0x85, 0xf3, 0x72, 0x6d, 0x41, 0xfe, 0x7b, 0xaa, 0xe7, 0xaf, 0xff, 0x61, 0xd9, 0xc6, 0x6c, 0x84, 0x6c, 0x1a, 0x9e, 0xda, 0x86, 0x15, 0xbc, 0x2a, 0xae, 0x84, 0x14, 0x94, 0x67, 0x95, 0xc4, 0xda, 0x35, 0x29, 0x8e, 0x80, 0x23, 0xc0, 0x4a, 0xdd, 0x0e, 0xb3, 0xb1, 0x7d, 0xc7, 0x3d, 0xea, 0x2c, 0x41, 0xb2, 0xed, 0xb4, 0x8b, 0x65, 0xd3, 0x62, 0x81, 0x0a, 0x25, 0x0c, 0x3b, 0xc9, 0x11, 0xa2, 0x50, 0x1f, 0xd0, 0xe9, 0x37, 0x9f, 0xa0, 0x7a, 0x34, 0x01, 0xdf, 0x32, 0x58, 0x3b, 0xf5, 0x4b, 0xd8, 0xab, 0x11, 0x5a, 0x9a, 0x1b, 0x83, 0x43, 0x06, 0xf4, 0x40, 0x1e, 0x5b, 0x92, 0xe8, 0x94, 0x0a, 0xbc, 0x57, 0x2f, 0x19, 0x69, 0xc6, 0xd2, 0x8b, 0x00, 0x03, 0xf4, 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x02, 0x3a, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3, 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a, 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a, 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f, 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1, 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4, 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53, 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f, 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73, 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b, 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb, 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4, 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19, 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65, 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80, 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99, 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75, 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e, 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf, 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2, 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37, 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, 0x4e, 0x04, 0xa7, 0x80, 0x7f, 0x10, 0x16, 0x43, 0x5e, 0x02, 0xad, 0xd7, 0x42, 0x80, 0xf4, 0xb0, 0x8e, 0xd2, 0xae, 0xb3, 0xeb, 0x11, 0x7d, 0x90, 0x84, 0x18, 0x7d, 0xe7, 0x90, 0x15, 0xfb, 0x49, 0x7f, 0xa8, 0x99, 0x05, 0x91, 0xbb, 0x7a, 0xc9, 0xd6, 0x3c, 0x37, 0x18, 0x09, 0x9a, 0xb6, 0xc7, 0x92, 0x20, 0x07, 0x35, 0x33, 0x09, 0xe4, 0x28, 0x63, 0x72, 0x0d, 0xb4, 0xe0, 0x32, 0x9c, 0x87, 0x98, 0xc4, 0x1b, 0x76, 0x89, 0x67, 0xc1, 0x50, 0x58, 0xb0, 0x13, 0xaa, 0x13, 0x1a, 0x1b, 0x32, 0xa5, 0xbe, 0xea, 0x11, 0x95, 0x4c, 0x48, 0x63, 0x49, 0xe9, 0x99, 0x5d, 0x20, 0x37, 0xcc, 0xfe, 0x2a, 0x69, 0x51, 0x16, 0x95, 0x4b, 0xa9, 0xde, 0x49, 0x82, 0xc0, 0x10, 0x70, 0xf4, 0x2c, 0xf3, 0xec, 0xbc, 0x24, 0x24, 0xd0, 0x4e, 0xac, 0xa5, 0xd9, 0x5e, 0x1e, 0x6d, 0x92, 0xc1, 0xa7, 0xac, 0x48, 0x35, 0x81, 0xf9, 0xe5, 0xe4, 0x9c, 0x65, 0x69, 0xcd, 0x87, 0xa4, 0x41, 0x50, 0x3f, 0x2e, 0x57, 0xa5, 0x91, 0x51, 0x12, 0x58, 0x0e, 0x8c, 0x09, 0xa1, 0xac, 0x7a, 0xa4, 0x12, 0xa5, 0x27, 0xf3, 0x9a, 0x10, 0x97, 0x7d, 0x55, 0x03, 0x06, 0xf7, 0x66, 0x58, 0x5f, 0x5f, 0x64, 0xe1, 0xab, 0x5d, 0x6d, 0xa5, 0x39, 0x48, 0x75, 0x98, 0x4c, 0x29, 0x5a, 0x3a, 0x8d, 0xd3, 0x2b, 0xca, 0x9c, 0x55, 0x04, 0xbf, 0xf4, 0xe6, 0x14, 0xd5, 0x80, 0xac, 0x26, 0xed, 0x17, 0x89, 0xa6, 0x93, 0x6c, 0x5c, 0xa4, 0xcc, 0xb8, 0xf0, 0x66, 0x8e, 0x64, 0xe3, 0x7d, 0x9a, 0xe2, 0x00, 0xb3, 0x49, 0xc7, 0xe4, 0x0a, 0xaa, 0xdd, 0x5b, 0x83, 0xc7, 0x70, 0x90, 0x46, 0x4e, 0xbe, 0xd0, 0xdb, 0x59, 0x96, 0x6c, 0x2e, 0xf5, 0x16, 0x36, 0xde, 0x71, 0xcc, 0x01, 0xc2, 0x12, 0xc1, 0x21, 0xc6, 0x16, 0x00, 0x03, 0x81, 0x30, 0x82, 0x03, 0x7d, 0x30, 0x82, 0x02, 0xe6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x12, 0xbb, 0xe6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x32, 0x30, 0x35, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x38, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0xcc, 0x18, 0x63, 0x30, 0xfd, 0xf4, 0x17, 0x23, 0x1a, 0x56, 0x7e, 0x5b, 0xdf, 0x3c, 0x6c, 0x38, 0xe4, 0x71, 0xb7, 0x78, 0x91, 0xd4, 0xbc, 0xa1, 0xd8, 0x4c, 0xf8, 0xa8, 0x43, 0xb6, 0x03, 0xe9, 0x4d, 0x21, 0x07, 0x08, 0x88, 0xda, 0x58, 0x2f, 0x66, 0x39, 0x29, 0xbd, 0x05, 0x78, 0x8b, 0x9d, 0x38, 0xe8, 0x05, 0xb7, 0x6a, 0x7e, 0x71, 0xa4, 0xe6, 0xc4, 0x60, 0xa6, 0xb0, 0xef, 0x80, 0xe4, 0x89, 0x28, 0x0f, 0x9e, 0x25, 0xd6, 0xed, 0x83, 0xf3, 0xad, 0xa6, 0x91, 0xc7, 0x98, 0xc9, 0x42, 0x18, 0x35, 0x14, 0x9d, 0xad, 0x98, 0x46, 0x92, 0x2e, 0x4f, 0xca, 0xf1, 0x87, 0x43, 0xc1, 0x16, 0x95, 0x57, 0x2d, 0x50, 0xef, 0x89, 0x2d, 0x80, 0x7a, 0x57, 0xad, 0xf2, 0xee, 0x5f, 0x6b, 0xd2, 0x00, 0x8d, 0xb9, 0x14, 0xf8, 0x14, 0x15, 0x35, 0xd9, 0xc0, 0x46, 0xa3, 0x7b, 0x72, 0xc8, 0x91, 0xbf, 0xc9, 0x55, 0x2b, 0xcd, 0xd0, 0x97, 0x3e, 0x9c, 0x26, 0x64, 0xcc, 0xdf, 0xce, 0x83, 0x19, 0x71, 0xca, 0x4e, 0xe6, 0xd4, 0xd5, 0x7b, 0xa9, 0x19, 0xcd, 0x55, 0xde, 0xc8, 0xec, 0xd2, 0x5e, 0x38, 0x53, 0xe5, 0x5c, 0x4f, 0x8c, 0x2d, 0xfe, 0x50, 0x23, 0x36, 0xfc, 0x66, 0xe6, 0xcb, 0x8e, 0xa4, 0x39, 0x19, 0x00, 0xb7, 0x95, 0x02, 0x39, 0x91, 0x0b, 0x0e, 0xfe, 0x38, 0x2e, 0xd1, 0x1d, 0x05, 0x9a, 0xf6, 0x4d, 0x3e, 0x6f, 0x0f, 0x07, 0x1d, 0xaf, 0x2c, 0x1e, 0x8f, 0x60, 0x39, 0xe2, 0xfa, 0x36, 0x53, 0x13, 0x39, 0xd4, 0x5e, 0x26, 0x2b, 0xdb, 0x3d, 0xa8, 0x14, 0xbd, 0x32, 0xeb, 0x18, 0x03, 0x28, 0x52, 0x04, 0x71, 0xe5, 0xab, 0x33, 0x3d, 0xe1, 0x38, 0xbb, 0x07, 0x36, 0x84, 0x62, 0x9c, 0x79, 0xea, 0x16, 0x30, 0xf4, 0x5f, 0xc0, 0x2b, 0xe8, 0x71, 0x6b, 0xe4, 0xf9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xf0, 0x30, 0x81, 0xed, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x48, 0xe6, 0x68, 0xf9, 0x2b, 0xd2, 0xb2, 0x95, 0xd7, 0x47, 0xd8, 0x23, 0x20, 0x10, 0x4f, 0x33, 0x98, 0x90, 0x9f, 0xd4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, 0x4e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4e, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x47, 0x30, 0x45, 0x30, 0x43, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x76, 0xe1, 0x12, 0x6e, 0x4e, 0x4b, 0x16, 0x12, 0x86, 0x30, 0x06, 0xb2, 0x81, 0x08, 0xcf, 0xf0, 0x08, 0xc7, 0xc7, 0x71, 0x7e, 0x66, 0xee, 0xc2, 0xed, 0xd4, 0x3b, 0x1f, 0xff, 0xf0, 0xf0, 0xc8, 0x4e, 0xd6, 0x43, 0x38, 0xb0, 0xb9, 0x30, 0x7d, 0x18, 0xd0, 0x55, 0x83, 0xa2, 0x6a, 0xcb, 0x36, 0x11, 0x9c, 0xe8, 0x48, 0x66, 0xa3, 0x6d, 0x7f, 0xb8, 0x13, 0xd4, 0x47, 0xfe, 0x8b, 0x5a, 0x5c, 0x73, 0xfc, 0xae, 0xd9, 0x1b, 0x32, 0x19, 0x38, 0xab, 0x97, 0x34, 0x14, 0xaa, 0x96, 0xd2, 0xeb, 0xa3, 0x1c, 0x14, 0x08, 0x49, 0xb6, 0xbb, 0xe5, 0x91, 0xef, 0x83, 0x36, 0xeb, 0x1d, 0x56, 0x6f, 0xca, 0xda, 0xbc, 0x73, 0x63, 0x90, 0xe4, 0x7f, 0x7b, 0x3e, 0x22, 0xcb, 0x3d, 0x07, 0xed, 0x5f, 0x38, 0x74, 0x9c, 0xe3, 0x03, 0x50, 0x4e, 0xa1, 0xaf, 0x98, 0xee, 0x61, 0xf2, 0x84, 0x3f, 0x12, 0x16, 0x03, 0x03, 0x01, 0x4d, 0x0c, 0x00, 0x01, 0x49, 0x03, 0x00, 0x17, 0x41, 0x04, 0x27, 0x7e, 0x6c, 0x81, 0xf1, 0xb4, 0xb5, 0x60, 0x22, 0x45, 0x9b, 0x26, 0x4f, 0xb8, 0xa8, 0xbd, 0xd2, 0x91, 0x88, 0x9b, 0xe0, 0xe8, 0x41, 0x4d, 0x7c, 0xab, 0xcf, 0xf7, 0x3f, 0x8f, 0x23, 0xd1, 0x18, 0xdd, 0xb7, 0x27, 0xbd, 0xcf, 0xd3, 0x14, 0x71, 0xca, 0xf9, 0x7e, 0xb8, 0xe8, 0x15, 0x59, 0xa2, 0x97, 0x66, 0x27, 0x45, 0xc3, 0x40, 0xf7, 0xa8, 0x77, 0x61, 0x05, 0x9b, 0xb2, 0xa9, 0xd0, 0x06, 0x01, 0x01, 0x00, 0x6e, 0xd0, 0x13, 0x15, 0x52, 0x29, 0xdb, 0x2c, 0x60, 0x3c, 0x2d, 0xf3, 0x6f, 0xc5, 0xac, 0x44, 0x53, 0x47, 0x3b, 0x17, 0xbc, 0xaf, 0xaa, 0x9f, 0x5d, 0xf5, 0x2e, 0x7a, 0x9c, 0x32, 0x58, 0xb5, 0x37, 0x1a, 0xce, 0x4c, 0x12, 0x9e, 0x47, 0xf0, 0xfd, 0x85, 0x38, 0x39, 0xc1, 0xec, 0xd8, 0x06, 0xc8, 0x84, 0x87, 0x03, 0xfa, 0x41, 0xf9, 0x88, 0xa0, 0xef, 0x84, 0x87, 0x76, 0x6e, 0x61, 0xfc, 0x1c, 0x78, 0xd8, 0x70, 0xa8, 0x65, 0x3a, 0x1e, 0x84, 0xac, 0x14, 0x78, 0x74, 0x18, 0x7f, 0xdd, 0x35, 0x2e, 0x99, 0xd8, 0x3d, 0x68, 0x66, 0x16, 0x7a, 0x83, 0x16, 0xa6, 0x21, 0x18, 0x71, 0x6f, 0x58, 0x32, 0x60, 0xa3, 0x70, 0xa6, 0xca, 0x04, 0xd5, 0x09, 0xbe, 0xc3, 0x32, 0xc9, 0xee, 0x5d, 0x9a, 0x56, 0xdb, 0xf6, 0x17, 0xf1, 0x2c, 0x6d, 0x71, 0x4f, 0xf7, 0x8a, 0x2a, 0xa3, 0xcf, 0xb9, 0x86, 0x0a, 0xc2, 0xfd, 0x75, 0xab, 0xb2, 0x75, 0x39, 0xb5, 0xf5, 0x2b, 0xb2, 0x80, 0x9e, 0x9b, 0x32, 0x26, 0x25, 0x6c, 0x0e, 0x71, 0xdf, 0xc0, 0x42, 0x4e, 0x74, 0xd8, 0xb0, 0x9b, 0xa5, 0x15, 0xe5, 0x96, 0xd7, 0x30, 0xdf, 0x33, 0x3d, 0xfd, 0xba, 0xf7, 0x59, 0x7d, 0xdb, 0xc9, 0x31, 0x3d, 0x70, 0xe4, 0xd4, 0x91, 0x97, 0x70, 0x2d, 0xf2, 0x48, 0xcd, 0x84, 0x2d, 0x70, 0x48, 0xbc, 0xd6, 0x6b, 0xaf, 0xdd, 0xf6, 0x7d, 0xad, 0xb9, 0x89, 0x94, 0x7c, 0x59, 0x0c, 0x3f, 0x3e, 0xe2, 0x8d, 0x4c, 0x81, 0x4a, 0x15, 0x09, 0xb9, 0xde, 0xc1, 0xe6, 0xe6, 0x5d, 0x28, 0x2d, 0x1d, 0xb8, 0x45, 0x17, 0x42, 0x55, 0xe3, 0x2a, 0xcf, 0x55, 0x26, 0x66, 0x79, 0xf1, 0xbb, 0x2a, 0x25, 0x28, 0x78, 0xa1, 0x63, 0x90, 0xec, 0xec, 0xa7, 0xee, 0x61, 0x1c, 0xac, 0x19, 0x45, 0xdd, 0x82, 0xae, 0x52, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00 ]; #[test] fn test_tls_record_serverhello() { let empty = &b""[..]; let bytes = &SERVER_REPLY1[0..64]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: 59, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::ServerHello( TlsServerHelloContents { version: TlsVersion::Tls12, random: &bytes[11..43], session_id: None, cipher: TlsCipherSuiteID(0xc02f), compression: TlsCompressionID(0), ext: Some(&bytes[49..]), }, ))], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[test] fn test_sslv3_record_serverhello() { let empty = &b""[..]; let bytes = &[ 0x16, 0x03, 0x00, 0x00, 0x3a, 0x02, 0x00, 0x00, 0x36, 0x03, 0x00, 0xf9, 0x5d, 0x75, 0x87, 0x68, 0x2b, 0x49, 0x8c, 0x72, 0xf8, 0x72, 0x3a, 0xb7, 0xb6, 0x79, 0x02, 0xee, 0x3c, 0xa9, 0xfc, 0x12, 0x90, 0xea, 0xab, 0x29, 0x46, 0xcc, 0xc2, 0x0d, 0xee, 0x12, 0x93, 0x10, 0xb3, 0xdc, 0xd8, 0x87, 0x0b, 0x14, 0xa0, 0x3a, 0x34, 0x90, 0xeb, 0x26, 0xec, 0x92, 0xe2, 0x42, 0x00, 0x10, 0x00, ]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Ssl30, len: 58, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::ServerHello( TlsServerHelloContents { version: TlsVersion::Ssl30, random: &[ 0xf9, 0x5d, 0x75, 0x87, 0x68, 0x2b, 0x49, 0x8c, 0x72, 0xf8, 0x72, 0x3a, 0xb7, 0xb6, 0x79, 0x02, 0xee, 0x3c, 0xa9, 0xfc, 0x12, 0x90, 0xea, 0xab, 0x29, 0x46, 0xcc, 0xc2, 0x0d, 0xee, 0x12, 0x93, ], session_id: Some(&[ 0xb3, 0xdc, 0xd8, 0x87, 0x0b, 0x14, 0xa0, 0x3a, 0x34, 0x90, 0xeb, 0x26, 0xec, 0x92, 0xe2, 0x42, ]), cipher: TlsCipherSuiteID(0x010), compression: TlsCompressionID(0), ext: None, }, ))], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[test] fn test_tls_record_certificate() { let empty = &b""[..]; let bytes = &SERVER_REPLY1[64..3150]; let chain = vec![ RawCertificate { data: &bytes[15..1171], }, RawCertificate { data: &bytes[1174..2186], }, RawCertificate { data: &bytes[2189..3086], }, ]; for cert in &chain { println!("cert len: {}", cert.data.len()); } let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: 3081, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::Certificate( TlsCertificateContents { cert_chain: chain }, ))], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[test] fn test_tls_record_serverkeyexchange() { let empty = &b""[..]; let bytes = &SERVER_REPLY1[3150..3488]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: 333, }, msg: vec![TlsMessage::Handshake( TlsMessageHandshake::ServerKeyExchange(TlsServerKeyExchangeContents { parameters: &bytes[9..], }), )], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[test] fn test_tls_record_serverdone() { let empty = &b""[..]; let bytes = &SERVER_REPLY1[3488..]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: 4, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::ServerDone( empty, ))], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } // client response, composed of 3 records: // - Client Key Exchange // - Change Cipher Spec // - an encrypted handshake message #[rustfmt::skip] static CLIENT_REPLY1: &[u8] = &[ 0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00, 0x42, 0x41, 0x04, 0x22, 0xd3, 0xf9, 0xbf, 0xbb, 0x7e, 0x34, 0xf9, 0x95, 0x68, 0x2e, 0xe2, 0xf8, 0xf3, 0xf8, 0x08, 0x9c, 0x78, 0x32, 0x81, 0xa8, 0x28, 0x33, 0x5e, 0x46, 0x11, 0xf2, 0x31, 0x2c, 0x9f, 0x77, 0xda, 0xc0, 0x88, 0xb5, 0xb4, 0x19, 0xc0, 0x97, 0x3d, 0xe0, 0x99, 0x5c, 0xec, 0x1e, 0xbc, 0x32, 0x62, 0x8e, 0x47, 0xc4, 0x7c, 0xcb, 0x31, 0x38, 0x5a, 0xed, 0x09, 0x1f, 0x82, 0xb1, 0xb3, 0xce, 0x43, 0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x28, 0x00, 0x74, 0x47, 0x18, 0x4c, 0x5f, 0xbf, 0x65, 0xfe, 0xb9, 0x34, 0xcf, 0x21, 0x8d, 0x6c, 0xd6, 0x99, 0xac, 0x24, 0xd3, 0x5a, 0x54, 0x44, 0x05, 0x41, 0x7b, 0x1a, 0x25, 0xe6, 0xbf, 0xe0, 0x82, 0x95, 0x72, 0x38, 0x7a, 0xa5, 0xd8, 0xf3, 0x72 ]; #[test] fn test_tls_record_clientkeyexchange() { let empty = &b""[..]; let bytes = &CLIENT_REPLY1[0..75]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: 70, }, msg: vec![TlsMessage::Handshake( TlsMessageHandshake::ClientKeyExchange(TlsClientKeyExchangeContents::Unknown( &bytes[9..], )), )], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[test] fn test_tls_record_changecipherspec() { let empty = &b""[..]; let bytes = &CLIENT_REPLY1[75..81]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::ChangeCipherSpec, version: TlsVersion::Tls12, len: 1, }, msg: vec![TlsMessage::ChangeCipherSpec], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[test] fn test_tls_record_encryptedhandshake() { let empty = &b""[..]; let bytes = &CLIENT_REPLY1[81..]; let expected = TlsEncrypted { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: bytes.len() as u16 - 5, }, msg: TlsEncryptedContent { blob: &bytes[5..] }, }; assert_eq!(parse_tls_encrypted(bytes), Ok((empty, expected))); } #[rustfmt::skip] static SERVER_HELLO1: &[u8] = &[ 0x16, 0x03, 0x03, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x37, 0x03, 0x03, 0x57, 0xc4, 0x57, 0xda, 0x9c, 0xd3, 0x24, 0x6d, 0x9d, 0x02, 0x26, 0xa2, 0xe5, 0x9a, 0xe8, 0xa5, 0x6f, 0x40, 0xad, 0x94, 0x30, 0xba, 0x49, 0x05, 0x3a, 0x1e, 0x1b, 0xe1, 0x94, 0xa1, 0xba, 0x41, 0x00, 0xc0, 0x2f, 0x00, 0x00, 0x0f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 ]; #[test] fn test_tls_record_invalid_recordlength() { let mut v = SERVER_HELLO1.to_vec(); let bytes = v.as_mut_slice(); bytes[4] = 0xff; // make record incomplete (longer than data) let expected = Err(Err::Incomplete(Needed::new(196))); let res = parse_tls_plaintext(bytes); assert_eq!(res, expected); } #[test] fn test_tls_record_invalid_recordlength2() { let mut v = SERVER_HELLO1.to_vec(); let bytes = v.as_mut_slice(); bytes[4] = 0x00; // make record incomplete (shorter than data) let res = parse_tls_plaintext(bytes); assert!(res.is_err()); } #[test] fn test_tls_record_invalid_messagelength() { let mut v = SERVER_HELLO1.to_vec(); let bytes = v.as_mut_slice(); bytes[8] = 0xff; // create message larger than record let res = parse_tls_plaintext(bytes); assert!(res.is_err()); } #[test] fn test_tls_record_invalid_messagelength2() { let mut v = SERVER_HELLO1.to_vec(); let bytes = v.as_mut_slice(); bytes[8] = 0x01; // create message shorter than record let res = parse_tls_plaintext(bytes); assert!(res.is_err()); } #[rustfmt::skip] static SERVER_CERTIFICATE_REQUEST_NOCA: &[u8] = &[ 0x16, 0x03, 0x03, 0x00, 0x2a, 0x0d, 0x00, 0x00, 0x26, 0x03, 0x01, 0x02, 0x40, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00 ]; #[test] fn test_tls_record_cert_request_noca() { let empty = &b""[..]; let bytes = SERVER_CERTIFICATE_REQUEST_NOCA; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: bytes.len() as u16 - 5, }, msg: vec![TlsMessage::Handshake( TlsMessageHandshake::CertificateRequest(TlsCertificateRequestContents { cert_types: vec![0x01, 0x02, 0x40], sig_hash_algs: Some(vec![ 0x0601, 0x0602, 0x0603, 0x0501, 0x0502, 0x0503, 0x0401, 0x0402, 0x0403, 0x0301, 0x0302, 0x0303, 0x0201, 0x0202, 0x0203, ]), unparsed_ca: vec![], }), )], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[rustfmt::skip] static SERVER_CERTIFICATE_REQUEST_CA: &[u8] = &[ 0x16, 0x03, 0x03, 0x00, 0x73, 0x0d, 0x00, 0x00, 0x6f, 0x03, 0x01, 0x02, 0x40, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x49, 0x00, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64 ]; #[test] fn test_tls_record_cert_request_ca() { let empty = &b""[..]; let bytes = SERVER_CERTIFICATE_REQUEST_CA; let ca1 = &bytes[49..]; let expected = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls12, len: bytes.len() as u16 - 5, }, msg: vec![TlsMessage::Handshake( TlsMessageHandshake::CertificateRequest(TlsCertificateRequestContents { cert_types: vec![0x01, 0x02, 0x40], sig_hash_algs: Some(vec![ 0x0601, 0x0602, 0x0603, 0x0501, 0x0502, 0x0503, 0x0401, 0x0402, 0x0403, 0x0301, 0x0302, 0x0303, 0x0201, 0x0202, 0x0203, ]), unparsed_ca: vec![ca1], }), )], }; assert_eq!(parse_tls_plaintext(bytes), Ok((empty, expected))); } #[rustfmt::skip] static SERVER_STATUS_RESPONSE: &[u8] = &[ 0x16, 0x00, 0x06, 0x3f, 0x01, 0x00, 0x06, 0x3b, 0x30, 0x82, 0x06, 0x37, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x06, 0x30, 0x30, 0x82, 0x06, 0x2c, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x06, 0x1d, 0x30, 0x82, 0x06, 0x19, 0x30, 0x81, 0x9e, 0xa2, 0x16, 0x04, 0x14, 0x9b, 0xe1, 0x51, 0x6a, 0xe3, 0xbe, 0x1a, 0x97, 0x21, 0x2b, 0x67, 0xb1, 0x07, 0xd4, 0x54, 0x6c, 0x4f, 0xae, 0x53, 0x3c, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x36, 0x31, 0x30, 0x31, 0x32, 0x32, 0x33, 0x34, 0x32, 0x35, 0x31, 0x5a, 0x30, 0x73, 0x30, 0x71, 0x30, 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x74, 0x24, 0x14, 0x67, 0x06, 0x9f, 0xf5, 0xe0, 0x98, 0x3f, 0x5e, 0x3e, 0x1a, 0x6b, 0xa0, 0x65, 0x2a, 0x54, 0x15, 0x75, 0x04, 0x14, 0x01, 0x59, 0xab, 0xe7, 0xdd, 0x3a, 0x0b, 0x59, 0xa6, 0x64, 0x63, 0xd6, 0xcf, 0x20, 0x07, 0x57, 0xd5, 0x91, 0xe7, 0x6a, 0x02, 0x10, 0x7e, 0x91, 0xc2, 0x1d, 0xe5, 0x0b, 0x21, 0x74, 0x6d, 0x19, 0x78, 0xfa, 0x4b, 0xde, 0xbe, 0x48, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x36, 0x31, 0x30, 0x31, 0x32, 0x32, 0x33, 0x34, 0x32, 0x35, 0x31, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x36, 0x31, 0x30, 0x31, 0x39, 0x32, 0x33, 0x34, 0x32, 0x35, 0x31, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x99, 0x41, 0xfe, 0x76, 0x22, 0x24, 0x0c, 0x9e, 0xdb, 0x2a, 0xc7, 0xad, 0xe5, 0xf5, 0xf7, 0x0f, 0x40, 0x2b, 0x04, 0x42, 0xb3, 0xe6, 0x0d, 0x4d, 0x52, 0xef, 0x0e, 0xd0, 0xe7, 0x96, 0x99, 0x14, 0x95, 0xef, 0xda, 0x98, 0x25, 0x08, 0xda, 0x7f, 0x8e, 0xbf, 0x0a, 0x63, 0x7c, 0xb0, 0x9f, 0x99, 0x41, 0x21, 0xd7, 0xf9, 0x11, 0x0e, 0x60, 0x41, 0x24, 0x03, 0x87, 0x15, 0x08, 0xc7, 0x60, 0xe8, 0x1c, 0xc6, 0x21, 0x7e, 0xc8, 0x08, 0x89, 0x7f, 0xbc, 0xa3, 0x75, 0x70, 0x5c, 0xc6, 0x24, 0x24, 0x7a, 0x85, 0x49, 0x40, 0xdb, 0x20, 0x18, 0x75, 0x0f, 0x94, 0x99, 0xb9, 0xcc, 0x4d, 0x8f, 0x06, 0xc8, 0xdf, 0x3a, 0xfc, 0x33, 0x6d, 0x06, 0x9b, 0x00, 0xf3, 0x73, 0xfd, 0x04, 0x9a, 0xe0, 0x3c, 0x2d, 0x14, 0xbd, 0x96, 0x8e, 0xf8, 0x01, 0xab, 0xb9, 0xc9, 0x0d, 0xb8, 0xa6, 0x3f, 0x16, 0x07, 0x0e, 0x46, 0x7b, 0x76, 0xe5, 0x48, 0xfe, 0xc2, 0xf6, 0xfa, 0x6c, 0xd9, 0x2e, 0xb4, 0x25, 0x20, 0x84, 0xd2, 0x6c, 0x8b, 0xc6, 0x48, 0x14, 0x2d, 0x17, 0x06, 0x91, 0xd9, 0x66, 0x73, 0xf4, 0x47, 0x2e, 0x81, 0x18, 0xa4, 0x72, 0xf1, 0x33, 0x12, 0x06, 0x3d, 0x12, 0xb6, 0x59, 0x8f, 0xf8, 0xa2, 0x74, 0x74, 0x29, 0x69, 0xad, 0xc9, 0x1d, 0xc9, 0x51, 0x08, 0x91, 0xf6, 0xda, 0xd6, 0xa6, 0x72, 0x46, 0xc4, 0x2a, 0x46, 0x40, 0xf0, 0xa2, 0xb7, 0xd7, 0x3a, 0x8d, 0x47, 0x5b, 0xe0, 0xf3, 0x06, 0x13, 0xf8, 0x40, 0xfa, 0xef, 0x70, 0x83, 0xfa, 0x9c, 0x5e, 0xfb, 0xe9, 0x2d, 0xbd, 0x25, 0x37, 0x58, 0xff, 0xc1, 0xa1, 0x2a, 0x47, 0xbb, 0x81, 0x31, 0x83, 0x74, 0xb1, 0x64, 0xd3, 0xf4, 0x1f, 0x88, 0x08, 0x9b, 0x4d, 0x52, 0x5d, 0x7b, 0xcf, 0x82, 0x1f, 0xd7, 0x05, 0x79, 0x1d, 0x95, 0xa0, 0x82, 0x04, 0x60, 0x30, 0x82, 0x04, 0x5c, 0x30, 0x82, 0x04, 0x58, 0x30, 0x82, 0x03, 0x40, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x30, 0x69, 0x79, 0x69, 0x01, 0x5d, 0xf2, 0x7c, 0x9f, 0x97, 0x0c, 0xd1, 0x93, 0xb4, 0x56, 0x38, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x77, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x14, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1f, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x56, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x39, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2e, 0x53, 0x79, 0x6d, 0x61, 0x6e, 0x74, 0x65, 0x63, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x56, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbe, 0x8e, 0xc9, 0x7c, 0x69, 0xd3, 0x09, 0x45, 0xd4, 0x5f, 0xa1, 0xc7, 0xe7, 0x8d, 0xdd, 0xbe, 0x9e, 0x17, 0x01, 0x8a, 0x6c, 0xb0, 0x57, 0xb9, 0x98, 0xfb, 0x2f, 0x07, 0xa4, 0xde, 0xc9, 0x0f, 0x4b, 0x9f, 0x26, 0xc9, 0x77, 0x90, 0xe6, 0xc0, 0xd0, 0xc2, 0xef, 0xc2, 0xc9, 0x3b, 0x4b, 0x86, 0xe0, 0xaf, 0xc7, 0x87, 0xef, 0x9a, 0xbf, 0x26, 0x33, 0x95, 0x55, 0xf2, 0x7b, 0xa6, 0x95, 0x86, 0x7d, 0x0d, 0x91, 0x82, 0xa8, 0x2c, 0x8a, 0xe5, 0x5c, 0x60, 0xb7, 0x98, 0x01, 0xec, 0xd0, 0x76, 0x2d, 0xd7, 0x3e, 0xaf, 0x6b, 0xc0, 0x35, 0xd0, 0x3a, 0xc1, 0xdf, 0x46, 0x84, 0xdf, 0x98, 0xdf, 0x09, 0xec, 0xdf, 0x82, 0xc4, 0x0f, 0x05, 0xc9, 0xdb, 0x66, 0x87, 0xb6, 0x4d, 0x25, 0x7d, 0x23, 0x43, 0x48, 0x71, 0x1c, 0x86, 0x21, 0xb2, 0x4f, 0xec, 0xf7, 0x03, 0xd1, 0xf4, 0x4b, 0x74, 0x13, 0x03, 0xd7, 0x85, 0xfe, 0xcd, 0xf5, 0xed, 0xf4, 0x89, 0xb1, 0x64, 0x1a, 0x2c, 0x4f, 0x2f, 0xee, 0xc5, 0x98, 0xec, 0xb7, 0xee, 0xab, 0x10, 0x2e, 0x8b, 0x5b, 0x59, 0x7e, 0x97, 0xcc, 0xc9, 0xd6, 0xa7, 0xa5, 0x3a, 0xde, 0x5a, 0x1a, 0xe6, 0x17, 0x17, 0xba, 0xc8, 0x94, 0x1b, 0x2e, 0xbc, 0x28, 0xb2, 0x5a, 0x6b, 0x0a, 0x81, 0x72, 0x51, 0xdd, 0x07, 0xed, 0x43, 0xcb, 0xde, 0xf4, 0xee, 0x41, 0x48, 0x56, 0x03, 0x8b, 0x9b, 0x1d, 0xc4, 0xe2, 0x3b, 0xae, 0x9f, 0xe2, 0xc5, 0x63, 0xca, 0xd9, 0x69, 0x30, 0x38, 0x87, 0x7e, 0x57, 0xaa, 0xa3, 0x4d, 0x30, 0x5f, 0xe7, 0x4d, 0xe9, 0x5c, 0xc1, 0x32, 0xec, 0x58, 0xc7, 0x88, 0xea, 0xa5, 0xd2, 0x92, 0xe2, 0x17, 0x8f, 0x9b, 0x25, 0xbf, 0xc5, 0xac, 0x16, 0xdb, 0xde, 0xf2, 0x38, 0xf8, 0xf7, 0xe7, 0xe2, 0xe6, 0xcf, 0xdf, 0x9b, 0x91, 0x7f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1c, 0x30, 0x82, 0x01, 0x18, 0x30, 0x0f, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05, 0x04, 0x02, 0x05, 0x00, 0x30, 0x22, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1b, 0x30, 0x19, 0xa4, 0x17, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x54, 0x47, 0x56, 0x2d, 0x44, 0x2d, 0x31, 0x37, 0x31, 0x39, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x01, 0x59, 0xab, 0xe7, 0xdd, 0x3a, 0x0b, 0x59, 0xa6, 0x64, 0x63, 0xd6, 0xcf, 0x20, 0x07, 0x57, 0xd5, 0x91, 0xe7, 0x6a, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9b, 0xe1, 0x51, 0x6a, 0xe3, 0xbe, 0x1a, 0x97, 0x21, 0x2b, 0x67, 0xb1, 0x07, 0xd4, 0x54, 0x6c, 0x4f, 0xae, 0x53, 0x3c, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x6e, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x67, 0x30, 0x65, 0x30, 0x63, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07, 0x17, 0x03, 0x30, 0x54, 0x30, 0x26, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x2a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x1e, 0x1a, 0x1c, 0x20, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x79, 0x6d, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x55, 0x8a, 0xbf, 0xb5, 0x01, 0xee, 0xc2, 0x12, 0x7f, 0xa4, 0xf9, 0x8e, 0xec, 0xb6, 0x8c, 0x40, 0x10, 0x91, 0x7b, 0x84, 0xa3, 0xc5, 0x3c, 0x12, 0x5d, 0xc4, 0x79, 0x55, 0xbf, 0xf9, 0xf0, 0x74, 0xfd, 0x9c, 0xd6, 0xae, 0x9e, 0x4b, 0x90, 0x04, 0x2e, 0xfd, 0x8f, 0xf8, 0x6b, 0x6c, 0x0b, 0x3f, 0x2b, 0x94, 0xaa, 0xc2, 0xe3, 0x07, 0xc6, 0xbe, 0xcc, 0x33, 0xe1, 0x68, 0x7e, 0x43, 0x8b, 0xd9, 0x36, 0x17, 0xb0, 0x32, 0x87, 0xec, 0xe1, 0x10, 0x4d, 0x72, 0x26, 0xad, 0xd5, 0xa5, 0xa2, 0x9a, 0xf3, 0x54, 0x21, 0x78, 0x0e, 0xdb, 0xa6, 0xba, 0xa5, 0x2e, 0x7f, 0x4d, 0xc6, 0x5a, 0xcd, 0xa5, 0xfd, 0x38, 0x0d, 0x34, 0x9d, 0xe0, 0x88, 0xd7, 0x51, 0x40, 0xd8, 0x73, 0xf3, 0x0c, 0xec, 0x53, 0x8f, 0x4e, 0x74, 0xda, 0xd3, 0x3c, 0x67, 0x23, 0xba, 0x0f, 0x1c, 0xa8, 0x46, 0x32, 0x19, 0x3a, 0xbc, 0xad, 0x4d, 0x3e, 0xd3, 0x4f, 0x89, 0xa9, 0xe9, 0xb8, 0x00, 0x1e, 0x1d, 0x04, 0xb5, 0x7f, 0x31, 0xfd, 0xc0, 0x9e, 0xd0, 0xa8, 0xad, 0x46, 0xab, 0x06, 0x91, 0x3f, 0xf4, 0xae, 0xce, 0xb7, 0x47, 0xb2, 0x4d, 0xcf, 0x93, 0x5b, 0x4c, 0x62, 0xf2, 0x43, 0xd6, 0xd1, 0xde, 0x27, 0x33, 0xe0, 0x64, 0xa9, 0x0e, 0x83, 0xa0, 0x93, 0x3c, 0xe8, 0xb2, 0xa0, 0x60, 0xb5, 0xcd, 0x48, 0x51, 0x1e, 0x66, 0x00, 0x46, 0xcd, 0xe5, 0x22, 0x9f, 0x55, 0x2a, 0xdc, 0xea, 0x61, 0xb3, 0xe5, 0x84, 0x81, 0x36, 0x29, 0x06, 0x6a, 0x1f, 0xe0, 0x48, 0x11, 0x53, 0xb0, 0x60, 0xcf, 0x88, 0x06, 0xc7, 0xbc, 0xb9, 0x57, 0xbe, 0x06, 0x12, 0xbf, 0x33, 0x8d, 0xc9, 0xe6, 0xa7, 0x36, 0x44, 0xb8, 0x67, 0x0b, 0xa7, 0xe3, 0x0e, 0xbb, 0xdf, 0x5c, 0xd8, 0x56, 0xcd, 0x25, 0x44, 0x93, 0xc9, 0x56, 0x22, 0xea ]; #[test] fn test_tls_message_status_response() { let empty = &b""[..]; let bytes = SERVER_STATUS_RESPONSE; let blob = &bytes[8..]; let expected = vec![TlsMessage::Handshake( TlsMessageHandshake::CertificateStatus(TlsCertificateStatusContents { status_type: 1, blob, }), )]; let hdr = TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion(0), len: 0x0, }; let res = parse_tls_record_with_header(bytes, &hdr); assert_eq!(res, Ok((empty, expected))); } } // mod tls_handshake tls-parser-0.12.2/tests/tls_tls13.rs000064400000000000000000000150001046102023000153360ustar 00000000000000extern crate nom; extern crate tls_parser; mod tls_13 { use tls_parser::*; // Test vectors from https://tools.ietf.org/html/draft-thomson-tls-tls13-vectors-01 #[rustfmt::skip] static TV_CLIENT_HELLO_1: &[u8] = &[ 0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03, 0xce, 0x05, 0xcf, 0xa3, 0xd9, 0x21, 0x70, 0xcb, 0xc2, 0x46, 0x5c, 0xdc, 0x3e, 0x3a, 0x2f, 0x57, 0x7f, 0x6e, 0xac, 0x80, 0x93, 0x61, 0x70, 0x8a, 0xb2, 0x44, 0xb0, 0x7d, 0x8f, 0xad, 0x86, 0x16, 0x00, 0x00, 0x3e, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x23, 0xc0, 0x27, 0xc0, 0x14, 0x00, 0x9e, 0xcc, 0xaa, 0x00, 0x33, 0x00, 0x32, 0x00, 0x67, 0x00, 0x39, 0x00, 0x38, 0x00, 0x6b, 0x00, 0x16, 0x00, 0x13, 0x00, 0x9c, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, 0x01, 0x95, 0x00, 0x15, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x28, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x2a, 0x98, 0x1d, 0xb6, 0xcd, 0xd0, 0x2a, 0x06, 0xc1, 0x76, 0x31, 0x02, 0xc9, 0xe7, 0x41, 0x36, 0x5a, 0xc4, 0xe6, 0xf7, 0x2b, 0x31, 0x76, 0xa6, 0xbd, 0x6a, 0x35, 0x23, 0xd3, 0xec, 0x0f, 0x4c, 0x00, 0x2b, 0x00, 0x07, 0x06, 0x7f, 0x12, 0x03, 0x03, 0x03, 0x02, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x01, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x02, 0x02, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, ]; #[rustfmt::skip] static TV_SERVER_HELLO_1: &[u8] = &[ 0x16, 0x03, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00, 0x4e, 0x7f, 0x12, 0x20, 0xb9, 0xc9, 0x20, 0x1c, 0xd1, 0x71, 0xa1, 0x5a, 0xbb, 0xa4, 0xe7, 0xed, 0xdc, 0xf3, 0xe8, 0x48, 0x8e, 0x71, 0x92, 0xff, 0xe0, 0x1e, 0xa5, 0xc1, 0x9f, 0x3d, 0x4b, 0x52, 0xff, 0xee, 0xbe, 0x13, 0x01, 0x00, 0x28, 0x00, 0x28, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9c, 0x1b, 0x0a, 0x74, 0x21, 0x91, 0x9a, 0x73, 0xcb, 0x57, 0xb3, 0xa0, 0xad, 0x9d, 0x68, 0x05, 0x86, 0x1a, 0x9c, 0x47, 0xe1, 0x1d, 0xf8, 0x63, 0x9d, 0x25, 0x32, 0x3b, 0x79, 0xce, 0x20, 0x1c, ]; #[test] fn test_tls13_ch() { let empty = &b""[..]; let bytes = TV_CLIENT_HELLO_1; let ciphers = &[ 0x1301, 0x1303, 0x1302, 0xc02b, 0xc02f, 0xcca9, 0xcca8, 0xc00a, 0xc009, 0xc013, 0xc023, 0xc027, 0xc014, 0x009e, 0xccaa, 0x0033, 0x0032, 0x0067, 0x0039, 0x0038, 0x006b, 0x0016, 0x0013, 0x009c, 0x002f, 0x003c, 0x0035, 0x003d, 0x000a, 0x0005, 0x0004, ]; let expected_ch = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls10, len: 512, }, msg: vec![TlsMessage::Handshake(TlsMessageHandshake::ClientHello( TlsClientHelloContents { version: TlsVersion::Tls12, random: &bytes[11..11 + 32], session_id: None, ciphers: ciphers.iter().map(|&x| TlsCipherSuiteID(x)).collect(), comp: vec![TlsCompressionID(0)], ext: Some(&bytes[112..]), }, ))], }; let ires = parse_tls_plaintext(bytes); assert_eq!(ires, Ok((empty, expected_ch))); } #[test] fn test_tls13_sh() { let empty = &b""[..]; let bytes = TV_SERVER_HELLO_1; let expected_sh = TlsPlaintext { hdr: TlsRecordHeader { record_type: TlsRecordType::Handshake, version: TlsVersion::Tls10, len: 82, }, msg: vec![TlsMessage::Handshake( TlsMessageHandshake::ServerHelloV13Draft18(TlsServerHelloV13Draft18Contents { version: TlsVersion::Tls13Draft18, random: &bytes[11..11 + 32], cipher: TlsCipherSuiteID(0x1301), ext: Some(&bytes[47..]), }), )], }; let expected_ext = vec![TlsExtension::KeyShareOld(&bytes[51..])]; let ires = parse_tls_plaintext(bytes); assert_eq!(ires, Ok((empty, expected_sh))); let res = ires.unwrap(); let msg = &res.1.msg[0]; let ext_raw = match *msg { TlsMessage::Handshake(TlsMessageHandshake::ServerHelloV13Draft18(ref sh)) => { sh.ext.unwrap() } _ => { panic!("Extensions parsing failed"); } }; let res_ext = parse_tls_extensions(ext_raw); assert_eq!(res_ext, Ok((empty, expected_ext))); } } // mod tls_13