}
-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
checkForImmediateRead();
}
-#if OPENSSL_VERSION_NUMBER >= 0x009080bfL
void AsyncSSLSocket::attachSSLContext(
const std::shared_ptr<SSLContext>& ctx) {
// 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);
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
// would not be thread safe.
SSL_set_SSL_CTX(ssl_, dummyCtx->getSSLCtx());
}
-#endif
#if FOLLY_OPENSSL_HAS_SNI
void AsyncSSLSocket::switchServerSSLContext(
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 {
}
bool AsyncSSLSocket::setupSSLBio() {
- auto sslBio = BIO_new(&sslBioMethod);
+ auto sslBio = BIO_new(getSSLBioMethod());
if (!sslBio) {
return false;
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;
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;
}
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
EVP_cleanup();
- ERR_remove_state(0);
+ ERR_clear_error();
locks().reset();
initialized_ = false;
}
#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 {
#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>;
#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);
}
}
+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)) {
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);
}
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);
}
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));
} // folly
namespace {
-#if defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
static int boringssl_bio_fd_non_fatal_error(int err) {
if (
#pragma once
#include <folly/Range.h>
+#include <folly/io/async/ssl/OpenSSLPtrTypes.h>
#include <folly/portability/Sockets.h>
#include <openssl/ssl.h>
*/
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));
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);
};
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;
* 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)) {
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);
}
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
}
}
* 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>
#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
#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>
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) {
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(
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) {
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(