Skip to content

Commit a6bedb1

Browse files
committed
crypto: guard against size_t overflow on experimental 32-bit arch
Refs: https://hackerone.com/reports/3655230 Signed-off-by: Filip Skokan <panva.ip@gmail.com>
1 parent 511a57a commit a6bedb1

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

src/crypto/crypto_turboshake.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,6 @@ bool KangarooTwelveTraits::DeriveBits(Environment* env,
589589
CryptoJobMode mode,
590590
CryptoErrorStore* errors) {
591591
CHECK_GT(params.output_length, 0);
592-
char* buf = MallocOpenSSL<char>(params.output_length);
593592

594593
const uint8_t* input = reinterpret_cast<const uint8_t*>(params.data.data());
595594
size_t input_len = params.data.size();
@@ -598,6 +597,18 @@ bool KangarooTwelveTraits::DeriveBits(Environment* env,
598597
reinterpret_cast<const uint8_t*>(params.customization.data());
599598
size_t custom_len = params.customization.size();
600599

600+
// Guard against size_t overflow in KangarooTwelve's s_len computation:
601+
// s_len = msg_len + custom_len + LengthEncode(custom_len).size()
602+
// LengthEncode produces at most sizeof(size_t) + 1 bytes.
603+
static constexpr size_t kMaxLengthEncodeSize = sizeof(size_t) + 1;
604+
if (input_len > SIZE_MAX - custom_len ||
605+
input_len + custom_len > SIZE_MAX - kMaxLengthEncodeSize) {
606+
errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED);
607+
return false;
608+
}
609+
610+
char* buf = MallocOpenSSL<char>(params.output_length);
611+
601612
switch (params.variant) {
602613
case KangarooTwelveVariant::KT128:
603614
KT128(input,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
// KangarooTwelve: data + customization size_t overflow on 32-bit platforms.
8+
// On 32-bit, msg_len + custom_len + LengthEncode(custom_len).size() can wrap
9+
// size_t, causing an undersized allocation and heap buffer overflow.
10+
// This test verifies the guard rejects such inputs.
11+
// When kMaxLength < 2^32 two max-sized buffers can overflow a 32-bit size_t.
12+
13+
const { kMaxLength } = require('buffer');
14+
15+
if (kMaxLength >= 2 ** 32)
16+
common.skip('only relevant when kMaxLength < 2^32');
17+
18+
const assert = require('assert');
19+
const { subtle } = globalThis.crypto;
20+
21+
let data, customization;
22+
try {
23+
data = new Uint8Array(kMaxLength);
24+
customization = new Uint8Array(kMaxLength);
25+
} catch {
26+
common.skip('insufficient memory to allocate test buffers');
27+
}
28+
29+
(async () => {
30+
await assert.rejects(
31+
subtle.digest(
32+
{ name: 'KT128', outputLength: 256, customization },
33+
data),
34+
{ name: 'OperationError' });
35+
36+
await assert.rejects(
37+
subtle.digest(
38+
{ name: 'KT256', outputLength: 512, customization },
39+
data),
40+
{ name: 'OperationError' });
41+
})().then(common.mustCall());

0 commit comments

Comments
 (0)