OpenSSL 1.1.0 compatibility
authorAnirudh Ramachandran <avr@fb.com>
Tue, 4 Apr 2017 06:29:59 +0000 (23:29 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 4 Apr 2017 06:41:02 +0000 (23:41 -0700)
Summary: Add more layers to support compiling with OpenSSL 1.1.0

Reviewed By: yfeldblum

Differential Revision: D4406876

fbshipit-source-id: 8eff7e4f8e096605fc9e1093ef533b5afe0ee539

folly/io/async/AsyncSSLSocket.cpp
folly/io/async/SSLContext.cpp
folly/io/async/ssl/OpenSSLPtrTypes.h
folly/io/async/ssl/OpenSSLUtils.cpp
folly/io/async/ssl/OpenSSLUtils.h
folly/io/async/test/AsyncSSLSocketTest.h
folly/portability/OpenSSL.cpp
folly/portability/OpenSSL.h
folly/ssl/OpenSSLHash.h

index 3d16fc6..f8e315f 100644 (file)
@@ -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) {
-  memcpy(&sslBioMethod, BIO_s_socket(), sizeof(sslBioMethod));
+  auto sslBioMethod = getSSLBioMethod();
   // override the bwrite method for MSG_EOR support
-  OpenSSLUtils::setCustomBioWriteMethod(
-      &sslBioMethod, AsyncSSLSocket::bioWrite);
-  OpenSSLUtils::setCustomBioReadMethod(&sslBioMethod, AsyncSSLSocket::bioRead);
+  OpenSSLUtils::setCustomBioWriteMethod(sslBioMethod, AsyncSSLSocket::bioWrite);
+  OpenSSLUtils::setCustomBioReadMethod(sslBioMethod, AsyncSSLSocket::bioRead);
 
   // Note that the sslBioMethod.type and sslBioMethod.name are not
   // set here. openssl code seems to be checking ".type == BIO_TYPE_SOCKET" and
@@ -480,7 +486,6 @@ void AsyncSSLSocket::sslAccept(
   checkForImmediateRead();
 }
 
-#if OPENSSL_VERSION_NUMBER >= 0x009080bfL
 void AsyncSSLSocket::attachSSLContext(
   const std::shared_ptr<SSLContext>& ctx) {
 
@@ -503,10 +508,16 @@ void AsyncSSLSocket::attachSSLContext(
   // We need to update the initial_ctx if necessary
   auto sslCtx = ctx->getSSLCtx();
   SSL_CTX_up_ref(sslCtx);
-#ifndef OPENSSL_NO_TLSEXT
-  // note that detachSSLContext has already freed ssl_->initial_ctx
-  ssl_->initial_ctx = sslCtx;
-#endif
+
+  // The 'initial_ctx' inside an SSL* points to the context that it was created
+  // with, which is also where session callbacks and servername callbacks
+  // 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
   // this lock.
   SpinLockGuard guard(dummyCtxLock);
@@ -521,14 +532,20 @@ void AsyncSSLSocket::detachSSLContext() {
   if (!ssl_) {
     return;
   }
-// Detach the initial_ctx as well.  Internally w/ OPENSSL_NO_TLSEXT
-// it is used for session info.  It will be reattached in attachSSLContext
-#ifndef OPENSSL_NO_TLSEXT
-  if (ssl_->initial_ctx) {
-    SSL_CTX_free(ssl_->initial_ctx);
-    ssl_->initial_ctx = nullptr;
+  // The 'initial_ctx' inside an SSL* points to the context that it was created
+  // with, which is also where session callbacks and servername callbacks
+  // happen.
+  // Detach the initial_ctx as well.  It will be reattached in attachSSLContext
+  // it is used for session info.
+  // 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);
   if (nullptr == dummyCtx) {
     // We need to lazily initialize the dummy context so we don't
@@ -541,7 +558,6 @@ void AsyncSSLSocket::detachSSLContext() {
   // would not be thread safe.
   SSL_set_SSL_CTX(ssl_, dummyCtx->getSSLCtx());
 }
-#endif
 
 #if FOLLY_OPENSSL_HAS_SNI
 void AsyncSSLSocket::switchServerSSLContext(
@@ -574,10 +590,8 @@ bool AsyncSSLSocket::isServerNameMatch() const {
     return false;
   }
 
-  if(!ss->tlsext_hostname) {
-    return false;
-  }
-  return (tlsextHostname_.compare(ss->tlsext_hostname) ? false : true);
+  auto tlsextHostname = SSL_SESSION_get0_hostname(ss);
+  return (tlsextHostname && !tlsextHostname_.compare(tlsextHostname));
 }
 
 void AsyncSSLSocket::setServerName(std::string serverName) noexcept {
@@ -723,7 +737,7 @@ void AsyncSSLSocket::applyVerificationOptions(SSL * ssl) {
 }
 
 bool AsyncSSLSocket::setupSSLBio() {
-  auto sslBio = BIO_new(&sslBioMethod);
+  auto sslBio = BIO_new(getSSLBioMethod());
 
   if (!sslBio) {
     return false;
@@ -911,7 +925,7 @@ int AsyncSSLSocket::getSSLVersion() const {
 const char *AsyncSSLSocket::getSSLCertSigAlgName() const {
   X509 *cert = (ssl_ != nullptr) ? SSL_get_certificate(ssl_) : nullptr;
   if (cert) {
-    int nid = OBJ_obj2nid(cert->sig_alg->algorithm);
+    int nid = X509_get_signature_nid(cert);
     return OBJ_nid2ln(nid);
   }
   return nullptr;
index 4874cdc..f3ca89f 100644 (file)
@@ -833,7 +833,7 @@ void SSLContext::initializeOpenSSLLocked() {
   SSL_load_error_strings();
   ERR_load_crypto_strings();
   // static locking
-  locks().reset(new SSLLock[size_t(::CRYPTO_num_locks())]);
+  locks().reset(new SSLLock[size_t(CRYPTO_num_locks())]);
   for (auto it: lockTypes()) {
     locks()[size_t(it.first)].lockType = it.second;
   }
@@ -869,7 +869,7 @@ void SSLContext::cleanupOpenSSLLocked() {
   CRYPTO_cleanup_all_ex_data();
   ERR_free_strings();
   EVP_cleanup();
-  ERR_remove_state(0);
+  ERR_clear_error();
   locks().reset();
   initialized_ = false;
 }
index 8e4be98..dfc55cc 100644 (file)
 #include <openssl/ecdsa.h>
 #endif
 #include <openssl/evp.h>
+#include <openssl/hmac.h>
 #include <openssl/rsa.h>
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 
 #include <folly/Memory.h>
+#include <folly/portability/OpenSSL.h>
 
 namespace folly {
 namespace ssl {
@@ -65,11 +67,19 @@ using EvpPkeyCtxUniquePtr = std::unique_ptr<EVP_PKEY_CTX, EvpPkeyCtxDeleter>;
 #else
 struct EVP_PKEY_CTX;
 #endif
+
 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>;
 
+// HMAC
+using HmacCtxDeleter = folly::static_function_deleter<HMAC_CTX, &HMAC_CTX_free>;
+using HmacCtxUniquePtr = std::unique_ptr<HMAC_CTX, HmacCtxDeleter>;
+
 // 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 BioUniquePtr = std::unique_ptr<BIO, BioDeleter>;
 using BioChainDeleter = folly::static_function_deleter<BIO, &BIO_free_all>;
index 232fcc4..db25b8b 100644 (file)
@@ -26,7 +26,7 @@
 #include <unordered_map>
 
 namespace {
-#if defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
 // BoringSSL doesn't (as of May 2016) export the equivalent
 // of BIO_sock_should_retry, so this is one way around it :(
 static int boringssl_bio_fd_should_retry(int err);
@@ -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(
     BIO_METHOD* bioMeth,
     int (*meth)(BIO*, char*, int)) {
@@ -214,7 +256,7 @@ bool OpenSSLUtils::setCustomBioWriteMethod(
 
 int OpenSSLUtils::getBioShouldRetryWrite(int r) {
   int ret = 0;
-#if defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
   ret = boringssl_bio_fd_should_retry(r);
 #else
   ret = BIO_sock_should_retry(r);
@@ -223,7 +265,7 @@ int OpenSSLUtils::getBioShouldRetryWrite(int r) {
 }
 
 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));
 #else
   BIO_set_app_data(b, ptr);
@@ -231,21 +273,13 @@ void OpenSSLUtils::setBioAppData(BIO* b, void* ptr) {
 }
 
 void* OpenSSLUtils::getBioAppData(BIO* b) {
-#if defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
   return BIO_get_callback_arg(b);
 #else
   return BIO_get_app_data(b);
 #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) {
 #ifdef _WIN32
   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) {
 } // folly
 
 namespace {
-#if defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
 
 static int boringssl_bio_fd_non_fatal_error(int err) {
   if (
index 9a3ac3d..877df15 100644 (file)
@@ -16,6 +16,7 @@
 #pragma once
 
 #include <folly/Range.h>
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
 #include <folly/portability/Sockets.h>
 
 #include <openssl/ssl.h>
@@ -91,10 +92,25 @@ class OpenSSLUtils {
    */
   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
   * versions/flavors of OpenSSL (including forks like BoringSSL)
   */
+  static BioMethodUniquePtr newSocketBioMethod();
   static bool setCustomBioReadMethod(
       BIO_METHOD* bioMeth,
       int (*meth)(BIO*, char*, int));
@@ -104,7 +120,6 @@ class OpenSSLUtils {
   static int getBioShouldRetryWrite(int ret);
   static void setBioAppData(BIO* b, void* ptr);
   static void* getBioAppData(BIO* b);
-  static void setCustomBioMethod(BIO*, BIO_METHOD*);
   static int getBioFd(BIO* b, int* fd);
   static void setBioFd(BIO* b, int fd, int flags);
 };
index ff70d3b..e4a73c1 100644 (file)
@@ -755,8 +755,10 @@ class TestSSLAsyncCacheServer : public TestSSLServer {
         int lookupDelay = 100) :
       TestSSLServer(acb) {
     SSL_CTX *sslCtx = ctx_->getSSLCtx();
+#ifdef SSL_ERROR_WANT_SESS_CACHE_LOOKUP
     SSL_CTX_sess_set_get_cb(sslCtx,
                             TestSSLAsyncCacheServer::getSessionCallback);
+#endif
     SSL_CTX_set_session_cache_mode(
       sslCtx, SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_SERVER);
     asyncCallbacks_ = 0;
index b1cb9cf..04512f6 100644 (file)
  * limitations under the License.
  */
 #include <folly/portability/OpenSSL.h>
+#include <stdexcept>
 
 namespace folly {
 namespace ssl {
 
-#ifdef OPENSSL_IS_BORINGSSL
-int SSL_CTX_set1_sigalgs_list(SSL_CTX*, const char*) {
-  return 1; // 0 implies error
-}
-
-int TLS1_get_client_version(SSL* s) {
-  return s->client_version;
+#if FOLLY_OPENSSL_IS_110
+////////////////////////////////////////////////////////////////////////////////
+// APIs needed in 1.1.0 only
+////////////////////////////////////////////////////////////////////////////////
+
+#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) {
+  OPENSSL_free((void*)biom);
 }
 
 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)) {
   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
-uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c) {
-  return c->id;
+const char* SSL_SESSION_get0_hostname(const SSL_SESSION* s) {
+  return s->tlsext_hostname;
 }
 
-int TLS1_get_client_version(const SSL* s) {
-  return (s->client_version >> 8) == TLS1_VERSION_MAJOR ? s->client_version : 0;
+EVP_MD_CTX* EVP_MD_CTX_new(void) {
+  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) {
   return CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
 }
@@ -62,18 +105,35 @@ int X509_up_ref(X509* x) {
   return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
 }
 
-int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int)) {
-  biom->bread = read;
-  return 1;
+#if FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100
+////////////////////////////////////////////////////////////////////////////////
+// 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)) {
-  biom->bwrite = write;
-  return 1;
+#endif
+
+#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 // !(OPENSSL_IS_BORINGSSL ||
+//          FOLLY_OPENSSL_IS_101 ||
+//          FOLLY_OPENSSL_IS_102 ||
+//          FOLLY_OPENSSL_IS_100)
+
+#endif // !FOLLY_OPENSSL_IS_110
 }
 }
index faf14f7..dc6ac48 100644 (file)
  * 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
 
 // This must come before the OpenSSL includes.
 #include <folly/portability/Windows.h>
 
+#include <openssl/evp.h>
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 #include <cstdint>
@@ -60,39 +70,68 @@ namespace ssl {
 #define FOLLY_OPENSSL_HAS_SNI 0
 #endif
 
-// This class attempts to "unify" the OpenSSL libssl APIs between OpenSSL 1.0.2,
-// 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
-// SSL_CTX_set1_sigalgs_list and so on which exist in 1.0.2 but were removed
-// in BoringSSL
+#if FOLLY_OPENSSL_IS_110
+////////////////////////////////////////////////////////////////////////////////
+// APIs needed in 1.1.0 only
+////////////////////////////////////////////////////////////////////////////////
+
+#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
+////////////////////////////////////////////////////////////////////////////////
+// APIs needed in BoringSSL only
+////////////////////////////////////////////////////////////////////////////////
 
 int SSL_CTX_set1_sigalgs_list(SSL_CTX* ctx, const char* sigalgs_list);
 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
+////////////////////////////////////////////////////////////////////////////////
+// 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*);
-int TLS1_get_client_version(const SSL*);
+#if FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_100
+////////////////////////////////////////////////////////////////////////////////
+// APIs needed in 1.0.1/1.0.0 (both deprecated)
+////////////////////////////////////////////////////////////////////////////////
+int X509_get_signature_nid(X509* cert);
 
 #endif
 
-int SSL_CTX_up_ref(SSL_CTX* session);
-int SSL_SESSION_up_ref(SSL_SESSION* session);
-int X509_up_ref(X509* x);
-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));
+#if FOLLY_OPENSSL_IS_100
+////////////////////////////////////////////////////////////////////////////////
+// APIs needed only in 1.0.0 only (deprecated)
+////////////////////////////////////////////////////////////////////////////////
 
-#elif FOLLY_OPENSSL_IS_110
+uint32_t SSL_CIPHER_get_id(const SSL_CIPHER*);
+int TLS1_get_client_version(const SSL*);
 
+#endif
 #else
 #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
 } // folly
index da05bb0..5d11e3b 100644 (file)
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
+#include <folly/portability/OpenSSL.h>
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 #include <openssl/sha.h>
@@ -33,18 +35,15 @@ class OpenSSLHash {
 
   class Digest {
    public:
-    Digest() {
-      EVP_MD_CTX_init(&ctx_);
-    }
-    ~Digest() {
-      EVP_MD_CTX_cleanup(&ctx_);
-    }
+    Digest() : ctx_(EVP_MD_CTX_new()) {}
+
     void hash_init(const EVP_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) {
-      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) {
       for (auto r : data) {
@@ -55,13 +54,13 @@ class OpenSSLHash {
       const auto size = EVP_MD_size(md_);
       check_out_size(size_t(size), out);
       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));
       md_ = nullptr;
     }
    private:
     const EVP_MD* md_ = nullptr;
-    EVP_MD_CTX ctx_;
+    EvpMdCtxUniquePtr ctx_{nullptr};
   };
 
   static void hash(
@@ -97,19 +96,16 @@ class OpenSSLHash {
 
   class Hmac {
    public:
-    Hmac() {
-      HMAC_CTX_init(&ctx_);
-    }
-    ~Hmac() {
-      HMAC_CTX_cleanup(&ctx_);
-    }
+    Hmac() : ctx_(HMAC_CTX_new()) {}
+
     void hash_init(const EVP_MD* md, ByteRange key) {
       md_ = md;
       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) {
-      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) {
       for (auto r : data) {
@@ -120,13 +116,13 @@ class OpenSSLHash {
       const auto size = EVP_MD_size(md_);
       check_out_size(size_t(size), out);
       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));
       md_ = nullptr;
     }
    private:
     const EVP_MD* md_ = nullptr;
-    HMAC_CTX ctx_;
+    HmacCtxUniquePtr ctx_{nullptr};
   };
 
   static void hmac(