Skip to main content

der/asn1/
boolean.rs

1//! ASN.1 `BOOLEAN` support.
2
3use crate::{
4    DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag,
5    Writer, asn1::AnyRef, ord::OrdIsValueOrd,
6};
7
8/// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1:
9///
10/// > If the encoding represents the boolean value TRUE, its single contents
11/// > octet shall have all eight bits set to one.
12const TRUE_OCTET: u8 = 0b11111111;
13
14/// Byte used to encode `false` in ASN.1 DER.
15const FALSE_OCTET: u8 = 0b00000000;
16
17impl<'a> DecodeValue<'a> for bool {
18    type Error = Error;
19
20    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
21        if header.length() != Length::ONE {
22            return Err(reader.error(ErrorKind::Length { tag: Self::TAG }));
23        }
24
25        match reader.read_byte()? {
26            FALSE_OCTET => Ok(false),
27            TRUE_OCTET => Ok(true),
28            _ => Err(reader.error(Self::TAG.non_canonical_error())),
29        }
30    }
31}
32
33impl EncodeValue for bool {
34    fn value_len(&self) -> Result<Length> {
35        Ok(Length::ONE)
36    }
37
38    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
39        writer.write_byte(if *self { TRUE_OCTET } else { FALSE_OCTET })
40    }
41}
42
43impl FixedTag for bool {
44    const TAG: Tag = Tag::Boolean;
45}
46
47impl OrdIsValueOrd for bool {}
48
49impl TryFrom<AnyRef<'_>> for bool {
50    type Error = Error;
51
52    fn try_from(any: AnyRef<'_>) -> Result<bool> {
53        any.decode_as()
54    }
55}
56
57#[cfg(test)]
58#[allow(clippy::unwrap_used, clippy::bool_assert_comparison)]
59mod tests {
60    use crate::{Decode, Encode, asn1::AnyRef};
61
62    #[test]
63    fn try_from_any() {
64        let true_value = AnyRef::from_der(&[0x01, 0x01, 0xFF]).unwrap();
65        let false_value = AnyRef::from_der(&[0x01, 0x01, 0x00]).unwrap();
66        assert_eq!(bool::try_from(true_value).unwrap(), true);
67        assert_eq!(bool::try_from(false_value).unwrap(), false);
68    }
69
70    #[test]
71    fn try_from_any_rejects_invalid_input() {
72        for bytes in [
73            &[0x02, 0x01, 0x00][..],   // Wrong tag: INTEGER.
74            &[0x01, 0x00],             // Empty BOOLEAN.
75            &[0x01, 0x02, 0x00, 0x00], // Overlong BOOLEAN.
76            &[0x01, 0x01, 0x01],       // Noncanonical TRUE.
77        ] {
78            let any = AnyRef::from_der(bytes).unwrap();
79            assert!(bool::try_from(any).is_err());
80        }
81    }
82
83    #[test]
84    fn decode() {
85        assert_eq!(true, bool::from_der(&[0x01, 0x01, 0xFF]).unwrap());
86        assert_eq!(false, bool::from_der(&[0x01, 0x01, 0x00]).unwrap());
87    }
88
89    #[test]
90    fn encode() {
91        let mut buffer = [0u8; 3];
92        assert_eq!(
93            &[0x01, 0x01, 0xFF],
94            true.encode_to_slice(&mut buffer).unwrap()
95        );
96        assert_eq!(
97            &[0x01, 0x01, 0x00],
98            false.encode_to_slice(&mut buffer).unwrap()
99        );
100    }
101
102    #[test]
103    fn reject_non_canonical() {
104        assert!(bool::from_der(&[0x01, 0x01, 0x01]).is_err());
105    }
106}