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
This commit is contained in:
parent
e57ab7ba06
commit
661190af13
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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…
x
Reference in New Issue
Block a user