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@netways.de>
This commit is contained in:
Uwe Ebel 2016-08-01 05:32:47 +02:00 committed by Gunnar Beutner
parent 5498dc5e4f
commit b2ac05ad7d
6 changed files with 48 additions and 0 deletions

View File

@ -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

View File

@ -181,6 +181,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.
*

View File

@ -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);

View File

@ -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 "'"));
}
}

View File

@ -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;

View File

@ -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 {