//! ASN.1 `BIT STRING` support. use crate::{ BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, iter::FusedIterator}; /// ASN.1 `BIT STRING` type. /// /// This type contains a sequence of any number of bits, modeled internally as /// a sequence of bytes with a known number of "unused bits". /// /// This is a zero-copy reference type which borrows from the input data. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct BitStringRef<'a> { /// Number of unused bits in the final octet. unused_bits: u8, /// Length of this `BIT STRING` in bits. bit_length: usize, /// Bitstring represented as a slice of bytes. inner: BytesRef<'a>, } impl<'a> BitStringRef<'a> { /// Maximum number of unused bits allowed. pub const MAX_UNUSED_BITS: u8 = 7; /// Create a new ASN.1 `BIT STRING` from a byte slice. /// /// Accepts an optional number of "unused bits" (0-7) which are omitted /// from the final octet. This number is 0 if the value is octet-aligned. pub fn new(unused_bits: u8, bytes: &'a [u8]) -> Result { if (unused_bits > Self::MAX_UNUSED_BITS) || (unused_bits != 0 && bytes.is_empty()) { return Err(Self::TAG.value_error()); } let inner = BytesRef::new(bytes).map_err(|_| Self::TAG.length_error())?; let bit_length = usize::try_from(inner.len())? .checked_mul(8) .and_then(|n| n.checked_sub(usize::from(unused_bits))) .ok_or(ErrorKind::Overflow)?; Ok(Self { unused_bits, bit_length, inner, }) } /// Create a new ASN.1 `BIT STRING` from the given bytes. /// /// The "unused bits" are set to 0. pub fn from_bytes(bytes: &'a [u8]) -> Result { Self::new(0, bytes) } /// Get the number of unused bits in this byte slice. pub fn unused_bits(&self) -> u8 { self.unused_bits } /// Is the number of unused bits a value other than 0? pub fn has_unused_bits(&self) -> bool { self.unused_bits != 0 } /// Get the length of this `BIT STRING` in bits. pub fn bit_len(&self) -> usize { self.bit_length } /// Get the number of bytes/octets needed to represent this `BIT STRING` /// when serialized in an octet-aligned manner. pub fn byte_len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Borrow the inner byte slice. /// /// Returns `None` if the number of unused bits is *not* equal to zero, /// i.e. if the `BIT STRING` is not octet aligned. /// /// Use [`BitString::raw_bytes`] to obtain access to the raw value /// regardless of the presence of unused bits. pub fn as_bytes(&self) -> Option<&'a [u8]> { if self.has_unused_bits() { None } else { Some(self.raw_bytes()) } } /// Borrow the raw bytes of this `BIT STRING`. /// /// Note that the byte string may contain extra unused bits in the final /// octet. If the number of unused bits is expected to be 0, the /// [`BitStringRef::as_bytes`] function can be used instead. pub fn raw_bytes(&self) -> &'a [u8] { self.inner.as_slice() } /// Iterator over the bits of this `BIT STRING`. pub fn bits(self) -> BitStringIter<'a> { BitStringIter { bit_string: self, position: 0, } } } impl_any_conversions!(BitStringRef<'a>, 'a); impl<'a> DecodeValue<'a> for BitStringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let header = Header { tag: header.tag, length: (header.length - Length::ONE)?, }; let unused_bits = reader.read_byte()?; let inner = BytesRef::decode_value(reader, header)?; Self::new(unused_bits, inner.as_slice()) } } impl EncodeValue for BitStringRef<'_> { fn value_len(&self) -> Result { self.byte_len() + Length::ONE } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write_byte(self.unused_bits)?; writer.write(self.raw_bytes()) } } impl ValueOrd for BitStringRef<'_> { fn value_cmp(&self, other: &Self) -> Result { match self.unused_bits.cmp(&other.unused_bits) { Ordering::Equal => self.inner.der_cmp(&other.inner), ordering => Ok(ordering), } } } impl<'a> From<&BitStringRef<'a>> for BitStringRef<'a> { fn from(value: &BitStringRef<'a>) -> BitStringRef<'a> { *value } } impl<'a> TryFrom<&'a [u8]> for BitStringRef<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result> { BitStringRef::from_bytes(bytes) } } /// Hack for simplifying the custom derive use case. impl<'a> TryFrom<&&'a [u8]> for BitStringRef<'a> { type Error = Error; fn try_from(bytes: &&'a [u8]) -> Result> { BitStringRef::from_bytes(bytes) } } impl<'a> TryFrom> for &'a [u8] { type Error = Error; fn try_from(bit_string: BitStringRef<'a>) -> Result<&'a [u8]> { bit_string .as_bytes() .ok_or_else(|| Tag::BitString.value_error()) } } impl<'a> FixedTag for BitStringRef<'a> { const TAG: Tag = Tag::BitString; } // Implement by hand because the derive would create invalid values. // Use the constructor to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for BitStringRef<'a> { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::new( u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, BytesRef::arbitrary(u)?.as_slice(), ) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) } } #[cfg(feature = "alloc")] pub use self::allocating::BitString; #[cfg(feature = "alloc")] mod allocating { use super::*; use crate::referenced::*; use alloc::vec::Vec; /// Owned form of ASN.1 `BIT STRING` type. /// /// This type provides the same functionality as [`BitStringRef`] but owns the /// backing data. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct BitString { /// Number of unused bits in the final octet. unused_bits: u8, /// Length of this `BIT STRING` in bits. bit_length: usize, /// Bitstring represented as a slice of bytes. inner: Vec, } impl BitString { /// Maximum number of unused bits allowed. pub const MAX_UNUSED_BITS: u8 = 7; /// Create a new ASN.1 `BIT STRING` from a byte slice. /// /// Accepts an optional number of "unused bits" (0-7) which are omitted /// from the final octet. This number is 0 if the value is octet-aligned. pub fn new(unused_bits: u8, bytes: impl Into>) -> Result { let inner = bytes.into(); // Ensure parameters parse successfully as a `BitStringRef`. let bit_length = BitStringRef::new(unused_bits, &inner)?.bit_length; Ok(BitString { unused_bits, bit_length, inner, }) } /// Create a new ASN.1 `BIT STRING` from the given bytes. /// /// The "unused bits" are set to 0. pub fn from_bytes(bytes: &[u8]) -> Result { Self::new(0, bytes) } /// Get the number of unused bits in the octet serialization of this /// `BIT STRING`. pub fn unused_bits(&self) -> u8 { self.unused_bits } /// Is the number of unused bits a value other than 0? pub fn has_unused_bits(&self) -> bool { self.unused_bits != 0 } /// Get the length of this `BIT STRING` in bits. pub fn bit_len(&self) -> usize { self.bit_length } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Borrow the inner byte slice. /// /// Returns `None` if the number of unused bits is *not* equal to zero, /// i.e. if the `BIT STRING` is not octet aligned. /// /// Use [`BitString::raw_bytes`] to obtain access to the raw value /// regardless of the presence of unused bits. pub fn as_bytes(&self) -> Option<&[u8]> { if self.has_unused_bits() { None } else { Some(self.raw_bytes()) } } /// Borrow the raw bytes of this `BIT STRING`. pub fn raw_bytes(&self) -> &[u8] { self.inner.as_slice() } /// Iterator over the bits of this `BIT STRING`. pub fn bits(&self) -> BitStringIter<'_> { BitStringRef::from(self).bits() } } impl_any_conversions!(BitString); impl<'a> DecodeValue<'a> for BitString { fn decode_value>(reader: &mut R, header: Header) -> Result { let inner_len = (header.length - Length::ONE)?; let unused_bits = reader.read_byte()?; let inner = reader.read_vec(inner_len)?; Self::new(unused_bits, inner) } } impl EncodeValue for BitString { fn value_len(&self) -> Result { Length::ONE + Length::try_from(self.inner.len())? } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write_byte(self.unused_bits)?; writer.write(&self.inner) } } impl FixedTag for BitString { const TAG: Tag = Tag::BitString; } impl<'a> From<&'a BitString> for BitStringRef<'a> { fn from(bit_string: &'a BitString) -> BitStringRef<'a> { // Ensured to parse successfully in constructor BitStringRef::new(bit_string.unused_bits, &bit_string.inner) .expect("invalid BIT STRING") } } impl ValueOrd for BitString { fn value_cmp(&self, other: &Self) -> Result { match self.unused_bits.cmp(&other.unused_bits) { Ordering::Equal => self.inner.der_cmp(&other.inner), ordering => Ok(ordering), } } } // Implement by hand because the derive would create invalid values. // Use the constructor to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for BitString { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::new( u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, BytesRef::arbitrary(u)?.as_slice(), ) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) } } impl<'a> RefToOwned<'a> for BitStringRef<'a> { type Owned = BitString; fn ref_to_owned(&self) -> Self::Owned { BitString { unused_bits: self.unused_bits, bit_length: self.bit_length, inner: Vec::from(self.inner.as_slice()), } } } impl OwnedToRef for BitString { type Borrowed<'a> = BitStringRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { self.into() } } } /// Iterator over the bits of a [`BitString`]. pub struct BitStringIter<'a> { /// [`BitString`] being iterated over. bit_string: BitStringRef<'a>, /// Current bit position within the iterator. position: usize, } impl<'a> Iterator for BitStringIter<'a> { type Item = bool; #[allow(clippy::integer_arithmetic)] fn next(&mut self) -> Option { if self.position >= self.bit_string.bit_len() { return None; } let byte = self.bit_string.raw_bytes().get(self.position / 8)?; let bit = 1u8 << (7 - (self.position % 8)); self.position = self.position.checked_add(1)?; Some(byte & bit != 0) } } impl<'a> ExactSizeIterator for BitStringIter<'a> { fn len(&self) -> usize { self.bit_string.bit_len() } } impl<'a> FusedIterator for BitStringIter<'a> {} #[cfg(feature = "flagset")] impl FixedTag for flagset::FlagSet { const TAG: Tag = BitStringRef::TAG; } #[cfg(feature = "flagset")] impl ValueOrd for flagset::FlagSet where T: flagset::Flags, T::Type: Ord, { fn value_cmp(&self, other: &Self) -> Result { Ok(self.bits().cmp(&other.bits())) } } #[cfg(feature = "flagset")] #[allow(clippy::integer_arithmetic)] impl<'a, T> DecodeValue<'a> for flagset::FlagSet where T: flagset::Flags, T::Type: From, T::Type: core::ops::Shl, { fn decode_value>(reader: &mut R, header: Header) -> Result { let position = reader.position(); let bits = BitStringRef::decode_value(reader, header)?; let mut flags = T::none().bits(); if bits.bit_len() > core::mem::size_of_val(&flags) * 8 { return Err(Error::new(ErrorKind::Overlength, position)); } for (i, bit) in bits.bits().enumerate() { flags |= T::Type::from(bit) << i; } Ok(Self::new_truncated(flags)) } } #[cfg(feature = "flagset")] #[allow(clippy::integer_arithmetic)] #[inline(always)] fn encode_flagset(set: &flagset::FlagSet) -> (usize, [u8; 16]) where T: flagset::Flags, u128: From, { let bits: u128 = set.bits().into(); let mut swap = 0u128; for i in 0..128 { let on = bits & (1 << i); swap |= on >> i << (128 - i - 1); } (bits.leading_zeros() as usize, swap.to_be_bytes()) } #[cfg(feature = "flagset")] #[allow(clippy::cast_possible_truncation, clippy::integer_arithmetic)] impl EncodeValue for flagset::FlagSet where T::Type: From, T::Type: core::ops::Shl, u128: From, { fn value_len(&self) -> Result { let (lead, buff) = encode_flagset(self); let buff = &buff[..buff.len() - lead / 8]; BitStringRef::new((lead % 8) as u8, buff)?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { let (lead, buff) = encode_flagset(self); let buff = &buff[..buff.len() - lead / 8]; BitStringRef::new((lead % 8) as u8, buff)?.encode_value(writer) } } #[cfg(test)] mod tests { use super::{BitStringRef, Result, Tag}; use crate::asn1::AnyRef; use hex_literal::hex; /// Parse a `BitString` from an ASN.1 `Any` value to test decoding behaviors. fn parse_bitstring(bytes: &[u8]) -> Result> { AnyRef::new(Tag::BitString, bytes)?.try_into() } #[test] fn decode_empty_bitstring() { let bs = parse_bitstring(&hex!("00")).unwrap(); assert_eq!(bs.as_bytes().unwrap(), &[]); } #[test] fn decode_non_empty_bitstring() { let bs = parse_bitstring(&hex!("00010203")).unwrap(); assert_eq!(bs.as_bytes().unwrap(), &[0x01, 0x02, 0x03]); } #[test] fn decode_bitstring_with_unused_bits() { let bs = parse_bitstring(&hex!("066e5dc0")).unwrap(); assert_eq!(bs.unused_bits(), 6); assert_eq!(bs.raw_bytes(), &hex!("6e5dc0")); // Expected: 011011100101110111 let mut bits = bs.bits(); assert_eq!(bits.len(), 18); for bit in [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1] { assert_eq!(u8::from(bits.next().unwrap()), bit) } // Ensure `None` is returned on successive calls assert_eq!(bits.next(), None); assert_eq!(bits.next(), None); } #[test] fn reject_unused_bits_in_empty_string() { assert_eq!( parse_bitstring(&[0x03]).err().unwrap().kind(), Tag::BitString.value_error().kind() ) } }