Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
60b8b73
crypto: use X509_STORE_CTX_new
davidben Sep 16, 2017
7702cc3
crypto: make node_crypto_bio compat w/ OpenSSL 1.1
davidben Sep 14, 2017
f51f3e9
crypto: estimate kExternalSize
davidben Sep 16, 2017
7530865
crypto: remove unnecessary SSLerr calls
davidben Sep 16, 2017
5dcf534
crypto: account for new 1.1.0 SSL APIs
davidben Sep 17, 2017
c6decc5
crypto: test DH keys work without a public half
davidben Sep 17, 2017
da9702a
crypto: use RSA and DH accessors
davidben Sep 17, 2017
3b967ab
crypto: remove locking callbacks for OpenSSL 1.1.0
davidben Sep 18, 2017
68ea095
crypto: make CipherBase 1.1.0-compatible
davidben Sep 20, 2017
0790a4c
crypto: make Hash 1.1.0-compatible
davidben Sep 22, 2017
612c103
crypto: make SignBase compatible with OpenSSL 1.1.0
davidben Sep 22, 2017
4485ba0
crypto: Make Hmac 1.1.0-compatible
davidben Sep 22, 2017
bdb4d70
crypto: add compat logic for "DSS1" and "dss1"
davidben Sep 23, 2017
7400a06
crypto: hard-code tlsSocket.getCipher().version
davidben Sep 23, 2017
ddf4987
test: update test expectations for OpenSSL 1.1.0
davidben Sep 17, 2017
4b4a17b
test: remove sha from test expectations
davidben Sep 23, 2017
ab02259
crypto: emulate OpenSSL 1.0 ticket scheme in 1.1
davidben Sep 23, 2017
31cf594
test: test with a larger RSA key
davidben Sep 23, 2017
28a9fac
test: revise test-tls-econnreset for OpenSSL 1.1.0
davidben Sep 23, 2017
11120dd
crypto: remove deprecated ECDH calls w/ OpenSSL 1.1
davidben Sep 23, 2017
7eb8740
test: configure certs in tests
davidben Sep 23, 2017
736dd79
test: fix test-https-agent-session-eviction for 1.1
davidben Sep 23, 2017
48a355d
crypto: make ALPN the same for OpenSSL 1.0.2 & 1.1.0
davidben Sep 23, 2017
37142c6
crypto: clear some SSL_METHOD deprecation warnings
davidben Sep 18, 2017
dfaf1ec
crypto: remove leftover initialization
MylesBorins Jan 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
crypto: make CipherBase 1.1.0-compatible
In OpenSSL 1.1.0, EVP_CIPHER_CTX must be heap-allocated. Once we're
heap-allocating them, there's no need in a separate initialised_ bit.
The presence of ctx_ is sufficient.

PR-URL: #16130
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Rod Vagg <rod@vagg.org>
  • Loading branch information
davidben authored and MylesBorins committed Feb 7, 2018
commit 68ea095234aced1797186e47b875d5dd04077222
72 changes: 36 additions & 36 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3457,7 +3457,7 @@ void CipherBase::Init(const char* cipher_type,
}
#endif // NODE_FIPS_MODE

CHECK_EQ(initialised_, false);
CHECK_EQ(ctx_, nullptr);
const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type);
if (cipher == nullptr) {
return env()->ThrowError("Unknown cipher");
Expand All @@ -3475,29 +3475,28 @@ void CipherBase::Init(const char* cipher_type,
key,
iv);

EVP_CIPHER_CTX_init(&ctx_);
ctx_ = EVP_CIPHER_CTX_new();
const bool encrypt = (kind_ == kCipher);
EVP_CipherInit_ex(&ctx_, cipher, nullptr, nullptr, nullptr, encrypt);
EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt);

int mode = EVP_CIPHER_CTX_mode(&ctx_);
int mode = EVP_CIPHER_CTX_mode(ctx_);
if (encrypt && (mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_GCM_MODE ||
mode == EVP_CIPH_CCM_MODE)) {
ProcessEmitWarning(env(), "Use Cipheriv for counter mode of %s",
cipher_type);
}

