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