diff --git a/lib/base/tlsstream.hpp b/lib/base/tlsstream.hpp index 63814d309..0ea833df1 100644 --- a/lib/base/tlsstream.hpp +++ b/lib/base/tlsstream.hpp @@ -20,6 +20,10 @@ #include #include +#ifdef _WIN32 +# include +#endif /* _WIN32 */ + namespace icinga { @@ -63,7 +67,30 @@ struct UnbufferedAsioTlsStreamParams const String& Hostname; }; -typedef SeenStream> AsioTcpTlsStream; +#ifdef _WIN32 +template +class TlsStream : public boost::wintls::stream +{ +public: + using boost::wintls::stream::stream; + + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + typedef boost::wintls::handshake_type handshake_type; + + static constexpr auto client = boost::wintls::handshake_type::client; + static constexpr auto server = boost::wintls::handshake_type::server; + + lowest_layer_type& lowest_layer() + { + return next_layer().lowest_layer(); + } +}; +#else /* _WIN32 */ +template +using TlsStream = boost::asio::ssl::stream; +#endif /* _WIN32 */ + +typedef SeenStream> AsioTcpTlsStream; class UnbufferedAsioTlsStream : public AsioTcpTlsStream { diff --git a/lib/base/tlsutility.cpp b/lib/base/tlsutility.cpp index 29b5588be..3fe65b856 100644 --- a/lib/base/tlsutility.cpp +++ b/lib/base/tlsutility.cpp @@ -245,14 +245,21 @@ void SetCipherListToSSLContext(const Shared::Ptr& context, const Str * @return The value of the corresponding TLS*_VERSION macro. */ 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 + "'"); } @@ -265,10 +272,26 @@ Shared::Ptr SetupSslContext(const String& certPath, const String& ke Shared::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 = Shared::Make(TlsContext::tls); + context = Shared::Make(method); InitSslContext(context, certPath, keyPath, caPath); } catch (const std::exception&) { @@ -294,6 +317,7 @@ Shared::Ptr SetupSslContext(const String& certPath, const String& ke } } +#ifndef _WIN32 if (!protocolmin.IsEmpty()){ try { SetTlsProtocolminToSSLContext(context, protocolmin); @@ -301,10 +325,12 @@ Shared::Ptr SetupSslContext(const String& certPath, const String& ke 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. * @@ -313,7 +339,7 @@ Shared::Ptr SetupSslContext(const String& certPath, const String& ke */ void SetTlsProtocolminToSSLContext(const Shared::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) { @@ -326,12 +352,13 @@ void SetTlsProtocolminToSSLContext(const Shared::Ptr& context, const << 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. diff --git a/lib/base/tlsutility.hpp b/lib/base/tlsutility.hpp index 90d15fb10..b3d4f23f9 100644 --- a/lib/base/tlsutility.hpp +++ b/lib/base/tlsutility.hpp @@ -22,6 +22,10 @@ #include #include +#ifdef _WIN32 +# include +#endif /* _WIN32 */ + namespace icinga { @@ -38,10 +42,16 @@ const auto LEAF_VALID_FOR = 60 * 60 * 24 * 397; const auto RENEW_THRESHOLD = 60 * 60 * 24 * 30; const auto RENEW_INTERVAL = 60 * 60 * 24; +#ifdef _WIN32 +typedef boost::wintls::context TlsContext; +typedef boost::wintls::method TlsProtocolMin; +#else /* _WIN32 */ typedef boost::asio::ssl::context TlsContext; - typedef int TlsProtocolMin; +void SetTlsProtocolminToSSLContext(const Shared::Ptr& context, const String& tlsProtocolmin); +#endif /* _WIN32 */ + void InitializeOpenSSL(); String GetOpenSSLVersion(); @@ -49,7 +59,6 @@ String GetOpenSSLVersion(); void AddCRLToSSLContext(const Shared::Ptr& context, const String& crlPath); void AddCRLToSSLContext(X509_STORE *x509_store, const String& crlPath); void SetCipherListToSSLContext(const Shared::Ptr& context, const String& cipherList); -void SetTlsProtocolminToSSLContext(const Shared::Ptr& context, const String& tlsProtocolmin); TlsProtocolMin ResolveTlsProtocolVersion(const std::string& version); Shared::Ptr SetupSslContext(const String& certPath = String(), const String& keyPath = String(), const String& caPath = String(),