Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RsaPublicKey::new_with_max_size; 4096-bit default max #176

Merged
merged 2 commits into from Aug 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/errors.rs
@@ -1,7 +1,7 @@
pub type Result<T> = core::result::Result<T, Error>;

/// Error types
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
InvalidPaddingScheme,
Expand Down
118 changes: 104 additions & 14 deletions src/key.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -229,11 +225,27 @@ 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;

/// 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<Self> {
let k = RsaPublicKey { n, e };
check_public(&k)?;
Self::new_with_max_size(n, e, Self::MAX_SIZE)
}

/// Create a new public key from its components.
pub fn new_with_max_size(n: BigUint, e: BigUint, max_size: usize) -> Result<Self> {
let k = RsaPublicKey { n, e };
check_public_with_max_size(&k, max_size)?;
Ok(k)
}
}
Expand Down Expand Up @@ -336,10 +348,9 @@ impl RsaPrivateKey {
/// Get the public key from the private key, cloning `n` and `e`.
///
/// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait,
/// but it can occationally be useful to discard the private information entirely.
/// but it can occasionally 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()
self.pubkey_components.clone()
}

/// Performs some calculations to speed up private key operations.
Expand Down Expand Up @@ -409,7 +420,7 @@ impl RsaPrivateKey {
}

/// Performs basic sanity checks on the key.
/// Returns `Ok(())` if everything is good, otherwise an approriate error.
/// Returns `Ok(())` if everything is good, otherwise an appropriate error.
pub fn validate(&self) -> Result<()> {
check_public(self)?;

Expand Down Expand Up @@ -549,7 +560,13 @@ 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 {
check_public_with_max_size(public_key, RsaPublicKey::MAX_SIZE)
}

/// Check that the public key is well formed and has an exponent within acceptable bounds.
#[inline]
fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize) -> Result<()> {
if public_key.n().bits() > max_size {
return Err(Error::ModulusTooLarge);
}

Expand All @@ -558,11 +575,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);
}

