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