if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
EVP_CIPHER_CTX_set_flags(ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);

CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(&ctx_, key_len));
CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(ctx_, key_len));

EVP_CipherInit_ex(&ctx_,
EVP_CipherInit_ex(ctx_,
nullptr,
nullptr,
reinterpret_cast<unsigned char*>(key),
reinterpret_cast<unsigned char*>(iv),
kind_ == kCipher);
initialised_ = true;
}


Expand Down Expand Up @@ -3540,32 +3539,33 @@ void CipherBase::InitIv(const char* cipher_type,
return env()->ThrowError("Invalid IV length");
}

EVP_CIPHER_CTX_init(&ctx_);
ctx_ = EVP_CIPHER_CTX_new();

if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
EVP_CIPHER_CTX_set_flags(ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);

const bool encrypt = (kind_ == kCipher);
EVP_CipherInit_ex(&ctx_, cipher, nullptr, nullptr, nullptr, encrypt);
EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt);

if (is_gcm_mode &&
!EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) {
EVP_CIPHER_CTX_cleanup(&ctx_);
!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) {
EVP_CIPHER_CTX_free(ctx_);
ctx_ = nullptr;
return env()->ThrowError("Invalid IV length");
}

if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) {
EVP_CIPHER_CTX_cleanup(&ctx_);
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
EVP_CIPHER_CTX_free(ctx_);
ctx_ = nullptr;
return env()->ThrowError("Invalid key length");
}

EVP_CipherInit_ex(&ctx_,
EVP_CipherInit_ex(ctx_,
nullptr,
nullptr,
reinterpret_cast<const unsigned char*>(key),
reinterpret_cast<const unsigned char*>(iv),
kind_ == kCipher);
initialised_ = true;
}


Expand Down Expand Up @@ -3593,8 +3593,8 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {

bool CipherBase::IsAuthenticatedMode() const {
// Check if this cipher operates in an AEAD mode that we support.
CHECK_EQ(initialised_, true);
const EVP_CIPHER* const cipher = EVP_CIPHER_CTX_cipher(&ctx_);
CHECK_NE(ctx_, nullptr);
const EVP_CIPHER* const cipher = EVP_CIPHER_CTX_cipher(ctx_);
int mode = EVP_CIPHER_mode(cipher);
return mode == EVP_CIPH_GCM_MODE;
}
Expand All @@ -3606,7 +3606,7 @@ void CipherBase::GetAuthTag(const FunctionCallbackInfo<Value>& args) {
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());

// Only callable after Final and if encrypting.
if (cipher->initialised_ ||
if (cipher->ctx_ != nullptr ||
cipher->kind_ != kCipher ||
cipher->auth_tag_len_ == 0) {
return env->ThrowError("Attempting to get auth tag in unsupported state");
Expand All @@ -3627,7 +3627,7 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {
CipherBase* cipher;
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());

if (!cipher->initialised_ ||
if (cipher->ctx_ == nullptr ||
!cipher->IsAuthenticatedMode() ||
cipher->kind_ != kDecipher) {
return env->ThrowError("Attempting to set auth tag in unsupported state");
Expand All @@ -3653,10 +3653,10 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {


bool CipherBase::SetAAD(const char* data, unsigned int len) {
if (!initialised_ || !IsAuthenticatedMode())
if (ctx_ == nullptr || !IsAuthenticatedMode())
return false;
int outlen;
if (!EVP_CipherUpdate(&ctx_,
if (!EVP_CipherUpdate(ctx_,
nullptr,
&outlen,
reinterpret_cast<const unsigned char*>(data),
Expand Down Expand Up @@ -3684,21 +3684,21 @@ bool CipherBase::Update(const char* data,
int len,
unsigned char** out,
int* out_len) {
if (!initialised_)
if (ctx_ == nullptr)
return 0;

// on first update:
if (kind_ == kDecipher && IsAuthenticatedMode() && auth_tag_len_ > 0) {
EVP_CIPHER_CTX_ctrl(&ctx_,
EVP_CIPHER_CTX_ctrl(ctx_,
EVP_CTRL_GCM_SET_TAG,
auth_tag_len_,
reinterpret_cast<unsigned char*>(auth_tag_));
auth_tag_len_ = 0;
}

*out_len = len + EVP_CIPHER_CTX_block_size(&ctx_);
*out_len = len + EVP_CIPHER_CTX_block_size(ctx_);
*out = Malloc<unsigned char>(static_cast<size_t>(*out_len));
return EVP_CipherUpdate(&ctx_,
return EVP_CipherUpdate(ctx_,
*out,
out_len,
reinterpret_cast<const unsigned char*>(data),
Expand Down Expand Up @@ -3746,9 +3746,9 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {


bool CipherBase::SetAutoPadding(bool auto_padding) {
if (!initialised_)
if (ctx_ == nullptr)
return false;
return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding);
return EVP_CIPHER_CTX_set_padding(ctx_, auto_padding);
}


Expand All @@ -3764,22 +3764,22 @@ void CipherBase::SetAutoPadding(const FunctionCallbackInfo<Value>& args) {


bool CipherBase::Final(unsigned char** out, int *out_len) {
if (!initialised_)
if (ctx_ == nullptr)
return false;

*out = Malloc<unsigned char>(
static_cast<size_t>(EVP_CIPHER_CTX_block_size(&ctx_)));
int r = EVP_CipherFinal_ex(&ctx_, *out, out_len);
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_)));
int r = EVP_CipherFinal_ex(ctx_, *out, out_len);

if (r == 1 && kind_ == kCipher && IsAuthenticatedMode()) {
auth_tag_len_ = sizeof(auth_tag_);
r = EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_,
r = EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_,
reinterpret_cast<unsigned char*>(auth_tag_));
CHECK_EQ(r, 1);
}

EVP_CIPHER_CTX_cleanup(&ctx_);
initialised_ = false;
EVP_CIPHER_CTX_free(ctx_);
ctx_ = nullptr;

return r == 1;
}
Expand All @@ -3790,7 +3790,7 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {

CipherBase* cipher;
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
if (!cipher->initialised_) return env->ThrowError("Unsupported state");
if (cipher->ctx_ == nullptr) return env->ThrowError("Unsupported state");

unsigned char* out_value = nullptr;
int out_len = -1;
Expand Down
11 changes: 3 additions & 8 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@
#include <openssl/rand.h>
#include <openssl/pkcs12.h>

#define EVP_F_EVP_DECRYPTFINAL 101

#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb)
# define NODE__HAVE_TLSEXT_STATUS_CB
#endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb)
Expand Down Expand Up @@ -442,9 +440,7 @@ class Connection : public AsyncWrap, public SSLWrap<Connection> {
class CipherBase : public BaseObject {
public:
~CipherBase() override {
if (!initialised_)
return;
EVP_CIPHER_CTX_cleanup(&ctx_);
EVP_CIPHER_CTX_free(ctx_);
}

static void Initialize(Environment* env, v8::Local<v8::Object> target);
Expand Down Expand Up @@ -483,15 +479,14 @@ class CipherBase : public BaseObject {
v8::Local<v8::Object> wrap,
CipherKind kind)
: BaseObject(env, wrap),
initialised_(false),
ctx_(nullptr),
kind_(kind),
auth_tag_len_(0) {
MakeWeak<CipherBase>(this);
}

private:
EVP_CIPHER_CTX ctx_; /* coverity[member_decl] */
bool initialised_;
EVP_CIPHER_CTX* ctx_;
const CipherKind kind_;
unsigned int auth_tag_len_;
char auth_tag_[EVP_GCM_TLS_TAG_LEN];
Expand Down