mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
crypto: add internal error codes
PR-URL: https://github.com/nodejs/node/pull/37650 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
1 parent
b10349a246
commit
a28cb93f88
6 files changed
+110
-53
No files matched your search
@@ -227,18 +227,18 @@ class CipherJob final : public CryptoJob<CipherTraits> {
|
||||
// Success!
|
||||
return;
|
||||
}
|
||||
CryptoErrorVector* errors = CryptoJob<CipherTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
|
||||
errors->Capture();
|
||||
if (errors->empty()) {
|
||||
if (errors->Empty()) {
|
||||
switch (status) {
|
||||
case WebCryptoCipherStatus::OK:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case WebCryptoCipherStatus::INVALID_KEY_TYPE:
|
||||
errors->emplace_back("Invalid key type.");
|
||||
errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
|
||||
break;
|
||||
case WebCryptoCipherStatus::FAILED:
|
||||
errors->emplace_back("Cipher job failed.");
|
||||
errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -248,17 +248,17 @@ class CipherJob final : public CryptoJob<CipherTraits> {
|
||||
v8::Local<v8::Value>* err,
|
||||
v8::Local<v8::Value>* result) override {
|
||||
Environment* env = AsyncWrap::env();
|
||||
CryptoErrorVector* errors = CryptoJob<CipherTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
|
||||
if (out_.size() > 0) {
|
||||
CHECK(errors->empty());
|
||||
CHECK(errors->Empty());
|
||||
*err = v8::Undefined(env->isolate());
|
||||
*result = out_.ToArrayBuffer(env);
|
||||
return v8::Just(!result->IsEmpty());
|
||||
}
|
||||
|
||||
if (errors->empty())
|
||||
if (errors->Empty())
|
||||
errors->Capture();
|
||||
CHECK(!errors->empty());
|
||||
CHECK(!errors->Empty());
|
||||
*result = v8::Undefined(env->isolate());
|
||||
return v8::Just(errors->ToException(env).ToLocal(err));
|
||||
}
|
||||
|
||||
@@ -551,7 +551,7 @@ void SecureContext::SetEngineKey(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
CHECK_EQ(args.Length(), 2);
|
||||
|
||||
CryptoErrorVector errors;
|
||||
CryptoErrorStore errors;
|
||||
Utf8Value engine_id(env->isolate(), args[1]);
|
||||
EnginePointer engine = LoadEngineById(*engine_id, &errors);
|
||||
if (!engine) {
|
||||
@@ -987,7 +987,7 @@ void SecureContext::SetClientCertEngine(
|
||||
// support multiple calls to SetClientCertEngine.
|
||||
CHECK(!sc->client_cert_engine_provided_);
|
||||
|
||||
CryptoErrorVector errors;
|
||||
CryptoErrorStore errors;
|
||||
const Utf8Value engine_id(env->isolate(), args[0]);
|
||||
EnginePointer engine = LoadEngineById(*engine_id, &errors);
|
||||
if (!engine) {
|
||||
|
||||
@@ -82,10 +82,10 @@ class KeyGenJob final : public CryptoJob<KeyGenTraits> {
|
||||
// Success!
|
||||
break;
|
||||
case KeyGenJobStatus::FAILED: {
|
||||
CryptoErrorVector* errors = CryptoJob<KeyGenTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
|
||||
errors->Capture();
|
||||
if (errors->empty())
|
||||
errors->push_back(std::string("Key generation job failed"));
|
||||
if (errors->Empty())
|
||||
errors->Insert(NodeCryptoError::KEY_GENERATION_JOB_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ class KeyGenJob final : public CryptoJob<KeyGenTraits> {
|
||||
v8::Local<v8::Value>* err,
|
||||
v8::Local<v8::Value>* result) override {
|
||||
Environment* env = AsyncWrap::env();
|
||||
CryptoErrorVector* errors = CryptoJob<KeyGenTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<KeyGenTraits>::errors();
|
||||
AdditionalParams* params = CryptoJob<KeyGenTraits>::params();
|
||||
if (status_ == KeyGenJobStatus::OK &&
|
||||
LIKELY(!KeyGenTraits::EncodeKey(env, params, result).IsNothing())) {
|
||||
@@ -102,9 +102,9 @@ class KeyGenJob final : public CryptoJob<KeyGenTraits> {
|
||||
return v8::Just(true);
|
||||
}
|
||||
|
||||
if (errors->empty())
|
||||
if (errors->Empty())
|
||||
errors->Capture();
|
||||
CHECK(!errors->empty());
|
||||
CHECK(!errors->Empty());
|
||||
*result = Undefined(env->isolate());
|
||||
return v8::Just(errors->ToException(env).ToLocal(err));
|
||||
}
|
||||
|
||||
@@ -347,18 +347,18 @@ class KeyExportJob final : public CryptoJob<KeyExportTraits> {
|
||||
// Success!
|
||||
return;
|
||||
}
|
||||
CryptoErrorVector* errors = CryptoJob<KeyExportTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
|
||||
errors->Capture();
|
||||
if (errors->empty()) {
|
||||
if (errors->Empty()) {
|
||||
switch (status) {
|
||||
case WebCryptoKeyExportStatus::OK:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case WebCryptoKeyExportStatus::INVALID_KEY_TYPE:
|
||||
errors->emplace_back("Invalid key type.");
|
||||
errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
|
||||
break;
|
||||
case WebCryptoKeyExportStatus::FAILED:
|
||||
errors->emplace_back("Cipher job failed.");
|
||||
errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -368,17 +368,17 @@ class KeyExportJob final : public CryptoJob<KeyExportTraits> {
|
||||
v8::Local<v8::Value>* err,
|
||||
v8::Local<v8::Value>* result) override {
|
||||
Environment* env = AsyncWrap::env();
|
||||
CryptoErrorVector* errors = CryptoJob<KeyExportTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
|
||||
if (out_.size() > 0) {
|
||||
CHECK(errors->empty());
|
||||
CHECK(errors->Empty());
|
||||
*err = v8::Undefined(env->isolate());
|
||||
*result = out_.ToArrayBuffer(env);
|
||||
return v8::Just(!result->IsEmpty());
|
||||
}
|
||||
|
||||
if (errors->empty())
|
||||
if (errors->Empty())
|
||||
errors->Capture();
|
||||
CHECK(!errors->empty());
|
||||
CHECK(!errors->Empty());
|
||||
*result = v8::Undefined(env->isolate());
|
||||
return v8::Just(errors->ToException(env).ToLocal(err));
|
||||
}
|
||||
|
||||
+25
-17
@@ -187,44 +187,52 @@ void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(enabled);
|
||||
}
|
||||
|
||||
void CryptoErrorVector::Capture() {
|
||||
clear();
|
||||
while (auto err = ERR_get_error()) {
|
||||
void CryptoErrorStore::Capture() {
|
||||
errors_.clear();
|
||||
while (const uint32_t err = ERR_get_error()) {
|
||||
char buf[256];
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
push_back(buf);
|
||||
errors_.emplace_back(buf);
|
||||
}
|
||||
std::reverse(begin(), end());
|
||||
std::reverse(std::begin(errors_), std::end(errors_));
|
||||
}
|
||||
|
||||
MaybeLocal<Value> CryptoErrorVector::ToException(
|
||||
bool CryptoErrorStore::Empty() const {
|
||||
return errors_.empty();
|
||||
}
|
||||
|
||||
MaybeLocal<Value> CryptoErrorStore::ToException(
|
||||
Environment* env,
|
||||
Local<String> exception_string) const {
|
||||
if (exception_string.IsEmpty()) {
|
||||
CryptoErrorVector copy(*this);
|
||||
if (copy.empty()) copy.push_back("no error"); // But possibly a bug...
|
||||
CryptoErrorStore copy(*this);
|
||||
if (copy.Empty()) {
|
||||
// But possibly a bug...
|
||||
copy.Insert(NodeCryptoError::OK);
|
||||
}
|
||||
// Use last element as the error message, everything else goes
|
||||
// into the .opensslErrorStack property on the exception object.
|
||||
const std::string& last_error_string = copy.errors_.back();
|
||||
Local<String> exception_string;
|
||||
if (!String::NewFromUtf8(
|
||||
env->isolate(),
|
||||
copy.back().data(),
|
||||
last_error_string.data(),
|
||||
NewStringType::kNormal,
|
||||
copy.back().size()).ToLocal(&exception_string)) {
|
||||
last_error_string.size()).ToLocal(&exception_string)) {
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
copy.pop_back();
|
||||
copy.errors_.pop_back();
|
||||
return copy.ToException(env, exception_string);
|
||||
}
|
||||
|
||||
Local<Value> exception_v = Exception::Error(exception_string);
|
||||
CHECK(!exception_v.IsEmpty());
|
||||
|
||||
if (!empty()) {
|
||||
if (!Empty()) {
|
||||
CHECK(exception_v->IsObject());
|
||||
Local<Object> exception = exception_v.As<Object>();
|
||||
Local<Value> stack;
|
||||
if (!ToV8Value(env->context(), *this).ToLocal(&stack) ||
|
||||
if (!ToV8Value(env->context(), errors_).ToLocal(&stack) ||
|
||||
exception->Set(env->context(), env->openssl_error_stack(), stack)
|
||||
.IsNothing()) {
|
||||
return MaybeLocal<Value>();
|
||||
@@ -509,7 +517,7 @@ void ThrowCryptoError(Environment* env,
|
||||
Local<Object> obj;
|
||||
if (!String::NewFromUtf8(env->isolate(), message).ToLocal(&exception_string))
|
||||
return;
|
||||
CryptoErrorVector errors;
|
||||
CryptoErrorStore errors;
|
||||
errors.Capture();
|
||||
if (!errors.ToException(env, exception_string).ToLocal(&exception) ||
|
||||
!exception->ToObject(env->context()).ToLocal(&obj) ||
|
||||
@@ -520,7 +528,7 @@ void ThrowCryptoError(Environment* env,
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
EnginePointer LoadEngineById(const char* id, CryptoErrorVector* errors) {
|
||||
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors) {
|
||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||
|
||||
EnginePointer engine(ENGINE_by_id(id));
|
||||
@@ -539,14 +547,14 @@ EnginePointer LoadEngineById(const char* id, CryptoErrorVector* errors) {
|
||||
if (ERR_get_error() != 0) {
|
||||
errors->Capture();
|
||||
} else {
|
||||
errors->push_back(std::string("Engine \"") + id + "\" was not found");
|
||||
errors->Insert(NodeCryptoError::ENGINE_NOT_FOUND, id);
|
||||
}
|
||||
}
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
bool SetEngine(const char* id, uint32_t flags, CryptoErrorVector* errors) {
|
||||
bool SetEngine(const char* id, uint32_t flags, CryptoErrorStore* errors) {
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
EnginePointer engine = LoadEngineById(id, errors);
|
||||
if (!engine)
|
||||
|
||||
+61
-12
@@ -159,15 +159,64 @@ void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
|
||||
}
|
||||
}
|
||||
|
||||
enum class NodeCryptoError {
|
||||
CIPHER_JOB_FAILED,
|
||||
DERIVING_BITS_FAILED,
|
||||
ENGINE_NOT_FOUND,
|
||||
INVALID_KEY_TYPE,
|
||||
KEY_GENERATION_JOB_FAILED,
|
||||
OK
|
||||
};
|
||||
|
||||
// Utility struct used to harvest error information from openssl's error stack
|
||||
struct CryptoErrorVector : public std::vector<std::string> {
|
||||
struct CryptoErrorStore final : public MemoryRetainer {
|
||||
public:
|
||||
void Capture();
|
||||
|
||||
bool Empty() const;
|
||||
|
||||
template <typename... Args>
|
||||
void Insert(const NodeCryptoError error, Args&&... args);
|
||||
|
||||
v8::MaybeLocal<v8::Value> ToException(
|
||||
Environment* env,
|
||||
v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const;
|
||||
|
||||
SET_NO_MEMORY_INFO()
|
||||
SET_MEMORY_INFO_NAME(CryptoErrorStore);
|
||||
SET_SELF_SIZE(CryptoErrorStore);
|
||||
|
||||
private:
|
||||
std::vector<std::string> errors_;
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) {
|
||||
const char* error_string = nullptr;
|
||||
switch (error) {
|
||||
case NodeCryptoError::CIPHER_JOB_FAILED:
|
||||
error_string = "Cipher job failed";
|
||||
break;
|
||||
case NodeCryptoError::DERIVING_BITS_FAILED:
|
||||
error_string = "Deriving bits failed";
|
||||
break;
|
||||
case NodeCryptoError::ENGINE_NOT_FOUND:
|
||||
error_string = "Engine \"%s\" was not found";
|
||||
break;
|
||||
case NodeCryptoError::INVALID_KEY_TYPE:
|
||||
error_string = "Invalid key type";
|
||||
break;
|
||||
case NodeCryptoError::KEY_GENERATION_JOB_FAILED:
|
||||
error_string = "Key generation failed";
|
||||
break;
|
||||
case NodeCryptoError::OK:
|
||||
error_string = "Ok";
|
||||
break;
|
||||
}
|
||||
errors_.emplace_back(SPrintF(error_string,
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* MallocOpenSSL(size_t count) {
|
||||
void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
|
||||
@@ -320,7 +369,7 @@ class CryptoJob : public AsyncWrap, public ThreadPoolWork {
|
||||
|
||||
CryptoJobMode mode() const { return mode_; }
|
||||
|
||||
CryptoErrorVector* errors() { return &errors_; }
|
||||
CryptoErrorStore* errors() { return &errors_; }
|
||||
|
||||
AdditionalParams* params() { return ¶ms_; }
|
||||
|
||||
@@ -364,7 +413,7 @@ class CryptoJob : public AsyncWrap, public ThreadPoolWork {
|
||||
|
||||
private:
|
||||
const CryptoJobMode mode_;
|
||||
CryptoErrorVector errors_;
|
||||
CryptoErrorStore errors_;
|
||||
AdditionalParams params_;
|
||||
};
|
||||
|
||||
@@ -412,10 +461,10 @@ class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
|
||||
if (!DeriveBitsTraits::DeriveBits(
|
||||
AsyncWrap::env(),
|
||||
*CryptoJob<DeriveBitsTraits>::params(), &out_)) {
|
||||
CryptoErrorVector* errors = CryptoJob<DeriveBitsTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
|
||||
errors->Capture();
|
||||
if (errors->empty())
|
||||
errors->push_back("Deriving bits failed");
|
||||
if (errors->Empty())
|
||||
errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED);
|
||||
return;
|
||||
}
|
||||
success_ = true;
|
||||
@@ -425,9 +474,9 @@ class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
|
||||
v8::Local<v8::Value>* err,
|
||||
v8::Local<v8::Value>* result) override {
|
||||
Environment* env = AsyncWrap::env();
|
||||
CryptoErrorVector* errors = CryptoJob<DeriveBitsTraits>::errors();
|
||||
CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
|
||||
if (success_) {
|
||||
CHECK(errors->empty());
|
||||
CHECK(errors->Empty());
|
||||
*err = v8::Undefined(env->isolate());
|
||||
return DeriveBitsTraits::EncodeOutput(
|
||||
env,
|
||||
@@ -436,9 +485,9 @@ class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
|
||||
result);
|
||||
}
|
||||
|
||||
if (errors->empty())
|
||||
if (errors->Empty())
|
||||
errors->Capture();
|
||||
CHECK(!errors->empty());
|
||||
CHECK(!errors->Empty());
|
||||
*result = v8::Undefined(env->isolate());
|
||||
return v8::Just(errors->ToException(env).ToLocal(err));
|
||||
}
|
||||
@@ -505,12 +554,12 @@ struct EnginePointer {
|
||||
}
|
||||
};
|
||||
|
||||
EnginePointer LoadEngineById(const char* id, CryptoErrorVector* errors);
|
||||
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
|
||||
|
||||
bool SetEngine(
|
||||
const char* id,
|
||||
uint32_t flags,
|
||||
CryptoErrorVector* errors = nullptr);
|
||||
CryptoErrorStore* errors = nullptr);
|
||||
|
||||
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
#endif // !OPENSSL_NO_ENGINE
|
||||
|
||||
Reference in new issue
Block a user