From 8b5d350a35524f77b24974c92e7e4139f27794b5 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Wed, 27 Mar 2019 18:42:57 -0700 Subject: [PATCH] src: add .code and SSL specific error properties SSL errors have a long structured message, but lacked the standard .code property which can be used for stable comparisons. Add a `code` property, as well as the 3 string components of an SSL error: `reason`, `library`, and `function`. Backport-PR-URL: https://github.com/nodejs/node/pull/26951 PR-URL: https://github.com/nodejs/node/pull/25093 Reviewed-By: James M Snell Reviewed-By: Daniel Bevenius --- src/env.h | 2 ++ src/tls_wrap.cc | 37 +++++++++++++++++++++++- test/parallel/test-tls-alert-handling.js | 14 +++++++-- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/env.h b/src/env.h index 0516c49f36ddcd..e75e336f9d935b 100644 --- a/src/env.h +++ b/src/env.h @@ -185,6 +185,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; V(fingerprint_string, "fingerprint") \ V(flags_string, "flags") \ V(fragment_string, "fragment") \ + V(function_string, "function") \ V(get_data_clone_error_string, "_getDataCloneError") \ V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \ V(gid_string, "gid") \ @@ -208,6 +209,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; V(issuercert_string, "issuerCertificate") \ V(kill_signal_string, "killSignal") \ V(kind_string, "kind") \ + V(library_string, "library") \ V(mac_string, "mac") \ V(main_string, "main") \ V(max_buffer_string, "maxBuffer") \ diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 412d9e8e86eac6..cf579af85ec124 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -40,6 +40,7 @@ using v8::Exception; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; +using v8::Isolate; using v8::Local; using v8::Object; using v8::ReadOnly; @@ -367,9 +368,43 @@ Local TLSWrap::GetSSLError(int status, int* err, std::string* msg) { BUF_MEM* mem; BIO_get_mem_ptr(bio, &mem); + Isolate* isolate = env()->isolate(); + Local context = isolate->GetCurrentContext(); + Local message = - OneByteString(env()->isolate(), mem->data, mem->length); + OneByteString(isolate, mem->data, mem->length); Local exception = Exception::Error(message); + Local obj = exception->ToObject(context).ToLocalChecked(); + + const char* ls = ERR_lib_error_string(ssl_err); + const char* fs = ERR_func_error_string(ssl_err); + const char* rs = ERR_reason_error_string(ssl_err); + + if (ls != nullptr) + obj->Set(context, env()->library_string(), + OneByteString(isolate, ls)).FromJust(); + if (fs != nullptr) + obj->Set(context, env()->function_string(), + OneByteString(isolate, fs)).FromJust(); + if (rs != nullptr) { + obj->Set(context, env()->reason_string(), + OneByteString(isolate, rs)).FromJust(); + + // SSL has no API to recover the error name from the number, so we + // transform reason strings like "this error" to "ERR_SSL_THIS_ERROR", + // which ends up being close to the original error macro name. + std::string code(rs); + + for (auto& c : code) { + if (c == ' ') + c = '_'; + else + c = ::toupper(c); + } + obj->Set(context, env()->code_string(), + OneByteString(isolate, ("ERR_SSL_" + code).c_str())) + .FromJust(); + } if (msg != nullptr) msg->assign(mem->data, mem->data + mem->length); diff --git a/test/parallel/test-tls-alert-handling.js b/test/parallel/test-tls-alert-handling.js index e88453b115e0ea..63b845122fc1f0 100644 --- a/test/parallel/test-tls-alert-handling.js +++ b/test/parallel/test-tls-alert-handling.js @@ -7,6 +7,7 @@ if (!common.hasCrypto) if (!common.opensslCli) common.skip('node compiled without OpenSSL CLI'); +const assert = require('assert'); const net = require('net'); const tls = require('tls'); const fixtures = require('../common/fixtures'); @@ -29,7 +30,11 @@ const opts = { const max_iter = 20; let iter = 0; -const errorHandler = common.mustCall(() => { +const errorHandler = common.mustCall((err) => { + assert.strictEqual(err.code, 'ERR_SSL_WRONG_VERSION_NUMBER'); + assert.strictEqual(err.library, 'SSL routines'); + assert.strictEqual(err.function, 'ssl3_get_record'); + assert.strictEqual(err.reason, 'wrong version number'); errorReceived = true; if (canCloseServer()) server.close(); @@ -81,5 +86,10 @@ function sendBADTLSRecord() { socket.end(BAD_RECORD); }); })); - client.on('error', common.mustCall()); + client.on('error', common.mustCall((err) => { + assert.strictEqual(err.code, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION'); + assert.strictEqual(err.library, 'SSL routines'); + assert.strictEqual(err.function, 'ssl3_read_bytes'); + assert.strictEqual(err.reason, 'tlsv1 alert protocol version'); + })); }