summaryrefslogtreecommitdiffstats
path: root/vendor/const-oid/src/arcs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/const-oid/src/arcs.rs')
-rw-r--r--vendor/const-oid/src/arcs.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/const-oid/src/arcs.rs b/vendor/const-oid/src/arcs.rs
new file mode 100644
index 000000000..7bf7a9a13
--- /dev/null
+++ b/vendor/const-oid/src/arcs.rs
@@ -0,0 +1,170 @@
+//! Arcs are integer values which exist within an OID's hierarchy.
+
+use crate::{Error, ObjectIdentifier, Result};
+use core::mem;
+
+/// Type alias used to represent an "arc" (i.e. integer identifier value).
+///
+/// X.660 does not define a maximum size of an arc.
+///
+/// The current representation is `u32`, which has been selected as being
+/// sufficient to cover the current PKCS/PKIX use cases this library has been
+/// used in conjunction with.
+///
+/// Future versions may potentially make it larger if a sufficiently important
+/// use case is discovered.
+pub type Arc = u32;
+
+/// Maximum value of the first arc in an OID.
+pub(crate) const ARC_MAX_FIRST: Arc = 2;
+
+/// Maximum value of the second arc in an OID.
+pub(crate) const ARC_MAX_SECOND: Arc = 39;
+
+/// Maximum number of bytes supported in an arc.
+const ARC_MAX_BYTES: usize = mem::size_of::<Arc>();
+
+/// Maximum value of the last byte in an arc.
+const ARC_MAX_LAST_OCTET: u8 = 0b11110000; // Max bytes of leading 1-bits
+
+/// [`Iterator`] over [`Arc`] values (a.k.a. nodes) in an [`ObjectIdentifier`].
+///
+/// This iterates over all arcs in an OID, including the root.
+pub struct Arcs<'a> {
+ /// OID we're iterating over
+ oid: &'a ObjectIdentifier,
+
+ /// Current position within the serialized DER bytes of this OID
+ cursor: Option<usize>,
+}
+
+impl<'a> Arcs<'a> {
+ /// Create a new iterator over the arcs of this OID
+ pub(crate) fn new(oid: &'a ObjectIdentifier) -> Self {
+ Self { oid, cursor: None }
+ }
+
+ /// Try to parse the next arc in this OID.
+ ///
+ /// This method is fallible so it can be used as a first pass to determine
+ /// that the arcs in the OID are well-formed.
+ pub(crate) fn try_next(&mut self) -> Result<Option<Arc>> {
+ match self.cursor {
+ // Indicates we're on the root OID
+ None => {
+ let root = RootArcs::try_from(self.oid.as_bytes()[0])?;
+ self.cursor = Some(0);
+ Ok(Some(root.first_arc()))
+ }
+ Some(0) => {
+ let root = RootArcs::try_from(self.oid.as_bytes()[0])?;
+ self.cursor = Some(1);
+ Ok(Some(root.second_arc()))
+ }
+ Some(offset) => {
+ let mut result = 0;
+ let mut arc_bytes = 0;
+
+ loop {
+ let len = checked_add!(offset, arc_bytes);
+
+ match self.oid.as_bytes().get(len).cloned() {
+ // The arithmetic below includes advance checks
+ // against `ARC_MAX_BYTES` and `ARC_MAX_LAST_OCTET`
+ // which ensure the operations will not overflow.
+ #[allow(clippy::integer_arithmetic)]
+ Some(byte) => {
+ arc_bytes = checked_add!(arc_bytes, 1);
+
+ if (arc_bytes > ARC_MAX_BYTES) && (byte & ARC_MAX_LAST_OCTET != 0) {
+ return Err(Error::ArcTooBig);
+ }
+
+ result = result << 7 | (byte & 0b1111111) as Arc;
+
+ if byte & 0b10000000 == 0 {
+ self.cursor = Some(checked_add!(offset, arc_bytes));
+ return Ok(Some(result));
+ }
+ }
+ None => {
+ if arc_bytes == 0 {
+ return Ok(None);
+ } else {
+ return Err(Error::Base128);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+impl<'a> Iterator for Arcs<'a> {
+ type Item = Arc;
+
+ fn next(&mut self) -> Option<Arc> {
+ // ObjectIdentifier constructors should ensure the OID is well-formed
+ self.try_next().expect("OID malformed")
+ }
+}
+
+/// Byte containing the first and second arcs of an OID.
+///
+/// This is represented this way in order to reduce the overall size of the
+/// [`ObjectIdentifier`] struct.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+struct RootArcs(u8);
+
+impl RootArcs {
+ /// Create [`RootArcs`] from the first and second arc values represented
+ /// as `Arc` integers.
+ pub(crate) const fn new(first_arc: Arc, second_arc: Arc) -> Result<Self> {
+ if first_arc > ARC_MAX_FIRST {
+ return Err(Error::ArcInvalid { arc: first_arc });
+ }
+
+ if second_arc > ARC_MAX_SECOND {
+ return Err(Error::ArcInvalid { arc: second_arc });
+ }
+
+ // The checks above ensure this operation will not overflow
+ #[allow(clippy::integer_arithmetic)]
+ let byte = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + second_arc as u8;
+
+ Ok(Self(byte))
+ }
+
+ /// Get the value of the first arc
+ #[allow(clippy::integer_arithmetic)]
+ pub(crate) const fn first_arc(self) -> Arc {
+ self.0 as Arc / (ARC_MAX_SECOND + 1)
+ }
+
+ /// Get the value of the second arc
+ #[allow(clippy::integer_arithmetic)]
+ pub(crate) const fn second_arc(self) -> Arc {
+ self.0 as Arc % (ARC_MAX_SECOND + 1)
+ }
+}
+
+impl TryFrom<u8> for RootArcs {
+ type Error = Error;
+
+ // Ensured not to overflow by constructor invariants
+ #[allow(clippy::integer_arithmetic)]
+ fn try_from(octet: u8) -> Result<Self> {
+ let first = octet as Arc / (ARC_MAX_SECOND + 1);
+ let second = octet as Arc % (ARC_MAX_SECOND + 1);
+ let result = Self::new(first, second)?;
+ debug_assert_eq!(octet, result.0);
+ Ok(result)
+ }
+}
+
+impl From<RootArcs> for u8 {
+ fn from(root_arcs: RootArcs) -> u8 {
+ root_arcs.0
+ }
+}