asn1_rs/asn1_types/
bitstring.rs

1use crate::*;
2use alloc::borrow::Cow;
3#[cfg(feature = "bits")]
4use bitvec::{order::Msb0, slice::BitSlice};
5use core::convert::TryFrom;
6
7/// ASN.1 `BITSTRING` type
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct BitString<'a> {
10    pub unused_bits: u8,
11    pub data: Cow<'a, [u8]>,
12}
13
14impl<'a> BitString<'a> {
15    // Length must be >= 1 (first byte is number of ignored bits)
16    pub const fn new(unused_bits: u8, s: &'a [u8]) -> Self {
17        BitString {
18            unused_bits,
19            data: Cow::Borrowed(s),
20        }
21    }
22
23    /// Test if bit `bitnum` is set
24    pub fn is_set(&self, bitnum: usize) -> bool {
25        let byte_pos = bitnum / 8;
26        if byte_pos >= self.data.len() {
27            return false;
28        }
29        let b = 7 - (bitnum % 8);
30        (self.data[byte_pos] & (1 << b)) != 0
31    }
32
33    /// Constructs a shared `&BitSlice` reference over the object data.
34    #[cfg(feature = "bits")]
35    pub fn as_bitslice(&self) -> Option<&BitSlice<u8, Msb0>> {
36        BitSlice::<_, Msb0>::try_from_slice(&self.data).ok()
37    }
38}
39
40impl<'a> AsRef<[u8]> for BitString<'a> {
41    fn as_ref(&self) -> &[u8] {
42        &self.data
43    }
44}
45
46impl<'a> TryFrom<Any<'a>> for BitString<'a> {
47    type Error = Error;
48
49    fn try_from(any: Any<'a>) -> Result<BitString<'a>> {
50        TryFrom::try_from(&any)
51    }
52}
53
54// non-consuming version
55impl<'a, 'b> TryFrom<&'b Any<'a>> for BitString<'a> {
56    type Error = Error;
57
58    fn try_from(any: &'b Any<'a>) -> Result<BitString<'a>> {
59        any.tag().assert_eq(Self::TAG)?;
60        if any.data.is_empty() {
61            return Err(Error::InvalidLength);
62        }
63        let s = any.data;
64        let (unused_bits, data) = (s[0], Cow::Borrowed(&s[1..]));
65        Ok(BitString { unused_bits, data })
66    }
67}
68
69impl<'a> CheckDerConstraints for BitString<'a> {
70    fn check_constraints(any: &Any) -> Result<()> {
71        // X.690 section 10.2
72        any.header.assert_primitive()?;
73        // Check that padding bits are all 0 (X.690 section 11.2.1)
74        match any.data.len() {
75            0 => Err(Error::InvalidLength),
76            1 => {
77                // X.690 section 11.2.2 Note 2
78                if any.data[0] == 0 {
79                    Ok(())
80                } else {
81                    Err(Error::InvalidLength)
82                }
83            }
84            len => {
85                let unused_bits = any.data[0];
86                let last_byte = any.data[len - 1];
87                if last_byte.trailing_zeros() < unused_bits as u32 {
88                    return Err(Error::DerConstraintFailed(DerConstraint::UnusedBitsNotZero));
89                }
90
91                Ok(())
92            }
93        }
94    }
95}
96
97impl DerAutoDerive for BitString<'_> {}
98
99impl<'a> Tagged for BitString<'a> {
100    const TAG: Tag = Tag::BitString;
101}
102
103#[cfg(feature = "std")]
104impl ToDer for BitString<'_> {
105    fn to_der_len(&self) -> Result<usize> {
106        let sz = self.data.len();
107        if sz < 127 {
108            // 1 (class+tag) + 1 (length) +  1 (unused bits) + len
109            Ok(3 + sz)
110        } else {
111            // 1 (class+tag) + n (length) + 1 (unused bits) + len
112            let n = Length::Definite(sz + 1).to_der_len()?;
113            Ok(2 + n + sz)
114        }
115    }
116
117    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
118        let header = Header::new(
119            Class::Universal,
120            false,
121            Self::TAG,
122            Length::Definite(1 + self.data.len()),
123        );
124        header.write_der_header(writer).map_err(Into::into)
125    }
126
127    fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
128        let sz = writer.write(&[self.unused_bits])?;
129        let sz = sz + writer.write(&self.data)?;
130        Ok(sz)
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::BitString;
137
138    #[test]
139    fn test_bitstring_is_set() {
140        let obj = BitString::new(0, &[0x0f, 0x00, 0x40]);
141        assert!(!obj.is_set(0));
142        assert!(obj.is_set(7));
143        assert!(!obj.is_set(9));
144        assert!(obj.is_set(17));
145    }
146
147    #[cfg(feature = "bits")]
148    #[test]
149    fn test_bitstring_to_bitvec() {
150        let obj = BitString::new(0, &[0x0f, 0x00, 0x40]);
151        let bv = obj.as_bitslice().expect("could not get bitslice");
152        assert_eq!(bv.get(0).as_deref(), Some(&false));
153        assert_eq!(bv.get(7).as_deref(), Some(&true));
154        assert_eq!(bv.get(9).as_deref(), Some(&false));
155        assert_eq!(bv.get(17).as_deref(), Some(&true));
156    }
157}