Browse Source

crypto: throw only in direct C++ methods

Do not throw in internal C++ methods, that clobbers logic and may lead
to the situations, where both exception was thrown and the value was
returned (via `args.GetReturnValue().Set()`). That doesn't play nicely
with v8.

fix #6912
v0.11.11-release
Fedor Indutny 11 years ago
parent
commit
661190af13
  1. 193
      src/node_crypto.cc
  2. 86
      src/node_crypto.h

193
src/node_crypto.cc

@ -2692,6 +2692,46 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
} }
void SignBase::CheckThrow(SignBase::Error error) {
HandleScope scope(node_isolate);
switch (error) {
case kSignUnknownDigest:
return ThrowError("Unknown message digest");
case kSignNotInitialised:
return ThrowError("Not initialised");
case kSignInit:
case kSignUpdate:
case kSignPrivateKey:
case kSignPublicKey:
{
unsigned long err = ERR_get_error();
if (err)
return ThrowCryptoError(err);
switch (error) {
case kSignInit:
return ThrowError("EVP_SignInit_ex failed");
case kSignUpdate:
return ThrowError("EVP_SignUpdate failed");
case kSignPrivateKey:
return ThrowError("PEM_read_bio_PrivateKey failed");
case kSignPublicKey:
return ThrowError("PEM_read_bio_PUBKEY failed");
default:
abort();
}
}
case kSignOk:
return;
}
}
void Sign::Initialize(Environment* env, v8::Handle<v8::Object> target) { void Sign::Initialize(Environment* env, v8::Handle<v8::Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New); Local<FunctionTemplate> t = FunctionTemplate::New(New);
@ -2712,17 +2752,18 @@ void Sign::New(const FunctionCallbackInfo<Value>& args) {
} }
void Sign::SignInit(const char* sign_type) { SignBase::Error Sign::SignInit(const char* sign_type) {
HandleScope scope(node_isolate);
assert(md_ == NULL); assert(md_ == NULL);
md_ = EVP_get_digestbyname(sign_type); md_ = EVP_get_digestbyname(sign_type);
if (!md_) { if (!md_)
return ThrowError("Uknown message digest"); return kSignUnknownDigest;
}
EVP_MD_CTX_init(&mdctx_); EVP_MD_CTX_init(&mdctx_);
EVP_SignInit_ex(&mdctx_, md_, NULL); if (!EVP_SignInit_ex(&mdctx_, md_, NULL))
return kSignInit;
initialised_ = true; initialised_ = true;
return kSignOk;
} }
@ -2736,15 +2777,16 @@ void Sign::SignInit(const FunctionCallbackInfo<Value>& args) {
} }
const String::Utf8Value sign_type(args[0]); const String::Utf8Value sign_type(args[0]);
sign->SignInit(*sign_type); CheckThrow(sign->SignInit(*sign_type));
} }
bool Sign::SignUpdate(const char* data, int len) { SignBase::Error Sign::SignUpdate(const char* data, int len) {
if (!initialised_) if (!initialised_)
return false; return kSignNotInitialised;
EVP_SignUpdate(&mdctx_, data, len); if (!EVP_SignUpdate(&mdctx_, data, len))
return true; return kSignUpdate;
return kSignOk;
} }
@ -2756,7 +2798,7 @@ void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) {
ASSERT_IS_STRING_OR_BUFFER(args[0]); ASSERT_IS_STRING_OR_BUFFER(args[0]);
// Only copy the data if we have to, because it's a string // Only copy the data if we have to, because it's a string
int r; Error err;
if (args[0]->IsString()) { if (args[0]->IsString()) {
Local<String> string = args[0].As<String>(); Local<String> string = args[0].As<String>();
enum encoding encoding = ParseEncoding(args[1], BINARY); enum encoding encoding = ParseEncoding(args[1], BINARY);
@ -2765,29 +2807,25 @@ void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) {
size_t buflen = StringBytes::StorageSize(string, encoding); size_t buflen = StringBytes::StorageSize(string, encoding);
char* buf = new char[buflen]; char* buf = new char[buflen];
size_t written = StringBytes::Write(buf, buflen, string, encoding); size_t written = StringBytes::Write(buf, buflen, string, encoding);
r = sign->SignUpdate(buf, written); err = sign->SignUpdate(buf, written);
delete[] buf; delete[] buf;
} else { } else {
char* buf = Buffer::Data(args[0]); char* buf = Buffer::Data(args[0]);
size_t buflen = Buffer::Length(args[0]); size_t buflen = Buffer::Length(args[0]);
r = sign->SignUpdate(buf, buflen); err = sign->SignUpdate(buf, buflen);
} }
if (!r) { CheckThrow(err);
return ThrowTypeError("SignUpdate fail");
}
} }
bool Sign::SignFinal(const char* key_pem, SignBase::Error Sign::SignFinal(const char* key_pem,
int key_pem_len, int key_pem_len,
const char* passphrase, const char* passphrase,
unsigned char** sig, unsigned char** sig,
unsigned int *sig_len) { unsigned int *sig_len) {
if (!initialised_) { if (!initialised_)
ThrowError("Sign not initalised"); return kSignNotInitialised;
return false;
}
BIO* bp = NULL; BIO* bp = NULL;
EVP_PKEY* pkey = NULL; EVP_PKEY* pkey = NULL;
@ -2820,17 +2858,10 @@ bool Sign::SignFinal(const char* key_pem,
EVP_MD_CTX_cleanup(&mdctx_); EVP_MD_CTX_cleanup(&mdctx_);
if (fatal) { if (fatal)
unsigned long err = ERR_get_error(); return kSignPrivateKey;
if (err) {
ThrowCryptoError(err);
} else {
ThrowError("PEM_read_bio_PrivateKey");
}
return false;
}
return true; return kSignOk;
} }
@ -2857,15 +2888,17 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
md_len = 8192; // Maximum key size is 8192 bits md_len = 8192; // Maximum key size is 8192 bits
md_value = new unsigned char[md_len]; md_value = new unsigned char[md_len];
bool r = sign->SignFinal(buf, Error err = sign->SignFinal(
buf_len, buf,
len >= 3 && !args[2]->IsNull() ? *passphrase : NULL, buf_len,
&md_value, len >= 3 && !args[2]->IsNull() ? *passphrase : NULL,
&md_len); &md_value,
if (!r) { &md_len);
if (err != kSignOk) {
delete[] md_value; delete[] md_value;
md_value = NULL; md_value = NULL;
md_len = 0; md_len = 0;
return CheckThrow(err);
} }
Local<Value> rc = StringBytes::Encode( Local<Value> rc = StringBytes::Encode(
@ -2896,18 +2929,18 @@ void Verify::New(const FunctionCallbackInfo<Value>& args) {
} }
void Verify::VerifyInit(const char* verify_type) { SignBase::Error Verify::VerifyInit(const char* verify_type) {
HandleScope scope(node_isolate);
assert(md_ == NULL); assert(md_ == NULL);
md_ = EVP_get_digestbyname(verify_type); md_ = EVP_get_digestbyname(verify_type);
if (md_ == NULL) { if (md_ == NULL)
return ThrowError("Unknown message digest"); return kSignUnknownDigest;
}
EVP_MD_CTX_init(&mdctx_); EVP_MD_CTX_init(&mdctx_);
EVP_VerifyInit_ex(&mdctx_, md_, NULL); if (!EVP_VerifyInit_ex(&mdctx_, md_, NULL))
return kSignInit;
initialised_ = true; initialised_ = true;
return kSignOk;
} }
@ -2921,15 +2954,18 @@ void Verify::VerifyInit(const FunctionCallbackInfo<Value>& args) {
} }
const String::Utf8Value verify_type(args[0]); const String::Utf8Value verify_type(args[0]);
verify->VerifyInit(*verify_type); CheckThrow(verify->VerifyInit(*verify_type));
} }
bool Verify::VerifyUpdate(const char* data, int len) { SignBase::Error Verify::VerifyUpdate(const char* data, int len) {
if (!initialised_) if (!initialised_)
return false; return kSignNotInitialised;
EVP_VerifyUpdate(&mdctx_, data, len);
return true; if (!EVP_VerifyUpdate(&mdctx_, data, len))
return kSignUpdate;
return kSignOk;
} }
@ -2941,7 +2977,7 @@ void Verify::VerifyUpdate(const FunctionCallbackInfo<Value>& args) {
ASSERT_IS_STRING_OR_BUFFER(args[0]); ASSERT_IS_STRING_OR_BUFFER(args[0]);
// Only copy the data if we have to, because it's a string // Only copy the data if we have to, because it's a string
bool r; Error err;
if (args[0]->IsString()) { if (args[0]->IsString()) {
Local<String> string = args[0].As<String>(); Local<String> string = args[0].As<String>();
enum encoding encoding = ParseEncoding(args[1], BINARY); enum encoding encoding = ParseEncoding(args[1], BINARY);
@ -2950,30 +2986,25 @@ void Verify::VerifyUpdate(const FunctionCallbackInfo<Value>& args) {
size_t buflen = StringBytes::StorageSize(string, encoding); size_t buflen = StringBytes::StorageSize(string, encoding);
char* buf = new char[buflen]; char* buf = new char[buflen];
size_t written = StringBytes::Write(buf, buflen, string, encoding); size_t written = StringBytes::Write(buf, buflen, string, encoding);
r = verify->VerifyUpdate(buf, written); err = verify->VerifyUpdate(buf, written);
delete[] buf; delete[] buf;
} else { } else {
char* buf = Buffer::Data(args[0]); char* buf = Buffer::Data(args[0]);
size_t buflen = Buffer::Length(args[0]); size_t buflen = Buffer::Length(args[0]);
r = verify->VerifyUpdate(buf, buflen); err = verify->VerifyUpdate(buf, buflen);
} }
if (!r) { CheckThrow(err);
return ThrowTypeError("VerifyUpdate fail");
}
} }
bool Verify::VerifyFinal(const char* key_pem, SignBase::Error Verify::VerifyFinal(const char* key_pem,
int key_pem_len, int key_pem_len,
const char* sig, const char* sig,
int siglen) { int siglen,
HandleScope scope(node_isolate); bool* verify_result) {
if (!initialised_)
if (!initialised_) { return kSignNotInitialised;
ThrowError("Verify not initalised");
return false;
}
ClearErrorOnReturn clear_error_on_return; ClearErrorOnReturn clear_error_on_return;
(void) &clear_error_on_return; // Silence compiler warning. (void) &clear_error_on_return; // Silence compiler warning.
@ -3036,13 +3067,11 @@ bool Verify::VerifyFinal(const char* key_pem,
EVP_MD_CTX_cleanup(&mdctx_); EVP_MD_CTX_cleanup(&mdctx_);
initialised_ = false; initialised_ = false;
if (fatal) { if (fatal)
unsigned long err = ERR_get_error(); return kSignPublicKey;
ThrowCryptoError(err);
return false;
}
return r == 1; *verify_result = r == 1;
return kSignOk;
} }
@ -3074,11 +3103,13 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
hbuf = Buffer::Data(args[1]); hbuf = Buffer::Data(args[1]);
} }
bool rc = verify->VerifyFinal(kbuf, klen, hbuf, hlen); bool verify_result;
if (args[1]->IsString()) { Error err = verify->VerifyFinal(kbuf, klen, hbuf, hlen, &verify_result);
if (args[1]->IsString())
delete[] hbuf; delete[] hbuf;
} if (err != kSignOk)
args.GetReturnValue().Set(rc); return CheckThrow(err);
args.GetReturnValue().Set(verify_result);
} }

