asn1/
object_identifier.rs1use crate::base128;
2use crate::parser::{ParseError, ParseErrorKind, ParseResult};
3use alloc::fmt;
4
5const MAX_OID_LENGTH: usize = 63;
6
7#[derive(PartialEq, Eq, Clone, Hash)]
22pub struct ObjectIdentifier {
23 der_encoded: [u8; MAX_OID_LENGTH],
25 der_encoded_len: u8,
26}
27
28impl ObjectIdentifier {
29 pub fn from_string(oid: &str) -> Option<ObjectIdentifier> {
31 let mut parts = oid.split('.');
32
33 let first = parts.next()?.parse::<u128>().ok()?;
34 let second = parts.next()?.parse::<u128>().ok()?;
35 if first > 2 || (first < 2 && second >= 40) {
36 return None;
37 }
38
39 let mut der_data = [0; MAX_OID_LENGTH];
40 let mut der_data_len = 0;
41 der_data_len +=
42 base128::write_base128_int(&mut der_data[der_data_len..], 40 * first + second)?;
43 for part in parts {
44 der_data_len += base128::write_base128_int(
45 &mut der_data[der_data_len..],
46 part.parse::<u128>().ok()?,
47 )?;
48 }
49 Some(ObjectIdentifier {
50 der_encoded: der_data,
51 der_encoded_len: der_data_len as u8,
52 })
53 }
54
55 pub fn from_der(data: &[u8]) -> ParseResult<ObjectIdentifier> {
58 if data.is_empty() {
59 return Err(ParseError::new(ParseErrorKind::InvalidValue));
60 } else if data.len() > MAX_OID_LENGTH {
61 return Err(ParseError::new(ParseErrorKind::OidTooLong));
62 }
63
64 let mut parsed = (0, data);
65 while !parsed.1.is_empty() {
66 parsed = base128::read_base128_int(parsed.1)
69 .map_err(|_| ParseError::new(ParseErrorKind::InvalidValue))?;
70 }
71
72 let mut storage = [0; MAX_OID_LENGTH];
73 storage[..data.len()].copy_from_slice(data);
74
75 Ok(ObjectIdentifier {
76 der_encoded: storage,
77 der_encoded_len: data.len() as u8,
78 })
79 }
80
81 #[doc(hidden)]
85 pub const fn from_der_unchecked(data: [u8; MAX_OID_LENGTH], data_len: u8) -> ObjectIdentifier {
86 ObjectIdentifier {
87 der_encoded: data,
88 der_encoded_len: data_len,
89 }
90 }
91
92 pub(crate) fn as_der(&self) -> &[u8] {
93 &self.der_encoded[..self.der_encoded_len as usize]
94 }
95}
96
97struct OidFormatter<'a>(&'a ObjectIdentifier);
98
99impl fmt::Debug for OidFormatter<'_> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 let mut parsed = (0, self.0.as_der());
102
103 parsed = base128::read_base128_int(parsed.1).unwrap();
104 if parsed.0 < 80 {
105 write!(f, "{}.{}", parsed.0 / 40, parsed.0 % 40)?;
106 } else {
107 write!(f, "2.{}", parsed.0 - 80)?;
108 }
109
110 while !parsed.1.is_empty() {
111 parsed = base128::read_base128_int(parsed.1).unwrap();
112 write!(f, ".{}", parsed.0)?;
113 }
114
115 Ok(())
116 }
117}
118
119impl fmt::Debug for ObjectIdentifier {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.debug_struct("ObjectIdentifier")
122 .field("oid", &OidFormatter(self))
123 .finish()
124 }
125}
126
127impl fmt::Display for ObjectIdentifier {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 fmt::Debug::fmt(&OidFormatter(self), f)
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::MAX_OID_LENGTH;
138 use crate::{ObjectIdentifier, ParseError, ParseErrorKind};
139 use alloc::format;
140 #[cfg(not(feature = "std"))]
141 use alloc::string::ToString;
142
143 #[test]
144 fn test_object_identifier_from_string() {
145 for val in &[
146 "",
147 "1",
148 "3.10",
149 "1.50",
150 "2.12.a3.4",
151 "a.4",
152 "1.a",
153 ".2.5",
154 "2..5",
155 "2.5.",
156 "1.3.6.1.4.1.1248.1.1.2.1.3.21.69.112.115.111.110.32.83.116.121.108.117.115.32.80.114.111.32.52.57.48.48.123.124412.31.213321.123.110.32.83.116.121.108.117.115.32.80.114.111.32.52.57.48.48.123.124412.31.213321.123",
157 ] {
158 assert_eq!(ObjectIdentifier::from_string(val), None);
159 }
160
161 for val in &[
162 "2.5",
163 "2.5.2",
164 "1.2.840.113549",
165 "1.2.3.4",
166 "1.2.840.133549.1.1.5",
167 "2.100.3",
168 "2.1.750304883",
169 "2.25.223663413560230117710484359924050447509",
170 "2.25.340282366920938463463374607431768211455",
171 ] {
172 assert!(ObjectIdentifier::from_string(val).is_some());
173 }
174 }
175
176 #[test]
177 fn test_from_der() {
178 assert_eq!(ObjectIdentifier::from_der(b"\x06\x40\x2b\x06\x01\x04\x01\x89\x60\x01\x01\x02\x01\x03\x15\x45\x70\x73\x6f\x6e\x20\x53\x74\x79\x6c\x75\x73\x20\x50\x72\x6f\x20\x34\x39\x30\x30\x7b\x87\xcb\x7c\x1f\x8d\x82\x49\x7b\x2b\x06\x01\x04\x01\x89\x60\x01\x01\x02\x01\x03\x15\x45\x70\x73\x6f\x6e\x20"), Err(ParseError::new(ParseErrorKind::OidTooLong)));
179 }
180
181 #[test]
182 fn test_from_der_unchecked() {
183 for (dotted_string, der) in &[("2.5", b"\x55" as &[u8]), ("2.100.3", b"\x81\x34\x03")] {
184 let mut data = [0; MAX_OID_LENGTH];
185 data[..der.len()].copy_from_slice(der);
186 assert_eq!(
187 ObjectIdentifier::from_string(dotted_string).unwrap(),
188 ObjectIdentifier::from_der_unchecked(data, der.len() as u8)
189 );
190 }
191 }
192
193 #[test]
194 fn test_debug() {
195 let oid = ObjectIdentifier::from_string("1.2.3.4").unwrap();
196 assert_eq!(format!("{oid:?}"), "ObjectIdentifier { oid: 1.2.3.4 }");
197 }
198
199 #[test]
200 fn test_to_string() {
201 for val in &[
202 "0.4",
203 "2.5",
204 "2.5.2",
205 "1.2.840.113549",
206 "1.2.3.4",
207 "1.2.840.133549.1.1.5",
208 "2.100.3",
209 "2.1.750304883",
210 "2.25.223663413560230117710484359924050447509",
211 "2.25.340282366920938463463374607431768211455",
212 ] {
213 assert_eq!(
214 &ObjectIdentifier::from_string(val).unwrap().to_string(),
215 val
216 );
217 }
218 }
219}