quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

commit f80e75edbecb86ddca12ffb61f48dde6cd13fa0a
parent 4ca4ac0bce6588bb565babbec41d32785b92d630
Author: Florian Dold <dold@taler.net>
Date:   Sun,  9 Aug 2026 21:22:13 +0200

tart: bound attacker-controlled crypto work

Diffstat:
Mtart_module.c | 27++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/tart_module.c b/tart_module.c @@ -38,6 +38,11 @@ static JSValue make_js_ta_copy(JSContext *ctx, uint8_t *data, size_t size); +#define TART_MAX_RANDOM_BYTES (64U * 1024U * 1024U) +#define TART_MAX_ARGON2_OUTPUT (64U * 1024U) +#define TART_MAX_RSA_MODULUS_BYTES 1024U +#define TART_MAX_RSA_EXPONENT_BYTES 8U + static JSValue js_encode_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -71,6 +76,9 @@ static JSValue js_random_bytes(JSContext *ctx, JSValueConst this_val, if (0 != JS_ToUint32(ctx, &nbytes, argv[0])) { return JS_EXCEPTION; } + if (nbytes > TART_MAX_RANDOM_BYTES) { + return JS_ThrowRangeError(ctx, "random byte request is too large"); + } if (nbytes != 0) { randbuf = js_malloc(ctx, nbytes); if (!randbuf) { @@ -93,7 +101,7 @@ static JSValue js_random_bytes(JSContext *ctx, JSValueConst this_val, * @param a a character * @return corresponding numeric value */ -static unsigned int +static int getValue__ (unsigned char a) { unsigned int dec; @@ -272,6 +280,10 @@ static JSValue js_talercrypto_decode_crock(JSContext *ctx, JSValue this_val, vbit = encoded_len % 5; /* padding! */ shift = 5 - vbit; bits = (ret = getValue__ (enc[--rpos])) >> shift; + if (ret < 0 || (ret & ((1U << shift) - 1)) != 0) { + JS_ThrowTypeError(ctx, "invalid padding bits in encoding"); + goto exception; + } } else { @@ -397,7 +409,9 @@ rsa_public_key_decode(RsaPub *pkey, uint8_t *inbuf, size_t inbuf_len) memcpy(&encoded_len, p, sizeof encoded_len); exp_len = ntohs(encoded_len); sz = 4 + mod_len + exp_len; - if (sz != inbuf_len || mod_len == 0 || exp_len == 0) { + if (sz != inbuf_len || + mod_len < 128 || mod_len > TART_MAX_RSA_MODULUS_BYTES || + exp_len == 0 || exp_len > TART_MAX_RSA_EXPONENT_BYTES) { ret = -1; goto cleanup; } @@ -557,12 +571,14 @@ static JSValue js_talercrypto_hash_argon2id(JSContext *ctx, JSValue this_val, } if (iters < crypto_pwhash_OPSLIMIT_MIN || - iters > crypto_pwhash_OPSLIMIT_MAX) { + iters > crypto_pwhash_OPSLIMIT_MAX || + iters > crypto_pwhash_OPSLIMIT_MODERATE) { JS_ThrowRangeError(ctx, "iterations out of range"); goto exception; } if (hash_len < crypto_pwhash_BYTES_MIN || - hash_len > crypto_pwhash_BYTES_MAX) { + hash_len > crypto_pwhash_BYTES_MAX || + hash_len > TART_MAX_ARGON2_OUTPUT) { JS_ThrowRangeError(ctx, "hash length out of range"); goto exception; } @@ -574,7 +590,8 @@ static JSValue js_talercrypto_hash_argon2id(JSContext *ctx, JSValue this_val, } if ((size_t) mem_size * 1024 < crypto_pwhash_MEMLIMIT_MIN || - (size_t) mem_size * 1024 > crypto_pwhash_MEMLIMIT_MAX) { + (size_t) mem_size * 1024 > crypto_pwhash_MEMLIMIT_MAX || + (size_t) mem_size * 1024 > crypto_pwhash_MEMLIMIT_MODERATE) { JS_ThrowRangeError(ctx, "memory size out of range"); goto exception; }