1 //! Arcs are integer values which exist within an OID's hierarchy.
2 
3 use crate::{Error, ObjectIdentifier, Result};
4 use core::mem;
5 
6 /// Type alias used to represent an "arc" (i.e. integer identifier value).
7 ///
8 /// X.660 does not define a maximum size of an arc.
9 ///
10 /// The current representation is `u32`, which has been selected as being
11 /// sufficient to cover the current PKCS/PKIX use cases this library has been
12 /// used in conjunction with.
13 ///
14 /// Future versions may potentially make it larger if a sufficiently important
15 /// use case is discovered.
16 pub type Arc = u32;
17 
18 /// Maximum value of the first arc in an OID.
19 pub(crate) const ARC_MAX_FIRST: Arc = 2;
20 
21 /// Maximum value of the second arc in an OID.
22 pub(crate) const ARC_MAX_SECOND: Arc = 39;
23 
24 /// Maximum number of bytes supported in an arc.
25 const ARC_MAX_BYTES: usize = mem::size_of::<Arc>();
26 
27 /// Maximum value of the last byte in an arc.
28 const ARC_MAX_LAST_OCTET: u8 = 0b11110000; // Max bytes of leading 1-bits
29 
30 /// [`Iterator`] over [`Arc`] values (a.k.a. nodes) in an [`ObjectIdentifier`].
31 ///
32 /// This iterates over all arcs in an OID, including the root.
33 pub struct Arcs<'a> {
34     /// OID we're iterating over
35     oid: &'a ObjectIdentifier,
36 
37     /// Current position within the serialized DER bytes of this OID
38     cursor: Option<usize>,
39 }
40 
41 impl<'a> Arcs<'a> {
42     /// Create a new iterator over the arcs of this OID
new(oid: &'a ObjectIdentifier) -> Self43     pub(crate) fn new(oid: &'a ObjectIdentifier) -> Self {
44         Self { oid, cursor: None }
45     }
46 
47     /// Try to parse the next arc in this OID.
48     ///
49     /// This method is fallible so it can be used as a first pass to determine
50     /// that the arcs in the OID are well-formed.
try_next(&mut self) -> Result<Option<Arc>>51     pub(crate) fn try_next(&mut self) -> Result<Option<Arc>> {
52         match self.cursor {
53             // Indicates we're on the root OID
54             None => {
55                 let root = RootArcs::try_from(self.oid.as_bytes()[0])?;
56                 self.cursor = Some(0);
57                 Ok(Some(root.first_arc()))
58             }
59             Some(0) => {
60                 let root = RootArcs::try_from(self.oid.as_bytes()[0])?;
61                 self.cursor = Some(1);
62                 Ok(Some(root.second_arc()))
63             }
64             Some(offset) => {
65                 let mut result = 0;
66                 let mut arc_bytes = 0;
67 
68                 loop {
69                     let len = checked_add!(offset, arc_bytes);
70 
71                     match self.oid.as_bytes().get(len).cloned() {
72                         // The arithmetic below includes advance checks
73                         // against `ARC_MAX_BYTES` and `ARC_MAX_LAST_OCTET`
74                         // which ensure the operations will not overflow.
75                         #[allow(clippy::integer_arithmetic)]
76                         Some(byte) => {
77                             arc_bytes = checked_add!(arc_bytes, 1);
78 
79                             if (arc_bytes > ARC_MAX_BYTES) && (byte & ARC_MAX_LAST_OCTET != 0) {
80                                 return Err(Error::ArcTooBig);
81                             }
82 
83                             result = result << 7 | (byte & 0b1111111) as Arc;
84 
85                             if byte & 0b10000000 == 0 {
86                                 self.cursor = Some(checked_add!(offset, arc_bytes));
87                                 return Ok(Some(result));
88                             }
89                         }
90                         None => {
91                             if arc_bytes == 0 {
92                                 return Ok(None);
93                             } else {
94                                 return Err(Error::Base128);
95                             }
96                         }
97                     }
98                 }
99             }
100         }
101     }
102 }
103 
104 impl<'a> Iterator for Arcs<'a> {
105     type Item = Arc;
106 
next(&mut self) -> Option<Arc>107     fn next(&mut self) -> Option<Arc> {
108         // ObjectIdentifier constructors should ensure the OID is well-formed
109         self.try_next().expect("OID malformed")
110     }
111 }
112 
113 /// Byte containing the first and second arcs of an OID.
114 ///
115 /// This is represented this way in order to reduce the overall size of the
116 /// [`ObjectIdentifier`] struct.
117 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
118 struct RootArcs(u8);
119 
120 impl RootArcs {
121     /// Create [`RootArcs`] from the first and second arc values represented
122     /// as `Arc` integers.
new(first_arc: Arc, second_arc: Arc) -> Result<Self>123     pub(crate) const fn new(first_arc: Arc, second_arc: Arc) -> Result<Self> {
124         if first_arc > ARC_MAX_FIRST {
125             return Err(Error::ArcInvalid { arc: first_arc });
126         }
127 
128         if second_arc > ARC_MAX_SECOND {
129             return Err(Error::ArcInvalid { arc: second_arc });
130         }
131 
132         // The checks above ensure this operation will not overflow
133         #[allow(clippy::integer_arithmetic)]
134         let byte = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + second_arc as u8;
135 
136         Ok(Self(byte))
137     }
138 
139     /// Get the value of the first arc
140     #[allow(clippy::integer_arithmetic)]
first_arc(self) -> Arc141     pub(crate) const fn first_arc(self) -> Arc {
142         self.0 as Arc / (ARC_MAX_SECOND + 1)
143     }
144 
145     /// Get the value of the second arc
146     #[allow(clippy::integer_arithmetic)]
second_arc(self) -> Arc147     pub(crate) const fn second_arc(self) -> Arc {
148         self.0 as Arc % (ARC_MAX_SECOND + 1)
149     }
150 }
151 
152 impl TryFrom<u8> for RootArcs {
153     type Error = Error;
154 
155     // Ensured not to overflow by constructor invariants
156     #[allow(clippy::integer_arithmetic)]
try_from(octet: u8) -> Result<Self>157     fn try_from(octet: u8) -> Result<Self> {
158         let first = octet as Arc / (ARC_MAX_SECOND + 1);
159         let second = octet as Arc % (ARC_MAX_SECOND + 1);
160         let result = Self::new(first, second)?;
161         debug_assert_eq!(octet, result.0);
162         Ok(result)
163     }
164 }
165 
166 impl From<RootArcs> for u8 {
from(root_arcs: RootArcs) -> u8167     fn from(root_arcs: RootArcs) -> u8 {
168         root_arcs.0
169     }
170 }
171