diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/const-oid/src/lib.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/const-oid/src/lib.rs')
-rw-r--r-- | vendor/const-oid/src/lib.rs | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/vendor/const-oid/src/lib.rs b/vendor/const-oid/src/lib.rs new file mode 100644 index 000000000..b00d4e2e7 --- /dev/null +++ b/vendor/const-oid/src/lib.rs @@ -0,0 +1,254 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::integer_arithmetic, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +#[cfg(feature = "std")] +extern crate std; + +#[macro_use] +mod checked; + +mod arcs; +mod encoder; +mod error; +mod parser; + +#[cfg(feature = "db")] +#[cfg_attr(docsrs, doc(cfg(feature = "db")))] +pub mod db; + +pub use crate::{ + arcs::{Arc, Arcs}, + error::{Error, Result}, +}; + +use crate::encoder::Encoder; +use core::{fmt, str::FromStr}; + +/// A trait which associates an OID with a type. +pub trait AssociatedOid { + /// The OID associated with this type. + const OID: ObjectIdentifier; +} + +/// A trait which associates a dynamic, `&self`-dependent OID with a type, +/// which may change depending on the type's value. +/// +/// This trait is object safe and auto-impl'd for any types which impl +/// [`AssociatedOid`]. +pub trait DynAssociatedOid { + /// Get the OID associated with this value. + fn oid(&self) -> ObjectIdentifier; +} + +impl<T: AssociatedOid> DynAssociatedOid for T { + fn oid(&self) -> ObjectIdentifier { + T::OID + } +} + +/// Object identifier (OID). +/// +/// OIDs are hierarchical structures consisting of "arcs", i.e. integer +/// identifiers. +/// +/// # Validity +/// +/// In order for an OID to be considered valid by this library, it must meet +/// the following criteria: +/// +/// - The OID MUST have at least 3 arcs +/// - The first arc MUST be within the range 0-2 +/// - The second arc MUST be within the range 0-39 +/// - The BER/DER encoding of the OID MUST be shorter than +/// [`ObjectIdentifier::MAX_SIZE`] +#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct ObjectIdentifier { + /// Length in bytes + length: u8, + + /// Array containing BER/DER-serialized bytes (no header) + bytes: [u8; Self::MAX_SIZE], +} + +#[allow(clippy::len_without_is_empty)] +impl ObjectIdentifier { + /// Maximum size of a BER/DER-encoded OID in bytes. + pub const MAX_SIZE: usize = 39; // makes `ObjectIdentifier` 40-bytes total w\ 1-byte length + + /// Parse an [`ObjectIdentifier`] from the dot-delimited string form, + /// panicking on parse errors. + /// + /// This function exists as a workaround for `unwrap` not yet being + /// stable in `const fn` contexts, and is intended to allow the result to + /// be bound to a constant value: + /// + /// ``` + /// use const_oid::ObjectIdentifier; + /// + /// pub const MY_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"); + /// ``` + /// + /// In future versions of Rust it should be possible to replace this with + /// `ObjectIdentifier::new(...).unwrap()`. + /// + /// Use [`ObjectIdentifier::new`] for fallible parsing. + // TODO(tarcieri): remove this when `Result::unwrap` is `const fn` + pub const fn new_unwrap(s: &str) -> Self { + match Self::new(s) { + Ok(oid) => oid, + Err(err) => err.panic(), + } + } + + /// Parse an [`ObjectIdentifier`] from the dot-delimited string form. + pub const fn new(s: &str) -> Result<Self> { + // TODO(tarcieri): use `?` when stable in `const fn` + match parser::Parser::parse(s) { + Ok(parser) => parser.finish(), + Err(err) => Err(err), + } + } + + /// Parse an OID from a slice of [`Arc`] values (i.e. integers). + pub fn from_arcs(arcs: impl IntoIterator<Item = Arc>) -> Result<Self> { + let mut encoder = Encoder::new(); + + for arc in arcs { + encoder = encoder.arc(arc)?; + } + + encoder.finish() + } + + /// Parse an OID from from its BER/DER encoding. + pub fn from_bytes(ber_bytes: &[u8]) -> Result<Self> { + let len = ber_bytes.len(); + + match len { + 0 => return Err(Error::Empty), + 3..=Self::MAX_SIZE => (), + _ => return Err(Error::NotEnoughArcs), + } + let mut bytes = [0u8; Self::MAX_SIZE]; + bytes[..len].copy_from_slice(ber_bytes); + + let oid = Self { + bytes, + length: len as u8, + }; + + // Ensure arcs are well-formed + let mut arcs = oid.arcs(); + while arcs.try_next()?.is_some() {} + + Ok(oid) + } + + /// Get the BER/DER serialization of this OID as bytes. + /// + /// Note that this encoding omits the tag/length, and only contains the + /// value portion of the encoded OID. + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[..self.length as usize] + } + + /// Return the arc with the given index, if it exists. + pub fn arc(&self, index: usize) -> Option<Arc> { + self.arcs().nth(index) + } + + /// Iterate over the arcs (a.k.a. nodes) of an [`ObjectIdentifier`]. + /// + /// Returns [`Arcs`], an iterator over [`Arc`] values. + pub fn arcs(&self) -> Arcs<'_> { + Arcs::new(self) + } + + /// Get the length of this [`ObjectIdentifier`] in arcs. + pub fn len(&self) -> usize { + self.arcs().count() + } + + /// Get the parent OID of this one (if applicable). + pub fn parent(&self) -> Option<Self> { + let num_arcs = self.len().checked_sub(1)?; + Self::from_arcs(self.arcs().take(num_arcs)).ok() + } + + /// Push an additional arc onto this OID, returning the child OID. + pub const fn push_arc(self, arc: Arc) -> Result<Self> { + // TODO(tarcieri): use `?` when stable in `const fn` + match Encoder::extend(self).arc(arc) { + Ok(encoder) => encoder.finish(), + Err(err) => Err(err), + } + } +} + +impl AsRef<[u8]> for ObjectIdentifier { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl FromStr for ObjectIdentifier { + type Err = Error; + + fn from_str(string: &str) -> Result<Self> { + Self::new(string) + } +} + +impl TryFrom<&[u8]> for ObjectIdentifier { + type Error = Error; + + fn try_from(ber_bytes: &[u8]) -> Result<Self> { + Self::from_bytes(ber_bytes) + } +} + +impl From<&ObjectIdentifier> for ObjectIdentifier { + fn from(oid: &ObjectIdentifier) -> ObjectIdentifier { + *oid + } +} + +impl fmt::Debug for ObjectIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ObjectIdentifier({})", self) + } +} + +impl fmt::Display for ObjectIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let len = self.arcs().count(); + + for (i, arc) in self.arcs().enumerate() { + write!(f, "{}", arc)?; + + if let Some(j) = i.checked_add(1) { + if j < len { + write!(f, ".")?; + } + } + } + + Ok(()) + } +} |