Skip to content

Commit

Permalink
crypto,errors: use byteLength, not length in safeTimingEqual
Browse files Browse the repository at this point in the history
crypto.timingSafeEqual() can cause the core to abort
if the length parameter matches; however the internal
byte length differs. This commit makes the length
validation use bytewise (ArrayBufferLike) byteLength
rather than array content length.

Reissuing of nodejs#21397 with various modifications and fixes.
  • Loading branch information
ZaneHannanAU authored and Zane Hannan committed Oct 10, 2018
1 parent 43a1bc3 commit 33f9fa2
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/internal/crypto/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function timingSafeEqual(buf1, buf2) {
throw new ERR_INVALID_ARG_TYPE('buf2',
['Buffer', 'TypedArray', 'DataView'], buf2);
}
if (buf1.length !== buf2.length) {
if (buf1.byteLength !== buf2.byteLength) {
throw new ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH();
}
return _timingSafeEqual(buf1, buf2);
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error);
// Switch to TypeError. The current implementation does not seem right.
E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign', Error);
E('ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH',
'Input buffers must have the same length', RangeError);
'Input buffers must have the same byteLength', RangeError);
E('ERR_DNS_SET_SERVERS_FAILED', 'c-ares failed to set servers: "%s" [%s]',
Error);
E('ERR_DOMAIN_CALLBACK_NOT_AVAILABLE',
Expand Down
104 changes: 103 additions & 1 deletion test/sequential/test-crypto-timing-safe-equal.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,114 @@ assert.strictEqual(
false
);

{
const ab32 = new ArrayBuffer(32);
const dv32 = new DataView(ab32);
dv32.setUint32(0, 1);
dv32.setUint32(4, 1, true);
dv32.setBigUint64(8, 1n);
dv32.setBigUint64(16, 1n, true);
dv32.setUint16(24, 1);
dv32.setUint16(26, 1, true);
dv32.setUint8(28, 1);
dv32.setUint8(29, 1);

// 'should consider equal buffers to be equal'
assert.strictEqual(
crypto.timingSafeEqual(Buffer.from(ab32), dv32),
true
);
assert.strictEqual(
crypto.timingSafeEqual(new Uint32Array(ab32), dv32),
true
);
assert.strictEqual(
crypto.timingSafeEqual(
new Uint8Array(ab32, 0, 16),
Buffer.from(ab32, 0, 16)
),
true
);
assert.strictEqual(
crypto.timingSafeEqual(
new Uint32Array(ab32, 0, 8),
Buffer.of(0, 0, 0, 1, // 4
1, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 1, // 16
1, 0, 0, 0, 0, 0, 0, 0, // 24
0, 1, // 26
1, 0, // 28
1, 1, // 30
0, 0) // 32
),
true
);

// 'should consider unequal buffer views to be unequal'
assert.strictEqual(
crypto.timingSafeEqual(
new Uint32Array(ab32, 16, 4),
Buffer.from(ab32, 0, 16)
),
false
);
assert.strictEqual(
crypto.timingSafeEqual(
new Uint8Array(ab32, 0, 16),
Buffer.from(ab32, 16, 16)
),
false
);
assert.strictEqual(
crypto.timingSafeEqual(
new Uint32Array(ab32, 0, 8),
Buffer.of(0, 0, 0, 1, // 4
1, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 1, // 16
1, 0, 0, 0, 0, 0, 0, 0, // 24
0, 1, // 26
1, 0, // 28
1, 1, // 30
0, 1) // 32
),
false
);
// 'buffers with differing byteLength must throw an equal length error'
common.expectsError(
() => crypto.timingSafeEqual(Buffer.from(ab32, 0, 8),
Buffer.from(ab32, 0, 9)),
{
code: 'ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH',
type: RangeError,
message: 'Input buffers must have the same byteLength'
}
);
common.expectsError(
() => crypto.timingSafeEqual(
new Uint32Array(ab32, 0, 8), // 32
Buffer.of(0, 0, 0, 1, // 4
1, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 1, // 16
1, 0, 0, 0, 0, 0, 0, 0, // 24
0, 1, // 26
1, 0, // 28
1, 1, // 30
0) // 31
),
{
code: 'ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH',
type: RangeError,
message: 'Input buffers must have the same byteLength'
}
);
}

common.expectsError(
() => crypto.timingSafeEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2])),
{
code: 'ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH',
type: RangeError,
message: 'Input buffers must have the same length'
message: 'Input buffers must have the same byteLength'
}
);

Expand Down

0 comments on commit 33f9fa2

Please sign in to comment.