From 67d21149a20fcad27100a5fd6dfa7c3de98a59cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sun, 2 Apr 2017 15:00:32 +0200 Subject: [PATCH] crypto: handle exceptions in hmac/hash.digest Forced conversion of the encoding parameter to a string within crypto.js, fixing segmentation faults in node_crypto.cc. Fixes: https://github.com/nodejs/node/issues/9819 PR-URL: https://github.com/nodejs/node/pull/12164 Reviewed-By: Ben Noordhuis Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- lib/crypto.js | 3 ++- src/node.cc | 2 ++ src/node_crypto.cc | 20 +++++++------------- test/parallel/test-regress-GH-9819.js | 24 ++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 test/parallel/test-regress-GH-9819.js diff --git a/lib/crypto.js b/lib/crypto.js index 9180ce70dce12e..1d8e294bd7bfe6 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -78,7 +78,8 @@ Hash.prototype.update = function update(data, encoding) { Hash.prototype.digest = function digest(outputEncoding) { outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; - return this._handle.digest(outputEncoding); + // Explicit conversion for backward compatibility. + return this._handle.digest(`${outputEncoding}`); }; diff --git a/src/node.cc b/src/node.cc index 7a7f2451d8b45c..3190d371f5ad04 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1443,6 +1443,8 @@ enum encoding ParseEncoding(const char* encoding, enum encoding ParseEncoding(Isolate* isolate, Local encoding_v, enum encoding default_encoding) { + CHECK(!encoding_v.IsEmpty()); + if (!encoding_v->IsString()) return default_encoding; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index a463a4667a63be..33732778af29ef 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3769,9 +3769,8 @@ void Hmac::HmacDigest(const FunctionCallbackInfo& args) { enum encoding encoding = BUFFER; if (args.Length() >= 1) { - encoding = ParseEncoding(env->isolate(), - args[0]->ToString(env->isolate()), - BUFFER); + CHECK(args[0]->IsString()); + encoding = ParseEncoding(env->isolate(), args[0], BUFFER); } unsigned char* md_value = nullptr; @@ -3893,9 +3892,8 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { enum encoding encoding = BUFFER; if (args.Length() >= 1) { - encoding = ParseEncoding(env->isolate(), - args[0]->ToString(env->isolate()), - BUFFER); + CHECK(args[0]->IsString()); + encoding = ParseEncoding(env->isolate(), args[0], BUFFER); } unsigned char md_value[EVP_MAX_MD_SIZE]; @@ -4118,10 +4116,8 @@ void Sign::SignFinal(const FunctionCallbackInfo& args) { unsigned int len = args.Length(); enum encoding encoding = BUFFER; - if (len >= 2 && args[1]->IsString()) { - encoding = ParseEncoding(env->isolate(), - args[1]->ToString(env->isolate()), - BUFFER); + if (len >= 2) { + encoding = ParseEncoding(env->isolate(), args[1], BUFFER); } node::Utf8Value passphrase(env->isolate(), args[2]); @@ -4334,9 +4330,7 @@ void Verify::VerifyFinal(const FunctionCallbackInfo& args) { enum encoding encoding = UTF8; if (args.Length() >= 3) { - encoding = ParseEncoding(env->isolate(), - args[2]->ToString(env->isolate()), - UTF8); + encoding = ParseEncoding(env->isolate(), args[2], UTF8); } ssize_t hlen = StringBytes::Size(env->isolate(), args[1], encoding); diff --git a/test/parallel/test-regress-GH-9819.js b/test/parallel/test-regress-GH-9819.js new file mode 100644 index 00000000000000..f043bc3b2848e7 --- /dev/null +++ b/test/parallel/test-regress-GH-9819.js @@ -0,0 +1,24 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const execFile = require('child_process').execFile; + +if (!common.hasCrypto) { + common.skip('missing crypto'); + return; +} + +const setup = 'const enc = { toString: () => { throw new Error("xyz"); } };'; + +const scripts = [ + 'crypto.createHash("sha256").digest(enc)', + 'crypto.createHmac("sha256", "msg").digest(enc)' +]; + +scripts.forEach((script) => { + const node = process.execPath; + const code = setup + ';' + script; + execFile(node, [ '-e', code ], common.mustCall((err, stdout, stderr) => { + assert(stderr.includes('Error: xyz'), 'digest crashes'); + })); +});