From 117dfea5efb2c3bfc40a6c7a275becf3746030e1 Mon Sep 17 00:00:00 2001 From: vulgraph Date: Sat, 2 May 2026 01:53:45 +0800 Subject: [PATCH] Add regression test for CVE-2026-21895 (prime == 1 rejection) Per @tarcieri's note in #690: the panic-on-prime-equal-1 fix landed on master via the num-bigint -> crypto-bigint refactor, but the regression test from upstream commit 2926c91bef (PR #624) was not carried over. This adds an adapted port of that test: - Original used num-bigint BigUint; this version uses crypto-bigint BoxedUint to match current master. - Original used a small public exponent (185) which the current from_components rejects via the standard exponent-size check; this version goes through from_components_with_large_exponent so the exact same numeric inputs from the original test can be used. The test is therefore gated on the hazmat feature, consistent with the other small/large-exponent tests in this module. - Asserts Err(Error::InvalidPrime) rather than a panic, matching the upstream fix's intent. No production-code changes; the underlying logic fix (prime <= one => InvalidPrime in validate_private_key_parts) is already present on master. Refs: GHSA-9c48-w39g-hm26, RustCrypto/RSA#690, RustCrypto/RSA#624 --- src/key.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/key.rs b/src/key.rs index d7b18121..c6d53dee 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1302,4 +1302,28 @@ mod tests { // Verify that the key is cryptographically valid assert!(validate_skip_exponent_size(&key_with_small_exp).is_ok()); } + + /// Regression test for CVE-2026-21895 / GHSA-9c48-w39g-hm26. + /// + /// Loading a secret key whose prime factor is `1` must be rejected with + /// `Error::InvalidPrime` rather than panicking via a divide-by-zero in + /// the validation/precompute path. + /// + /// Adapted from the test added in upstream commit 2926c91bef (PR #624); + /// the original used `num-bigint` `BigUint` types, this version uses + /// `crypto-bigint` `BoxedUint` and goes through + /// `from_components_with_large_exponent` so the small (out-of-range) `e` + /// can be supplied verbatim from the original test. + #[test] + #[cfg(feature = "hazmat")] + fn test_key_invalid_primes() { + let e = RsaPrivateKey::from_components_with_large_exponent( + BoxedUint::from(239u64), + BoxedUint::from(185u64), + BoxedUint::from(0u64), + vec![BoxedUint::from(1u64), BoxedUint::from(239u64)], + ) + .unwrap_err(); + assert_eq!(e, Error::InvalidPrime); + } }