]> granicus.if.org Git - icinga2/commitdiff
Make ApiListener#m_SSLContext a Boost ASIO SSL context
authorAlexander A. Klimov <alexander.klimov@icinga.com>
Fri, 8 Feb 2019 13:23:10 +0000 (14:23 +0100)
committerAlexander A. Klimov <alexander.klimov@icinga.com>
Mon, 1 Apr 2019 09:40:14 +0000 (11:40 +0200)
lib/base/tlsstream.cpp
lib/base/tlsstream.hpp
lib/base/tlsutility.cpp
lib/base/tlsutility.hpp
lib/remote/apilistener.cpp
lib/remote/apilistener.hpp

index 5d76784176c0f4cba6463bb704a0bbb3286a5109..129d0bc74d631b1b307ae610a59835fca37dd1e6 100644 (file)
@@ -6,6 +6,7 @@
 #include "base/logger.hpp"
 #include "base/configuration.hpp"
 #include "base/convert.hpp"
+#include <boost/asio/ssl/context.hpp>
 #include <iostream>
 
 #ifndef _WIN32
@@ -26,6 +27,28 @@ bool TlsStream::m_SSLIndexInitialized = false;
  * @param sslContext The SSL context for the client.
  */
 TlsStream::TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const std::shared_ptr<SSL_CTX>& sslContext)
+       : TlsStream(socket, hostname, role, sslContext.get())
+{
+}
+
+/**
+ * Constructor for the TlsStream class.
+ *
+ * @param role The role of the client.
+ * @param sslContext The SSL context for the client.
+ */
+TlsStream::TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const std::shared_ptr<boost::asio::ssl::context>& sslContext)
+       : TlsStream(socket, hostname, role, sslContext->native_handle())
+{
+}
+
+/**
+ * Constructor for the TlsStream class.
+ *
+ * @param role The role of the client.
+ * @param sslContext The SSL context for the client.
+ */
+TlsStream::TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, SSL_CTX* sslContext)
        : SocketEvents(socket), m_Eof(false), m_HandshakeOK(false), m_VerifyOK(true), m_ErrorCode(0),
        m_ErrorOccurred(false),  m_Socket(socket), m_Role(role), m_SendQ(new FIFO()), m_RecvQ(new FIFO()),
        m_CurrentAction(TlsActionNone), m_Retry(false), m_Shutdown(false)
@@ -33,7 +56,7 @@ TlsStream::TlsStream(const Socket::Ptr& socket, const String& hostname, Connecti
        std::ostringstream msgbuf;
        char errbuf[120];
 
-       m_SSL = std::shared_ptr<SSL>(SSL_new(sslContext.get()), SSL_free);
+       m_SSL = std::shared_ptr<SSL>(SSL_new(sslContext), SSL_free);
 
        if (!m_SSL) {
                msgbuf << "SSL_new() failed with code " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
index 8af5fb58eb1ef5b456a240a94695793261628912..cd3d0abfa44b7d73a2441d4e2fc217c2ac34af1a 100644 (file)
@@ -9,6 +9,7 @@
 #include "base/stream.hpp"
 #include "base/tlsutility.hpp"
 #include "base/fifo.hpp"
+#include <boost/asio/ssl/context.hpp>
 
 namespace icinga
 {
@@ -32,6 +33,7 @@ public:
        DECLARE_PTR_TYPEDEFS(TlsStream);
 
        TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const std::shared_ptr<SSL_CTX>& sslContext = MakeSSLContext());
+       TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, const std::shared_ptr<boost::asio::ssl::context>& sslContext);
        ~TlsStream() override;
 
        Socket::Ptr GetSocket() const;
@@ -80,6 +82,8 @@ private:
        static int m_SSLIndex;
        static bool m_SSLIndexInitialized;
 
+       TlsStream(const Socket::Ptr& socket, const String& hostname, ConnectionRole role, SSL_CTX* sslContext);
+
        void OnEvent(int revents) override;
 
        void HandleError() const;
index 35f4d3ba504951544dea6f0bd8cf4edd97e9d259..57f8d19016c8b14f6490b42a6fb960547033e14c 100644 (file)
@@ -7,6 +7,7 @@
 #include "base/utility.hpp"
 #include "base/application.hpp"
 #include "base/exception.hpp"
+#include <boost/asio/ssl/context.hpp>
 #include <fstream>
 
 namespace icinga
@@ -57,35 +58,23 @@ void InitializeOpenSSL()
        l_SSLInitialized = true;
 }
 
