diff --git a/doc/6-object-types.md b/doc/6-object-types.md
index b192ca018..9e3e7e9af 100644
--- a/doc/6-object-types.md
+++ b/doc/6-object-types.md
@@ -50,6 +50,7 @@ Configuration Attributes:
bind\_port |**Optional.** The port the api listener should be bound to. Defaults to `5665`.
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.
## ApiUser
diff --git a/lib/base/tlsutility.cpp b/lib/base/tlsutility.cpp
index 37f53b919..65bb83d34 100644
--- a/lib/base/tlsutility.cpp
+++ b/lib/base/tlsutility.cpp
@@ -158,6 +158,29 @@ boost::shared_ptr MakeSSLContext(const String& pubkey, const String& pr
return sslContext;
}
+/**
+ * Set the cipher list to the specified SSL context.
+ * @param context The ssl context.
+ * @param cipherList The ciper list.
+ **/
+void SetCipherListToSSLContext(const boost::shared_ptr& context, const String& cipherList)
+{
+ char errbuf[256];
+
+ if (SSL_CTX_set_cipher_list(context.get(), cipherList.CStr()) == 0) {
+ Log(LogCritical, "SSL")
+ << "Error with cipher list '"
+ << cipherList
+ << "' results in no availabe ciphers: "
+ << ERR_peek_error() << ", \""
+ << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
+
+ BOOST_THROW_EXCEPTION(openssl_error()
+ << boost::errinfo_api_function("SSL_CTX_set_cipher_list")
+ << errinfo_openssl_error(ERR_peek_error()));
+ }
+}
+
/**
* Loads a CRL and appends its certificates to the specified SSL context.
*
diff --git a/lib/base/tlsutility.hpp b/lib/base/tlsutility.hpp
index 3bafb26db..6a41d4818 100644
--- a/lib/base/tlsutility.hpp
+++ b/lib/base/tlsutility.hpp
@@ -40,6 +40,7 @@ namespace icinga
void I2_BASE_API InitializeOpenSSL(void);
boost::shared_ptr 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& context, const String& crlPath);
+void I2_BASE_API SetCipherListToSSLContext(const boost::shared_ptr& context, const String& cipherList);
String I2_BASE_API GetCertificateCN(const boost::shared_ptr& certificate);
boost::shared_ptr 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 c51a1a869..4a31eb8e9 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -95,6 +95,15 @@ void ApiListener::OnConfigLoaded(void)
+ GetCrlPath() + "'.", GetDebugInfo()));
}
}
+
+ if (!GetCipherList().IsEmpty()) {
+ try {
+ SetCipherListToSSLContext(m_SSLContext, GetCipherList());
+ } catch (const std::exception&) {
+ BOOST_THROW_EXCEPTION(ScriptError("Cannot set cipher list to SSL context for cipher list: '"
+ + GetCipherList() + "'.", GetDebugInfo()));
+ }
+ }
}
void ApiListener::OnAllConfigLoaded(void)
diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti
index 34e235cce..91e4b0e51 100644
--- a/lib/remote/apilistener.ti
+++ b/lib/remote/apilistener.ti
@@ -32,6 +32,9 @@ class ApiListener : ConfigObject
[config, required] String key_path;
[config, required] String ca_path;
[config] String crl_path;
+ [config] String cipher_list {
+ default {{{ return "ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL"; }}}
+ };
[config] String bind_host;
[config] String bind_port {