[icinga-checkins] icinga.org: icinga2/master: Make the minimum TLS protocol version configurable

git at icinga.org git at icinga.org
Wed Aug 3 07:46:58 CEST 2016


Module: icinga2
Branch: master
Commit: b2ac05ad7df7bfc54b66345cd7feeca11af904f8
URL:    https://git.icinga.org/?p=icinga2.git;a=commit;h=b2ac05ad7df7bfc54b66345cd7feeca11af904f8

Author: Uwe Ebel <kobmaki at aol.com>
Date:   Mon Aug  1 05:32:47 2016 +0200

Make the minimum TLS protocol version configurable

The ApiListener accepts all TLS versions that the underlying
OpenSSL library supports. This patch give the ability to restrict
the connection to a minimum TLS version.

fixes #11292

Signed-off-by: Gunnar Beutner <gunnar.beutner at netways.de>

---

 doc/6-object-types.md      |    1 +
 lib/base/tlsutility.cpp    |   22 ++++++++++++++++++++++
 lib/base/tlsutility.hpp    |    1 +
 lib/remote/apilistener.cpp |   19 +++++++++++++++++++
 lib/remote/apilistener.hpp |    2 ++
 lib/remote/apilistener.ti  |    3 +++
 6 files changed, 48 insertions(+)

diff --git a/doc/6-object-types.md b/doc/6-object-types.md
index 3b87ff8..049fc5e 100644
--- a/doc/6-object-types.md
+++ b/doc/6-object-types.md
@@ -51,6 +51,7 @@ Configuration Attributes:
   accept\_config            |**Optional.** Accept zone configuration. Defaults to `false`.
   accept\_commands          |**Optional.** Accept remote commands. Defaults to `false`.
   cipher\_list		    |**Optional.** Cipher list that is allowed.
+  tls\_protocolmin          |**Optional.** Minimum TLS protocol version. Must be one of `TLSv1`, `TLSv1.1` or `TLSv1.2`. Defaults to `TLSv1`.
 
 ## <a id="objecttype-apiuser"></a> ApiUser
 
diff --git a/lib/base/tlsutility.cpp b/lib/base/tlsutility.cpp
index 0315a1d..057fc18 100644
--- a/lib/base/tlsutility.cpp
+++ b/lib/base/tlsutility.cpp
@@ -182,6 +182,28 @@ void SetCipherListToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const
 }
 
 /**
+ * Set the minimum TLS protocol version to the specified SSL context.
+ *
+ * @param context The ssl context.
+ * @param tlsProtocolmin The minimum TLS protocol version.
+ */
+void SetTlsProtocolminToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const String& tlsProtocolmin)
+{
+	long flags = SSL_CTX_get_options(context.get());
+
+	flags |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+
+	if (tlsProtocolmin == SSL_TXT_TLSV1_1)
+		flags |= SSL_OP_NO_TLSv1;
+	else if (tlsProtocolmin == SSL_TXT_TLSV1_2)
+		flags |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
+	else if (tlsProtocolmin != SSL_TXT_TLSV1)
+		BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid TLS protocol version specified."));
+
+	SSL_CTX_set_options(context.get(), flags);
+}
+
+/**
  * Loads a CRL and appends its certificates to the specified SSL context.
  *
  * @param context The SSL context.
diff --git a/lib/base/tlsutility.hpp b/lib/base/tlsutility.hpp
index 6a41d48..aef59af 100644
--- a/lib/base/tlsutility.hpp
+++ b/lib/base/tlsutility.hpp
@@ -41,6 +41,7 @@ void I2_BASE_API InitializeOpenSSL(void);
 boost::shared_ptr<SSL_CTX> I2_BASE_API MakeSSLContext(const String& pubkey = String(), const String& privkey = String(), const String& cakey = String());
 void I2_BASE_API AddCRLToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const String& crlPath);
 void I2_BASE_API SetCipherListToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const String& cipherList);
+void I2_BASE_API SetTlsProtocolminToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const String& tlsProtocolmin);
 String I2_BASE_API GetCertificateCN(const boost::shared_ptr<X509>& certificate);
 boost::shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile);
 int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), const String& serialFile = String(), bool ca = false);
diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp
index e1b0025..370c47a 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -104,6 +104,14 @@ void ApiListener::OnConfigLoaded(void)
 			    + GetCipherList() + "'.", GetDebugInfo()));
 		}
 	}
+
+	if (!GetTlsProtocolmin().IsEmpty()){
+		try {
+			SetTlsProtocolminToSSLContext(m_SSLContext, GetTlsProtocolmin());
+		} catch (const std::exception&) {
+			BOOST_THROW_EXCEPTION(ScriptError("Cannot set minimum TLS protocol version to SSL context with tls_protocolmin: '" + GetTlsProtocolmin() + "'.", GetDebugInfo()));
+		}
+	}
 }
 
 void ApiListener::OnAllConfigLoaded(void)
@@ -1171,3 +1179,14 @@ Endpoint::Ptr ApiListener::GetLocalEndpoint(void) const
 {
 	return m_LocalEndpoint;
 }
+
+void ApiListener::ValidateTlsProtocolmin(const String& value, const ValidationUtils& utils) override
+{
+	ObjectImpl<ApiListener>::ValidateTlsProtocolmin(value, utils);
+
+	if (value != SSL_TXT_TLSV1 && value != SSL_TXT_TLSV1_1 &&
+	    value != SSL_TXT_TLSV1_2) {
+		BOOST_THROW_EXCEPTION(ValidationError(this, boost::assign::list_of("tls_protocolmin"), "Invalid TLS version. "
+		    "Must be one of '" SSL_TXT_TLSV1 "', '" SSL_TXT_TLSV1_1 "' or '" SSL_TXT_TLSV1_2 "'"));
+	}
+}
diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp
index 3f9a325..4c17713 100644
--- a/lib/remote/apilistener.hpp
+++ b/lib/remote/apilistener.hpp
@@ -105,6 +105,8 @@ protected:
 	virtual void OnAllConfigLoaded(void) override;
 	virtual void Start(bool runtimeCreated) override;
 
+	virtual void ValidateTlsProtocolmin(const String& value, const ValidationUtils& utils) override;
+
 private:
 	boost::shared_ptr<SSL_CTX> m_SSLContext;
 	std::set<TcpSocket::Ptr> m_Servers;
diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti
index 91e4b0e..fee11f2 100644
--- a/lib/remote/apilistener.ti
+++ b/lib/remote/apilistener.ti
@@ -35,6 +35,9 @@ class ApiListener : ConfigObject
 	[config] String cipher_list {
 		default {{{ return "ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL"; }}}
 	};
+	[config] String tls_protocolmin {
+		default {{{ return "TLSv1"; }}}
+	};
 
 	[config] String bind_host;
 	[config] String bind_port {



More information about the icinga-checkins mailing list