#[cfg(all(not(feature = "std"), feature = "serde"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use smallvec::SmallVec;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObjectIdentifier {
components: SmallVec<[u32; 10]>,
}
impl ObjectIdentifier {
pub fn new(components: &[u32]) -> crate::Result<Self> {
if components.len() < 2 {
return Err(crate::Error::InvalidOid { position: 0 });
}
if components[0] > 2 {
return Err(crate::Error::InvalidOid { position: 0 });
}
if components[0] < 2 && components[1] >= 40 {
return Err(crate::Error::InvalidOid { position: 0 });
}
Ok(Self {
components: SmallVec::from_slice(components),
})
}
pub fn components(&self) -> &[u32] {
&self.components
}
pub fn from_content_bytes(data: &[u8]) -> crate::Result<Self> {
if data.is_empty() {
return Err(crate::Error::InvalidOid { position: 0 });
}
let mut components: SmallVec<[u32; 10]> = SmallVec::new();
let mut i = 0;
let mut combined: u32 = 0;
loop {
if i >= data.len() {
return Err(crate::Error::InvalidOid { position: i });
}
let byte = data[i];
i += 1;
if combined > (u32::MAX >> 7) {
return Err(crate::Error::InvalidOid { position: i });
}
combined = (combined << 7) | ((byte & 0x7F) as u32);
if (byte & 0x80) == 0 {
break;
}
}
if combined < 40 {
components.push(0);
components.push(combined);
} else if combined < 80 {
components.push(1);
components.push(combined - 40);
} else {
components.push(2);
components.push(combined - 80);
}
while i < data.len() {
let mut value: u32 = 0;
loop {
if i >= data.len() {
return Err(crate::Error::InvalidOid { position: i });
}
let byte = data[i];
i += 1;
if value > (u32::MAX >> 7) {
return Err(crate::Error::InvalidOid { position: i });
}
value = (value << 7) | ((byte & 0x7F) as u32);
if (byte & 0x80) == 0 {
break;
}
}
components.push(value);
}
Ok(Self { components })
}
#[inline]
pub(crate) fn from_components_unchecked(components: SmallVec<[u32; 10]>) -> Self {
Self { components }
}
}
impl core::fmt::Display for ObjectIdentifier {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut iter = self.components.iter();
if let Some(first) = iter.next() {
write!(f, "{}", first)?;
for component in iter {
write!(f, ".{}", component)?;
}
}
Ok(())
}
}
#[cfg(feature = "std")]
impl core::str::FromStr for ObjectIdentifier {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut components: SmallVec<[u32; 10]> = SmallVec::new();
for part in s.split('.') {
let v: u32 = part
.parse()
.map_err(|_| crate::Error::InvalidOid { position: 0 })?;
components.push(v);
}
if components.len() < 2 {
return Err(crate::Error::InvalidOid { position: 0 });
}
if components[0] > 2 {
return Err(crate::Error::InvalidOid { position: 0 });
}
if components[0] < 2 && components[1] >= 40 {
return Err(crate::Error::InvalidOid { position: 0 });
}
Ok(Self { components })
}
}
impl crate::traits::Decode<'_> for ObjectIdentifier {
fn decode(decoder: &mut crate::der::decoder::Decoder) -> crate::Result<Self> {
use crate::tag::TAG_OBJECT_IDENTIFIER;
let tag = decoder.read_tag()?;
let expected_tag = crate::Tag::universal(TAG_OBJECT_IDENTIFIER);
if tag != expected_tag {
return Err(crate::Error::UnexpectedTag {
position: decoder.position(),
expected: expected_tag,
actual: tag,
});
}
let length = decoder.read_length()?;
let len = length.definite()?;
if len == 0 {
return Err(crate::Error::InvalidOid {
position: decoder.position(),
});
}
let bytes = decoder.read_bytes(len)?;
ObjectIdentifier::from_content_bytes(bytes).map_err(|_| crate::Error::InvalidOid {
position: decoder.position(),
})
}
}
impl crate::traits::Encode for ObjectIdentifier {
fn encode(&self, encoder: &mut crate::der::encoder::Encoder) -> crate::Result<()> {
use crate::tag::TAG_OBJECT_IDENTIFIER;
if self.components.len() < 2 {
return Err(crate::Error::InvalidOid { position: 0 });
}
let tag = crate::Tag::universal(TAG_OBJECT_IDENTIFIER);
encoder.write_tag(tag)?;
let mut content = Vec::new();
let first = self.components[0];
let second = self.components[1];
let combined = first * 40 + second;
encode_base128(combined, &mut content);
for &component in &self.components[2..] {
encode_base128(component, &mut content);
}
encoder.write_length(content.len())?;
encoder.write_bytes(&content);
Ok(())
}
fn encoded_len(&self) -> crate::Result<usize> {
if self.components.len() < 2 {
return Err(crate::Error::InvalidOid { position: 0 });
}
let tag_len = 1;
let first = self.components[0];
let second = self.components[1];
let combined = first * 40 + second;
let mut content_len = base128_len(combined);
for &component in &self.components[2..] {
content_len += base128_len(component);
}
let length_len = crate::Length::Definite(content_len).encoded_len()?;
Ok(tag_len + length_len + content_len)
}
}
impl crate::traits::Tagged for ObjectIdentifier {
fn tag() -> crate::Tag {
crate::Tag::universal(crate::tag::TAG_OBJECT_IDENTIFIER)
}
}
fn encode_base128(mut value: u32, buffer: &mut Vec<u8>) {
if value == 0 {
buffer.push(0);
return;
}
let mut bytes = Vec::new();
while value > 0 {
bytes.push((value & 0x7F) as u8);
value >>= 7;
}
for (i, &byte) in bytes.iter().rev().enumerate() {
if i < bytes.len() - 1 {
buffer.push(byte | 0x80);
} else {
buffer.push(byte);
}
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for ObjectIdentifier {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use core::fmt::Write;
let mut buf = String::new();
for (i, &component) in self.components().iter().enumerate() {
if i > 0 {
buf.push('.');
}
let _ = write!(buf, "{}", component);
}
s.serialize_str(&buf)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for ObjectIdentifier {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
struct OidVisitor;
impl<'de> serde::de::Visitor<'de> for OidVisitor {
type Value = ObjectIdentifier;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "an OID in dotted-decimal notation (e.g. \"1.2.840\")")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<ObjectIdentifier, E> {
let components: Result<Vec<u32>, _> =
v.split('.').map(|p| p.parse::<u32>()).collect();
let components = components.map_err(|_| E::custom("invalid OID component"))?;
ObjectIdentifier::new(&components).map_err(|_| E::custom("invalid OID"))
}
}
d.deserialize_str(OidVisitor)
}
}
fn base128_len(value: u32) -> usize {
if value == 0 {
return 1;
}
let mut len = 0;
let mut v = value;
while v > 0 {
len += 1;
v >>= 7;
}
len
}