quickjs-tart

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

commit add82df147abf984d7494f62f9908c1384feb3fa
parent 201c563e2906b184aab8ea4490289d31fc861c03
Author: Florian Dold <dold@taler.net>
Date:   Sun,  9 Aug 2026 21:08:49 +0200

tart: reject malformed RSA inputs

Diffstat:
Mtart_module.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 94 insertions(+), 41 deletions(-)

diff --git a/tart_module.c b/tart_module.c @@ -388,11 +388,15 @@ rsa_public_key_decode(RsaPub *pkey, uint8_t *inbuf, size_t inbuf_len) goto cleanup; } p = inbuf; - mod_len = ntohs(*((uint16_t *) p)); + uint16_t encoded_len; + + memcpy(&encoded_len, p, sizeof encoded_len); + mod_len = ntohs(encoded_len); p += sizeof(uint16_t); - exp_len = ntohs(*((uint16_t *) p)); + memcpy(&encoded_len, p, sizeof encoded_len); + exp_len = ntohs(encoded_len); sz = 4 + mod_len + exp_len; - if (sz != inbuf_len) { + if (sz != inbuf_len || mod_len == 0 || exp_len == 0) { ret = -1; goto cleanup; } @@ -400,6 +404,14 @@ rsa_public_key_decode(RsaPub *pkey, uint8_t *inbuf, size_t inbuf_len) MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->N, p, mod_len)); p += mod_len; MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->e, p, exp_len)); + if (mbedtls_mpi_cmp_int(&pkey->N, 3) <= 0 || + mbedtls_mpi_get_bit(&pkey->N, 0) == 0 || + mbedtls_mpi_cmp_int(&pkey->e, 3) < 0 || + mbedtls_mpi_get_bit(&pkey->e, 0) == 0 || + mbedtls_mpi_cmp_mpi(&pkey->e, &pkey->N) >= 0) { + ret = -1; + goto cleanup; + } cleanup: if (ret != 0) { @@ -909,55 +921,74 @@ exception: goto done; } -/** FIXME: Should return int */ -void +static int kdf_mod_mpi(mbedtls_mpi *r, const mbedtls_mpi *n, const void *xts, size_t xts_len, const void *skm, size_t skm_len, const char *ctx) { - int rc; + int ret = -1; size_t nbits; - uint16_t ctr; + uint32_t ctr; size_t ctxlen = strlen(ctx); size_t my_ctx_len = ctxlen + 2; - unsigned char *my_ctx = malloc(my_ctx_len); - uint16_t *ctr_nbo_p = (uint16_t *) (my_ctx + ctxlen); + unsigned char *my_ctx = NULL; + uint8_t *buf = NULL; + size_t bsize; + my_ctx = malloc(my_ctx_len); + if (!my_ctx) { + goto cleanup; + } memcpy(my_ctx, ctx, ctxlen); nbits = mbedtls_mpi_bitlen(n); - ctr = 0; - while (1) { - /* Not clear if n is always divisible by 8 */ - size_t bsize = (nbits - 1) / 8 + 1; - uint8_t buf[bsize]; - - *ctr_nbo_p = htons (ctr); - - rc = kdf (buf, bsize, - skm, skm_len, - xts, xts_len, - my_ctx, my_ctx_len); - CHECK(0 == rc); - rc = mbedtls_mpi_read_binary(r, buf, bsize); - CHECK(0 == rc); + if (nbits == 0) { + goto cleanup; + } + bsize = (nbits + 7) / 8; + buf = malloc(bsize); + if (!buf) { + goto cleanup; + } + for (ctr = 0; ctr <= UINT16_MAX; ctr++) { + uint16_t ctr_nbo = htons((uint16_t) ctr); + + memcpy(my_ctx + ctxlen, &ctr_nbo, sizeof ctr_nbo); + if (0 != kdf(buf, bsize, + skm, skm_len, + xts, xts_len, + my_ctx, my_ctx_len)) { + goto cleanup; + } + if (0 != mbedtls_mpi_read_binary(r, buf, bsize)) { + goto cleanup; + } while (1) { size_t rlen = mbedtls_mpi_bitlen(r); if (rlen <= nbits) { break; } - mbedtls_mpi_set_bit(r, rlen - 1, 0); + if (0 != mbedtls_mpi_set_bit(r, rlen - 1, 0)) { + goto cleanup; + } } - ++ctr; /* We reject this FDH if either r > n and retry with another ctr */ if (0 > mbedtls_mpi_cmp_mpi (r, n)) { + ret = 0; break; } mbedtls_mpi_free (r); + mbedtls_mpi_init (r); } +cleanup: + if (buf) { + sodium_memzero(buf, bsize); + } + free(buf); free(my_ctx); + return ret; } @@ -985,7 +1016,7 @@ rsa_gcd_validate (mbedtls_mpi *r, if (mbedtls_mpi_cmp_int(&g, 1) == 0) { ret = 0; } else { - goto cleanup; + ret = 1; } cleanup: @@ -1002,11 +1033,13 @@ rsa_blinding_key_derive(mbedtls_mpi *r, /* Trusts bks' randomness more */ const char *xts = "Blinding KDF extractor HMAC key"; - kdf_mod_mpi(r, - &pkey->N, - xts, strlen(xts), - bks, sizeof(*bks), - "Blinding KDF"); + if (0 != kdf_mod_mpi(r, + &pkey->N, + xts, strlen(xts), + bks, sizeof(*bks), + "Blinding KDF")) { + return -1; + } if (0 != rsa_gcd_validate (r, &pkey->N)) { return -1; @@ -1030,6 +1063,9 @@ rsa_public_key_encode(const RsaPub *pkey, uint8_t **outbuf, size_t *outbuf_len) mod_len = mbedtls_mpi_size(&pkey->N); exp_len = mbedtls_mpi_size(&pkey->e); + if (mod_len > UINT16_MAX || exp_len > UINT16_MAX) { + return -1; + } sz = 2 + 2 + exp_len + mod_len; buf = malloc(sz); if (!buf) { @@ -1037,9 +1073,11 @@ rsa_public_key_encode(const RsaPub *pkey, uint8_t **outbuf, size_t *outbuf_len) } p = buf; - *((uint16_t *) p) = htons(mod_len); + uint16_t encoded_len = htons((uint16_t) mod_len); + memcpy(p, &encoded_len, sizeof encoded_len); p += sizeof (uint16_t); - *((uint16_t *) p) = htons(exp_len); + encoded_len = htons((uint16_t) exp_len); + memcpy(p, &encoded_len, sizeof encoded_len); p += sizeof (uint16_t); MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->N, p, mod_len)); p += mod_len; @@ -1086,13 +1124,18 @@ rsa_full_domain_hash (mbedtls_mpi *r, const RsaPub *pkey, Mihir Bellare and Phillip Rogaway. Doing this lowers the degree of the hypothetical polyomial-time attack on RSA-KTI created by a polynomial-time one-more forgary attack. Yey seeding! */ - rsa_public_key_encode(pkey, &xts, &xts_len); + if (0 != rsa_public_key_encode(pkey, &xts, &xts_len)) { + return -1; + } - kdf_mod_mpi(r, - &pkey->N, - xts, xts_len, - hash, sizeof(*hash), - "RSA-FDA FTpsW!"); + if (0 != kdf_mod_mpi(r, + &pkey->N, + xts, xts_len, + hash, sizeof(*hash), + "RSA-FDA FTpsW!")) { + free(xts); + return -1; + } free(xts); if (0 == rsa_gcd_validate (r, &pkey->N)) { return 0; @@ -1131,6 +1174,10 @@ rsa_blind(const HashCode *hash, outsize = (mbedtls_mpi_bitlen(&data_r_e) + 7) / 8; outbuf = malloc(outsize); + if (outsize != 0 && !outbuf) { + ret = -1; + goto cleanup; + } MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&data_r_e, outbuf, outsize)); @@ -1162,7 +1209,7 @@ rsa_unblind (const mbedtls_mpi *sig_blinded, MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks)); MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&r_inv, &bkey, &pkey->N)); MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ubsig, sig_blinded, &r_inv)); - MBEDTLS_MPI_CHK(mbedtls_mpi_copy(sig_ret, &ubsig)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(sig_ret, &ubsig, &pkey->N)); cleanup: mbedtls_mpi_free(&bkey); @@ -1184,6 +1231,12 @@ rsa_verify(const HashCode *hash, mbedtls_mpi_init(&r); mbedtls_mpi_init(&sig_e); + if (mbedtls_mpi_cmp_int(sig, 0) < 0 || + mbedtls_mpi_cmp_mpi(sig, &pkey->N) >= 0) { + ret = -1; + goto cleanup; + } + /* Can fail if RSA key is malicious since rsa_gcd_validate failed here. * It should have failed during GNUNET_CRYPTO_rsa_blind too though, * so the exchange is being malicious in an unfamilair way, maybe