Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,12 @@ source and a list of supported platforms.

## Security

Security flaws in Node.js should be reported by emailing security@nodejs.org.
Please do not disclose security bugs publicly until they have been handled by
the security team.
If you find a security vulnerability in Node.js, please report it to
security@nodejs.org. Please withhold public disclosure until after the security
team has addressed the vulnerability.

Your email will be acknowledged within 24 hours, and you will receive a more
detailed response to your email within 48 hours indicating the next steps in
handling your report.
The security team will acknowledge your email within 24 hours. You will receive
a more detailed response within 48 hours.

There are no hard and fast rules to determine if a bug is worth reporting as
a security issue. The general rule is an issue worth reporting should allow an
Expand Down
2 changes: 1 addition & 1 deletion doc/api/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ changes:
first byte is the length of the next protocol name. Passing an array is
usually much simpler, e.g. `['hello', 'world']`.
* `servername`: {string} Server name for the SNI (Server Name Indication) TLS
extension.
extension. It must be a host name, and not an IP address.
* `checkServerIdentity(servername, cert)` {Function} A callback function
to be used (instead of the builtin `tls.checkServerIdentity()` function)
when checking the server's hostname (or the provided `servername` when
Expand Down
32 changes: 13 additions & 19 deletions lib/_http_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,13 @@ function parserOnMessageComplete() {
const parsers = new FreeList('parsers', 1000, function parsersCb() {
const parser = new HTTPParser(HTTPParser.REQUEST);

parser._headers = [];
parser._url = '';
parser._consumed = false;

parser.socket = null;
parser.incoming = null;
parser.outgoing = null;

parser.maxHeaderPairs = MAX_HEADER_PAIRS;
cleanParser(parser);

parser.onIncoming = null;
parser[kOnHeaders] = parserOnHeaders;
parser[kOnHeadersComplete] = parserOnHeadersComplete;
parser[kOnBody] = parserOnBody;
parser[kOnMessageComplete] = parserOnMessageComplete;
parser[kOnExecute] = null;

return parser;
});
Expand All @@ -182,17 +173,9 @@ function closeParserInstance(parser) { parser.close(); }
// should be all that is needed.
function freeParser(parser, req, socket) {
if (parser) {
parser._headers = [];
parser._url = '';
parser.maxHeaderPairs = MAX_HEADER_PAIRS;
parser.onIncoming = null;
if (parser._consumed)
parser.unconsume();
parser._consumed = false;
parser.socket = null;
parser.incoming = null;
parser.outgoing = null;
parser[kOnExecute] = null;
cleanParser(parser);
if (parsers.free(parser) === false) {
// Make sure the parser's stack has unwound before deleting the
// corresponding C++ object through .close().
Expand Down Expand Up @@ -238,6 +221,17 @@ function checkInvalidHeaderChar(val) {
return headerCharRegex.test(val);
}

function cleanParser(parser) {
parser._headers = [];
parser._url = '';
parser.socket = null;
parser.incoming = null;
parser.outgoing = null;
parser.maxHeaderPairs = MAX_HEADER_PAIRS;
parser[kOnExecute] = null;
parser._consumed = false;
}

module.exports = {
_checkInvalidHeaderChar: checkInvalidHeaderChar,
_checkIsHttpToken: checkIsHttpToken,
Expand Down
46 changes: 44 additions & 2 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,46 @@ function uvException(ctx) {
return err;
}

/**
* This creates an error compatible with errors produced in the C++
* This function should replace the deprecated
* `exceptionWithHostPort()` function.
*
* @param {number} err - A libuv error number
* @param {string} syscall
* @param {string} address
* @param {number} [port]
* @param {string} [additional]
* @returns {Error}
*/
function uvExceptionWithHostPort(err, syscall, address, port, additional) {
const [ code, uvmsg ] = errmap.get(err);
const message = `${syscall} ${code}: ${uvmsg}`;
let details = '';

if (port && port > 0) {
details = ` ${address}:${port}`;
} else if (address) {
details = ` ${address}`;
}
if (additional) {
details += ` - Local (${additional})`;
}

// eslint-disable-next-line no-restricted-syntax
const ex = new Error(`${message}${details}`);
ex.code = code;
ex.errno = code;
ex.syscall = syscall;
ex.address = address;
if (port) {
ex.port = port;
}

Error.captureStackTrace(ex, uvExceptionWithHostPort);
return ex;
}

/**
* This used to be util._errnoException().
*
Expand Down Expand Up @@ -315,8 +355,9 @@ function errnoException(err, syscall, original) {
}

/**
* This used to be util._exceptionWithHostPort().
*
* Deprecated, new function is `uvExceptionWithHostPort()`
* New function added the error description directly
* from C++. this method for backwards compatibility
* @param {number} err - A libuv error number
* @param {string} syscall
* @param {string} address
Expand Down Expand Up @@ -440,6 +481,7 @@ module.exports = {
errnoException,
exceptionWithHostPort,
uvException,
uvExceptionWithHostPort,
isStackOverflowError,
getMessage,
SystemError,
Expand Down
7 changes: 3 additions & 4 deletions lib/internal/wrap_js_stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ class JSStreamWrap extends Socket {
}

doShutdown(req) {
assert.strictEqual(this[kCurrentShutdownRequest], null);
this[kCurrentShutdownRequest] = req;

// TODO(addaleax): It might be nice if we could get into a state where
// DoShutdown() is not called on streams while a write is still pending.
//
Expand All @@ -113,8 +110,10 @@ class JSStreamWrap extends Socket {
// so for now that is supported here.

if (this[kCurrentWriteRequest] !== null)
return this.on('drain', () => this.doShutdown(req));
return this.once('drain', () => this.doShutdown(req));
assert.strictEqual(this[kCurrentWriteRequest], null);
assert.strictEqual(this[kCurrentShutdownRequest], null);
this[kCurrentShutdownRequest] = req;

const handle = this._handle;

Expand Down
10 changes: 7 additions & 3 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ const kLastWriteQueueSize = Symbol('lastWriteQueueSize');
let cluster;
let dns;

const { errnoException, exceptionWithHostPort } = errors;
const {
errnoException,
exceptionWithHostPort,
uvExceptionWithHostPort
} = errors;

const {
kTimeout,
Expand Down Expand Up @@ -1266,7 +1270,7 @@ function setupListenHandle(address, port, addressType, backlog, fd) {
rval = createServerHandle(address, port, addressType, fd);

if (typeof rval === 'number') {
var error = exceptionWithHostPort(rval, 'listen', address, port);
var error = uvExceptionWithHostPort(rval, 'listen', address, port);
process.nextTick(emitErrorNT, this, error);
return;
}
Expand All @@ -1283,7 +1287,7 @@ function setupListenHandle(address, port, addressType, backlog, fd) {
var err = this._handle.listen(backlog || 511);

if (err) {
var ex = exceptionWithHostPort(err, 'listen', address, port);
var ex = uvExceptionWithHostPort(err, 'listen', address, port);
this._handle.close();
this._handle = null;
defaultTriggerAsyncIdScope(this[async_id_symbol],
Expand Down
4 changes: 2 additions & 2 deletions lib/zlib.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ function zlibBufferSync(engine, buffer) {
return buffer;
}

function zlibOnError(message, errno) {
function zlibOnError(message, errno, code) {
var self = this[owner_symbol];
// there is no way to cleanly recover.
// continuing only obscures problems.
Expand All @@ -153,7 +153,7 @@ function zlibOnError(message, errno) {
// eslint-disable-next-line no-restricted-syntax
const error = new Error(message);
error.errno = errno;
error.code = codes[errno];
error.code = code;
self.emit('error', error);
}

Expand Down
43 changes: 5 additions & 38 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,24 +236,7 @@ class NodeTraceStateObserver :
trace_process->SetString("napi", node_napi_version);

#if HAVE_OPENSSL
// Stupid code to slice out the version string.
{ // NOLINT(whitespace/braces)
size_t i, j, k;
int c;
for (i = j = 0, k = sizeof(OPENSSL_VERSION_TEXT) - 1; i < k; ++i) {
c = OPENSSL_VERSION_TEXT[i];
if ('0' <= c && c <= '9') {
for (j = i + 1; j < k; ++j) {
c = OPENSSL_VERSION_TEXT[j];
if (c == ' ')
break;
}
break;
}
}
trace_process->SetString("openssl",
std::string(&OPENSSL_VERSION_TEXT[i], j - i));
}
trace_process->SetString("openssl", crypto::GetOpenSSLVersion());
#endif
trace_process->EndDictionary();

Expand Down Expand Up @@ -1762,26 +1745,10 @@ void SetupProcessObject(Environment* env,
FIXED_ONE_BYTE_STRING(env->isolate(), node_napi_version));

#if HAVE_OPENSSL
// Stupid code to slice out the version string.
{ // NOLINT(whitespace/braces)
size_t i, j, k;
int c;
for (i = j = 0, k = sizeof(OPENSSL_VERSION_TEXT) - 1; i < k; ++i) {
c = OPENSSL_VERSION_TEXT[i];
if ('0' <= c && c <= '9') {
for (j = i + 1; j < k; ++j) {
c = OPENSSL_VERSION_TEXT[j];
if (c == ' ')
break;
}
break;
}
}
READONLY_PROPERTY(
versions,
"openssl",
OneByteString(env->isolate(), &OPENSSL_VERSION_TEXT[i], j - i));
}
READONLY_PROPERTY(
versions,
"openssl",
OneByteString(env->isolate(), crypto::GetOpenSSLVersion().c_str()));
#endif

// process.arch
Expand Down
36 changes: 36 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,19 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyIVIndex"),
Integer::NewFromUnsigned(env->isolate(), kTicketKeyIVIndex));

Local<FunctionTemplate> ctx_getter_templ =
FunctionTemplate::New(env->isolate(),
CtxGetter,
env->as_external(),
Signature::New(env->isolate(), t));


t->PrototypeTemplate()->SetAccessorProperty(
FIXED_ONE_BYTE_STRING(env->isolate(), "_external"),
ctx_getter_templ,
Local<FunctionTemplate>(),
static_cast<PropertyAttribute>(ReadOnly | DontDelete));

target->Set(secureContextString,
t->GetFunction(env->context()).ToLocalChecked());
env->set_secure_context_constructor_template(t);
Expand Down Expand Up @@ -1327,6 +1340,14 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
}


void SecureContext::CtxGetter(const FunctionCallbackInfo<Value>& info) {
SecureContext* sc;
ASSIGN_OR_RETURN_UNWRAP(&sc, info.This());
Local<External> ext = External::New(info.GetIsolate(), sc->ctx_.get());
info.GetReturnValue().Set(ext);
}


template <bool primary>
void SecureContext::GetCertificate(const FunctionCallbackInfo<Value>& args) {
SecureContext* wrap;
Expand Down Expand Up @@ -5724,6 +5745,21 @@ void Initialize(Local<Object> target,
#endif // OPENSSL_NO_SCRYPT
}

constexpr int search(const char* s, int n, int c) {
return *s == c ? n : search(s + 1, n + 1, c);
}

std::string GetOpenSSLVersion() {
// sample openssl version string format
// for reference: "OpenSSL 1.1.0i 14 Aug 2018"
char buf[128];
const int start = search(OPENSSL_VERSION_TEXT, 0, ' ') + 1;
const int end = search(OPENSSL_VERSION_TEXT + start, start, ' ') + 1;
const int len = end - start;
snprintf(buf, len, "%.*s\n", len, &OPENSSL_VERSION_TEXT[start]);
return std::string(buf);
}

} // namespace crypto
} // namespace node

Expand Down
2 changes: 2 additions & 0 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx);
extern void UseExtraCaCerts(const std::string& file);

void InitCryptoOnce();
std::string GetOpenSSLVersion();

class SecureContext : public BaseObject {
public:
Expand Down Expand Up @@ -165,6 +166,7 @@ class SecureContext : public BaseObject {
const v8::FunctionCallbackInfo<v8::Value>& args);
static void EnableTicketKeyCallback(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void CtxGetter(const v8::FunctionCallbackInfo<v8::Value>& info);

template <bool primary>
static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down
Loading