-/**
- * 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.
- */
-std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey)
+static void SetupSslContext(SSL_CTX *sslContext, const String& pubkey, const String& privkey, const String& cakey)
 {
        char errbuf[120];
 
-       InitializeOpenSSL();
-
-       std::shared_ptr<SSL_CTX> sslContext = std::shared_ptr<SSL_CTX>(SSL_CTX_new(SSLv23_method()), SSL_CTX_free);
-
        long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_CIPHER_SERVER_PREFERENCE;
 
 #ifdef SSL_OP_NO_COMPRESSION
        flags |= SSL_OP_NO_COMPRESSION;
 #endif /* SSL_OP_NO_COMPRESSION */
 
-       SSL_CTX_set_options(sslContext.get(), flags);
+       SSL_CTX_set_options(sslContext, flags);
 
-       SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-       SSL_CTX_set_session_id_context(sslContext.get(), (const unsigned char *)"Icinga 2", 8);
+       SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+       SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)"Icinga 2", 8);
 
        if (!pubkey.IsEmpty()) {
-               if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.CStr())) {
+               if (!SSL_CTX_use_certificate_chain_file(sslContext, pubkey.CStr())) {
                        Log(LogCritical, "SSL")
                                << "Error with public key file '" << pubkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
                        BOOST_THROW_EXCEPTION(openssl_error()
@@ -96,7 +85,7 @@ std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& priv
        }
 
        if (!privkey.IsEmpty()) {
-               if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.CStr(), SSL_FILETYPE_PEM)) {
+               if (!SSL_CTX_use_PrivateKey_file(sslContext, privkey.CStr(), SSL_FILETYPE_PEM)) {
                        Log(LogCritical, "SSL")
                                << "Error with private key file '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
                        BOOST_THROW_EXCEPTION(openssl_error()
@@ -105,7 +94,7 @@ std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& priv
                                << boost::errinfo_file_name(privkey));
                }
 
-               if (!SSL_CTX_check_private_key(sslContext.get())) {
+               if (!SSL_CTX_check_private_key(sslContext)) {
                        Log(LogCritical, "SSL")
                                << "Error checking private key '" << privkey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
                        BOOST_THROW_EXCEPTION(openssl_error()
@@ -115,7 +104,7 @@ std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& priv
        }
 
        if (!cakey.IsEmpty()) {
-               if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), nullptr)) {
+               if (!SSL_CTX_load_verify_locations(sslContext, cakey.CStr(), nullptr)) {
                        Log(LogCritical, "SSL")
                                << "Error loading and verifying locations in ca key file '" << cakey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
                        BOOST_THROW_EXCEPTION(openssl_error()
@@ -136,22 +125,60 @@ std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& priv
                                << boost::errinfo_file_name(cakey));
                }
 
-               SSL_CTX_set_client_CA_list(sslContext.get(), cert_names);
+               SSL_CTX_set_client_CA_list(sslContext, cert_names);
        }
+}
+
+/**
+ * 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.
+ */
+std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey)
+{
+       InitializeOpenSSL();
+
+       std::shared_ptr<SSL_CTX> sslContext = std::shared_ptr<SSL_CTX>(SSL_CTX_new(SSLv23_method()), SSL_CTX_free);
+
+       SetupSslContext(sslContext.get(), pubkey, privkey, cakey);
 
        return sslContext;
 }
 
