diff options
author | Jack Lloyd <[email protected]> | 2017-09-01 11:44:01 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-09-01 11:44:01 -0400 |
commit | 18bfd3ff33dc7fbb45465b2c0a4c997d716882f8 (patch) | |
tree | fbbba38ea487e202628080eb4765c02f61db0478 /src | |
parent | bbde24b89a7867f6acde1fba3022205502e8f392 (diff) |
Add a CLI util for inspecting TLS client hellos
Diffstat (limited to 'src')
-rw-r--r-- | src/cli/tls_utils.cpp | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/cli/tls_utils.cpp b/src/cli/tls_utils.cpp index b24af1656..15341d974 100644 --- a/src/cli/tls_utils.cpp +++ b/src/cli/tls_utils.cpp @@ -10,6 +10,8 @@ #include <botan/tls_policy.h> #include <botan/tls_version.h> +#include <botan/tls_messages.h> +#include <botan/hex.h> namespace Botan_CLI { @@ -130,6 +132,115 @@ class TLS_Ciphersuites final : public Command BOTAN_REGISTER_COMMAND("tls_ciphers", TLS_Ciphersuites); +class TLS_Client_Hello_Reader final : public Command + { + public: + TLS_Client_Hello_Reader() + : Command("tls_client_hello --hex input") {} + + virtual void go() + { + const std::string input_file = get_arg("input"); + std::vector<uint8_t> input; + + if(flag_set("hex")) + { + input = Botan::hex_decode(slurp_file_as_str(input_file)); + } + else + { + input = slurp_file(input_file); + } + + if(input.size() < 45) + { + error_output() << "Input too short to be valid\n"; + return; + } + + // Input also contains the record layer header, strip it + if(input[0] == 22) + { + const size_t len = Botan::make_uint16(input[3], input[4]); + + if(input.size() != len + 5) + { + error_output() << "Record layer length invalid\n"; + return; + } + + input = std::vector<uint8_t>(input.begin() + 5, input.end()); + } + + // Assume the handshake header is there, strip it + if(input[0] != 1) + { + error_output() << "Input message is not a TLS client hello\n"; + return; + } + + const size_t hs_len = Botan::make_uint32(0, input[1], input[2], input[3]); + + if(input.size() != hs_len + 4) + { + error_output() << "Handshake layer length invalid\n"; + return; + } + + input = std::vector<uint8_t>(input.begin() + 4, input.end()); + + try + { + Botan::TLS::Client_Hello hello(input); + + output() << format_hello(hello); + } + catch(std::exception& e) + { + error_output() << "Parsing client hello failed: " << e.what() << "\n"; + } + } + + private: + std::string format_hello(const Botan::TLS::Client_Hello& hello) + { + std::ostringstream oss; + oss << "Version: " << hello.version().to_string() << "\n" + << "Random: " << Botan::hex_encode(hello.random()) << "\n"; + + if(!hello.session_id().empty()) + oss << "SessionID: " << Botan::hex_encode(hello.session_id()) << "\n"; + for(uint16_t csuite_id : hello.ciphersuites()) + oss << "Cipher: " << Botan::TLS::Ciphersuite::by_id(csuite_id).to_string() << "\n"; + + oss << "Supported signature schemes: "; + + if(hello.supported_algos().empty()) + { + oss << "Did not send signature_algorithms extension\n"; + } + else + { + for(auto&& hash_and_sig : hello.supported_algos()) + oss << hash_and_sig.second << '+' << hash_and_sig.first << ' '; + oss << "\n"; + } + + std::map<std::string, bool> hello_flags; + hello_flags["ALPN"] = hello.supports_alpn(); + hello_flags["Encrypt Then Mac"] = hello.supports_encrypt_then_mac(); + hello_flags["Extended Master Secret"] = hello.supports_extended_master_secret(); + hello_flags["Session Ticket"] = hello.supports_session_ticket(); + + for(auto&& i : hello_flags) + oss << "Supports " << i.first << "? " << (i.second ? "yes" : "no") << "\n"; + + return oss.str(); + } + }; + +BOTAN_REGISTER_COMMAND("tls_client_hello", TLS_Client_Hello_Reader); + } #endif |