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:
| M | tart_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