-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CVE‐2026‐17508
Title: Password-based KDF cost parameters honoured unbounded from untrusted input across the remaining PBE entry points.
Issue affecting: BC before 1.86, BC-LTS before 2.73.13, BC-FJA before bcpkix-fips 1.0.13, 2.0.13 and 2.1.13.
Fixed versions: BC 1.86, BC-LTS 2.73.13, BC-FJA bcpkix-fips 1.0.13, 2.0.13 and 2.1.13.
Platform affected: Java 8 and later.
A password-based KDF is run before anything about the input has been authenticated — the whole point of the MAC or the decryption it feeds is that neither has happened yet. Where the cost parameters driving that KDF are read from the same untrusted structure, a small input dictates an arbitrary amount of work, and the work happens whether or not the password is right. BC 1.85 bounded the PKCS#8 / PBES2 decryptors on exactly this reasoning (CVE-2026-15055); the entry points below were the ones that fix did not reach.
RFC 9579 PBMAC1 iteration count and key length. JcePBMac1CalculatorBuilder.build() took the PBKDF2 iterationCount straight out of a PBMAC1Params, unlike every sibling PBE/PBMAC1 path in the tree, and the derived-key length was likewise unbounded — including in PKCS12PBEUtils.createPBMac1Calculator, reached from PKCS12PfxPdu.isMacValid through the lightweight BcPKCS12PBMac1CalculatorBuilder. keyLength is an octet count fed to PKCS5S2ParametersGenerator.generateDerivedKey, whose first act is to allocate a buffer of that size, so a PFX of a couple of hundred bytes declaring a few hundred megabytes forced the allocation before any password comparison. Both the iteration count and the key length are now bounded at every PBMAC1 call site.
scrypt parallelization parameter. The checkScryptCost guards in JcePKCSPBEInputDecryptorProviderBuilder and JceOpenSSLPKCS8DecryptorProviderBuilder bounded the cost parameter N and the block size r against org.bouncycastle.pbe.max_scrypt_memory, but never read p. scrypt's scratch space scales with 128 * r * p independently of N (RFC 7914), so minimal N and r with p at the engine's own integer-overflow ceiling sailed through the guard and then allocated hundreds of megabytes — the configured ceiling was evaded entirely, however low it had been set. N and p are now each bounded against the memory budget, leaving the original N-only limit exactly where it was so a key at the old boundary still loads.
Raw JCA PBKDF2. org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2 applied no bound to the iteration count, so SecretKeyFactory.getInstance("PBKDF2WithHmac...").generateSecret(spec) ran for as long as the spec asked.
OpenSSH bcrypt rounds. The bcrypt round count for an encrypted OpenSSH v1 private key is read from the key's own kdfoptions and drives the KDF before anything about the key has been verified, so a few hundred bytes could request CPU-months of work. It is now capped, configurably, through the new org.bouncycastle.openssh.max_rounds property.
In every case the bound rejects the structure before the derivation runs rather than partway through it, and inputs with sane parameters are unaffected.
The fix was introduced in commit 882fdab53f6c, commit 442393bf187c, commit 20ed9e203cae, commit 766a31026ac2, commit e72bc0681ff4 and commit 480d878aa6f7.
Credit: Mirko Swillus on behalf of Alpha-Omega (alpha-omega.dev), using Scrutineer with an Anthropic Claude model provided through Project Glasswing; and Yu Bao from the PayPal Cyber Security Team.