Skip to content

Commit 4cae3bd

Browse files
authored
Validate RSA public exponents before verification (#19)
* Validate RSA public exponents before verification * test(rsa): cover minimum public exponent bound
1 parent f03b200 commit 4cae3bd

1 file changed

Lines changed: 47 additions & 7 deletions

File tree

src/verify.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,20 +258,33 @@ unsafe impl Sync for Params {}
258258
// https://docs.rs/rustls-webpki/0.103.13/src/webpki/aws_lc_rs_algs.rs.html#162-182
259259
const RSA_MIN_MODULUS_BITS: usize = 2048;
260260
const RSA_MAX_MODULUS_BITS: usize = 8192;
261+
// ring/aws-lc-rs accept small odd public exponents for verification: 2-33 bits,
262+
// which is equivalent to e >= 3 and e <= 2^33 - 1 for positive integers.
263+
const RSA_MIN_PUBLIC_EXPONENT_BITS: usize = 2;
264+
const RSA_MAX_PUBLIC_EXPONENT_BITS: usize = 33;
261265

262266
fn rsa_public_key_allowed_by_webpki(key: &RsaPublicKey<'_>) -> bool {
263267
(RSA_MIN_MODULUS_BITS..=RSA_MAX_MODULUS_BITS)
264-
.contains(&rsa_modulus_bit_len(key.modulus.as_bytes()))
268+
.contains(&rsa_big_endian_bit_len(key.modulus.as_bytes()))
269+
&& rsa_public_exponent_allowed_by_webpki(key.public_exponent.as_bytes())
265270
}
266271

267-
fn rsa_modulus_bit_len(modulus: &[u8]) -> usize {
268-
let Some(first) = modulus.first() else {
272+
fn rsa_public_exponent_allowed_by_webpki(exponent: &[u8]) -> bool {
273+
(RSA_MIN_PUBLIC_EXPONENT_BITS..=RSA_MAX_PUBLIC_EXPONENT_BITS)
274+
.contains(&rsa_big_endian_bit_len(exponent))
275+
&& exponent.last().is_some_and(|byte| byte & 1 == 1)
276+
}
277+
278+
fn rsa_big_endian_bit_len(bytes: &[u8]) -> usize {
279+
let Some((first_nonzero_index, first_nonzero)) =
280+
bytes.iter().enumerate().find(|(_, byte)| **byte != 0)
281+
else {
269282
return 0;
270283
};
271284

272-
let first_byte_bits =
273-
usize::try_from(u8::BITS - first.leading_zeros()).expect("u8 bit width fits in usize");
274-
(modulus.len() - 1) * 8 + first_byte_bits
285+
let first_byte_bits = usize::try_from(u8::BITS - first_nonzero.leading_zeros())
286+
.expect("u8 bit width fits in usize");
287+
(bytes.len() - first_nonzero_index - 1) * 8 + first_byte_bits
275288
}
276289

277290
#[derive(Debug)]
@@ -444,10 +457,37 @@ mod tests {
444457
assert!(!rsa_public_key_allowed_by_webpki(&key_8193));
445458
}
446459

460+
#[test]
461+
fn rsa_public_key_policy_matches_webpki_public_exponent_bounds() {
462+
let minimum_exponent = rsa_public_key_with_exponent(&[0x03]);
463+
let valid_exponent_65537 = rsa_public_key_with_exponent(&[0x01, 0x00, 0x01]);
464+
let maximum_exponent = rsa_public_key_with_exponent(&[0x01, 0xff, 0xff, 0xff, 0xff]);
465+
let exponent_1 = rsa_public_key_with_exponent(&[0x01]);
466+
let exponent_2 = rsa_public_key_with_exponent(&[0x02]);
467+
let even_exponent = rsa_public_key_with_exponent(&[0x01, 0x00, 0x00]);
468+
let oversized_exponent = rsa_public_key_with_exponent(&[0x02, 0x00, 0x00, 0x00, 0x01]);
469+
470+
assert!(rsa_public_key_allowed_by_webpki(&minimum_exponent));
471+
assert!(rsa_public_key_allowed_by_webpki(&valid_exponent_65537));
472+
assert!(rsa_public_key_allowed_by_webpki(&maximum_exponent));
473+
assert!(!rsa_public_key_allowed_by_webpki(&exponent_1));
474+
assert!(!rsa_public_key_allowed_by_webpki(&exponent_2));
475+
assert!(!rsa_public_key_allowed_by_webpki(&even_exponent));
476+
assert!(!rsa_public_key_allowed_by_webpki(&oversized_exponent));
477+
}
478+
447479
fn rsa_public_key_with_modulus(modulus: &[u8]) -> RsaPublicKey<'static> {
480+
rsa_public_key_with_components(modulus, &[0x01, 0x00, 0x01])
481+
}
482+
483+
fn rsa_public_key_with_exponent(exponent: &[u8]) -> RsaPublicKey<'static> {
484+
rsa_public_key_with_components(&modulus_with_bit_len(2048), exponent)
485+
}
486+
487+
fn rsa_public_key_with_components(modulus: &[u8], exponent: &[u8]) -> RsaPublicKey<'static> {
448488
let mut der = Vec::new();
449489
append_der_integer(&mut der, modulus);
450-
append_der_integer(&mut der, &[0x01, 0x00, 0x01]);
490+
append_der_integer(&mut der, exponent);
451491

452492
let mut sequence = Vec::new();
453493
sequence.push(0x30);

0 commit comments

Comments
 (0)