Unverified Commit a90fecd2 authored by Igor [hyperxor]'s avatar Igor [hyperxor] Committed by GitHub

SSL usage improvements: using RAII for ssl context resource (#740)

* SSL usage improvements: using RAII for ssl context resource

* Remove C style casts in listener
parent 3a72456c
...@@ -80,7 +80,7 @@ public: ...@@ -80,7 +80,7 @@ public:
* [1] https://en.wikipedia.org/wiki/BREACH * [1] https://en.wikipedia.org/wiki/BREACH
* [2] https://en.wikipedia.org/wiki/CRIME * [2] https://en.wikipedia.org/wiki/CRIME
*/ */
void useSSL(std::string cert, std::string key, bool use_compression = false); void useSSL(const std::string &cert, const std::string &key, bool use_compression = false);
/*! /*!
* \brief Use SSL certificate authentication on this endpoint * \brief Use SSL certificate authentication on this endpoint
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <pistache/net.h> #include <pistache/net.h>
#include <pistache/os.h> #include <pistache/os.h>
#include <pistache/reactor.h> #include <pistache/reactor.h>
#include <pistache/ssl_wrappers.h>
#include <pistache/tcp.h> #include <pistache/tcp.h>
#include <sys/resource.h> #include <sys/resource.h>
...@@ -97,8 +98,8 @@ private: ...@@ -97,8 +98,8 @@ private:
int acceptConnection(struct sockaddr_in &peer_addr) const; int acceptConnection(struct sockaddr_in &peer_addr) const;
void dispatchPeer(const std::shared_ptr<Peer> &peer); void dispatchPeer(const std::shared_ptr<Peer> &peer);
bool useSSL_; bool useSSL_ = false;
void *ssl_ctx_; ssl::SSLCtxPtr ssl_ctx_ = nullptr;
}; };
} // namespace Tcp } // namespace Tcp
......
#pragma once
#ifdef PISTACHE_USE_SSL
#include <openssl/ssl.h>
#endif
#include <memory>
namespace Pistache {
namespace ssl {
struct SSLCtxDeleter {
void operator()(void *ptr) {
#ifdef PISTACHE_USE_SSL
SSL_CTX_free(reinterpret_cast<SSL_CTX *>(ptr));
// EVP_cleanup call is not related to cleaning SSL_CTX, just global cleanup routine.
// TODO: Think about removing EVP_cleanup call at all
// It was deprecated in openssl 1.1.0 version (see
// https://www.openssl.org/news/changelog.txt):
// "Make various cleanup routines no-ops and mark them as deprecated."
EVP_cleanup();
#else
(void)ptr;
#endif
}
};
using SSLCtxPtr = std::unique_ptr<void, SSLCtxDeleter>;
#ifdef PISTACHE_USE_SSL
inline SSL_CTX* GetSSLContext(ssl::SSLCtxPtr &ctx) {
return reinterpret_cast<SSL_CTX *>(ctx.get());
}
#endif
}
}
...@@ -77,7 +77,7 @@ void Endpoint::serveThreaded() { serveImpl(&Tcp::Listener::runThreaded); } ...@@ -77,7 +77,7 @@ void Endpoint::serveThreaded() { serveImpl(&Tcp::Listener::runThreaded); }
void Endpoint::shutdown() { listener.shutdown(); } void Endpoint::shutdown() { listener.shutdown(); }
void Endpoint::useSSL(std::string cert, std::string key, bool use_compression) { void Endpoint::useSSL(const std::string &cert, const std::string &key, bool use_compression) {
#ifndef PISTACHE_USE_SSL #ifndef PISTACHE_USE_SSL
(void)cert; (void)cert;
(void)key; (void)key;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <pistache/listener.h> #include <pistache/listener.h>
#include <pistache/os.h> #include <pistache/os.h>
#include <pistache/peer.h> #include <pistache/peer.h>
#include <pistache/ssl_wrappers.h>
#include <pistache/transport.h> #include <pistache/transport.h>
#include <arpa/inet.h> #include <arpa/inet.h>
...@@ -67,12 +68,12 @@ void setSocketOptions(Fd fd, Flags<Options> options) { ...@@ -67,12 +68,12 @@ void setSocketOptions(Fd fd, Flags<Options> options) {
Listener::Listener() Listener::Listener()
: addr_(), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(), : addr_(), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(),
poller(), options_(), workers_(Const::DefaultWorkers), workersName_(), poller(), options_(), workers_(Const::DefaultWorkers), workersName_(),
reactor_(), transportKey(), useSSL_(false), ssl_ctx_(nullptr) {} reactor_(), transportKey() {}
Listener::Listener(const Address &address) Listener::Listener(const Address &address)
: addr_(address), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(), : addr_(address), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(),
poller(), options_(), workers_(Const::DefaultWorkers), workersName_(), poller(), options_(), workers_(Const::DefaultWorkers), workersName_(),
reactor_(), transportKey(), useSSL_(false), ssl_ctx_(nullptr) {} reactor_(), transportKey() {}
Listener::~Listener() { Listener::~Listener() {
if (isBound()) if (isBound())
...@@ -84,12 +85,6 @@ Listener::~Listener() { ...@@ -84,12 +85,6 @@ Listener::~Listener() {
close(listen_fd); close(listen_fd);
listen_fd = -1; listen_fd = -1;
} }
#ifdef PISTACHE_USE_SSL
if (this->useSSL_) {
SSL_CTX_free((SSL_CTX *)this->ssl_ctx_);
EVP_cleanup();
}
#endif /* PISTACHE_USE_SSL */
} }
void Listener::init(size_t workers, Flags<Options> options, void Listener::init(size_t workers, Flags<Options> options,
...@@ -316,7 +311,7 @@ void Listener::handleNewConnection() { ...@@ -316,7 +311,7 @@ void Listener::handleNewConnection() {
#ifdef PISTACHE_USE_SSL #ifdef PISTACHE_USE_SSL
if (this->useSSL_) { if (this->useSSL_) {
SSL *ssl_data = SSL_new((SSL_CTX *)this->ssl_ctx_); SSL *ssl_data = SSL_new(GetSSLContext(ssl_ctx_));
if (ssl_data == nullptr) { if (ssl_data == nullptr) {
close(client_fd); close(client_fd);
throw std::runtime_error("Cannot create SSL connection"); throw std::runtime_error("Cannot create SSL connection");
...@@ -370,23 +365,22 @@ void Listener::dispatchPeer(const std::shared_ptr<Peer> &peer) { ...@@ -370,23 +365,22 @@ void Listener::dispatchPeer(const std::shared_ptr<Peer> &peer) {
#ifdef PISTACHE_USE_SSL #ifdef PISTACHE_USE_SSL
static SSL_CTX *ssl_create_context(const std::string &cert, namespace {
ssl::SSLCtxPtr ssl_create_context(const std::string &cert,
const std::string &key, const std::string &key,
bool use_compression) { bool use_compression) {
const SSL_METHOD *method; const SSL_METHOD* method = SSLv23_server_method();
SSL_CTX *ctx;
method = SSLv23_server_method();
ctx = SSL_CTX_new(method); ssl::SSLCtxPtr ctx{SSL_CTX_new(method)};
if (ctx == NULL) { if (ctx == nullptr) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
throw std::runtime_error("Cannot setup SSL context"); throw std::runtime_error("Cannot setup SSL context");
} }
if (!use_compression) { if (!use_compression) {
/* Disable compression to prevent BREACH and CRIME vulnerabilities. */ /* Disable compression to prevent BREACH and CRIME vulnerabilities. */
if (!SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION)) { if (!SSL_CTX_set_options(GetSSLContext(ctx), SSL_OP_NO_COMPRESSION)) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
throw std::runtime_error("Cannot disable compression"); throw std::runtime_error("Cannot disable compression");
} }
...@@ -397,17 +391,17 @@ static SSL_CTX *ssl_create_context(const std::string &cert, ...@@ -397,17 +391,17 @@ static SSL_CTX *ssl_create_context(const std::string &cert,
SSL_CTX_set_ecdh_auto(ctx, 1); SSL_CTX_set_ecdh_auto(ctx, 1);
#endif /* OPENSSL_VERSION_NUMBER */ #endif /* OPENSSL_VERSION_NUMBER */
if (SSL_CTX_use_certificate_file(ctx, cert.c_str(), SSL_FILETYPE_PEM) <= 0) { if (SSL_CTX_use_certificate_file(GetSSLContext(ctx), cert.c_str(), SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
throw std::runtime_error("Cannot load SSL certificate"); throw std::runtime_error("Cannot load SSL certificate");
} }
if (SSL_CTX_use_PrivateKey_file(ctx, key.c_str(), SSL_FILETYPE_PEM) <= 0) { if (SSL_CTX_use_PrivateKey_file(GetSSLContext(ctx), key.c_str(), SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
throw std::runtime_error("Cannot load SSL private key"); throw std::runtime_error("Cannot load SSL private key");
} }
if (!SSL_CTX_check_private_key(ctx)) { if (!SSL_CTX_check_private_key(GetSSLContext(ctx))) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
throw std::runtime_error( throw std::runtime_error(
"Private key does not match public key in the certificate"); "Private key does not match public key in the certificate");
...@@ -416,13 +410,15 @@ static SSL_CTX *ssl_create_context(const std::string &cert, ...@@ -416,13 +410,15 @@ static SSL_CTX *ssl_create_context(const std::string &cert,
return ctx; return ctx;
} }
}
void Listener::setupSSLAuth(const std::string &ca_file, void Listener::setupSSLAuth(const std::string &ca_file,
const std::string &ca_path, const std::string &ca_path,
int (*cb)(int, void *) = NULL) { int (*cb)(int, void *) = NULL) {
const char *__ca_file = NULL; const char *__ca_file = NULL;
const char *__ca_path = NULL; const char *__ca_path = NULL;
if (this->ssl_ctx_ == NULL) if (ssl_ctx_ == nullptr)
throw std::runtime_error("SSL Context is not initialized"); throw std::runtime_error("SSL Context is not initialized");
if (!ca_file.empty()) if (!ca_file.empty())
...@@ -430,13 +426,13 @@ void Listener::setupSSLAuth(const std::string &ca_file, ...@@ -430,13 +426,13 @@ void Listener::setupSSLAuth(const std::string &ca_file,
if (!ca_path.empty()) if (!ca_path.empty())
__ca_path = ca_path.c_str(); __ca_path = ca_path.c_str();
if (SSL_CTX_load_verify_locations((SSL_CTX *)this->ssl_ctx_, __ca_file, if (SSL_CTX_load_verify_locations(GetSSLContext(ssl_ctx_), __ca_file,
__ca_path) <= 0) { __ca_path) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
throw std::runtime_error("Cannot verify SSL locations"); throw std::runtime_error("Cannot verify SSL locations");
} }
SSL_CTX_set_verify((SSL_CTX *)this->ssl_ctx_, SSL_CTX_set_verify(GetSSLContext(ssl_ctx_),
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
SSL_VERIFY_CLIENT_ONCE, SSL_VERIFY_CLIENT_ONCE,
/* Callback type did change in 1.0.1 */ /* Callback type did change in 1.0.1 */
...@@ -453,8 +449,8 @@ void Listener::setupSSL(const std::string &cert_path, ...@@ -453,8 +449,8 @@ void Listener::setupSSL(const std::string &cert_path,
SSL_load_error_strings(); SSL_load_error_strings();
OpenSSL_add_ssl_algorithms(); OpenSSL_add_ssl_algorithms();
this->ssl_ctx_ = ssl_create_context(cert_path, key_path, use_compression); ssl_ctx_ = ssl_create_context(cert_path, key_path, use_compression);
this->useSSL_ = true; useSSL_ = true;
} }
#endif /* PISTACHE_USE_SSL */ #endif /* PISTACHE_USE_SSL */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment