From 2888f809e3010d60943c4406511a6b409baba271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sat, 22 Sep 2018 00:56:16 +0200 Subject: [PATCH] crypto: deduplicate cipher initialization code CipherBase::Init and CipherBase::InitIv contain a lot of duplicate code, this commit moves that into a separate function. PR-URL: https://github.com/nodejs/node/pull/23011 Reviewed-By: Anna Henningsen Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Ujjwal Sharma --- src/node_crypto.cc | 130 +++++++++++++++++++-------------------------- src/node_crypto.h | 11 +++- 2 files changed, 64 insertions(+), 77 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index abe744a5e026ae..1b246509baf473 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2539,6 +2539,12 @@ int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) { return 1; } +static bool IsSupportedAuthenticatedMode(int mode) { + return mode == EVP_CIPH_CCM_MODE || + mode == EVP_CIPH_GCM_MODE || + mode == EVP_CIPH_OCB_MODE; +} + void CipherBase::Initialize(Environment* env, Local target) { Local t = env->NewFunctionTemplate(New); @@ -2565,6 +2571,43 @@ void CipherBase::New(const FunctionCallbackInfo& args) { new CipherBase(env, args.This(), kind); } +void CipherBase::CommonInit(const char* cipher_type, + const EVP_CIPHER* cipher, + const unsigned char* key, + int key_len, + const unsigned char* iv, + int iv_len, + unsigned int auth_tag_len) { + CHECK(!ctx_); + ctx_.reset(EVP_CIPHER_CTX_new()); + + const int mode = EVP_CIPHER_mode(cipher); + if (mode == EVP_CIPH_WRAP_MODE) + EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + + const bool encrypt = (kind_ == kCipher); + if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr, + nullptr, nullptr, encrypt)) { + return ThrowCryptoError(env(), ERR_get_error(), + "Failed to initialize cipher"); + } + + if (IsSupportedAuthenticatedMode(mode)) { + CHECK_GE(iv_len, 0); + if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len)) + return; + } + + if (!EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)) { + ctx_.reset(); + return env()->ThrowError("Invalid key length"); + } + + if (1 != EVP_CipherInit_ex(ctx_.get(), nullptr, nullptr, key, iv, encrypt)) { + return ThrowCryptoError(env(), ERR_get_error(), + "Failed to initialize cipher"); + } +} void CipherBase::Init(const char* cipher_type, const char* key_buf, @@ -2580,7 +2623,6 @@ void CipherBase::Init(const char* cipher_type, } #endif // NODE_FIPS_MODE - CHECK(!ctx_); const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type); if (cipher == nullptr) return env()->ThrowError("Unknown cipher"); @@ -2598,21 +2640,10 @@ void CipherBase::Init(const char* cipher_type, iv); CHECK_NE(key_len, 0); - ctx_.reset(EVP_CIPHER_CTX_new()); - const int mode = EVP_CIPHER_mode(cipher); - if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); - - const bool encrypt = (kind_ == kCipher); - if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr, - nullptr, nullptr, encrypt)) { - return ThrowCryptoError(env(), ERR_get_error(), - "Failed to initialize cipher"); - } - - if (encrypt && (mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_GCM_MODE || - mode == EVP_CIPH_CCM_MODE)) { + if (kind_ == kCipher && (mode == EVP_CIPH_CTR_MODE || + mode == EVP_CIPH_GCM_MODE || + mode == EVP_CIPH_CCM_MODE)) { // Ignore the return value (i.e. possible exception) because we are // not calling back into JS anyway. ProcessEmitWarning(env(), @@ -2620,23 +2651,8 @@ void CipherBase::Init(const char* cipher_type, cipher_type); } - if (IsAuthenticatedMode()) { - if (!InitAuthenticated(cipher_type, EVP_CIPHER_iv_length(cipher), - auth_tag_len)) - return; - } - - CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)); - - if (1 != EVP_CipherInit_ex(ctx_.get(), - nullptr, - nullptr, - reinterpret_cast(key), - reinterpret_cast(iv), - encrypt)) { - return ThrowCryptoError(env(), ERR_get_error(), - "Failed to initialize cipher"); - } + CommonInit(cipher_type, cipher, key, key_len, iv, + EVP_CIPHER_iv_length(cipher), auth_tag_len); } @@ -2663,16 +2679,10 @@ void CipherBase::Init(const FunctionCallbackInfo& args) { cipher->Init(*cipher_type, key_buf, key_buf_len, auth_tag_len); } -static bool IsSupportedAuthenticatedMode(int mode) { - return mode == EVP_CIPH_CCM_MODE || - mode == EVP_CIPH_GCM_MODE || - mode == EVP_CIPH_OCB_MODE; -} - void CipherBase::InitIv(const char* cipher_type, - const char* key, + const unsigned char* key, int key_len, - const char* iv, + const unsigned char* iv, int iv_len, unsigned int auth_tag_len) { HandleScope scope(env()->isolate()); @@ -2700,38 +2710,7 @@ void CipherBase::InitIv(const char* cipher_type, return env()->ThrowError("Invalid IV length"); } - ctx_.reset(EVP_CIPHER_CTX_new()); - - if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); - - const bool encrypt = (kind_ == kCipher); - if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr, - nullptr, nullptr, encrypt)) { - return ThrowCryptoError(env(), ERR_get_error(), - "Failed to initialize cipher"); - } - - if (is_authenticated_mode) { - CHECK(has_iv); - if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len)) - return; - } - - if (!EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)) { - ctx_.reset(); - return env()->ThrowError("Invalid key length"); - } - - if (1 != EVP_CipherInit_ex(ctx_.get(), - nullptr, - nullptr, - reinterpret_cast(key), - reinterpret_cast(iv), - encrypt)) { - return ThrowCryptoError(env(), ERR_get_error(), - "Failed to initialize cipher"); - } + CommonInit(cipher_type, cipher, key, key_len, iv, iv_len, auth_tag_len); } @@ -2744,14 +2723,15 @@ void CipherBase::InitIv(const FunctionCallbackInfo& args) { const node::Utf8Value cipher_type(env->isolate(), args[0]); ssize_t key_len = Buffer::Length(args[1]); - const char* key_buf = Buffer::Data(args[1]); + const unsigned char* key_buf = reinterpret_cast( + Buffer::Data(args[1])); ssize_t iv_len; - const char* iv_buf; + const unsigned char* iv_buf; if (args[2]->IsNull()) { iv_buf = nullptr; iv_len = -1; } else { - iv_buf = Buffer::Data(args[2]); + iv_buf = reinterpret_cast(Buffer::Data(args[2])); iv_len = Buffer::Length(args[2]); } diff --git a/src/node_crypto.h b/src/node_crypto.h index 1a93ae7a47e2cf..714afd0d3bb868 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -370,14 +370,21 @@ class CipherBase : public BaseObject { }; static const unsigned kNoAuthTagLength = static_cast(-1); + void CommonInit(const char* cipher_type, + const EVP_CIPHER* cipher, + const unsigned char* key, + int key_len, + const unsigned char* iv, + int iv_len, + unsigned int auth_tag_len); void Init(const char* cipher_type, const char* key_buf, int key_buf_len, unsigned int auth_tag_len); void InitIv(const char* cipher_type, - const char* key, + const unsigned char* key, int key_len, - const char* iv, + const unsigned char* iv, int iv_len, unsigned int auth_tag_len); bool InitAuthenticated(const char* cipher_type, int iv_len,