Commit 95c8e072 authored by Anirudh Ramachandran's avatar Anirudh Ramachandran Committed by Facebook Github Bot

OpenSSL 1.1.0 compatibility

Summary: Add more layers to support compiling with OpenSSL 1.1.0

Reviewed By: yfeldblum

Differential Revision: D4406876

fbshipit-source-id: 8eff7e4f8e096605fc9e1093ef533b5afe0ee539
parent 7d0d018f
...@@ -177,14 +177,20 @@ void setup_SSL_CTX(SSL_CTX *ctx) { ...@@ -177,14 +177,20 @@ void setup_SSL_CTX(SSL_CTX *ctx) {
} }
BIO_METHOD sslBioMethod; // Note: This is a Leaky Meyer's Singleton. The reason we can't use a non-leaky
// thing is because we will be setting this BIO_METHOD* inside BIOs owned by
// various SSL objects which may get callbacks even during teardown. We may
// eventually try to fix this
static BIO_METHOD* getSSLBioMethod() {
static auto const instance = OpenSSLUtils::newSocketBioMethod().release();
return instance;
}
void* initsslBioMethod(void) { void* initsslBioMethod(void) {
memcpy(&sslBioMethod, BIO_s_socket(), sizeof(sslBioMethod)); auto sslBioMethod = getSSLBioMethod();
// override the bwrite method for MSG_EOR support // override the bwrite method for MSG_EOR support
OpenSSLUtils::setCustomBioWriteMethod( OpenSSLUtils::setCustomBioWriteMethod(sslBioMethod, AsyncSSLSocket::bioWrite);
&sslBioMethod, AsyncSSLSocket::bioWrite); OpenSSLUtils::setCustomBioReadMethod(sslBioMethod, AsyncSSLSocket::bioRead);
OpenSSLUtils::setCustomBioReadMethod(&sslBioMethod, AsyncSSLSocket::bioRead);
// Note that the sslBioMethod.type and sslBioMethod.name are not // Note that the sslBioMethod.type and sslBioMethod.name are not
// set here. openssl code seems to be checking ".type == BIO_TYPE_SOCKET" and // set here. openssl code seems to be checking ".type == BIO_TYPE_SOCKET" and
...@@ -480,7 +486,6 @@ void AsyncSSLSocket::sslAccept( ...@@ -480,7 +486,6 @@ void AsyncSSLSocket::sslAccept(
checkForImmediateRead(); checkForImmediateRead();
} }
#if OPENSSL_VERSION_NUMBER >= 0x009080bfL
void AsyncSSLSocket::attachSSLContext( void AsyncSSLSocket::attachSSLContext(
const std::shared_ptr<SSLContext>& ctx) { const std::shared_ptr<SSLContext>& ctx) {
...@@ -503,10 +508,16 @@ void AsyncSSLSocket::attachSSLContext( ...@@ -503,10 +508,16 @@ void AsyncSSLSocket::attachSSLContext(
// We need to update the initial_ctx if necessary // We need to update the initial_ctx if necessary
auto sslCtx = ctx->getSSLCtx(); auto sslCtx = ctx->getSSLCtx();
SSL_CTX_up_ref(sslCtx); SSL_CTX_up_ref(sslCtx);
#ifndef OPENSSL_NO_TLSEXT
// note that detachSSLContext has already freed ssl_->initial_ctx // The 'initial_ctx' inside an SSL* points to the context that it was created
ssl_->initial_ctx = sslCtx; // with, which is also where session callbacks and servername callbacks
#endif // happen.
// When we switch to a different SSL_CTX, we want to update the initial_ctx as
// well so that any callbacks don't go to a different object
// NOTE: this will only work if we have access to ssl_ internals, so it may
// not work on
// OpenSSL version >= 1.1.0
OpenSSLUtils::setSSLInitialCtx(ssl_, sslCtx);
// Detach sets the socket's context to the dummy context. Thus we must acquire // Detach sets the socket's context to the dummy context. Thus we must acquire
// this lock. // this lock.
SpinLockGuard guard(dummyCtxLock); SpinLockGuard guard(dummyCtxLock);
...@@ -521,14 +532,20 @@ void AsyncSSLSocket::detachSSLContext() { ...@@ -521,14 +532,20 @@ void AsyncSSLSocket::detachSSLContext() {
if (!ssl_) { if (!ssl_) {
return; return;
} }
// Detach the initial_ctx as well. Internally w/ OPENSSL_NO_TLSEXT // The 'initial_ctx' inside an SSL* points to the context that it was created
// it is used for session info. It will be reattached in attachSSLContext // with, which is also where session callbacks and servername callbacks
#ifndef OPENSSL_NO_TLSEXT // happen.
if (ssl_->initial_ctx) { // Detach the initial_ctx as well. It will be reattached in attachSSLContext
SSL_CTX_free(ssl_->initial_ctx); // it is used for session info.
ssl_->initial_ctx = nullptr; // NOTE: this will only work if we have access to ssl_ internals, so it may
// not work on
// OpenSSL version >= 1.1.0
SSL_CTX* initialCtx = OpenSSLUtils::getSSLInitialCtx(ssl_);
if (initialCtx) {
SSL_CTX_free(initialCtx);
OpenSSLUtils::setSSLInitialCtx(ssl_, nullptr);
} }
#endif
SpinLockGuard guard(dummyCtxLock); SpinLockGuard guard(dummyCtxLock);
if (nullptr == dummyCtx) { if (nullptr == dummyCtx) {
// We need to lazily initialize the dummy context so we don't // We need to lazily initialize the dummy context so we don't
...@@ -541,7 +558,6 @@ void AsyncSSLSocket::detachSSLContext() { ...@@ -541,7 +558,6 @@ void AsyncSSLSocket::detachSSLContext() {
// would not be thread safe. // would not be thread safe.
SSL_set_SSL_CTX(ssl_, dummyCtx->getSSLCtx()); SSL_set_SSL_CTX(ssl_, dummyCtx->getSSLCtx());
} }
#endif
#if FOLLY_OPENSSL_HAS_SNI #if FOLLY_OPENSSL_HAS_SNI
void AsyncSSLSocket::switchServerSSLContext( void AsyncSSLSocket::switchServerSSLContext(
...@@ -574,10 +590,8 @@ bool AsyncSSLSocket::isServerNameMatch() const { ...@@ -574,10 +590,8 @@ bool AsyncSSLSocket::isServerNameMatch() const {
return false; return false;
} }
if(!ss->tlsext_hostname) { auto tlsextHostname = SSL_SESSION_get0_hostname(ss);
return false; return (tlsextHostname && !tlsextHostname_.compare(tlsextHostname));
}
return (tlsextHostname_.compare(ss->tlsext_hostname) ? false : true);
} }
void AsyncSSLSocket::setServerName(std::string serverName) noexcept { void AsyncSSLSocket::setServerName(std::string serverName) noexcept {
...@@ -723,7 +737,7 @@ void AsyncSSLSocket::applyVerificationOptions(SSL * ssl) { ...@@ -723,7 +737,7 @@ void AsyncSSLSocket::applyVerificationOptions(SSL * ssl) {
} }
bool AsyncSSLSocket::setupSSLBio() { bool AsyncSSLSocket::setupSSLBio() {
auto sslBio = BIO_new(&sslBioMethod); auto sslBio = BIO_new(getSSLBioMethod());
if (!sslBio) { if (!sslBio) {
return false; return false;
...@@ -911,7 +925,7 @@ int AsyncSSLSocket::getSSLVersion() const { ...@@ -911,7 +925,7 @@ int AsyncSSLSocket::getSSLVersion() const {
const char *AsyncSSLSocket::getSSLCertSigAlgName() const { const char *AsyncSSLSocket::getSSLCertSigAlgName() const {
X509 *cert = (ssl_ != nullptr) ? SSL_get_certificate(ssl_) : nullptr; X509 *cert = (ssl_ != nullptr) ? SSL_get_certificate(ssl_) : nullptr;
if (cert) { if (cert) {
int nid = OBJ_obj2nid(cert->sig_alg->algorithm); int nid = X509_get_signature_nid(cert);
return OBJ_nid2ln(nid); return OBJ_nid2ln(nid);
} }
return nullptr; return nullptr;
......
...@@ -833,7 +833,7 @@ void SSLContext::initializeOpenSSLLocked() { ...@@ -833,7 +833,7 @@ void SSLContext::initializeOpenSSLLocked() {
SSL_load_error_strings(); SSL_load_error_strings();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
// static locking // static locking
locks().reset(new SSLLock[size_t(::CRYPTO_num_locks())]); locks().reset(new SSLLock[size_t(CRYPTO_num_locks())]);
for (auto it: lockTypes()) { for (auto it: lockTypes()) {
locks()[size_t(it.first)].lockType = it.second; locks()[size_t(it.first)].lockType = it.second;
} }
...@@ -869,7 +869,7 @@ void SSLContext::cleanupOpenSSLLocked() { ...@@ -869,7 +869,7 @@ void SSLContext::cleanupOpenSSLLocked() {
CRYPTO_cleanup_all_ex_data(); CRYPTO_cleanup_all_ex_data();
ERR_free_strings(); ERR_free_strings();
EVP_cleanup(); EVP_cleanup();
ERR_remove_state(0); ERR_clear_error();
locks().reset(); locks().reset();
initialized_ = false; initialized_ = false;
} }
......
...@@ -26,11 +26,13 @@ ...@@ -26,11 +26,13 @@
#include <openssl/ecdsa.h> #include <openssl/ecdsa.h>
#endif #endif
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <folly/Memory.h> #include <folly/Memory.h>
#include <folly/portability/OpenSSL.h>
namespace folly { namespace folly {
namespace ssl { namespace ssl {
...@@ -65,11 +67,19 @@ using EvpPkeyCtxUniquePtr = std::unique_ptr<EVP_PKEY_CTX, EvpPkeyCtxDeleter>; ...@@ -65,11 +67,19 @@ using EvpPkeyCtxUniquePtr = std::unique_ptr<EVP_PKEY_CTX, EvpPkeyCtxDeleter>;
#else #else
struct EVP_PKEY_CTX; struct EVP_PKEY_CTX;
#endif #endif
using EvpMdCtxDeleter = using EvpMdCtxDeleter =
folly::static_function_deleter<EVP_MD_CTX, &EVP_MD_CTX_destroy>; folly::static_function_deleter<EVP_MD_CTX, &EVP_MD_CTX_free>;
using EvpMdCtxUniquePtr = std::unique_ptr<EVP_MD_CTX, EvpMdCtxDeleter>; using EvpMdCtxUniquePtr = std::unique_ptr<EVP_MD_CTX, EvpMdCtxDeleter>;
// HMAC
using HmacCtxDeleter = folly::static_function_deleter<HMAC_CTX, &HMAC_CTX_free>;
using HmacCtxUniquePtr = std::unique_ptr<HMAC_CTX, HmacCtxDeleter>;
// BIO // BIO
using BioMethodDeleter =
folly::static_function_deleter<BIO_METHOD, &BIO_meth_free>;
using BioMethodUniquePtr = std::unique_ptr<BIO_METHOD, BioMethodDeleter>;
using BioDeleter = folly::static_function_deleter<BIO, &BIO_vfree>; using BioDeleter = folly::static_function_deleter<BIO, &BIO_vfree>;
using BioUniquePtr = std::unique_ptr<BIO, BioDeleter>; using BioUniquePtr = std::unique_ptr<BIO, BioDeleter>;
using BioChainDeleter = folly::static_function_deleter<BIO, &BIO_free_all>; using BioChainDeleter = folly::static_function_deleter<BIO, &BIO_free_all>;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <unordered_map> #include <unordered_map>
namespace { namespace {
#if defined(OPENSSL_IS_BORINGSSL) #ifdef OPENSSL_IS_BORINGSSL
// BoringSSL doesn't (as of May 2016) export the equivalent // BoringSSL doesn't (as of May 2016) export the equivalent
// of BIO_sock_should_retry, so this is one way around it :( // of BIO_sock_should_retry, so this is one way around it :(
static int boringssl_bio_fd_should_retry(int err); static int boringssl_bio_fd_should_retry(int err);
...@@ -196,6 +196,48 @@ const std::string& OpenSSLUtils::getCipherName(uint16_t cipherCode) { ...@@ -196,6 +196,48 @@ const std::string& OpenSSLUtils::getCipherName(uint16_t cipherCode) {
} }
} }
void OpenSSLUtils::setSSLInitialCtx(SSL* ssl, SSL_CTX* ctx) {
#if !FOLLY_OPENSSL_IS_110 && !defined(OPENSSL_NO_TLSEXT)
if (ssl) {
ssl->initial_ctx = ctx;
}
#endif
}
SSL_CTX* OpenSSLUtils::getSSLInitialCtx(SSL* ssl) {
#if !FOLLY_OPENSSL_IS_110 && !defined(OPENSSL_NO_TLSEXT)
if (ssl) {
return ssl->initial_ctx;
}
#endif
return nullptr;
}
BioMethodUniquePtr OpenSSLUtils::newSocketBioMethod() {
BIO_METHOD* newmeth = nullptr;
#if FOLLY_OPENSSL_IS_110
if (!(newmeth = BIO_meth_new(BIO_TYPE_SOCKET, "socket_bio_method"))) {
return nullptr;
}
auto meth = const_cast<BIO_METHOD*>(BIO_s_socket());
BIO_meth_set_create(newmeth, BIO_meth_get_create(meth));
BIO_meth_set_destroy(newmeth, BIO_meth_get_destroy(meth));
BIO_meth_set_ctrl(newmeth, BIO_meth_get_ctrl(meth));
BIO_meth_set_callback_ctrl(newmeth, BIO_meth_get_callback_ctrl(meth));
BIO_meth_set_read(newmeth, BIO_meth_get_read(meth));
BIO_meth_set_write(newmeth, BIO_meth_get_write(meth));
BIO_meth_set_gets(newmeth, BIO_meth_get_gets(meth));
BIO_meth_set_puts(newmeth, BIO_meth_get_puts(meth));
#else
if (!(newmeth = (BIO_METHOD*)OPENSSL_malloc(sizeof(BIO_METHOD)))) {
return nullptr;
}
memcpy(newmeth, BIO_s_socket(), sizeof(BIO_METHOD));
#endif
return BioMethodUniquePtr(newmeth);
}
bool OpenSSLUtils::setCustomBioReadMethod( bool OpenSSLUtils::setCustomBioReadMethod(
BIO_METHOD* bioMeth, BIO_METHOD* bioMeth,
int (*meth)(BIO*, char*, int)) { int (*meth)(BIO*, char*, int)) {
...@@ -214,7 +256,7 @@ bool OpenSSLUtils::setCustomBioWriteMethod( ...@@ -214,7 +256,7 @@ bool OpenSSLUtils::setCustomBioWriteMethod(
int OpenSSLUtils::getBioShouldRetryWrite(int r) { int OpenSSLUtils::getBioShouldRetryWrite(int r) {
int ret = 0; int ret = 0;
#if defined(OPENSSL_IS_BORINGSSL) #ifdef OPENSSL_IS_BORINGSSL
ret = boringssl_bio_fd_should_retry(r); ret = boringssl_bio_fd_should_retry(r);
#else #else
ret = BIO_sock_should_retry(r); ret = BIO_sock_should_retry(r);
...@@ -223,7 +265,7 @@ int OpenSSLUtils::getBioShouldRetryWrite(int r) { ...@@ -223,7 +265,7 @@ int OpenSSLUtils::getBioShouldRetryWrite(int r) {
} }
void OpenSSLUtils::setBioAppData(BIO* b, void* ptr) { void OpenSSLUtils::setBioAppData(BIO* b, void* ptr) {
#if defined(OPENSSL_IS_BORINGSSL) #ifdef OPENSSL_IS_BORINGSSL
BIO_set_callback_arg(b, static_cast<char*>(ptr)); BIO_set_callback_arg(b, static_cast<char*>(ptr));
#else #else
BIO_set_app_data(b, ptr); BIO_set_app_data(b, ptr);
...@@ -231,21 +273,13 @@ void OpenSSLUtils::setBioAppData(BIO* b, void* ptr) { ...@@ -231,21 +273,13 @@ void OpenSSLUtils::setBioAppData(BIO* b, void* ptr) {
} }
void* OpenSSLUtils::getBioAppData(BIO* b) { void* OpenSSLUtils::getBioAppData(BIO* b) {
#if defined(OPENSSL_IS_BORINGSSL) #ifdef OPENSSL_IS_BORINGSSL
return BIO_get_callback_arg(b); return BIO_get_callback_arg(b);
#else #else
return BIO_get_app_data(b); return BIO_get_app_data(b);
#endif #endif
} }
void OpenSSLUtils::setCustomBioMethod(BIO* b, BIO_METHOD* meth) {
#if defined(OPENSSL_IS_BORINGSSL)
b->method = meth;
#else
BIO_set(b, meth);
#endif
}
int OpenSSLUtils::getBioFd(BIO* b, int* fd) { int OpenSSLUtils::getBioFd(BIO* b, int* fd) {
#ifdef _WIN32 #ifdef _WIN32
int ret = portability::sockets::socket_to_fd((SOCKET)BIO_get_fd(b, fd)); int ret = portability::sockets::socket_to_fd((SOCKET)BIO_get_fd(b, fd));
...@@ -275,7 +309,7 @@ void OpenSSLUtils::setBioFd(BIO* b, int fd, int flags) { ...@@ -275,7 +309,7 @@ void OpenSSLUtils::setBioFd(BIO* b, int fd, int flags) {
} // folly } // folly
namespace { namespace {
#if defined(OPENSSL_IS_BORINGSSL) #ifdef OPENSSL_IS_BORINGSSL
static int boringssl_bio_fd_non_fatal_error(int err) { static int boringssl_bio_fd_non_fatal_error(int err) {
if ( if (
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#pragma once #pragma once
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
#include <folly/portability/Sockets.h> #include <folly/portability/Sockets.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
...@@ -91,10 +92,25 @@ class OpenSSLUtils { ...@@ -91,10 +92,25 @@ class OpenSSLUtils {
*/ */
static const std::string& getCipherName(uint16_t cipherCode); static const std::string& getCipherName(uint16_t cipherCode);
/**
* Set the 'initial_ctx' SSL_CTX* inside an SSL. The initial_ctx is used to
* point to the SSL_CTX on which servername callback and session callbacks,
* as well as session caching stats are set. If we want to enforce SSL_CTX
* thread-based ownership (e.g., thread-local SSL_CTX) in the application, we
* need to also set/reset the initial_ctx when we call SSL_set_SSL_CTX.
*
* @param ssl SSL pointer
* @param ctx SSL_CTX pointer
* @return Cipher name, or empty if the code is not found
*/
static void setSSLInitialCtx(SSL* ssl, SSL_CTX* ctx);
static SSL_CTX* getSSLInitialCtx(SSL* ssl);
/** /**
* Wrappers for BIO operations that may be different across different * Wrappers for BIO operations that may be different across different
* versions/flavors of OpenSSL (including forks like BoringSSL) * versions/flavors of OpenSSL (including forks like BoringSSL)
*/ */
static BioMethodUniquePtr newSocketBioMethod();
static bool setCustomBioReadMethod( static bool setCustomBioReadMethod(
BIO_METHOD* bioMeth, BIO_METHOD* bioMeth,
int (*meth)(BIO*, char*, int)); int (*meth)(BIO*, char*, int));
...@@ -104,7 +120,6 @@ class OpenSSLUtils { ...@@ -104,7 +120,6 @@ class OpenSSLUtils {
static int getBioShouldRetryWrite(int ret); static int getBioShouldRetryWrite(int ret);
static void setBioAppData(BIO* b, void* ptr); static void setBioAppData(BIO* b, void* ptr);
static void* getBioAppData(BIO* b); static void* getBioAppData(BIO* b);
static void setCustomBioMethod(BIO*, BIO_METHOD*);
static int getBioFd(BIO* b, int* fd); static int getBioFd(BIO* b, int* fd);
static void setBioFd(BIO* b, int fd, int flags); static void setBioFd(BIO* b, int fd, int flags);
}; };
......
...@@ -755,8 +755,10 @@ class TestSSLAsyncCacheServer : public TestSSLServer { ...@@ -755,8 +755,10 @@ class TestSSLAsyncCacheServer : public TestSSLServer {
int lookupDelay = 100) : int lookupDelay = 100) :
TestSSLServer(acb) { TestSSLServer(acb) {
SSL_CTX *sslCtx = ctx_->getSSLCtx(); SSL_CTX *sslCtx = ctx_->getSSLCtx();
#ifdef SSL_ERROR_WANT_SESS_CACHE_LOOKUP
SSL_CTX_sess_set_get_cb(sslCtx, SSL_CTX_sess_set_get_cb(sslCtx,
TestSSLAsyncCacheServer::getSessionCallback); TestSSLAsyncCacheServer::getSessionCallback);
#endif
SSL_CTX_set_session_cache_mode( SSL_CTX_set_session_cache_mode(
sslCtx, SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_SERVER); sslCtx, SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_SERVER);
asyncCallbacks_ = 0; asyncCallbacks_ = 0;
......
...@@ -14,17 +14,22 @@ ...@@ -14,17 +14,22 @@
* limitations under the License. * limitations under the License.
*/ */
#include <folly/portability/OpenSSL.h> #include <folly/portability/OpenSSL.h>
#include <stdexcept>
namespace folly { namespace folly {
namespace ssl { namespace ssl {
#ifdef OPENSSL_IS_BORINGSSL #if FOLLY_OPENSSL_IS_110
int SSL_CTX_set1_sigalgs_list(SSL_CTX*, const char*) { ////////////////////////////////////////////////////////////////////////////////
return 1; // 0 implies error // APIs needed in 1.1.0 only
} ////////////////////////////////////////////////////////////////////////////////
int TLS1_get_client_version(SSL* s) { #else
return s->client_version; ////////////////////////////////////////////////////////////////////////////////
// APIs needed in BoringSSL and OpenSSL != 1.1.0 (1.0.2, 1.0.1, 1.0.0...)
////////////////////////////////////////////////////////////////////////////////
void BIO_meth_free(BIO_METHOD* biom) {
OPENSSL_free((void*)biom);
} }
int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int)) { int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int)) {
...@@ -37,19 +42,57 @@ int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int)) { ...@@ -37,19 +42,57 @@ int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int)) {
return 1; return 1;
} }
#elif FOLLY_OPENSSL_IS_102 || FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100 void EVP_MD_CTX_free(EVP_MD_CTX* ctx) {
EVP_MD_CTX_destroy(ctx);
}
#if FOLLY_OPENSSL_IS_100 const char* SSL_SESSION_get0_hostname(const SSL_SESSION* s) {
uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c) { return s->tlsext_hostname;
return c->id;
} }
int TLS1_get_client_version(const SSL* s) { EVP_MD_CTX* EVP_MD_CTX_new(void) {
return (s->client_version >> 8) == TLS1_VERSION_MAJOR ? s->client_version : 0; EVP_MD_CTX* ctx = (EVP_MD_CTX*)OPENSSL_malloc(sizeof(EVP_MD_CTX));
if (!ctx) {
throw std::runtime_error("Cannot allocate EVP_MD_CTX");
}
EVP_MD_CTX_init(ctx);
return ctx;
} }
#endif HMAC_CTX* HMAC_CTX_new(void) {
HMAC_CTX* ctx = (HMAC_CTX*)OPENSSL_malloc(sizeof(HMAC_CTX));
if (!ctx) {
throw std::runtime_error("Cannot allocate HMAC_CTX");
}
HMAC_CTX_init(ctx);
return ctx;
}
void HMAC_CTX_free(HMAC_CTX* ctx) {
if (ctx) {
OPENSSL_free(ctx);
}
}
#ifdef OPENSSL_IS_BORINGSSL
////////////////////////////////////////////////////////////////////////////////
// APIs needed in BoringSSL only
////////////////////////////////////////////////////////////////////////////////
int SSL_CTX_set1_sigalgs_list(SSL_CTX*, const char*) {
return 1; // 0 implies error
}
int TLS1_get_client_version(SSL* s) {
// Note that this isn't the client version, and the API to
// get this has been hidden. It may be found by parsing the
// ClientHello (there is a callback via the SSL_HANDSHAKE struct)
return s->version;
}
#elif FOLLY_OPENSSL_IS_102 || FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100
////////////////////////////////////////////////////////////////////////////////
// APIs needed in 1.0.2 and 1.0.1/1.0.0 (both deprecated)
////////////////////////////////////////////////////////////////////////////////
int SSL_CTX_up_ref(SSL_CTX* ctx) { int SSL_CTX_up_ref(SSL_CTX* ctx) {
return CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); return CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
} }
...@@ -62,18 +105,35 @@ int X509_up_ref(X509* x) { ...@@ -62,18 +105,35 @@ int X509_up_ref(X509* x) {
return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
} }
int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int)) { #if FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100
biom->bread = read; ////////////////////////////////////////////////////////////////////////////////
return 1; // APIs needed in 1.0.1/1.0.0 (both deprecated)
////////////////////////////////////////////////////////////////////////////////
int X509_get_signature_nid(X509* cert) {
return OBJ_obj2nid(cert->sig_alg->algorithm);
} }
int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int)) { #endif
biom->bwrite = write;
return 1; #if FOLLY_OPENSSL_IS_100
////////////////////////////////////////////////////////////////////////////////
// APIs needed only in 1.0.0 only (deprecated)
////////////////////////////////////////////////////////////////////////////////
uint32_t SSL_CIPHER_get_id(const SSL_CIPHER* c) {
return c->id;
} }
#elif FOLLY_OPENSSL_IS_110 int TLS1_get_client_version(const SSL* s) {
return (s->client_version >> 8) == TLS1_VERSION_MAJOR ? s->client_version : 0;
}
#endif #endif
#endif // !(OPENSSL_IS_BORINGSSL ||
// FOLLY_OPENSSL_IS_101 ||
// FOLLY_OPENSSL_IS_102 ||
// FOLLY_OPENSSL_IS_100)
#endif // !FOLLY_OPENSSL_IS_110
} }
} }
...@@ -14,11 +14,21 @@ ...@@ -14,11 +14,21 @@
* limitations under the License. * limitations under the License.
*/ */
//
// This class attempts to "unify" the OpenSSL libcrypto/libssl APIs between
// OpenSSL 1.0.2, 1.1.0 (and some earlier versions) and BoringSSL. The general
// idea is to provide namespaced wrapper methods for versions which do not
// which already exist in BoringSSL and 1.1.0, but there are few APIs such as
// SSL_CTX_set1_sigalgs_list and so on which exist in 1.0.2 but were removed
// in BoringSSL
//
#pragma once #pragma once
// This must come before the OpenSSL includes. // This must come before the OpenSSL includes.
#include <folly/portability/Windows.h> #include <folly/portability/Windows.h>
#include <openssl/evp.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <cstdint> #include <cstdint>
...@@ -60,39 +70,68 @@ namespace ssl { ...@@ -60,39 +70,68 @@ namespace ssl {
#define FOLLY_OPENSSL_HAS_SNI 0 #define FOLLY_OPENSSL_HAS_SNI 0
#endif #endif
// This class attempts to "unify" the OpenSSL libssl APIs between OpenSSL 1.0.2, #if FOLLY_OPENSSL_IS_110
// 1.1.0 and BoringSSL. The general idea is to provide wrapper methods for 1.0.2 ////////////////////////////////////////////////////////////////////////////////
// which already exist in BoringSSL and 1.1.0, but there are few APIs such as // APIs needed in 1.1.0 only
// SSL_CTX_set1_sigalgs_list and so on which exist in 1.0.2 but were removed ////////////////////////////////////////////////////////////////////////////////
// in BoringSSL
#else
////////////////////////////////////////////////////////////////////////////////
// APIs needed in BoringSSL and OpenSSL != 1.1.0 (1.0.2, 1.0.1, 1.0.0...)
////////////////////////////////////////////////////////////////////////////////
void BIO_meth_free(BIO_METHOD* biom);
int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int));
int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int));
void EVP_MD_CTX_free(EVP_MD_CTX* ctx);
const char* SSL_SESSION_get0_hostname(const SSL_SESSION* s);
EVP_MD_CTX* EVP_MD_CTX_new(void);
void EVP_MD_CTX_free(EVP_MD_CTX* ctx);
HMAC_CTX* HMAC_CTX_new(void);
void HMAC_CTX_free(HMAC_CTX* ctx);
#ifdef OPENSSL_IS_BORINGSSL #ifdef OPENSSL_IS_BORINGSSL
////////////////////////////////////////////////////////////////////////////////
// APIs needed in BoringSSL only
////////////////////////////////////////////////////////////////////////////////
int SSL_CTX_set1_sigalgs_list(SSL_CTX* ctx, const char* sigalgs_list); int SSL_CTX_set1_sigalgs_list(SSL_CTX* ctx, const char* sigalgs_list);
int TLS1_get_client_version(SSL* s); int TLS1_get_client_version(SSL* s);
int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int));
int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int));
#elif FOLLY_OPENSSL_IS_102 || FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100 #elif FOLLY_OPENSSL_IS_102 || FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100
////////////////////////////////////////////////////////////////////////////////
// APIs needed in 1.0.2 and 1.0.1/1.0.0 (both deprecated)
////////////////////////////////////////////////////////////////////////////////
#if FOLLY_OPENSSL_IS_100 int SSL_CTX_up_ref(SSL_CTX* session);
int SSL_SESSION_up_ref(SSL_SESSION* session);
int X509_up_ref(X509* x);
uint32_t SSL_CIPHER_get_id(const SSL_CIPHER*); #if FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100
int TLS1_get_client_version(const SSL*); ////////////////////////////////////////////////////////////////////////////////
// APIs needed in 1.0.1/1.0.0 (both deprecated)
////////////////////////////////////////////////////////////////////////////////
int X509_get_signature_nid(X509* cert);
#endif #endif
int SSL_CTX_up_ref(SSL_CTX* session); #if FOLLY_OPENSSL_IS_100
int SSL_SESSION_up_ref(SSL_SESSION* session); ////////////////////////////////////////////////////////////////////////////////
int X509_up_ref(X509* x); // APIs needed only in 1.0.0 only (deprecated)
int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int)); ////////////////////////////////////////////////////////////////////////////////
int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int));
#elif FOLLY_OPENSSL_IS_110 uint32_t SSL_CIPHER_get_id(const SSL_CIPHER*);
int TLS1_get_client_version(const SSL*);
#endif
#else #else
#warning Compiling with unsupported OpenSSL version #warning Compiling with unsupported OpenSSL version
#endif
#endif // !(OPENSSL_IS_BORINGSSL || FOLLY_OPENSSL_IS_101 ||
// FOLLY_OPENSSL_IS_102 || FOLLY_OPENSSL_IS_100)
#endif // !FOLLY_OPENSSL_IS_110
} // ssl } // ssl
} // folly } // folly
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#pragma once #pragma once
#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
#include <folly/portability/OpenSSL.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/sha.h> #include <openssl/sha.h>
...@@ -33,18 +35,15 @@ class OpenSSLHash { ...@@ -33,18 +35,15 @@ class OpenSSLHash {
class Digest { class Digest {
public: public:
Digest() { Digest() : ctx_(EVP_MD_CTX_new()) {}
EVP_MD_CTX_init(&ctx_);
}
~Digest() {
EVP_MD_CTX_cleanup(&ctx_);
}
void hash_init(const EVP_MD* md) { void hash_init(const EVP_MD* md) {
md_ = md; md_ = md;
check_libssl_result(1, EVP_DigestInit_ex(&ctx_, md, nullptr)); check_libssl_result(1, EVP_DigestInit_ex(ctx_.get(), md, nullptr));
} }
void hash_update(ByteRange data) { void hash_update(ByteRange data) {
check_libssl_result(1, EVP_DigestUpdate(&ctx_, data.data(), data.size())); check_libssl_result(
1, EVP_DigestUpdate(ctx_.get(), data.data(), data.size()));
} }
void hash_update(const IOBuf& data) { void hash_update(const IOBuf& data) {
for (auto r : data) { for (auto r : data) {
...@@ -55,13 +54,13 @@ class OpenSSLHash { ...@@ -55,13 +54,13 @@ class OpenSSLHash {
const auto size = EVP_MD_size(md_); const auto size = EVP_MD_size(md_);
check_out_size(size_t(size), out); check_out_size(size_t(size), out);
unsigned int len = 0; unsigned int len = 0;
check_libssl_result(1, EVP_DigestFinal_ex(&ctx_, out.data(), &len)); check_libssl_result(1, EVP_DigestFinal_ex(ctx_.get(), out.data(), &len));
check_libssl_result(size, int(len)); check_libssl_result(size, int(len));
md_ = nullptr; md_ = nullptr;
} }
private: private:
const EVP_MD* md_ = nullptr; const EVP_MD* md_ = nullptr;
EVP_MD_CTX ctx_; EvpMdCtxUniquePtr ctx_{nullptr};
}; };
static void hash( static void hash(
...@@ -97,19 +96,16 @@ class OpenSSLHash { ...@@ -97,19 +96,16 @@ class OpenSSLHash {
class Hmac { class Hmac {
public: public:
Hmac() { Hmac() : ctx_(HMAC_CTX_new()) {}
HMAC_CTX_init(&ctx_);
}
~Hmac() {
HMAC_CTX_cleanup(&ctx_);
}
void hash_init(const EVP_MD* md, ByteRange key) { void hash_init(const EVP_MD* md, ByteRange key) {
md_ = md; md_ = md;
check_libssl_result( check_libssl_result(
1, HMAC_Init_ex(&ctx_, key.data(), int(key.size()), md_, nullptr)); 1,
HMAC_Init_ex(ctx_.get(), key.data(), int(key.size()), md_, nullptr));
} }
void hash_update(ByteRange data) { void hash_update(ByteRange data) {
check_libssl_result(1, HMAC_Update(&ctx_, data.data(), data.size())); check_libssl_result(1, HMAC_Update(ctx_.get(), data.data(), data.size()));
} }
void hash_update(const IOBuf& data) { void hash_update(const IOBuf& data) {
for (auto r : data) { for (auto r : data) {
...@@ -120,13 +116,13 @@ class OpenSSLHash { ...@@ -120,13 +116,13 @@ class OpenSSLHash {
const auto size = EVP_MD_size(md_); const auto size = EVP_MD_size(md_);
check_out_size(size_t(size), out); check_out_size(size_t(size), out);
unsigned int len = 0; unsigned int len = 0;
check_libssl_result(1, HMAC_Final(&ctx_, out.data(), &len)); check_libssl_result(1, HMAC_Final(ctx_.get(), out.data(), &len));
check_libssl_result(size, int(len)); check_libssl_result(size, int(len));
md_ = nullptr; md_ = nullptr;
} }
private: private:
const EVP_MD* md_ = nullptr; const EVP_MD* md_ = nullptr;
HMAC_CTX ctx_; HmacCtxUniquePtr ctx_{nullptr};
}; };
static void hmac( static void hmac(
......
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