+/**
+ * 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.
+ */
+std::shared_ptr<boost::asio::ssl::context> MakeAsioSslContext(const String& pubkey, const String& privkey, const String& cakey)
+{
+       namespace ssl = boost::asio::ssl;
+
+       InitializeOpenSSL();
+
+       auto context (std::make_shared<ssl::context>(ssl::context::sslv23));
+
+       SetupSslContext(context->native_handle(), 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 std::shared_ptr<SSL_CTX>& context, const String& cipherList)
+void SetCipherListToSSLContext(const std::shared_ptr<boost::asio::ssl::context>& context, const String& cipherList)
 {
        char errbuf[256];
 
-       if (SSL_CTX_set_cipher_list(context.get(), cipherList.CStr()) == 0) {
+       if (SSL_CTX_set_cipher_list(context->native_handle(), cipherList.CStr()) == 0) {
                Log(LogCritical, "SSL")
                        << "Cipher list '"
                        << cipherList
@@ -171,9 +198,9 @@ void SetCipherListToSSLContext(const std::shared_ptr<SSL_CTX>& context, const St
  * @param context The ssl context.
  * @param tlsProtocolmin The minimum TLS protocol version.
  */
-void SetTlsProtocolminToSSLContext(const std::shared_ptr<SSL_CTX>& context, const String& tlsProtocolmin)
+void SetTlsProtocolminToSSLContext(const std::shared_ptr<boost::asio::ssl::context>& context, const String& tlsProtocolmin)
 {
-       long flags = SSL_CTX_get_options(context.get());
+       long flags = SSL_CTX_get_options(context->native_handle());
 
        flags |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
 
@@ -190,7 +217,7 @@ void SetTlsProtocolminToSSLContext(const std::shared_ptr<SSL_CTX>& context, cons
        if (tlsProtocolmin != SSL_TXT_TLSV1)
                BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid TLS protocol version specified."));
 
-       SSL_CTX_set_options(context.get(), flags);
+       SSL_CTX_set_options(context->native_handle(), flags);
 }
 
 /**
@@ -199,10 +226,10 @@ void SetTlsProtocolminToSSLContext(const std::shared_ptr<SSL_CTX>& context, cons
  * @param context The SSL context.
  * @param crlPath The path to the CRL file.
  */
-void AddCRLToSSLContext(const std::shared_ptr<SSL_CTX>& context, const String& crlPath)
+void AddCRLToSSLContext(const std::shared_ptr<boost::asio::ssl::context>& context, const String& crlPath)
 {
        char errbuf[120];
-       X509_STORE *x509_store = SSL_CTX_get_cert_store(context.get());
+       X509_STORE *x509_store = SSL_CTX_get_cert_store(context->native_handle());
 
        X509_LOOKUP *lookup;
        lookup = X509_STORE_add_lookup(x509_store, X509_LOOKUP_file());
index afe21f2e461744be4ee43dbd21b84adc511fa23f..69b10786c97d10ec2fdb37404cbf9ad6e64e5a75 100644 (file)
@@ -14,6 +14,7 @@
 #include <openssl/x509v3.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
+#include <boost/asio/ssl/context.hpp>
 #include <boost/exception/info.hpp>
 
 namespace icinga
@@ -21,9 +22,10 @@ namespace icinga
 
 void InitializeOpenSSL();
 std::shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey = String(), const String& privkey = String(), const String& cakey = String());
-void AddCRLToSSLContext(const std::shared_ptr<SSL_CTX>& context, const String& crlPath);
-void SetCipherListToSSLContext(const std::shared_ptr<SSL_CTX>& context, const String& cipherList);
-void SetTlsProtocolminToSSLContext(const std::shared_ptr<SSL_CTX>& context, const String& tlsProtocolmin);
+std::shared_ptr<boost::asio::ssl::context> MakeAsioSslContext(const String& pubkey = String(), const String& privkey = String(), const String& cakey = String());
+void AddCRLToSSLContext(const std::shared_ptr<boost::asio::ssl::context>& context, const String& crlPath);
+void SetCipherListToSSLContext(const std::shared_ptr<boost::asio::ssl::context>& context, const String& cipherList);
+void SetTlsProtocolminToSSLContext(const std::shared_ptr<boost::asio::ssl::context>& context, const String& tlsProtocolmin);
 String GetCertificateCN(const std::shared_ptr<X509>& certificate);
 std::shared_ptr<X509> GetX509Certificate(const String& pemfile);
 int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), bool ca = false);
index d8e1832eed3fd5a0751801039cda74e23e5fc9a7..d680cc76a34a8ee13d7be9161c0cf9a59f2c8343 100644 (file)
@@ -22,6 +22,7 @@
 #include <boost/asio/ip/tcp.hpp>
 #include <boost/asio/ip/v6_only.hpp>
 #include <boost/asio/spawn.hpp>
+#include <boost/asio/ssl/context.hpp>
 #include <climits>
 #include <fstream>
 #include <memory>
@@ -165,10 +166,12 @@ void ApiListener::OnConfigLoaded()
 
 void ApiListener::UpdateSSLContext()
 {
-       std::shared_ptr<SSL_CTX> context;
+       namespace ssl = boost::asio::ssl;
+
+       std::shared_ptr<ssl::context> context;
 
        try {
-               context = MakeSSLContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath());
+               context = MakeAsioSslContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath());
        } catch (const std::exception&) {
                BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '"
                        + GetDefaultCertPath() + "' key path: '" + GetDefaultKeyPath() + "' ca path: '" + GetDefaultCaPath() + "'.", GetDebugInfo()));
@@ -338,7 +341,7 @@ bool ApiListener::AddListener(const String& node, const String& service)
 
        ObjectLock olock(this);
 
-       std::shared_ptr<SSL_CTX> sslContext = m_SSLContext;
+       auto sslContext (m_SSLContext);
 
        if (!sslContext) {
                Log(LogCritical, "ApiListener", "SSL context is required for AddListener()");
@@ -389,7 +392,7 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
        {
                ObjectLock olock(this);
 
-               std::shared_ptr<SSL_CTX> sslContext = m_SSLContext;
+               auto sslContext (m_SSLContext);
 
                if (!sslContext) {
                        Log(LogCritical, "ApiListener", "SSL context is required for AddConnection()");
index 96861d74b75b7cf653b7366a5b16e553cc65e00a..1de66ed4fc015bb49e47ee64eb936111f1a7fd19 100644 (file)
@@ -15,6 +15,7 @@
 #include "base/tlsstream.hpp"
 #include "base/threadpool.hpp"
 #include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl/context.hpp>
 #include <set>
 
 namespace icinga
@@ -106,7 +107,7 @@ protected:
        void ValidateTlsHandshakeTimeout(const Lazy<double>& lvalue, const ValidationUtils& utils) override;
 
 private:
-       std::shared_ptr<SSL_CTX> m_SSLContext;
+       std::shared_ptr<boost::asio::ssl::context> m_SSLContext;
 
        mutable boost::mutex m_AnonymousClientsLock;
        mutable boost::mutex m_HttpClientsLock;