-
Notifications
You must be signed in to change notification settings - Fork 584
Windows: use (existing) Schannel, not (shipped) OpenSSL #9956
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e86ec27
c84cb45
17cb8af
a850b84
09ec955
5f6aeb0
7938d60
fa08e90
86ba556
8ebc6a9
f5ffd86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
FIND_PATH(BoostWinTLS_HEADERS wintls.hpp HINTS "${PROJECT_SOURCE_DIR}/third-party/boost-wintls/include/boost") | ||
|
||
if(BoostWinTLS_HEADERS) | ||
set(BoostWinTLS_INCLUDE "${BoostWinTLS_HEADERS}/..") | ||
message(STATUS "Found Boost.WinTLS: ${BoostWinTLS_INCLUDE}") | ||
else() | ||
message(FATAL_ERROR "Unable to include wintls.hpp") | ||
endif() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ | |
#include <openssl/ssl.h> | ||
#include <openssl/ssl3.h> | ||
#include <fstream> | ||
#include <utility> | ||
|
||
namespace icinga | ||
{ | ||
|
@@ -72,18 +73,18 @@ void InitializeOpenSSL() | |
l_SSLInitialized = true; | ||
} | ||
|
||
static void InitSslContext(const Shared<boost::asio::ssl::context>::Ptr& context, const String& pubkey, const String& privkey, const String& cakey) | ||
static void InitSslContext(const Shared<TlsContext>::Ptr& context, const String& pubkey, const String& privkey, const String& cakey) | ||
{ | ||
char errbuf[256]; | ||
|
||
// Enforce TLS v1.2 as minimum | ||
context->set_options( | ||
boost::asio::ssl::context::default_workarounds | | ||
boost::asio::ssl::context::no_compression | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MS seems to have disabled compression by default, so we don't need/have an equivalent here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GnuTLS 3.6.0 and even OpenSSL 1.1.1 disabled compression, too. |
||
boost::asio::ssl::context::no_sslv2 | | ||
boost::asio::ssl::context::no_sslv3 | | ||
boost::asio::ssl::context::no_tlsv1 | | ||
boost::asio::ssl::context::no_tlsv1_1 | ||
TlsContext::default_workarounds | | ||
TlsContext::no_compression | | ||
TlsContext::no_sslv2 | | ||
TlsContext::no_sslv3 | | ||
TlsContext::no_tlsv1 | | ||
TlsContext::no_tlsv1_1 | ||
); | ||
|
||
// Custom TLS flags | ||
|
@@ -194,33 +195,12 @@ static void InitSslContext(const Shared<boost::asio::ssl::context>::Ptr& context | |
} | ||
} | ||
|
||
/** | ||
* Initializes an SSL context using the specified certificates. | ||
* | ||
* @param pubkey The public key. | ||
* @param privkey The matching private key. | ||
* @param cakey CA certificate chain file. | ||
* @returns An SSL context. | ||
*/ | ||
Shared<boost::asio::ssl::context>::Ptr MakeAsioSslContext(const String& pubkey, const String& privkey, const String& cakey) | ||
{ | ||
namespace ssl = boost::asio::ssl; | ||
|
||
InitializeOpenSSL(); | ||
|
||
auto context (Shared<ssl::context>::Make(ssl::context::tls)); | ||
|
||
InitSslContext(context, pubkey, privkey, cakey); | ||
|
||
return context; | ||
} | ||
|
||
/** | ||
* Set the cipher list to the specified SSL context. | ||
* @param context The ssl context. | ||
* @param cipherList The ciper list. | ||
**/ | ||
void SetCipherListToSSLContext(const Shared<boost::asio::ssl::context>::Ptr& context, const String& cipherList) | ||
void SetCipherListToSSLContext(const Shared<TlsContext>::Ptr& context, const String& cipherList) | ||
{ | ||
char errbuf[256]; | ||
|
||
|
@@ -264,40 +244,67 @@ void SetCipherListToSSLContext(const Shared<boost::asio::ssl::context>::Ptr& con | |
* @param version String of a TLS version, for example "TLSv1.2". | ||
* @return The value of the corresponding TLS*_VERSION macro. | ||
*/ | ||
int ResolveTlsProtocolVersion(const std::string& version) { | ||
TlsProtocolMin ResolveTlsProtocolVersion(const std::string& version) { | ||
#ifdef _WIN32 | ||
if (version == "TLSv1.2") { | ||
return TlsProtocolMin((int)TlsProtocolMin::tlsv12 | (int)TlsProtocolMin::tlsv13); | ||
} else if (version == "TLSv1.3") { | ||
return TlsProtocolMin::tlsv13; | ||
#else /* _WIN32 */ | ||
if (version == "TLSv1.2") { | ||
return TLS1_2_VERSION; | ||
} else if (version == "TLSv1.3") { | ||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L | ||
# if OPENSSL_VERSION_NUMBER >= 0x10101000L | ||
return TLS1_3_VERSION; | ||
#else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ | ||
# else /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ | ||
throw std::runtime_error("'" + version + "' is only supported with OpenSSL 1.1.1 or newer"); | ||
#endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ | ||
# endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ | ||
#endif /* _WIN32 */ | ||
} else { | ||
throw std::runtime_error("Unknown TLS protocol version '" + version + "'"); | ||
} | ||
} | ||
|
||
Shared<boost::asio::ssl::context>::Ptr SetupSslContext(String certPath, String keyPath, | ||
String caPath, String crlPath, String cipherList, String protocolmin, DebugInfo di) | ||
Shared<TlsContext>::Ptr SetupSslContext(const String& certPath, const String& keyPath, | ||
const String& caPath, const String& crlPath, const String& cipherList, const String& protocolmin, DebugInfo di) | ||
{ | ||
namespace ssl = boost::asio::ssl; | ||
|
||
Shared<ssl::context>::Ptr context; | ||
Shared<TlsContext>::Ptr context; | ||
|
||
#ifdef _WIN32 | ||
auto method (TlsProtocolMin::system_default); | ||
#else /* _WIN32 */ | ||
auto method (TlsContext::tls); | ||
#endif /* _WIN32 */ | ||
|
||
InitializeOpenSSL(); | ||
|
||
#ifdef _WIN32 | ||
if (!protocolmin.IsEmpty()) { | ||
try { | ||
method = ResolveTlsProtocolVersion(protocolmin); | ||
} catch (const std::exception&) { | ||
BOOST_THROW_EXCEPTION(ScriptError("Cannot set minimum TLS protocol version to SSL context with tls_protocolmin: '" + protocolmin + "'.", std::move(di))); | ||
} | ||
} | ||
#endif /* _WIN32 */ | ||
|
||
try { | ||
context = MakeAsioSslContext(certPath, keyPath, caPath); | ||
context = Shared<TlsContext>::Make(method); | ||
|
||
InitSslContext(context, certPath, keyPath, caPath); | ||
} catch (const std::exception&) { | ||
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '" | ||
+ certPath + "' key path: '" + keyPath + "' ca path: '" + caPath + "'.", di)); | ||
+ certPath + "' key path: '" + keyPath + "' ca path: '" + caPath + "'.", std::move(di))); | ||
} | ||
|
||
if (!crlPath.IsEmpty()) { | ||
try { | ||
AddCRLToSSLContext(context, crlPath); | ||
} catch (const std::exception&) { | ||
BOOST_THROW_EXCEPTION(ScriptError("Cannot add certificate revocation list to SSL context for crl path: '" | ||
+ crlPath + "'.", di)); | ||
+ crlPath + "'.", std::move(di))); | ||
} | ||
} | ||
|
||
|
@@ -306,30 +313,33 @@ Shared<boost::asio::ssl::context>::Ptr SetupSslContext(String certPath, String k | |
SetCipherListToSSLContext(context, cipherList); | ||
} catch (const std::exception&) { | ||
BOOST_THROW_EXCEPTION(ScriptError("Cannot set cipher list to SSL context for cipher list: '" | ||
+ cipherList + "'.", di)); | ||
+ cipherList + "'.", std::move(di))); | ||
} | ||
} | ||
|
||
#ifndef _WIN32 | ||
if (!protocolmin.IsEmpty()){ | ||
try { | ||
SetTlsProtocolminToSSLContext(context, protocolmin); | ||
} catch (const std::exception&) { | ||
BOOST_THROW_EXCEPTION(ScriptError("Cannot set minimum TLS protocol version to SSL context with tls_protocolmin: '" + protocolmin + "'.", di)); | ||
BOOST_THROW_EXCEPTION(ScriptError("Cannot set minimum TLS protocol version to SSL context with tls_protocolmin: '" + protocolmin + "'.", std::move(di))); | ||
} | ||
} | ||
#endif /* _WIN32 */ | ||
|
||
return context; | ||
} | ||
|
||
#ifndef _WIN32 | ||
/** | ||
* 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 Shared<boost::asio::ssl::context>::Ptr& context, const String& tlsProtocolmin) | ||
void SetTlsProtocolminToSSLContext(const Shared<TlsContext>::Ptr& context, const String& tlsProtocolmin) | ||
{ | ||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L | ||
# if OPENSSL_VERSION_NUMBER >= 0x10100000L | ||
int ret = SSL_CTX_set_min_proto_version(context->native_handle(), ResolveTlsProtocolVersion(tlsProtocolmin)); | ||
|
||
if (ret != 1) { | ||
|
@@ -342,20 +352,21 @@ void SetTlsProtocolminToSSLContext(const Shared<boost::asio::ssl::context>::Ptr& | |
<< boost::errinfo_api_function("SSL_CTX_set_min_proto_version") | ||
<< errinfo_openssl_error(ERR_peek_error())); | ||
} | ||
#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ | ||
# else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ | ||
// This should never happen. On this OpenSSL version, ResolveTlsProtocolVersion() should either return TLS 1.2 | ||
// or throw an exception, as that's the only TLS version supported by both Icinga and ancient OpenSSL. | ||
VERIFY(ResolveTlsProtocolVersion(tlsProtocolmin) == TLS1_2_VERSION); | ||
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ | ||
# endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ | ||
} | ||
#endif /* _WIN32 */ | ||
|
||
/** | ||
* Loads a CRL and appends its certificates to the specified Boost SSL context. | ||
* | ||
* @param context The SSL context. | ||
* @param crlPath The path to the CRL file. | ||
*/ | ||
void AddCRLToSSLContext(const Shared<boost::asio::ssl::context>::Ptr& context, const String& crlPath) | ||
void AddCRLToSSLContext(const Shared<TlsContext>::Ptr& context, const String& crlPath) | ||
{ | ||
X509_STORE *x509_store = SSL_CTX_get_cert_store(context->native_handle()); | ||
AddCRLToSSLContext(x509_store, crlPath); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is SSL_OP_ALL, which workarounds bugs in foreign clients, e.g. SSL_OP_SAFARI_ECDHE_ECDSA_BUG. If nobody's against, I'd omit this on Windows (given there's an equivalent at all).