@@ -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
259259const RSA_MIN_MODULUS_BITS : usize = 2048 ;
260260const 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
262266fn 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,35 @@ 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 valid_exponent_65537 = rsa_public_key_with_exponent ( & [ 0x01 , 0x00 , 0x01 ] ) ;
463+ let maximum_exponent = rsa_public_key_with_exponent ( & [ 0x01 , 0xff , 0xff , 0xff , 0xff ] ) ;
464+ let exponent_1 = rsa_public_key_with_exponent ( & [ 0x01 ] ) ;
465+ let exponent_2 = rsa_public_key_with_exponent ( & [ 0x02 ] ) ;
466+ let even_exponent = rsa_public_key_with_exponent ( & [ 0x01 , 0x00 , 0x00 ] ) ;
467+ let oversized_exponent = rsa_public_key_with_exponent ( & [ 0x02 , 0x00 , 0x00 , 0x00 , 0x01 ] ) ;
468+
469+ assert ! ( rsa_public_key_allowed_by_webpki( & valid_exponent_65537) ) ;
470+ assert ! ( rsa_public_key_allowed_by_webpki( & maximum_exponent) ) ;
471+ assert ! ( !rsa_public_key_allowed_by_webpki( & exponent_1) ) ;
472+ assert ! ( !rsa_public_key_allowed_by_webpki( & exponent_2) ) ;
473+ assert ! ( !rsa_public_key_allowed_by_webpki( & even_exponent) ) ;
474+ assert ! ( !rsa_public_key_allowed_by_webpki( & oversized_exponent) ) ;
475+ }
476+
447477 fn rsa_public_key_with_modulus ( modulus : & [ u8 ] ) -> RsaPublicKey < ' static > {
478+ rsa_public_key_with_components ( modulus, & [ 0x01 , 0x00 , 0x01 ] )
479+ }
480+
481+ fn rsa_public_key_with_exponent ( exponent : & [ u8 ] ) -> RsaPublicKey < ' static > {
482+ rsa_public_key_with_components ( & modulus_with_bit_len ( 2048 ) , exponent)
483+ }
484+
485+ fn rsa_public_key_with_components ( modulus : & [ u8 ] , exponent : & [ u8 ] ) -> RsaPublicKey < ' static > {
448486 let mut der = Vec :: new ( ) ;
449487 append_der_integer ( & mut der, modulus) ;
450- append_der_integer ( & mut der, & [ 0x01 , 0x00 , 0x01 ] ) ;
488+ append_der_integer ( & mut der, exponent ) ;
451489
452490 let mut sequence = Vec :: new ( ) ;
453491 sequence. push ( 0x30 ) ;
0 commit comments