mirror of https://github.com/Icinga/icinga2.git
Make ApiListener#m_SSLContext a Boost ASIO SSL context
This commit is contained in:
parent
e4f3422b3a
commit
2615967e7f
|
@ -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) << "\"";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()");
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue