diff --git a/lib/crypto.js b/lib/crypto.js index 3e7ed5e9c86960..0785ab617ea376 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -100,7 +100,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 2eadc71982256d..5b5be22bf3b3f7 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1483,6 +1483,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 45b06eaff50385..0f9ed3434eca09 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3797,9 +3797,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; @@ -3921,9 +3920,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]; @@ -4201,10 +4199,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]); @@ -4452,9 +4448,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'); + })); +});