1 #![no_std]
2 #![cfg_attr(docsrs, feature(doc_cfg))]
3 #![doc = include_str!("../README.md")]
4 #![doc(
5     html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
6     html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
7 )]
8 #![forbid(unsafe_code)]
9 #![warn(
10     clippy::integer_arithmetic,
11     clippy::panic,
12     clippy::panic_in_result_fn,
13     clippy::unwrap_used,
14     missing_docs,
15     rust_2018_idioms,
16     unused_lifetimes,
17     unused_qualifications
18 )]
19 
20 /// Local Android change: Use std to allow building as a dylib.
21 #[cfg(android_dylib)]
22 extern crate std;
23 
24 #[cfg(feature = "std")]
25 extern crate std;
26 
27 #[macro_use]
28 mod checked;
29 
30 mod arcs;
31 mod encoder;
32 mod error;
33 mod parser;
34 
35 #[cfg(feature = "db")]
36 #[cfg_attr(docsrs, doc(cfg(feature = "db")))]
37 pub mod db;
38 
39 pub use crate::{
40     arcs::{Arc, Arcs},
41     error::{Error, Result},
42 };
43 
44 use crate::encoder::Encoder;
45 use core::{fmt, str::FromStr};
46 
47 /// A trait which associates an OID with a type.
48 pub trait AssociatedOid {
49     /// The OID associated with this type.
50     const OID: ObjectIdentifier;
51 }
52 
53 /// A trait which associates a dynamic, `&self`-dependent OID with a type,
54 /// which may change depending on the type's value.
55 ///
56 /// This trait is object safe and auto-impl'd for any types which impl
57 /// [`AssociatedOid`].
58 pub trait DynAssociatedOid {
59     /// Get the OID associated with this value.
oid(&self) -> ObjectIdentifier60     fn oid(&self) -> ObjectIdentifier;
61 }
62 
63 impl<T: AssociatedOid> DynAssociatedOid for T {
oid(&self) -> ObjectIdentifier64     fn oid(&self) -> ObjectIdentifier {
65         T::OID
66     }
67 }
68 
69 /// Object identifier (OID).
70 ///
71 /// OIDs are hierarchical structures consisting of "arcs", i.e. integer
72 /// identifiers.
73 ///
74 /// # Validity
75 ///
76 /// In order for an OID to be considered valid by this library, it must meet
77 /// the following criteria:
78 ///
79 /// - The OID MUST have at least 3 arcs
80 /// - The first arc MUST be within the range 0-2
81 /// - The second arc MUST be within the range 0-39
82 /// - The BER/DER encoding of the OID MUST be shorter than
83 ///   [`ObjectIdentifier::MAX_SIZE`]
84 #[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
85 pub struct ObjectIdentifier {
86     /// Length in bytes
87     length: u8,
88 
89     /// Array containing BER/DER-serialized bytes (no header)
90     bytes: [u8; Self::MAX_SIZE],
91 }
92 
93 #[allow(clippy::len_without_is_empty)]
94 impl ObjectIdentifier {
95     /// Maximum size of a BER/DER-encoded OID in bytes.
96     pub const MAX_SIZE: usize = 39; // makes `ObjectIdentifier` 40-bytes total w\ 1-byte length
97 
98     /// Parse an [`ObjectIdentifier`] from the dot-delimited string form,
99     /// panicking on parse errors.
100     ///
101     /// This function exists as a workaround for `unwrap` not yet being
102     /// stable in `const fn` contexts, and is intended to allow the result to
103     /// be bound to a constant value:
104     ///
105     /// ```
106     /// use const_oid::ObjectIdentifier;
107     ///
108     /// pub const MY_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1");
109     /// ```
110     ///
111     /// In future versions of Rust it should be possible to replace this with
112     /// `ObjectIdentifier::new(...).unwrap()`.
113     ///
114     /// Use [`ObjectIdentifier::new`] for fallible parsing.
115     // TODO(tarcieri): remove this when `Result::unwrap` is `const fn`
new_unwrap(s: &str) -> Self116     pub const fn new_unwrap(s: &str) -> Self {
117         match Self::new(s) {
118             Ok(oid) => oid,
119             Err(err) => err.panic(),
120         }
121     }
122 
123     /// Parse an [`ObjectIdentifier`] from the dot-delimited string form.
new(s: &str) -> Result<Self>124     pub const fn new(s: &str) -> Result<Self> {
125         // TODO(tarcieri): use `?` when stable in `const fn`
126         match parser::Parser::parse(s) {
127             Ok(parser) => parser.finish(),
128             Err(err) => Err(err),
129         }
130     }
131 
132     /// Parse an OID from a slice of [`Arc`] values (i.e. integers).
from_arcs(arcs: impl IntoIterator<Item = Arc>) -> Result<Self>133     pub fn from_arcs(arcs: impl IntoIterator<Item = Arc>) -> Result<Self> {
134         let mut encoder = Encoder::new();
135 
136         for arc in arcs {
137             encoder = encoder.arc(arc)?;
138         }
139 
140         encoder.finish()
141     }
142 
143     /// Parse an OID from from its BER/DER encoding.
from_bytes(ber_bytes: &[u8]) -> Result<Self>144     pub fn from_bytes(ber_bytes: &[u8]) -> Result<Self> {
145         let len = ber_bytes.len();
146 
147         match len {
148             0 => return Err(Error::Empty),
149             3..=Self::MAX_SIZE => (),
150             _ => return Err(Error::NotEnoughArcs),
151         }
152         let mut bytes = [0u8; Self::MAX_SIZE];
153         bytes[..len].copy_from_slice(ber_bytes);
154 
155         let oid = Self {
156             bytes,
157             length: len as u8,
158         };
159 
160         // Ensure arcs are well-formed
161         let mut arcs = oid.arcs();
162         while arcs.try_next()?.is_some() {}
163 
164         Ok(oid)
165     }
166 
167     /// Get the BER/DER serialization of this OID as bytes.
168     ///
169     /// Note that this encoding omits the tag/length, and only contains the
170     /// value portion of the encoded OID.
as_bytes(&self) -> &[u8]171     pub fn as_bytes(&self) -> &[u8] {
172         &self.bytes[..self.length as usize]
173     }
174 
175     /// Return the arc with the given index, if it exists.
arc(&self, index: usize) -> Option<Arc>176     pub fn arc(&self, index: usize) -> Option<Arc> {
177         self.arcs().nth(index)
178     }
179 
180     /// Iterate over the arcs (a.k.a. nodes) of an [`ObjectIdentifier`].
181     ///
182     /// Returns [`Arcs`], an iterator over [`Arc`] values.
arcs(&self) -> Arcs<'_>183     pub fn arcs(&self) -> Arcs<'_> {
184         Arcs::new(self)
185     }
186 
187     /// Get the length of this [`ObjectIdentifier`] in arcs.
len(&self) -> usize188     pub fn len(&self) -> usize {
189         self.arcs().count()
190     }
191 
192     /// Get the parent OID of this one (if applicable).
parent(&self) -> Option<Self>193     pub fn parent(&self) -> Option<Self> {
194         let num_arcs = self.len().checked_sub(1)?;
195         Self::from_arcs(self.arcs().take(num_arcs)).ok()
196     }
197 
198     /// Push an additional arc onto this OID, returning the child OID.
push_arc(self, arc: Arc) -> Result<Self>199     pub const fn push_arc(self, arc: Arc) -> Result<Self> {
200         // TODO(tarcieri): use `?` when stable in `const fn`
201         match Encoder::extend(self).arc(arc) {
202             Ok(encoder) => encoder.finish(),
203             Err(err) => Err(err),
204         }
205     }
206 }
207 
208 impl AsRef<[u8]> for ObjectIdentifier {
as_ref(&self) -> &[u8]209     fn as_ref(&self) -> &[u8] {
210         self.as_bytes()
211     }
212 }
213 
214 impl FromStr for ObjectIdentifier {
215     type Err = Error;
216 
from_str(string: &str) -> Result<Self>217     fn from_str(string: &str) -> Result<Self> {
218         Self::new(string)
219     }
220 }
221 
222 impl TryFrom<&[u8]> for ObjectIdentifier {
223     type Error = Error;
224 
try_from(ber_bytes: &[u8]) -> Result<Self>225     fn try_from(ber_bytes: &[u8]) -> Result<Self> {
226         Self::from_bytes(ber_bytes)
227     }
228 }
229 
230 impl From<&ObjectIdentifier> for ObjectIdentifier {
from(oid: &ObjectIdentifier) -> ObjectIdentifier231     fn from(oid: &ObjectIdentifier) -> ObjectIdentifier {
232         *oid
233     }
234 }
235 
236 impl fmt::Debug for ObjectIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result237     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238         write!(f, "ObjectIdentifier({})", self)
239     }
240 }
241 
242 impl fmt::Display for ObjectIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result243     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244         let len = self.arcs().count();
245 
246         for (i, arc) in self.arcs().enumerate() {
247             write!(f, "{}", arc)?;
248 
249             if let Some(j) = i.checked_add(1) {
250                 if j < len {
251                     write!(f, ".")?;
252                 }
253             }
254         }
255 
256         Ok(())
257     }
258 }
259 
260 // Implement by hand because the derive would create invalid values.
261 // Use the constructor to create a valid oid with at least 3 arcs.
262 #[cfg(feature = "arbitrary")]
263 impl<'a> arbitrary::Arbitrary<'a> for ObjectIdentifier {
arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self>264     fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
265         let first = u.int_in_range(0..=arcs::ARC_MAX_FIRST)?;
266         let second = u.int_in_range(0..=arcs::ARC_MAX_SECOND)?;
267         let third = u.arbitrary()?;
268 
269         let mut oid = Self::from_arcs([first, second, third])
270             .map_err(|_| arbitrary::Error::IncorrectFormat)?;
271 
272         for arc in u.arbitrary_iter()? {
273             oid = oid
274                 .push_arc(arc?)
275                 .map_err(|_| arbitrary::Error::IncorrectFormat)?;
276         }
277 
278         Ok(oid)
279     }
280 
size_hint(depth: usize) -> (usize, Option<usize>)281     fn size_hint(depth: usize) -> (usize, Option<usize>) {
282         (Arc::size_hint(depth).0.saturating_mul(3), None)
283     }
284 }
285