From efd9bc36faf1f62bb45c9945690c736c7497b007 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 14 Sep 2017 19:44:06 -0400 Subject: [PATCH] crypto: make node_crypto_bio compat w/ OpenSSL 1.1 This is cherry-picked from PR #8491 and then tidied up. The original had an unnecessarily large diff and messed up some public/private bits. PR-URL: https://github.com/nodejs/node/pull/16130 Reviewed-By: Ben Noordhuis Reviewed-By: Rod Vagg --- src/node_crypto_bio.cc | 91 +++++++++++++++++++++++++++++------------- src/node_crypto_bio.h | 19 ++++++--- 2 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/node_crypto_bio.cc b/src/node_crypto_bio.cc index eb1399f0bffb96..eb0500952b15a5 100644 --- a/src/node_crypto_bio.cc +++ b/src/node_crypto_bio.cc @@ -28,24 +28,20 @@ namespace node { namespace crypto { -const BIO_METHOD NodeBIO::method = { - BIO_TYPE_MEM, - "node.js SSL buffer", - NodeBIO::Write, - NodeBIO::Read, - NodeBIO::Puts, - NodeBIO::Gets, - NodeBIO::Ctrl, - NodeBIO::New, - NodeBIO::Free, - nullptr -}; +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define BIO_set_data(bio, data) bio->ptr = data +#define BIO_get_data(bio) bio->ptr +#define BIO_set_shutdown(bio, shutdown_) bio->shutdown = shutdown_ +#define BIO_get_shutdown(bio) bio->shutdown +#define BIO_set_init(bio, init_) bio->init = init_ +#define BIO_get_init(bio) bio->init +#endif BIO* NodeBIO::New() { // The const_cast doesn't violate const correctness. OpenSSL's usage of // BIO_METHOD is effectively const but BIO_new() takes a non-const argument. - return BIO_new(const_cast(&method)); + return BIO_new(const_cast(GetMethod())); } @@ -70,12 +66,11 @@ void NodeBIO::AssignEnvironment(Environment* env) { int NodeBIO::New(BIO* bio) { - bio->ptr = new NodeBIO(); + BIO_set_data(bio, new NodeBIO()); // XXX Why am I doing it?! - bio->shutdown = 1; - bio->init = 1; - bio->num = -1; + BIO_set_shutdown(bio, 1); + BIO_set_init(bio, 1); return 1; } @@ -85,10 +80,10 @@ int NodeBIO::Free(BIO* bio) { if (bio == nullptr) return 0; - if (bio->shutdown) { - if (bio->init && bio->ptr != nullptr) { + if (BIO_get_shutdown(bio)) { + if (BIO_get_init(bio) && BIO_get_data(bio) != nullptr) { delete FromBIO(bio); - bio->ptr = nullptr; + BIO_set_data(bio, nullptr); } } @@ -97,13 +92,13 @@ int NodeBIO::Free(BIO* bio) { int NodeBIO::Read(BIO* bio, char* out, int len) { - int bytes; BIO_clear_retry_flags(bio); - bytes = FromBIO(bio)->Read(out, len); + NodeBIO* nbio = FromBIO(bio); + int bytes = nbio->Read(out, len); if (bytes == 0) { - bytes = bio->num; + bytes = nbio->eof_return(); if (bytes != 0) { BIO_set_retry_read(bio); } @@ -161,7 +156,7 @@ int NodeBIO::Puts(BIO* bio, const char* str) { int NodeBIO::Gets(BIO* bio, char* out, int size) { - NodeBIO* nbio = FromBIO(bio); + NodeBIO* nbio = FromBIO(bio); if (nbio->Length() == 0) return 0; @@ -201,7 +196,7 @@ long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) ret = nbio->Length() == 0; break; case BIO_C_SET_BUF_MEM_EOF_RETURN: - bio->num = num; + nbio->set_eof_return(num); break; case BIO_CTRL_INFO: ret = nbio->Length(); @@ -216,10 +211,10 @@ long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) ret = 0; break; case BIO_CTRL_GET_CLOSE: - ret = bio->shutdown; + ret = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: - bio->shutdown = num; + BIO_set_shutdown(bio, num); break; case BIO_CTRL_WPENDING: ret = 0; @@ -241,6 +236,41 @@ long NodeBIO::Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) } +const BIO_METHOD* NodeBIO::GetMethod() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + static const BIO_METHOD method = { + BIO_TYPE_MEM, + "node.js SSL buffer", + Write, + Read, + Puts, + Gets, + Ctrl, + New, + Free, + nullptr + }; + + return &method; +#else + static BIO_METHOD* method = nullptr; + + if (method == nullptr) { + method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer"); + BIO_meth_set_write(method, Write); + BIO_meth_set_read(method, Read); + BIO_meth_set_puts(method, Puts); + BIO_meth_set_gets(method, Gets); + BIO_meth_set_ctrl(method, Ctrl); + BIO_meth_set_create(method, New); + BIO_meth_set_destroy(method, Free); + } + + return method; +#endif +} + + void NodeBIO::TryMoveReadHead() { // `read_pos_` and `write_pos_` means the position of the reader and writer // inside the buffer, respectively. When they're equal - its safe to reset @@ -488,5 +518,12 @@ NodeBIO::~NodeBIO() { write_head_ = nullptr; } + +NodeBIO* NodeBIO::FromBIO(BIO* bio) { + CHECK_NE(BIO_get_data(bio), nullptr); + return static_cast(BIO_get_data(bio)); +} + + } // namespace crypto } // namespace node diff --git a/src/node_crypto_bio.h b/src/node_crypto_bio.h index 6ec256d008153b..380a3a6b4c64f5 100644 --- a/src/node_crypto_bio.h +++ b/src/node_crypto_bio.h @@ -37,6 +37,7 @@ class NodeBIO { NodeBIO() : env_(nullptr), initial_(kInitialBufferLength), length_(0), + eof_return_(-1), read_head_(nullptr), write_head_(nullptr) { } @@ -95,14 +96,19 @@ class NodeBIO { return length_; } + inline void set_eof_return(int num) { + eof_return_ = num; + } + + inline int eof_return() { + return eof_return_; + } + inline void set_initial(size_t initial) { initial_ = initial; } - static inline NodeBIO* FromBIO(BIO* bio) { - CHECK_NE(bio->ptr, nullptr); - return static_cast(bio->ptr); - } + static NodeBIO* FromBIO(BIO* bio); private: static int New(BIO* bio); @@ -114,12 +120,12 @@ class NodeBIO { static long Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) void* ptr); + static const BIO_METHOD* GetMethod(); + // Enough to handle the most of the client hellos static const size_t kInitialBufferLength = 1024; static const size_t kThroughputBufferLength = 16384; - static const BIO_METHOD method; - class Buffer { public: Buffer(Environment* env, size_t len) : env_(env), @@ -151,6 +157,7 @@ class NodeBIO { Environment* env_; size_t initial_; size_t length_; + int eof_return_; Buffer* read_head_; Buffer* write_head_; };