From 72883a57553a1e6845eec71d1b53254ee041c6ec Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 23 Jan 2015 22:29:13 +0000 Subject: Add support for configuring a TLS::Policy by text file --- src/lib/tls/tls_policy.cpp | 48 ++++++++++++++++- src/lib/tls/tls_policy.h | 121 ++++++++++++++++++++++++++++++++++++++++-- src/lib/utils/info.txt | 2 +- src/lib/utils/parsing.h | 11 +--- src/lib/utils/read_cfg.cpp | 129 +++++++++++++-------------------------------- 5 files changed, 202 insertions(+), 109 deletions(-) (limited to 'src/lib') diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index fc8f54e8e..e9f5bb209 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -119,9 +119,9 @@ std::string Policy::choose_curve(const std::vector& curve_names) co return ""; // no shared curve } -DL_Group Policy::dh_group() const +std::string Policy::dh_group() const { - return DL_Group("modp/ietf/2048"); + return "modp/ietf/2048"; } size_t Policy::minimum_dh_group_size() const @@ -311,6 +311,50 @@ std::vector Policy::ciphersuite_list(Protocol_Version version, return ciphersuite_codes; } +namespace { + +void print_vec(std::ostream& o, + const char* key, + const std::vector& v) + { + o << key << " = "; + for(size_t i = 0; i != v.size(); ++i) + { + o << v[i]; + if(i != v.size() - 1) + o << ' '; + } + o << '\n'; + } + +void print_bool(std::ostream& o, + const char* key, bool b) + { + o << key << " = " << (b ? "true" : "false") << '\n'; + } + +} + +void Policy::print(std::ostream& o) const + { + print_vec(o, "ciphers", allowed_ciphers()); + print_vec(o, "macs", allowed_macs()); + print_vec(o, "signature_hashes", allowed_signature_hashes()); + print_vec(o, "signature_methods", allowed_signature_methods()); + print_vec(o, "key_exchange_methods", allowed_key_exchange_methods()); + print_vec(o, "ecc_curves", allowed_ecc_curves()); + + print_bool(o, "negotiate_heartbeat_support", negotiate_heartbeat_support()); + print_bool(o, "allow_insecure_renegotiation", allow_insecure_renegotiation()); + print_bool(o, "include_time_in_hello_random", include_time_in_hello_random()); + print_bool(o, "allow_server_initiated_renegotiation", allow_server_initiated_renegotiation()); + print_bool(o, "hide_unknown_users", hide_unknown_users()); + print_bool(o, "server_uses_own_ciphersuite_preferences", server_uses_own_ciphersuite_preferences()); + o << "session_ticket_lifetime = " << session_ticket_lifetime() << '\n'; + o << "dh_group = " << dh_group() << '\n'; + o << "minimum_dh_group_size = " << minimum_dh_group_size() << '\n'; + } + } } diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index 089494f24..fdfbb6478 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -102,10 +102,7 @@ class BOTAN_DLL Policy */ virtual bool allow_server_initiated_renegotiation() const; - /** - * Return the group to use for ephemeral Diffie-Hellman key agreement - */ - virtual DL_Group dh_group() const; + virtual std::string dh_group() const; /** * Return the minimum DH group size we're willing to use @@ -176,6 +173,8 @@ class BOTAN_DLL Policy virtual std::vector ciphersuite_list(Protocol_Version version, bool have_srp) const; + virtual void print(std::ostream& o) const; + virtual ~Policy() {} }; @@ -220,6 +219,120 @@ class BOTAN_DLL Datagram_Policy : public Policy { return version == Protocol_Version::DTLS_V12; } }; +class BOTAN_DLL Text_Policy : public Policy + { + public: + + std::vector allowed_ciphers() const override + { return get_list("ciphers", Policy::allowed_ciphers()); } + + std::vector allowed_signature_hashes() const override + { return get_list("signature_hashes", Policy::allowed_signature_hashes()); } + + std::vector allowed_macs() const override + { return get_list("macs", Policy::allowed_macs()); } + + std::vector allowed_key_exchange_methods() const override + { return get_list("key_exchange_methods", Policy::allowed_key_exchange_methods()); } + + std::vector allowed_signature_methods() const override + { return get_list("signature_methods", Policy::allowed_signature_methods()); } + + std::vector allowed_ecc_curves() const override + { return get_list("ecc_curves", Policy::allowed_ecc_curves()); } + + bool negotiate_heartbeat_support() const override + { return get_bool("negotiate_heartbeat_support", Policy::negotiate_heartbeat_support()); } + + bool allow_insecure_renegotiation() const override + { return get_bool("allow_insecure_renegotiation", Policy::allow_insecure_renegotiation()); } + + bool include_time_in_hello_random() const override + { return get_bool("include_time_in_hello_random", Policy::include_time_in_hello_random()); } + + bool allow_server_initiated_renegotiation() const override + { return get_bool("allow_server_initiated_renegotiation", Policy::allow_server_initiated_renegotiation()); } + + bool server_uses_own_ciphersuite_preferences() const override + { return get_bool("server_uses_own_ciphersuite_preferences", Policy::server_uses_own_ciphersuite_preferences()); } + + std::string dh_group() const override + { return get_str("dh_group", Policy::dh_group()); } + + size_t minimum_dh_group_size() const override + { return get_len("minimum_dh_group_size", Policy::minimum_dh_group_size()); } + + bool hide_unknown_users() const override + { return get_bool("hide_unknown_users", Policy::hide_unknown_users()); } + + u32bit session_ticket_lifetime() const override + { return get_len("session_ticket_lifetime", Policy::session_ticket_lifetime()); } + + std::vector srtp_profiles() const override + { + std::vector r; + for(auto&& p : get_list("srtp_profiles", std::vector())) + { + r.push_back(to_u32bit(p)); + } + return r; + } + + Text_Policy(std::istream& in) + { + m_kv = read_cfg(in); + } + + private: + + std::vector get_list(const std::string& key, + const std::vector& def) const + { + const std::string v = get_str(key); + + if(v == "") + return def; + + return split_on(v, ' '); + } + + size_t get_len(const std::string& key, size_t def) const + { + const std::string v = get_str(key); + + if(v == "") + return def; + + return to_u32bit(v); + } + + bool get_bool(const std::string& key, bool def) const + { + const std::string v = get_str(key); + + if(v == "") + return def; + + if(v == "true" || v == "True") + return true; + else if(v == "false" || v == "False") + return false; + else + throw std::runtime_error("Invalid boolean '" + v + "'"); + } + + std::string get_str(const std::string& key, const std::string& def = "") const + { + auto i = m_kv.find(key); + if(i == m_kv.end()) + return def; + + return i->second; + } + + std::map m_kv; + }; + } } diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt index 84e1c8740..fafb73c72 100644 --- a/src/lib/utils/info.txt +++ b/src/lib/utils/info.txt @@ -1,4 +1,4 @@ -define UTIL_FUNCTIONS 20131128 +define UTIL_FUNCTIONS 20140123 load_on always diff --git a/src/lib/utils/parsing.h b/src/lib/utils/parsing.h index 8e7a3a22a..24d0576fd 100644 --- a/src/lib/utils/parsing.h +++ b/src/lib/utils/parsing.h @@ -124,16 +124,7 @@ BOTAN_DLL u32bit string_to_ipv4(const std::string& ip_str); */ BOTAN_DLL std::string ipv4_to_string(u32bit ip_addr); -void BOTAN_DLL lex_cfg(std::istream& is, - std::function cb); - -void BOTAN_DLL lex_cfg_w_headers(std::istream& is, - std::function cb, - std::function header_cb); - -std::map> -BOTAN_DLL -parse_cfg(std::istream& is); +std::map BOTAN_DLL read_cfg(std::istream& is); } diff --git a/src/lib/utils/read_cfg.cpp b/src/lib/utils/read_cfg.cpp index 8f186cefd..02708c3d6 100644 --- a/src/lib/utils/read_cfg.cpp +++ b/src/lib/utils/read_cfg.cpp @@ -1,121 +1,66 @@ /* * Simple config/test file reader -* (C) 2013,2014 Jack Lloyd +* (C) 2013,2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include -#include namespace Botan { -void lex_cfg(std::istream& is, - std::function cb) +namespace { + +std::string clean_ws(const std::string& s) { + const char* ws = " \t\n"; + auto start = s.find_first_not_of(ws); + auto end = s.find_last_not_of(ws); + + if(start == std::string::npos) + return ""; + + if(end == std::string::npos) + return s.substr(start, end); + else + return s.substr(start, start + end + 1); + } + +} + +std::map read_cfg(std::istream& is) + { + std::map kv; + size_t line = 0; + while(is.good()) { std::string s; std::getline(is, s); - while(is.good() && s.back() == '\\') - { - while(s.size() && (s.back() == '\\' || s.back() == '\n')) - s.resize(s.size()-1); - - std::string x; - std::getline(is, x); - - size_t i = 0; + ++line; - while(i < x.size() && (::isspace(x[i]))) - ++i; - - s += x.substr(i); - } + if(s == "" || s[0] == '#') + continue; - auto comment = s.find('#'); - if(comment) - s = s.substr(0, comment); + s = clean_ws(s.substr(0, s.find('#'))); - if(s.empty()) + if(s == "") continue; - auto parts = split_on_pred(s, [](char c) { return ::isspace(c); }); - - for(auto& p : parts) - { - if(p.empty()) - continue; - - auto eq = p.find("="); - - if(eq == std::string::npos || p.size() < 2) - { - cb(p); - } - else if(eq == 0) - { - cb("="); - cb(p.substr(1, std::string::npos)); - } - else if(eq == p.size() - 1) - { - cb(p.substr(0, p.size() - 1)); - cb("="); - } - else if(eq != std::string::npos) - { - cb(p.substr(0, eq)); - cb("="); - cb(p.substr(eq + 1, std::string::npos)); - } - } - } - } + auto eq = s.find("="); -void lex_cfg_w_headers(std::istream& is, - std::function cb, - std::function hdr_cb) - { - auto intercept = [cb,hdr_cb](const std::string& s) - { - if(s[0] == '[' && s[s.length()-1] == ']') - hdr_cb(s.substr(1, s.length()-2)); - else - cb(s); - }; + if(eq == std::string::npos || eq == 0 || eq == s.size() - 1) + throw std::runtime_error("Bad read_cfg input '" + s + "' on line " + std::to_string(line)); - lex_cfg(is, intercept); - } + const std::string key = clean_ws(s.substr(0, eq)); + const std::string val = clean_ws(s.substr(eq + 1, std::string::npos)); -std::map> - parse_cfg(std::istream& is) - { - std::string header = "default"; - std::map> vals; - std::string key; + kv[key] = val; + } - auto header_cb = [&header](const std::string i) { header = i; }; - auto cb = [&header,&key,&vals](const std::string s) - { - if(s == "=") - { - BOTAN_ASSERT(!key.empty(), "Valid assignment in config"); - } - else if(key.empty()) - key = s; - else - { - vals[header][key] = s; - key = ""; - } - }; - - lex_cfg_w_headers(is, cb, header_cb); - - return vals; + return kv; } } -- cgit v1.2.3