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 {