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