86
src/node_crypto.h

@ -446,23 +446,50 @@ class Hash : public BaseObject {
bool initialised_; bool initialised_;
}; };
class Sign : public BaseObject { class SignBase : public BaseObject {
public: public:
~Sign() { typedef enum {
kSignOk,
kSignUnknownDigest,
kSignInit,
kSignNotInitialised,
kSignUpdate,
kSignPrivateKey,
kSignPublicKey
} Error;
SignBase(Environment* env, v8::Local<v8::Object> wrap)
: BaseObject(env, wrap),
md_(NULL),
initialised_(false) {
}
~SignBase() {
if (!initialised_) if (!initialised_)
return; return;
EVP_MD_CTX_cleanup(&mdctx_); EVP_MD_CTX_cleanup(&mdctx_);
} }
protected:
static void CheckThrow(Error error);
EVP_MD_CTX mdctx_; /* coverity[member_decl] */
const EVP_MD* md_; /* coverity[member_decl] */
bool initialised_;
};
class Sign : public SignBase {
public:
static void Initialize(Environment* env, v8::Handle<v8::Object> target); static void Initialize(Environment* env, v8::Handle<v8::Object> target);
void SignInit(const char* sign_type); Error SignInit(const char* sign_type);
bool SignUpdate(const char* data, int len); Error SignUpdate(const char* data, int len);
bool SignFinal(const char* key_pem, Error SignFinal(const char* key_pem,
int key_pem_len, int key_pem_len,
const char* passphrase, const char* passphrase,
unsigned char** sig, unsigned char** sig,
unsigned int *sig_len); unsigned int *sig_len);
protected: protected:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -470,35 +497,22 @@ class Sign : public BaseObject {
static void SignUpdate(const v8::FunctionCallbackInfo<v8::Value>& args); static void SignUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SignFinal(const v8::FunctionCallbackInfo<v8::Value>& args); static void SignFinal(const v8::FunctionCallbackInfo<v8::Value>& args);
Sign(Environment* env, v8::Local<v8::Object> wrap) Sign(Environment* env, v8::Local<v8::Object> wrap) : SignBase(env, wrap) {
: BaseObject(env, wrap),
md_(NULL),
initialised_(false) {
MakeWeak<Sign>(this); MakeWeak<Sign>(this);
} }
private:
EVP_MD_CTX mdctx_; /* coverity[member_decl] */
const EVP_MD* md_; /* coverity[member_decl] */
bool initialised_;
}; };
class Verify : public BaseObject { class Verify : public SignBase {
public: public:
~Verify() {
if (!initialised_)
return;
EVP_MD_CTX_cleanup(&mdctx_);
}
static void Initialize(Environment* env, v8::Handle<v8::Object> target); static void Initialize(Environment* env, v8::Handle<v8::Object> target);
void VerifyInit(const char* verify_type); Error VerifyInit(const char* verify_type);
bool VerifyUpdate(const char* data, int len); Error VerifyUpdate(const char* data, int len);
bool VerifyFinal(const char* key_pem, Error VerifyFinal(const char* key_pem,
int key_pem_len, int key_pem_len,
const char* sig, const char* sig,
int siglen); int siglen,
bool* verify_result);
protected: protected:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -506,17 +520,9 @@ class Verify : public BaseObject {
static void VerifyUpdate(const v8::FunctionCallbackInfo<v8::Value>& args); static void VerifyUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void VerifyFinal(const v8::FunctionCallbackInfo<v8::Value>& args); static void VerifyFinal(const v8::FunctionCallbackInfo<v8::Value>& args);
Verify(Environment* env, v8::Local<v8::Object> wrap) Verify(Environment* env, v8::Local<v8::Object> wrap) : SignBase(env, wrap) {
: BaseObject(env, wrap),
md_(NULL),
initialised_(false) {
MakeWeak<Verify>(this); MakeWeak<Verify>(this);
} }
private:
EVP_MD_CTX mdctx_; /* coverity[member_decl] */
const EVP_MD* md_; /* coverity[member_decl] */
bool initialised_;
}; };
class DiffieHellman : public BaseObject { class DiffieHellman : public BaseObject {

Loading…
Cancel
Save