From 3e9d5d3f3a5fe77c3b9737d1c2710053d9f43fce Mon Sep 17 00:00:00 2001 From: Joe Birr-Pixton Date: Mon, 20 Apr 2026 06:45:49 +0100 Subject: [PATCH 1/2] Correct validation of BIT STRING constraints --- src/crl/types.rs | 18 ++++++++++++++++++ src/der.rs | 33 +++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/crl/types.rs b/src/crl/types.rs index d303bb7b..2a24d3d7 100644 --- a/src/crl/types.rs +++ b/src/crl/types.rs @@ -1267,4 +1267,22 @@ mod tests { include_bytes!("../../tests/client_auth_revocation/ee_revoked_crl_ku_ee_depth.crl.der"); assert!(OwnedCertRevocationList::from_der(crl).is_ok()) } + + #[test] + fn test_crl_issuing_distribution_point_illegal_bit_string() { + let crl = &[ + 0x30, 0x65, 0x30, 0x50, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x01, 0x41, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0xa0, 0x10, 0x30, 0x0e, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x1c, 0x04, 0x05, 0x30, 0x03, 0x83, 0x01, 0x00, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x02, 0x00, 0x00, + ]; + assert_eq!( + BorrowedCertRevocationList::from_der(crl).err(), + Some(Error::UnsupportedRevocationReasonsPartitioning) + ); + } } diff --git a/src/der.rs b/src/der.rs index 6dad75c0..ed7fd9ac 100644 --- a/src/der.rs +++ b/src/der.rs @@ -379,20 +379,19 @@ pub(crate) fn bit_string_flags(input: untrusted::Input<'_>) -> Result 7 || (raw_bits.is_empty() && padding_bits != 0) { - return Err(Error::BadDer); - } + match (padding_bits, raw_bits.last()) { + // It's illegal to have more than 7 bits of padding. + (8.., _) => Err(Error::BadDer), + + // If the raw bitflags are empty there should be no padding. + (0, None) => Ok(BitStringFlags { raw_bits }), + (_, None) => Err(Error::BadDer), - // If there are padding bits then the last bit of the last raw byte must be 0 or the - // distinguished encoding rules are not being followed. - let last_byte = raw_bits[raw_bits.len() - 1]; - let padding_mask = (1 << padding_bits) - 1; + // If there are padding bits then the last bit of the last raw byte must be 0 or the + // distinguished encoding rules are not being followed. + (1..=7, Some(last)) if last & ((1 << padding_bits) - 1) != 0 => Err(Error::BadDer), - match padding_bits > 0 && (last_byte & padding_mask) != 0 { - true => Err(Error::BadDer), - false => Ok(BitStringFlags { raw_bits }), + (_, Some(_)) => Ok(BitStringFlags { raw_bits }), } }) } @@ -792,6 +791,16 @@ mod tests { assert!(!res.bit_set(256)); } + #[test] + fn empty_bit_string_flags() { + let bs = super::bit_string_flags(untrusted::Input::from(&[0x00])).unwrap(); + + // all bits are unset + for b in 0..256 { + assert!(!bs.bit_set(b)); + } + } + #[test] fn test_small_nonnegative_integer() { use super::{Error, FromDer, Tag}; From 6ea889948e9473891f7b970845767076c082733c Mon Sep 17 00:00:00 2001 From: Joe Birr-Pixton Date: Mon, 20 Apr 2026 10:15:59 +0100 Subject: [PATCH 2/2] Improve tests for padding of `BitStringFlags` --- src/der.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/der.rs b/src/der.rs index ed7fd9ac..76c6da46 100644 --- a/src/der.rs +++ b/src/der.rs @@ -765,6 +765,14 @@ mod tests { bit_string_flags(bad_padding_example), Err(Error::BadDer) )); + + // invalid padding for empty set + for pad in 1..=255 { + assert_eq!( + bit_string_flags(untrusted::Input::from(&[pad])).err(), + Some(Error::BadDer) + ); + } } #[test] @@ -801,6 +809,14 @@ mod tests { } } + #[test] + fn mispadded_bit_string_flags() { + assert_eq!( + super::bit_string_flags(untrusted::Input::from(&[0x04, 0xff])).err(), + Some(super::Error::BadDer) + ); + } + #[test] fn test_small_nonnegative_integer() { use super::{Error, FromDer, Tag};