Skip to main content

der/asn1/
oid.rs

1//! ASN.1 `OBJECT IDENTIFIER`
2
3use crate::{
4    DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Tagged, Writer,
5    asn1::AnyRef, ord::OrdIsValueOrd,
6};
7use const_oid::{ObjectIdentifier, ObjectIdentifierRef};
8
9#[cfg(feature = "alloc")]
10use super::Any;
11
12impl<'a, const MAX_SIZE: usize> DecodeValue<'a> for ObjectIdentifier<MAX_SIZE> {
13    type Error = Error;
14
15    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
16        let mut buf = [0u8; MAX_SIZE];
17        let slice = buf
18            .get_mut(..header.length().try_into()?)
19            .ok_or_else(|| reader.error(Self::TAG.length_error()))?;
20
21        let actual_len = reader.read_into(slice)?.len();
22        debug_assert_eq!(actual_len, header.length().try_into()?);
23
24        ObjectIdentifierRef::from_bytes(slice)
25            .and_then(TryInto::try_into)
26            .map_err(|oid_err| reader.error(Error::from(oid_err).kind()))
27    }
28}
29
30impl<const MAX_SIZE: usize> EncodeValue for ObjectIdentifier<MAX_SIZE> {
31    fn value_len(&self) -> Result<Length> {
32        Length::try_from(self.as_bytes().len())
33    }
34
35    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
36        writer.write(self.as_bytes())
37    }
38}
39
40impl<const MAX_SIZE: usize> FixedTag for ObjectIdentifier<MAX_SIZE> {
41    const TAG: Tag = Tag::ObjectIdentifier;
42}
43
44impl<const MAX_SIZE: usize> OrdIsValueOrd for ObjectIdentifier<MAX_SIZE> {}
45
46impl<'a, const MAX_SIZE: usize> From<&'a ObjectIdentifier<MAX_SIZE>> for AnyRef<'a> {
47    fn from(oid: &'a ObjectIdentifier<MAX_SIZE>) -> AnyRef<'a> {
48        // Note: ensuring an infallible conversion is possible relies on the
49        // invariant that `const_oid::MAX_LEN <= Length::max()`.
50        //
51        // The `length()` test below ensures this is the case.
52        let value = oid
53            .as_bytes()
54            .try_into()
55            .expect("OID length invariant violated");
56
57        AnyRef::from_tag_and_value(Tag::ObjectIdentifier, value)
58    }
59}
60
61#[cfg(feature = "alloc")]
62impl<const MAX_SIZE: usize> From<ObjectIdentifier<MAX_SIZE>> for Any {
63    fn from(oid: ObjectIdentifier<MAX_SIZE>) -> Any {
64        AnyRef::from(&oid).into()
65    }
66}
67
68impl<const MAX_SIZE: usize> TryFrom<AnyRef<'_>> for ObjectIdentifier<MAX_SIZE> {
69    type Error = Error;
70
71    fn try_from(any: AnyRef<'_>) -> Result<ObjectIdentifier<MAX_SIZE>> {
72        any.tag().assert_eq(Tag::ObjectIdentifier)?;
73        Ok(ObjectIdentifierRef::from_bytes(any.value())?.try_into()?)
74    }
75}
76
77#[cfg(test)]
78#[allow(clippy::unwrap_used)]
79mod tests {
80    use super::ObjectIdentifier;
81    use crate::{Decode, Encode, Length};
82
83    const EXAMPLE_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549");
84    const EXAMPLE_OID_BYTES: &[u8; 8] = &[0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d];
85
86    #[test]
87    fn decode() {
88        let oid = ObjectIdentifier::from_der(EXAMPLE_OID_BYTES).unwrap();
89        assert_eq!(EXAMPLE_OID, oid);
90    }
91
92    #[test]
93    fn encode() {
94        let mut buffer = [0u8; 8];
95        assert_eq!(
96            EXAMPLE_OID_BYTES,
97            EXAMPLE_OID.encode_to_slice(&mut buffer).unwrap()
98        );
99    }
100
101    #[test]
102    fn length() {
103        // Ensure an infallible `From` conversion to `Any` will never panic
104        assert!(ObjectIdentifier::MAX_SIZE <= Length::MAX.try_into().unwrap());
105    }
106}