/rust/registry/src/index.crates.io-1949cf8c6b5b557f/const-oid-0.9.6/src/arcs.rs
Line | Count | Source |
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 |
43 | 0 | pub(crate) fn new(oid: &'a ObjectIdentifier) -> Self { |
44 | 0 | Self { oid, cursor: None } |
45 | 0 | } |
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. |
51 | 0 | pub(crate) fn try_next(&mut self) -> Result<Option<Arc>> { |
52 | 0 | match self.cursor { |
53 | | // Indicates we're on the root OID |
54 | | None => { |
55 | 0 | let root = RootArcs::try_from(self.oid.as_bytes()[0])?; |
56 | 0 | self.cursor = Some(0); |
57 | 0 | Ok(Some(root.first_arc())) |
58 | | } |
59 | | Some(0) => { |
60 | 0 | let root = RootArcs::try_from(self.oid.as_bytes()[0])?; |
61 | 0 | self.cursor = Some(1); |
62 | 0 | Ok(Some(root.second_arc())) |
63 | | } |
64 | 0 | Some(offset) => { |
65 | 0 | let mut result = 0; |
66 | 0 | let mut arc_bytes = 0; |
67 | | |
68 | | loop { |
69 | 0 | let len = checked_add!(offset, arc_bytes); |
70 | | |
71 | 0 | 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 | 0 | Some(byte) => { |
77 | 0 | arc_bytes = checked_add!(arc_bytes, 1); |
78 | | |
79 | 0 | if (arc_bytes > ARC_MAX_BYTES) && (byte & ARC_MAX_LAST_OCTET != 0) { |
80 | 0 | return Err(Error::ArcTooBig); |
81 | 0 | } |
82 | | |
83 | 0 | result = result << 7 | (byte & 0b1111111) as Arc; |
84 | | |
85 | 0 | if byte & 0b10000000 == 0 { |
86 | 0 | self.cursor = Some(checked_add!(offset, arc_bytes)); |
87 | 0 | return Ok(Some(result)); |
88 | 0 | } |
89 | | } |
90 | | None => { |
91 | 0 | if arc_bytes == 0 { |
92 | 0 | return Ok(None); |
93 | | } else { |
94 | 0 | return Err(Error::Base128); |
95 | | } |
96 | | } |
97 | | } |
98 | | } |
99 | | } |
100 | | } |
101 | 0 | } |
102 | | } |
103 | | |
104 | | impl<'a> Iterator for Arcs<'a> { |
105 | | type Item = Arc; |
106 | | |
107 | 0 | fn next(&mut self) -> Option<Arc> { |
108 | | // ObjectIdentifier constructors should ensure the OID is well-formed |
109 | 0 | self.try_next().expect("OID malformed") |
110 | 0 | } |
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. |
123 | 0 | pub(crate) const fn new(first_arc: Arc, second_arc: Arc) -> Result<Self> { |
124 | 0 | if first_arc > ARC_MAX_FIRST { |
125 | 0 | return Err(Error::ArcInvalid { arc: first_arc }); |
126 | 0 | } |
127 | | |
128 | 0 | if second_arc > ARC_MAX_SECOND { |
129 | 0 | return Err(Error::ArcInvalid { arc: second_arc }); |
130 | 0 | } |
131 | | |
132 | | // The checks above ensure this operation will not overflow |
133 | | #[allow(clippy::integer_arithmetic)] |
134 | 0 | let byte = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + second_arc as u8; |
135 | | |
136 | 0 | Ok(Self(byte)) |
137 | 0 | } |
138 | | |
139 | | /// Get the value of the first arc |
140 | | #[allow(clippy::integer_arithmetic)] |
141 | 0 | pub(crate) const fn first_arc(self) -> Arc { |
142 | 0 | self.0 as Arc / (ARC_MAX_SECOND + 1) |
143 | 0 | } |
144 | | |
145 | | /// Get the value of the second arc |
146 | | #[allow(clippy::integer_arithmetic)] |
147 | 0 | pub(crate) const fn second_arc(self) -> Arc { |
148 | 0 | self.0 as Arc % (ARC_MAX_SECOND + 1) |
149 | 0 | } |
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)] |
157 | 0 | fn try_from(octet: u8) -> Result<Self> { |
158 | 0 | let first = octet as Arc / (ARC_MAX_SECOND + 1); |
159 | 0 | let second = octet as Arc % (ARC_MAX_SECOND + 1); |
160 | 0 | let result = Self::new(first, second)?; |
161 | 0 | debug_assert_eq!(octet, result.0); |
162 | 0 | Ok(result) |
163 | 0 | } |
164 | | } |
165 | | |
166 | | impl From<RootArcs> for u8 { |
167 | 0 | fn from(root_arcs: RootArcs) -> u8 { |
168 | 0 | root_arcs.0 |
169 | 0 | } |
170 | | } |