From e1a77cd80f5c580b219dba3adaaf33f885d383e6 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 30 Jul 2022 17:25:16 -0600 Subject: [PATCH] [WIP] Bound `RsaPublicKey::new` on 4096-bits; add `::new_large` This commit fixes #166 by enforcing a 4096-bit upper limit by default, which prevents potential DoS by using maliciously large RSA keys. The PKCS#1/PKCS#8 parsers use this API, limiting the size of keys parsed from these formats to 4096-bits. An `RsaPrivateKey::new_large` constructor has been added which enforces the 16384-bit limit added in #170. This can be used for unusual applications that need to support larger keys. `RsaPrivateKey::from_components` uses the `::new_large` constructor, so private keys follow the 16384-bit limit only. The `RsaPrivateKey::MAX_SIZE` and `RsaPrivateKey::MAX_SIZE_LARGE` inherent constants specify the maximum allowed sizes. --- src/key.rs | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/key.rs b/src/key.rs index fe3a3446..5999f6a5 100644 --- a/src/key.rs +++ b/src/key.rs @@ -16,10 +16,6 @@ use crate::padding::PaddingScheme; use crate::raw::{DecryptionPrimitive, EncryptionPrimitive}; use crate::{oaep, pkcs1v15, pss}; -const MIN_PUB_EXPONENT: u64 = 2; -const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1; -const MAX_MODULUS_BITS: usize = 16384; - pub trait PublicKeyParts { /// Returns the modulus of the key. fn n(&self) -> &BigUint; @@ -229,8 +225,39 @@ impl PublicKey for RsaPublicKey { } impl RsaPublicKey { - /// Create a new key from its components. + /// Minimum value of the public exponent `e`. + pub const MIN_PUB_EXPONENT: u64 = 2; + + /// Maximum value of the public exponent `e`. + pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1; + + /// Maximum size of the modulus `n` in bits. + pub const MAX_SIZE: usize = 4096; + + /// Maximum size of the modulus `n` in bits when using the + /// [`RsaPublicKey::new_large`] constructor. + pub const MAX_SIZE_LARGE: usize = 16384; + + /// Create a new public key from its components. + /// + /// This function accepts public keys with a modulus size up to 4096-bits, + /// i.e. [`RsaPublicKey::MAX_SIZE`]. pub fn new(n: BigUint, e: BigUint) -> Result { + if n.bits() <= Self::MAX_SIZE { + Self::new_large(n, e) + } else { + Err(Error::ModulusTooLarge) + } + } + + /// Create a new public key from its components. + /// + /// This function accepts unusually large public keys with a modulus size + /// up to 16384-bits, i.e. [`RsaPublicKey::MAX_SIZE_LARGE`]. + /// + /// We don't generally recommend using keys that large. This API is + /// provided for interoperability with unusual applications only. + pub fn new_large(n: BigUint, e: BigUint) -> Result { let k = RsaPublicKey { n, e }; check_public(&k)?; @@ -339,7 +366,7 @@ impl RsaPrivateKey { /// but it can occationally be useful to discard the private information entirely. pub fn to_public_key(&self) -> RsaPublicKey { // Safe to unwrap since n and e are already verified. - RsaPublicKey::new(self.n().clone(), self.e().clone()).unwrap() + RsaPublicKey::new_large(self.n().clone(), self.e().clone()).unwrap() } /// Performs some calculations to speed up private key operations. @@ -549,7 +576,7 @@ impl RsaPrivateKey { /// Check that the public key is well formed and has an exponent within acceptable bounds. #[inline] pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> { - if public_key.n().bits() > MAX_MODULUS_BITS { + if public_key.n().bits() > RsaPublicKey::MAX_SIZE_LARGE { return Err(Error::ModulusTooLarge); } @@ -558,11 +585,11 @@ pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> { .to_u64() .ok_or(Error::PublicExponentTooLarge)?; - if e < MIN_PUB_EXPONENT { + if e < RsaPublicKey::MIN_PUB_EXPONENT { return Err(Error::PublicExponentTooSmall); } - if e > MAX_PUB_EXPONENT { + if e > RsaPublicKey::MAX_PUB_EXPONENT { return Err(Error::PublicExponentTooLarge); }