Skip to content

Commit 79992fe

Browse files
deepview-autofixclaudeChALkeR
authored
lib: fix unsigned conversion of 4-byte RSA publicExponent
`bigIntArrayToUnsignedInt` used the signed `<<` operator, so when the most significant byte of a 4-byte input had its top bit set (e.g. `[0x80, 0x00, 0x00, 0x01]`) the result was a negative Int32 instead of the intended unsigned 32-bit value. This caused any RSA `publicExponent` exactly 4 bytes long with the top bit set to be parsed incorrectly. Coerce the final value with `>>> 0` and add a unit test. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: DeepView Autofix <276251120+deepview-autofix@users.noreply.github.com> Co-Authored-By: Nikita Skovoroda <chalkerx@gmail.com> Signed-off-by: Nikita Skovoroda <chalkerx@gmail.com>
1 parent 14e16db commit 79992fe

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

lib/internal/crypto/util.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,10 @@ function bigIntArrayToUnsignedInt(input) {
696696
result |= input[n] << 8 * n_reversed;
697697
}
698698

699-
return result;
699+
// Coerce the result to an unsigned 32-bit integer. Without this, a most
700+
// significant byte with the top bit set (e.g. [0x80, 0x00, 0x00, 0x01])
701+
// would be returned as a negative Int32 because of the signed `<<` operator.
702+
return result >>> 0;
700703
}
701704

702705
function bigIntArrayToUnsignedBigInt(input) {

test/parallel/test-webcrypto-util.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,28 @@ if (!common.hasCrypto)
88
const assert = require('assert');
99

1010
const {
11+
bigIntArrayToUnsignedInt,
1112
normalizeAlgorithm,
1213
} = require('internal/crypto/util');
1314

15+
// bigIntArrayToUnsignedInt must return an unsigned 32-bit value even when
16+
// the most significant byte has its top bit set. Otherwise the signed `<<`
17+
// operator yields a negative Int32 for inputs like [0x80, 0x00, 0x00, 0x01].
18+
{
19+
assert.strictEqual(
20+
bigIntArrayToUnsignedInt(new Uint8Array([0x80, 0x00, 0x00, 0x01])),
21+
0x80000001);
22+
assert.strictEqual(
23+
bigIntArrayToUnsignedInt(new Uint8Array([0xff, 0xff, 0xff, 0xff])),
24+
0xffffffff);
25+
assert.strictEqual(
26+
bigIntArrayToUnsignedInt(new Uint8Array([1, 0, 1])),
27+
65537);
28+
assert.strictEqual(
29+
bigIntArrayToUnsignedInt(new Uint8Array([1, 0, 0, 0, 0])),
30+
undefined);
31+
}
32+
1433
{
1534
// Check that normalizeAlgorithm does not mutate object inputs.
1635
const algorithm = { name: 'ECDSA', hash: 'SHA-256' };

0 commit comments

Comments
 (0)