webauthn_rp

WebAuthn Level 3 RP library.
git clone https://git.philomathiclife.com/repos/webauthn_rp
Log | Files | Refs | README

commit 27188a769b4ac4f2e32ea0a86a27923487469014
parent 96ac16a178abccc48d0d508209801eb091f06bc7
Author: Zack Newman <zack@philomathiclife.com>
Date:   Sat, 14 Jun 2025 11:13:51 -0600

disallow even rsa exponents

Diffstat:
Msrc/response/register.rs | 21+++++++++++++--------
Msrc/response/register/error.rs | 7+++++--
2 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/response/register.rs b/src/response/register.rs @@ -1383,6 +1383,8 @@ pub const MAX_RSA_N_BITS: usize = 0x4000; pub const MIN_RSA_N_BITS: usize = 0x800; /// [`MIN_RSA_N_BITS`]–[`MAX_RSA_N_BITS`] bits representing the big-endian modulus and a `u32` `>=` /// [`MIN_RSA_E`] representing the exponent of an alleged RSA public key. +/// +/// Note the modulus and exponent are always odd. #[derive(Clone, Copy, Debug)] pub struct RsaPubKey<T>(T, u32); impl<T> RsaPubKey<T> { @@ -1436,26 +1438,29 @@ impl<'a: 'b, 'b> TryFrom<(&'a [u8], u32)> for RsaPubKey<&'b [u8]> { #[inline] fn try_from((n, e): (&'a [u8], u32)) -> Result<Self, Self::Error> { n.first().map_or(Err(RsaPubKeyErr::NSize), |fst| { - if *fst == 0 { + // `fst.leading_zeros()` is inclusively between `0` and `8`, so it's safe to convert to a + // `usize`. + let zeros = fst.leading_zeros() as usize; + if zeros == 8 { Err(RsaPubKeyErr::NLeading0) } else if let Some(bits) = n.len().checked_mul(8) { if (MIN_RSA_N_BITS..=MAX_RSA_N_BITS) - // `fst.leading_zeros()` is inclusively between `0` and `8`, so it's safe to convert to a - // `usize`. // `bits` is at least 8 since `n.len()` is at least 1; thus underflow cannot occur. - .contains(&(bits - fst.leading_zeros() as usize)) + .contains(&(bits - zeros)) { - // We know `n` is not `empty`, so this won't `panic`. + // We know `n` is not empty, so this won't `panic`. if n.last() .unwrap_or_else(|| unreachable!("there is a bug in RsaPubKey::try_from")) & 1 == 0 { Err(RsaPubKeyErr::NEven) - } else if e >= MIN_RSA_E { - Ok(Self(n, e)) + } else if e < MIN_RSA_E { + Err(RsaPubKeyErr::ESize) + } else if e & 1 == 0 { + Err(RsaPubKeyErr::EEven) } else { - Err(RsaPubKeyErr::E) + Ok(Self(n, e)) } } else { Err(RsaPubKeyErr::NSize) diff --git a/src/response/register/error.rs b/src/response/register/error.rs @@ -112,7 +112,9 @@ pub enum RsaPubKeyErr { /// Variant returned when the modulus is even. NEven, /// Variant returned when the exponent is less than [`MIN_RSA_E`]. - E, + ESize, + /// Variant returned when the exponent is even. + EEven, } impl Display for RsaPubKeyErr { #[inline] @@ -123,7 +125,8 @@ impl Display for RsaPubKeyErr { "the RSA public key modulus was less than 2048 bits or greater than 16384" } Self::NEven => "the RSA public key modulus was even", - Self::E => "the RSA public key exponent was less than 3", + Self::ESize => "the RSA public key exponent was less than 3", + Self::EEven => "the RSA public key exponent was even", }) } }