Expand Down Expand Up @@ -601,6 +618,7 @@ mod tests {

use alloc::string::String;
use digest::{Digest, DynDigest};
use hex_literal::hex;
use num_traits::{FromPrimitive, ToPrimitive};
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
Expand Down Expand Up @@ -801,6 +819,78 @@ mod tests {
.unwrap();
}

#[test]
fn reject_oversized_private_key() {
// -----BEGIN PUBLIC KEY-----
// MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAkMBiB8qsNVXAsJR6Xoto
// H1r2rtZl/xzUK2tIfy99aPE489u+5tLxCQhQf+a89158vSDpr2/xwgK8w9u0Xpu2
// m7XRKjVMS0Y6UIINFoeTc87rVXT92Scr47kNVcGmSFXez4BSDpS+LKpWwXN+0AQu
// +cmcfdtsx2862iEbqQvq4PwKGQJOdOR0yldH8O4yeJK/buvIOXRHjb++vtQND/xi
// bFGAcd9WJqvaOG7tclhbZ277mbO6ER+y9Lj7AyO8ywybWqNeHaVPHMysPhT7HUWI
// 17m59i1OpuVwwEnvzDQQEUf9d5hUmkLYb5qQzuf6Ddnx/04QJCKAgkhyr9CXgnV6
// vEZ3PKtpicCHRxk7eqTEmgBlgwqH5vflRFV1iywQMXJnuRhzWOQaXl/vb8v4HIvF
// 4TatEZKqfzpbyScLIiYbPEAhHXKdZMd2zY8hkSbicifePApAZmuNpAxxJDZzphh7
// r4lD6t8MPT/RUAdtrZfihqaBhduFI6YeVIy6emg05M6YWvlUyer7nYGaPRS1JqD4
// 0v7xOtme5I8Qw6APiFPXhTqBK3occr7TgGb3V3lpC8Eq+esNHrji98R1fITkFXJW
// KdFcTWjBghPxiobUzMCFUrPIDJcWXeBzrARAryU+hXjEiFfzluXrps0B7RJQ/rLD
// LXeTn4vovUeHQVHa7YfoyWMy9pfqeVC+56LBK7SEIAvL0I3lrq5vIv+ZIuOAdbVg
// JiRy8DneCOk2LP3RnA8M0HSevYW93DiC+4h/l4ntjjiOfi6yRVOZ8WbVyXZ/83j4
// 6+pGWgvi0uMyb+btgOXjBQv7bGqdyHMc5Lqk5bF7ExETx51vKQMYCV4351caS6aX
// q16lYZATHgbTADEAZHdroDMJB+HMQaze9O6qU5ZO8wxxAjw89xry0dnoOQD/yA4H
// 7CRCo9vVDpV2hqIvHY9RI2T7cek28kmQpKvNvvK+ovmM138dHKViWULHk0fBRt7m
// 4wQ+tiL2PmJ/Tr8g1gVhM6S9D1XdE9z0KeDnODCWn1Q8sx2G2ah4ynnYQURDWcwO
// McAoP6bdJ7cCt+4F2tEsMPf4S/EwlnjvuNoQjvztxCPahYe9EnyggtQXyHJveIn7
// gDJsP6b93VB6x4QbLy5ch4DUhqDWginuKVeo7CTgDkq03j/IEaS1BHwreSDQceny
// +bYWONwV+4TMpGytKOHvU5288kmHbyZHdXuaXk8LLqbnqr30fa6Cbp4llCi9sH5a
// Kmi5jxQfVTe+elkMs7oVsLsVgkZS6NqPcOuEckAFijNqG223+IJoqvifCzO5Bdcs
// JTOLE+YaUYc8LUJwIaPykgcXmtMvQjeT8MCQ3aAlzkHfDpSvvICrXtqbGiaKolU6
// mQIDAQAB
// -----END PUBLIC KEY-----

let n = BigUint::from_bytes_be(&hex!(
"
90c06207caac3555c0b0947a5e8b681f5af6aed665ff1cd42b6b487f2f7d68f1
38f3dbbee6d2f10908507fe6bcf75e7cbd20e9af6ff1c202bcc3dbb45e9bb69b
b5d12a354c4b463a50820d16879373ceeb5574fdd9272be3b90d55c1a64855de
cf80520e94be2caa56c1737ed0042ef9c99c7ddb6cc76f3ada211ba90beae0fc
0a19024e74e474ca5747f0ee327892bf6eebc83974478dbfbebed40d0ffc626c
518071df5626abda386eed72585b676efb99b3ba111fb2f4b8fb0323bccb0c9b
5aa35e1da54f1cccac3e14fb1d4588d7b9b9f62d4ea6e570c049efcc34101147
fd7798549a42d86f9a90cee7fa0dd9f1ff4e10242280824872afd09782757abc
46773cab6989c08747193b7aa4c49a0065830a87e6f7e54455758b2c10317267
b9187358e41a5e5fef6fcbf81c8bc5e136ad1192aa7f3a5bc9270b22261b3c40
211d729d64c776cd8f219126e27227de3c0a40666b8da40c71243673a6187baf
8943eadf0c3d3fd150076dad97e286a68185db8523a61e548cba7a6834e4ce98
5af954c9eafb9d819a3d14b526a0f8d2fef13ad99ee48f10c3a00f8853d7853a
812b7a1c72bed38066f75779690bc12af9eb0d1eb8e2f7c4757c84e415725629
d15c4d68c18213f18a86d4ccc08552b3c80c97165de073ac0440af253e8578c4
8857f396e5eba6cd01ed1250feb2c32d77939f8be8bd47874151daed87e8c963
32f697ea7950bee7a2c12bb484200bcbd08de5aeae6f22ff9922e38075b56026
2472f039de08e9362cfdd19c0f0cd0749ebd85bddc3882fb887f9789ed8e388e
7e2eb2455399f166d5c9767ff378f8ebea465a0be2d2e3326fe6ed80e5e3050b
fb6c6a9dc8731ce4baa4e5b17b131113c79d6f290318095e37e7571a4ba697ab
5ea56190131e06d300310064776ba0330907e1cc41acdef4eeaa53964ef30c71
023c3cf71af2d1d9e83900ffc80e07ec2442a3dbd50e957686a22f1d8f512364
fb71e936f24990a4abcdbef2bea2f98cd77f1d1ca5625942c79347c146dee6e3
043eb622f63e627f4ebf20d6056133a4bd0f55dd13dcf429e0e73830969f543c
b31d86d9a878ca79d841444359cc0e31c0283fa6dd27b702b7ee05dad12c30f7
f84bf1309678efb8da108efcedc423da8587bd127ca082d417c8726f7889fb80
326c3fa6fddd507ac7841b2f2e5c8780d486a0d68229ee2957a8ec24e00e4ab4
de3fc811a4b5047c2b7920d071e9f2f9b61638dc15fb84cca46cad28e1ef539d
bcf249876f2647757b9a5e4f0b2ea6e7aabdf47dae826e9e259428bdb07e5a2a
68b98f141f5537be7a590cb3ba15b0bb15824652e8da8f70eb847240058a336a
1b6db7f88268aaf89f0b33b905d72c25338b13e61a51873c2d427021a3f29207
179ad32f423793f0c090dda025ce41df0e94afbc80ab5eda9b1a268aa2553a99"
));

let e = BigUint::from_u64(65537).unwrap();

assert_eq!(
RsaPublicKey::new(n, e).err().unwrap(),
Error::ModulusTooLarge
);
}

fn get_private_key() -> RsaPrivateKey {
// -----BEGIN RSA PRIVATE KEY-----
// MIIEpAIBAAKCAQEA05e4TZikwmE47RtpWoEG6tkdVTvwYEG2LT/cUKBB4iK49FKW
Expand Down