Skip to content

crypto/rsa: bound public modulus size to prevent verify-path CPU-exhaustion DoS#81

Merged
hdm merged 2 commits into
mainfrom
security/rsa-max-public-modulus-bitlen
May 31, 2026
Merged

crypto/rsa: bound public modulus size to prevent verify-path CPU-exhaustion DoS#81
hdm merged 2 commits into
mainfrom
security/rsa-max-public-modulus-bitlen

Conversation

@hdm

@hdm hdm commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

checkKeySize is intentionally permissive about the RSA modulus size (so weak/odd keys found in the wild can still be parsed and inspected). That leaves the modular-exponentiation cost during public-key operations — O(bitlen(E) · bitlen(N)²) — otherwise unbounded: a malicious certificate/key presenting a multi-megabit modulus can force tens of seconds to minutes of CPU per signature check (≈60s for a 2,000,000-bit modulus). During a TLS scan that can pin a worker on a single connection — a CPU-exhaustion DoS.

This adds MaxPublicModulusBitLen (default 16384), enforced in checkPublicKeySize next to the existing MaxPublicExponentBitLen, so VerifyPKCS1v15 / VerifyPSS / EncryptPKCS1v15 / EncryptOAEP reject an oversized modulus before the modexp runs.

  • Parsing functions and crypto/x509 do not consult the variable — inspecting an oversized key remains safe (consistent with MaxPublicExponentBitLen).
  • Default 16384 comfortably exceeds every legitimate RSA modulus in use.
  • Set it to 0 to disable the bound and restore the previous unbounded behavior.

Test

crypto/rsa/rsa_test.go adds TestMaxPublicModulusBitLen: a ~2,000,000-bit modulus is rejected by VerifyPKCS1v15 in <2s (vs ~60s unmitigated), and MaxPublicModulusBitLen = 0 does not gate. Full go test ./crypto/rsa/ passes.

🤖 Generated with Claude Code

hdm and others added 2 commits May 30, 2026 22:44
…ustion DoS

checkKeySize is intentionally permissive about the RSA modulus size so that
weak/odd keys found in the wild can still be parsed and inspected. That leaves
the modular-exponentiation cost during public-key operations — O(bitlen(E) ·
bitlen(N)^2) — otherwise unbounded: a malicious certificate/key presenting a
multi-megabit modulus can force tens of seconds to minutes of CPU per signature
check (e.g. ~60s for a 2,000,000-bit modulus), which during a TLS scan can pin a
worker on a single connection — a CPU-exhaustion DoS.

Add MaxPublicModulusBitLen (default 16384), enforced in checkPublicKeySize
alongside the existing MaxPublicExponentBitLen, so VerifyPKCS1v15 / VerifyPSS /
EncryptPKCS1v15 / EncryptOAEP reject an oversized modulus *before* the modexp.
Parsing functions and crypto/x509 do not consult it, so inspecting an oversized
key remains safe; setting it to 0 restores the previous unbounded behavior.

Addresses runZero platform audit finding TLS-01.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hdm hdm merged commit 890e392 into main May 31, 2026
6 checks passed
@hdm hdm deleted the security/rsa-max-public-modulus-bitlen branch May 31, 2026 03:50
@hdm hdm changed the title crypto/rsa: bound public modulus size (verify-path CPU-exhaustion DoS, TLS-01) crypto/rsa: bound public modulus size to prevent verify-path CPU-exhaustion DoS May 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant