diff --git a/src/crypto/crypto_timing.cc b/src/crypto/crypto_timing.cc index a0194f22cfd51e..0601f70926b245 100644 --- a/src/crypto/crypto_timing.cc +++ b/src/crypto/crypto_timing.cc @@ -56,6 +56,20 @@ bool FastTimingSafeEqual(Local receiver, // NOLINTNEXTLINE(runtime/references) FastApiCallbackOptions& options) { HandleScope scope(options.isolate); + if (!IsAnyBufferSource(a_obj)) { + TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.error"); + THROW_ERR_INVALID_ARG_TYPE(options.isolate, + "The \"buf1\" argument must be an instance of " + "ArrayBuffer, Buffer, TypedArray, or DataView."); + return false; + } + if (!IsAnyBufferSource(b_obj)) { + TRACK_V8_FAST_API_CALL("crypto.timingSafeEqual.error"); + THROW_ERR_INVALID_ARG_TYPE(options.isolate, + "The \"buf2\" argument must be an instance of " + "ArrayBuffer, Buffer, TypedArray, or DataView."); + return false; + } ArrayBufferViewContents a(a_obj); ArrayBufferViewContents b(b_obj); if (a.length() != b.length()) { diff --git a/test/sequential/test-crypto-timing-safe-equal-fast.js b/test/sequential/test-crypto-timing-safe-equal-fast.js new file mode 100644 index 00000000000000..0774eeae561fbb --- /dev/null +++ b/test/sequential/test-crypto-timing-safe-equal-fast.js @@ -0,0 +1,40 @@ +// Test v8 fast path for crypto.timingSafeEqual works correctly. +// Flags: --expose-internals --allow-natives-syntax +'use strict'; + +const common = require('../common'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const crypto = require('crypto'); + +// V8 Fast API +const foo = Buffer.from('foo'); +const bar = Buffer.from('bar'); +const longer = Buffer.from('longer'); +function testFastPath(buf1, buf2) { + return crypto.timingSafeEqual(buf1, buf2); +} +eval('%PrepareFunctionForOptimization(testFastPath)'); +assert.strictEqual(testFastPath(foo, bar), false); +eval('%OptimizeFunctionOnNextCall(testFastPath)'); +assert.strictEqual(testFastPath(foo, bar), false); +assert.strictEqual(testFastPath(foo, foo), true); +assert.throws(() => testFastPath(foo, longer), { + code: 'ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH', +}); +assert.throws(() => testFastPath(foo, ''), { + code: 'ERR_INVALID_ARG_TYPE', +}); +assert.throws(() => testFastPath('', ''), { + code: 'ERR_INVALID_ARG_TYPE', +}); + +if (common.isDebug) { + const { internalBinding } = require('internal/test/binding'); + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('crypto.timingSafeEqual.ok'), 2); + assert.strictEqual(getV8FastApiCallCount('crypto.timingSafeEqual.error'), 3); +} diff --git a/test/sequential/test-crypto-timing-safe-equal.js b/test/sequential/test-crypto-timing-safe-equal.js index 80b3a69e59cb2d..74ae39fbafcd0c 100644 --- a/test/sequential/test-crypto-timing-safe-equal.js +++ b/test/sequential/test-crypto-timing-safe-equal.js @@ -1,4 +1,4 @@ -// Flags: --expose-internals --no-warnings --allow-natives-syntax +// Flags: --no-warnings 'use strict'; const common = require('../common'); if (!common.hasCrypto) @@ -92,28 +92,3 @@ assert.throws( name: 'TypeError', } ); - -{ - // V8 Fast API - const foo = Buffer.from('foo'); - const bar = Buffer.from('bar'); - const longer = Buffer.from('longer'); - function testFastPath(buf1, buf2) { - return crypto.timingSafeEqual(buf1, buf2); - } - eval('%PrepareFunctionForOptimization(testFastPath)'); - assert.strictEqual(testFastPath(foo, bar), false); - eval('%OptimizeFunctionOnNextCall(testFastPath)'); - assert.strictEqual(testFastPath(foo, bar), false); - assert.strictEqual(testFastPath(foo, foo), true); - assert.throws(() => testFastPath(foo, longer), { - code: 'ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH', - }); - - if (common.isDebug) { - const { internalBinding } = require('internal/test/binding'); - const { getV8FastApiCallCount } = internalBinding('debug'); - assert.strictEqual(getV8FastApiCallCount('crypto.timingSafeEqual.ok'), 2); - assert.strictEqual(getV8FastApiCallCount('crypto.timingSafeEqual.error'), 1); - } -}