From 276fcd8903ff8ec5bbd394d7221e65fbfa005bfe Mon Sep 17 00:00:00 2001 From: Denis Glazachev Date: Fri, 12 Jun 2020 21:59:47 +0400 Subject: [PATCH] Add/rename parameters that control TLS --- programs/server/config.xml | 25 +++++++--- src/Access/ExternalAuthenticators.cpp | 70 +++++++++++++++++++-------- src/Access/LDAPClient.cpp | 58 ++++++++++++++++++---- src/Access/LDAPParams.h | 21 ++++++-- 4 files changed, 134 insertions(+), 40 deletions(-) diff --git a/programs/server/config.xml b/programs/server/config.xml index 372f418c812..f43ecad9a78 100644 --- a/programs/server/config.xml +++ b/programs/server/config.xml @@ -209,20 +209,29 @@ Specify 'no' for plain text (ldap://) protocol (not recommended). Specify 'yes' for LDAP over SSL/TLS (ldaps://) protocol (recommended, the default). Specify 'starttls' for legacy StartTLS protocol (plain text (ldap://) protocol, upgraded to TLS). - tls_cert_verify - TLS peer certificate verification behavior. - Accepted values are: never, allow, try, demand. - ca_cert_dir - path to CA certificates directory. - ca_cert_file - path to CA certificate file. - Example: + tls_minimum_protocol_version - the minimum protocol version of SSL/TLS. + Accepted values are: 'ssl2', 'ssl3', 'tls1.0', 'tls1.1', 'tls1.2' (the default). + tls_require_cert - SSL/TLS peer certificate verification behavior. + Accepted values are: 'never', 'allow', 'try', 'demand' (the default). + tls_cert_file - path to certificate file. + tls_key_file - path to certificate key file. + tls_ca_cert_file - path to CA certificate file. + tls_ca_cert_dir - path to the directory containing CA certificates. + tls_cipher_suite - allowed cipher suite. + Example: localhost 636 cn= , ou=users, dc=example, dc=com yes - demand - /path/to/ca_cert_dir - /path/to/ca_cert_file + tls1.2 + demand + /path/to/tls_cert_file + /path/to/tls_key_file + /path/to/tls_ca_cert_file + /path/to/tls_ca_cert_dir + SECURE256:+SECURE128:-VERS-TLS-ALL:+VERS-TLS1.2:-RSA:-DHE-DSS:-CAMELLIA-128-CBC:-CAMELLIA-256-CBC --> diff --git a/src/Access/ExternalAuthenticators.cpp b/src/Access/ExternalAuthenticators.cpp index 8d0487bfd31..fcb7317a52d 100644 --- a/src/Access/ExternalAuthenticators.cpp +++ b/src/Access/ExternalAuthenticators.cpp @@ -30,9 +30,13 @@ auto parseLDAPServer(const Poco::Util::AbstractConfiguration & config, const Str const bool has_auth_dn_prefix = config.has(ldap_server_config + ".auth_dn_prefix"); const bool has_auth_dn_suffix = config.has(ldap_server_config + ".auth_dn_suffix"); const bool has_enable_tls = config.has(ldap_server_config + ".enable_tls"); - const bool has_tls_cert_verify = config.has(ldap_server_config + ".tls_cert_verify"); - const bool has_ca_cert_dir = config.has(ldap_server_config + ".ca_cert_dir"); - const bool has_ca_cert_file = config.has(ldap_server_config + ".ca_cert_file"); + const bool has_tls_minimum_protocol_version = config.has(ldap_server_config + ".tls_minimum_protocol_version"); + const bool has_tls_require_cert = config.has(ldap_server_config + ".tls_require_cert"); + const bool has_tls_cert_file = config.has(ldap_server_config + ".tls_cert_file"); + const bool has_tls_key_file = config.has(ldap_server_config + ".tls_key_file"); + const bool has_tls_ca_cert_file = config.has(ldap_server_config + ".tls_ca_cert_file"); + const bool has_tls_ca_cert_dir = config.has(ldap_server_config + ".tls_ca_cert_dir"); + const bool has_tls_cipher_suite = config.has(ldap_server_config + ".tls_cipher_suite"); if (!has_host) throw Exception("Missing 'host' entry", ErrorCodes::BAD_ARGUMENTS); @@ -61,28 +65,56 @@ auto parseLDAPServer(const Poco::Util::AbstractConfiguration & config, const Str params.enable_tls = LDAPServerParams::TLSEnable::NO; } - if (has_tls_cert_verify) + if (has_tls_minimum_protocol_version) { - String tls_cert_verify_lc_str = config.getString(ldap_server_config + ".tls_cert_verify"); - boost::to_lower(tls_cert_verify_lc_str); + String tls_minimum_protocol_version_lc_str = config.getString(ldap_server_config + ".tls_minimum_protocol_version"); + boost::to_lower(tls_minimum_protocol_version_lc_str); - if (tls_cert_verify_lc_str == "never") - params.tls_cert_verify = LDAPServerParams::TLSCertVerify::NEVER; - else if (tls_cert_verify_lc_str == "allow") - params.tls_cert_verify = LDAPServerParams::TLSCertVerify::ALLOW; - else if (tls_cert_verify_lc_str == "try") - params.tls_cert_verify = LDAPServerParams::TLSCertVerify::TRY; - else if (tls_cert_verify_lc_str == "demand") - params.tls_cert_verify = LDAPServerParams::TLSCertVerify::DEMAND; + if (tls_minimum_protocol_version_lc_str == "ssl2") + params.tls_minimum_protocol_version = LDAPServerParams::TLSProtocolVersion::SSL2; + else if (tls_minimum_protocol_version_lc_str == "ssl3") + params.tls_minimum_protocol_version = LDAPServerParams::TLSProtocolVersion::SSL3; + else if (tls_minimum_protocol_version_lc_str == "tls1.0") + params.tls_minimum_protocol_version = LDAPServerParams::TLSProtocolVersion::TLS1_0; + else if (tls_minimum_protocol_version_lc_str == "tls1.1") + params.tls_minimum_protocol_version = LDAPServerParams::TLSProtocolVersion::TLS1_1; + else if (tls_minimum_protocol_version_lc_str == "tls1.2") + params.tls_minimum_protocol_version = LDAPServerParams::TLSProtocolVersion::TLS1_2; else - throw Exception("Bad value for 'tls_cert_verify' entry, allowed values are: 'never', 'allow', 'try', 'demand'", ErrorCodes::BAD_ARGUMENTS); + throw Exception("Bad value for 'tls_minimum_protocol_version' entry, allowed values are: 'ssl2', 'ssl3', 'tls1.0', 'tls1.1', 'tls1.2'", ErrorCodes::BAD_ARGUMENTS); } - if (has_ca_cert_dir) - params.ca_cert_dir = config.getString(ldap_server_config + ".ca_cert_dir"); + if (has_tls_require_cert) + { + String tls_require_cert_lc_str = config.getString(ldap_server_config + ".tls_require_cert"); + boost::to_lower(tls_require_cert_lc_str); - if (has_ca_cert_file) - params.ca_cert_file = config.getString(ldap_server_config + ".ca_cert_file"); + if (tls_require_cert_lc_str == "never") + params.tls_require_cert = LDAPServerParams::TLSRequireCert::NEVER; + else if (tls_require_cert_lc_str == "allow") + params.tls_require_cert = LDAPServerParams::TLSRequireCert::ALLOW; + else if (tls_require_cert_lc_str == "try") + params.tls_require_cert = LDAPServerParams::TLSRequireCert::TRY; + else if (tls_require_cert_lc_str == "demand") + params.tls_require_cert = LDAPServerParams::TLSRequireCert::DEMAND; + else + throw Exception("Bad value for 'tls_require_cert' entry, allowed values are: 'never', 'allow', 'try', 'demand'", ErrorCodes::BAD_ARGUMENTS); + } + + if (has_tls_cert_file) + params.tls_cert_file = config.getString(ldap_server_config + ".tls_cert_file"); + + if (has_tls_key_file) + params.tls_key_file = config.getString(ldap_server_config + ".tls_key_file"); + + if (has_tls_ca_cert_file) + params.tls_ca_cert_file = config.getString(ldap_server_config + ".tls_ca_cert_file"); + + if (has_tls_ca_cert_dir) + params.tls_ca_cert_dir = config.getString(ldap_server_config + ".tls_ca_cert_dir"); + + if (has_tls_cipher_suite) + params.tls_cipher_suite = config.getString(ldap_server_config + ".tls_cipher_suite"); if (has_port) { diff --git a/src/Access/LDAPClient.cpp b/src/Access/LDAPClient.cpp index b538c06c9ea..02c24bc9a9e 100644 --- a/src/Access/LDAPClient.cpp +++ b/src/Access/LDAPClient.cpp @@ -140,19 +140,23 @@ int LDAPClient::openConnection(const bool graceful_bind_failure) diag(ldap_set_option(handle, LDAP_OPT_KEEPCONN, LDAP_OPT_ON)); #endif +#ifdef LDAP_OPT_TIMEOUT { ::timeval operation_timeout; operation_timeout.tv_sec = params.operation_timeout.count(); operation_timeout.tv_usec = 0; diag(ldap_set_option(handle, LDAP_OPT_TIMEOUT, &operation_timeout)); } +#endif +#ifdef LDAP_OPT_NETWORK_TIMEOUT { ::timeval network_timeout; network_timeout.tv_sec = params.network_timeout.count(); network_timeout.tv_usec = 0; diag(ldap_set_option(handle, LDAP_OPT_NETWORK_TIMEOUT, &network_timeout)); } +#endif { const int search_timeout = params.search_timeout.count(); @@ -164,23 +168,59 @@ int LDAPClient::openConnection(const bool graceful_bind_failure) diag(ldap_set_option(handle, LDAP_OPT_SIZELIMIT, &size_limit)); } +#ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN { int value = 0; - switch (params.tls_cert_verify) + switch (params.tls_minimum_protocol_version) { - case LDAPServerParams::TLSCertVerify::NEVER: value = LDAP_OPT_X_TLS_NEVER; break; - case LDAPServerParams::TLSCertVerify::ALLOW: value = LDAP_OPT_X_TLS_ALLOW; break; - case LDAPServerParams::TLSCertVerify::TRY: value = LDAP_OPT_X_TLS_TRY; break; - case LDAPServerParams::TLSCertVerify::DEMAND: value = LDAP_OPT_X_TLS_DEMAND; break; + case LDAPServerParams::TLSProtocolVersion::SSL2: value = LDAP_OPT_X_TLS_PROTOCOL_SSL2; break; + case LDAPServerParams::TLSProtocolVersion::SSL3: value = LDAP_OPT_X_TLS_PROTOCOL_SSL3; break; + case LDAPServerParams::TLSProtocolVersion::TLS1_0: value = LDAP_OPT_X_TLS_PROTOCOL_TLS1_0; break; + case LDAPServerParams::TLSProtocolVersion::TLS1_1: value = LDAP_OPT_X_TLS_PROTOCOL_TLS1_1; break; + case LDAPServerParams::TLSProtocolVersion::TLS1_2: value = LDAP_OPT_X_TLS_PROTOCOL_TLS1_2; break; + } + diag(ldap_set_option(handle, LDAP_OPT_X_TLS_PROTOCOL_MIN, &value)); + } +#endif + +#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT + { + int value = 0; + switch (params.tls_require_cert) + { + case LDAPServerParams::TLSRequireCert::NEVER: value = LDAP_OPT_X_TLS_NEVER; break; + case LDAPServerParams::TLSRequireCert::ALLOW: value = LDAP_OPT_X_TLS_ALLOW; break; + case LDAPServerParams::TLSRequireCert::TRY: value = LDAP_OPT_X_TLS_TRY; break; + case LDAPServerParams::TLSRequireCert::DEMAND: value = LDAP_OPT_X_TLS_DEMAND; break; } diag(ldap_set_option(handle, LDAP_OPT_X_TLS_REQUIRE_CERT, &value)); } +#endif - if (!params.ca_cert_dir.empty()) - diag(ldap_set_option(handle, LDAP_OPT_X_TLS_CACERTDIR, params.ca_cert_dir.c_str())); +#ifdef LDAP_OPT_X_TLS_CERTFILE + if (!params.tls_cert_file.empty()) + diag(ldap_set_option(handle, LDAP_OPT_X_TLS_CERTFILE, params.tls_cert_file.c_str())); +#endif - if (!params.ca_cert_file.empty()) - diag(ldap_set_option(handle, LDAP_OPT_X_TLS_CACERTFILE, params.ca_cert_file.c_str())); +#ifdef LDAP_OPT_X_TLS_KEYFILE + if (!params.tls_key_file.empty()) + diag(ldap_set_option(handle, LDAP_OPT_X_TLS_KEYFILE, params.tls_key_file.c_str())); +#endif + +#ifdef LDAP_OPT_X_TLS_CACERTFILE + if (!params.tls_ca_cert_file.empty()) + diag(ldap_set_option(handle, LDAP_OPT_X_TLS_CACERTFILE, params.tls_ca_cert_file.c_str())); +#endif + +#ifdef LDAP_OPT_X_TLS_CACERTDIR + if (!params.tls_ca_cert_dir.empty()) + diag(ldap_set_option(handle, LDAP_OPT_X_TLS_CACERTDIR, params.tls_ca_cert_dir.c_str())); +#endif + +#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE + if (!params.tls_cipher_suite.empty()) + diag(ldap_set_option(handle, LDAP_OPT_X_TLS_CIPHER_SUITE, params.tls_cipher_suite.c_str())); +#endif #ifdef LDAP_OPT_X_TLS_NEWCTX { diff --git a/src/Access/LDAPParams.h b/src/Access/LDAPParams.h index ed28526d29d..0d7c7dd17cd 100644 --- a/src/Access/LDAPParams.h +++ b/src/Access/LDAPParams.h @@ -23,7 +23,16 @@ struct LDAPServerParams YES }; - enum class TLSCertVerify + enum class TLSProtocolVersion + { + SSL2, + SSL3, + TLS1_0, + TLS1_1, + TLS1_2 + }; + + enum class TLSRequireCert { NEVER, ALLOW, @@ -42,9 +51,13 @@ struct LDAPServerParams std::uint16_t port = 636; TLSEnable enable_tls = TLSEnable::YES; - TLSCertVerify tls_cert_verify = TLSCertVerify::DEMAND; - String ca_cert_dir; - String ca_cert_file; + TLSProtocolVersion tls_minimum_protocol_version = TLSProtocolVersion::TLS1_2; + TLSRequireCert tls_require_cert = TLSRequireCert::DEMAND; + String tls_cert_file; + String tls_key_file; + String tls_ca_cert_file; + String tls_ca_cert_dir; + String tls_cipher_suite; SASLMechanism sasl_mechanism = SASLMechanism::SIMPLE;