summaryrefslogtreecommitdiffstats
path: root/rust/vendor/der-parser/src/ber/ber.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
commita0aa2307322cd47bbf416810ac0292925e03be87 (patch)
tree37076262a026c4b48c8a0e84f44ff9187556ca35 /rust/vendor/der-parser/src/ber/ber.rs
parentInitial commit. (diff)
downloadsuricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz
suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'rust/vendor/der-parser/src/ber/ber.rs')
-rw-r--r--rust/vendor/der-parser/src/ber/ber.rs950
1 files changed, 950 insertions, 0 deletions
diff --git a/rust/vendor/der-parser/src/ber/ber.rs b/rust/vendor/der-parser/src/ber/ber.rs
new file mode 100644
index 0000000..3063ff2
--- /dev/null
+++ b/rust/vendor/der-parser/src/ber/ber.rs
@@ -0,0 +1,950 @@
+use super::{Class, Header, Length, Tag};
+use crate::ber::bitstring_to_u64;
+use crate::ber::integer::*;
+use crate::error::BerError;
+use crate::oid::Oid;
+use alloc::borrow::ToOwned;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use asn1_rs::ASN1DateTime;
+use asn1_rs::Any;
+#[cfg(feature = "bitvec")]
+use bitvec::{order::Msb0, slice::BitSlice};
+use core::convert::AsRef;
+use core::convert::From;
+use core::ops::Index;
+
+/// Representation of a BER-encoded (X.690) object
+///
+/// A BER object is composed of a header describing the object class, type and length,
+/// and the content.
+///
+/// Note that the content may sometimes not match the header tag (for ex when parsing IMPLICIT
+/// tagged values).
+#[derive(Debug, Clone, PartialEq)]
+pub struct BerObject<'a> {
+ pub header: Header<'a>,
+ pub content: BerObjectContent<'a>,
+}
+
+/// BER object content
+#[derive(Debug, Clone, PartialEq)]
+#[allow(clippy::upper_case_acronyms)]
+pub enum BerObjectContent<'a> {
+ /// EOC (no content)
+ EndOfContent,
+ /// BOOLEAN: decoded value
+ Boolean(bool),
+ /// INTEGER: raw bytes
+ ///
+ /// Note: the reason to store the raw bytes is that integers have non-finite length in the
+ /// spec, and also that the raw encoding is also important for some applications.
+ ///
+ /// To extract the number, see the `as_u64`, `as_u32`, `as_bigint` and `as_biguint` methods.
+ Integer(&'a [u8]),
+ /// BIT STRING: number of unused bits, and object
+ BitString(u8, BitStringObject<'a>),
+ /// OCTET STRING: slice
+ OctetString(&'a [u8]),
+ /// NULL (no content)
+ Null,
+ /// ENUMERATED: decoded enum number
+ Enum(u64),
+ /// OID
+ OID(Oid<'a>),
+ /// RELATIVE OID
+ RelativeOID(Oid<'a>),
+ /// NumericString: decoded string
+ NumericString(&'a str),
+ /// VisibleString: decoded string
+ VisibleString(&'a str),
+ /// PrintableString: decoded string
+ PrintableString(&'a str),
+ /// IA5String: decoded string
+ IA5String(&'a str),
+ /// UTF8String: decoded string
+ UTF8String(&'a str),
+ /// T61String: decoded string
+ T61String(&'a str),
+ /// VideotexString: decoded string
+ VideotexString(&'a str),
+
+ /// BmpString: decoded string
+ BmpString(&'a str),
+ /// UniversalString: raw object bytes
+ UniversalString(&'a [u8]),
+
+ /// SEQUENCE: list of objects
+ Sequence(Vec<BerObject<'a>>),
+ /// SET: list of objects
+ Set(Vec<BerObject<'a>>),
+
+ /// UTCTime: decoded string
+ UTCTime(ASN1DateTime),
+ /// GeneralizedTime: decoded string
+ GeneralizedTime(ASN1DateTime),
+
+ /// Object descriptor: decoded string
+ ObjectDescriptor(&'a str),
+ /// GraphicString: decoded string
+ GraphicString(&'a str),
+ /// GeneralString: decoded string
+ GeneralString(&'a str),
+
+ /// Optional object
+ Optional(Option<Box<BerObject<'a>>>),
+ /// Tagged object (EXPLICIT): class, tag and content of inner object
+ Tagged(Class, Tag, Box<BerObject<'a>>),
+
+ /// Private or Unknown (for ex. unknown tag) object
+ Unknown(Any<'a>),
+}
+
+impl<'a> BerObject<'a> {
+ /// Build a BerObject from a header and content.
+ ///
+ /// Note: values are not checked, so the tag can be different from the real content, or flags
+ /// can be invalid.
+ #[inline]
+ pub const fn from_header_and_content<'o>(
+ header: Header<'o>,
+ content: BerObjectContent<'o>,
+ ) -> BerObject<'o> {
+ BerObject { header, content }
+ }
+
+ /// Build a BerObject from its content, using default flags (no class, correct tag,
+ /// and constructed flag set only for Set and Sequence)
+ pub const fn from_obj(c: BerObjectContent) -> BerObject {
+ let class = Class::Universal;
+ let tag = c.tag();
+ let constructed = matches!(tag, Tag::Sequence | Tag::Set);
+ let header = Header::new(class, constructed, tag, Length::Definite(0));
+ BerObject { header, content: c }
+ }
+
+ /// Build a DER integer object from a slice containing an encoded integer
+ pub const fn from_int_slice(i: &'a [u8]) -> BerObject<'a> {
+ let header = Header::new(Class::Universal, false, Tag::Integer, Length::Definite(0));
+ BerObject {
+ header,
+ content: BerObjectContent::Integer(i),
+ }
+ }
+
+ /// Set a tag for the BER object
+ pub fn set_raw_tag(self, raw_tag: Option<&'a [u8]>) -> BerObject {
+ let header = self.header.with_raw_tag(raw_tag.map(|x| x.into()));
+ BerObject { header, ..self }
+ }
+
+ /// Build a DER sequence object from a vector of DER objects
+ pub const fn from_seq(l: Vec<BerObject>) -> BerObject {
+ BerObject::from_obj(BerObjectContent::Sequence(l))
+ }
+
+ /// Build a DER set object from a vector of DER objects
+ pub const fn from_set(l: Vec<BerObject>) -> BerObject {
+ BerObject::from_obj(BerObjectContent::Set(l))
+ }
+
+ /// Attempt to read a signed integer value from DER object.
+ ///
+ /// This can fail if the object is not an integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use der_parser::ber::BerObject;
+ /// let der_int = BerObject::from_int_slice(b"\x80");
+ /// assert_eq!(
+ /// der_int.as_i64(),
+ /// Ok(-128)
+ /// );
+ /// ```
+ pub fn as_i64(&self) -> Result<i64, BerError> {
+ self.content.as_i64()
+ }
+
+ /// Attempt to read a signed integer value from DER object.
+ ///
+ /// This can fail if the object is not an integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use der_parser::ber::BerObject;
+ /// let der_int = BerObject::from_int_slice(b"\x80");
+ /// assert_eq!(
+ /// der_int.as_i32(),
+ /// Ok(-128)
+ /// );
+ /// ```
+ pub fn as_i32(&self) -> Result<i32, BerError> {
+ self.content.as_i32()
+ }
+
+ /// Attempt to read integer value from DER object.
+ ///
+ /// This can fail if the object is not an unsigned integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use der_parser::ber::BerObject;
+ /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01");
+ /// assert_eq!(
+ /// der_int.as_u64(),
+ /// Ok(0x10001)
+ /// );
+ /// ```
+ pub fn as_u64(&self) -> Result<u64, BerError> {
+ self.content.as_u64()
+ }
+
+ /// Attempt to read integer value from DER object.
+ ///
+ /// This can fail if the object is not an unsigned integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate der_parser;
+ /// # use der_parser::ber::{BerObject,BerObjectContent};
+ /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01"));
+ /// assert_eq!(
+ /// der_int.as_u32(),
+ /// Ok(0x10001)
+ /// );
+ /// ```
+ pub fn as_u32(&self) -> Result<u32, BerError> {
+ self.content.as_u32()
+ }
+
+ /// Attempt to read integer value from DER object.
+ /// This can fail if the object is not a boolean.
+ pub fn as_bool(&self) -> Result<bool, BerError> {
+ self.content.as_bool()
+ }
+
+ /// Attempt to read an OID value from DER object.
+ /// This can fail if the object is not an OID.
+ pub fn as_oid(&self) -> Result<&Oid<'a>, BerError> {
+ self.content.as_oid()
+ }
+
+ /// Attempt to read an OID value from DER object.
+ /// This can fail if the object is not an OID.
+ pub fn as_oid_val(&self) -> Result<Oid<'a>, BerError> {
+ self.content.as_oid_val()
+ }
+
+ /// Attempt to get a reference on the content from an optional object.
+ /// This can fail if the object is not optional.
+ pub fn as_optional(&self) -> Result<Option<&BerObject<'a>>, BerError> {
+ self.content.as_optional()
+ }
+
+ /// Attempt to get a reference on the content from a tagged object.
+ /// This can fail if the object is not tagged.
+ pub fn as_tagged(&self) -> Result<(Class, Tag, &BerObject<'a>), BerError> {
+ self.content.as_tagged()
+ }
+
+ /// Attempt to read a reference to a BitString value from DER object.
+ /// This can fail if the object is not an BitString.
+ ///
+ /// Note that this function returns a reference to the BitString. To get an owned value,
+ /// use [`as_bitstring`](struct.BerObject.html#method.as_bitstring)
+ pub fn as_bitstring_ref(&self) -> Result<&BitStringObject, BerError> {
+ self.content.as_bitstring_ref()
+ }
+
+ /// Attempt to read a BitString value from DER object.
+ /// This can fail if the object is not an BitString.
+ pub fn as_bitstring(&self) -> Result<BitStringObject<'a>, BerError> {
+ self.content.as_bitstring()
+ }
+
+ /// Constructs a shared `&BitSlice` reference over the object data, if available as slice.
+ #[cfg(feature = "bitvec")]
+ pub fn as_bitslice(&self) -> Result<&BitSlice<Msb0, u8>, BerError> {
+ self.content.as_bitslice()
+ }
+
+ /// Attempt to extract the list of objects from a DER sequence.
+ /// This can fail if the object is not a sequence.
+ pub fn as_sequence(&self) -> Result<&Vec<BerObject<'a>>, BerError> {
+ self.content.as_sequence()
+ }
+
+ /// Attempt to extract the list of objects from a DER set.
+ /// This can fail if the object is not a set.
+ pub fn as_set(&self) -> Result<&Vec<BerObject<'a>>, BerError> {
+ self.content.as_set()
+ }
+
+ /// Attempt to get the content from a DER object, as a slice.
+ /// This can fail if the object does not contain a type directly equivalent to a slice (e.g a
+ /// sequence).
+ /// This function mostly concerns string types, integers, or unknown DER objects.
+ pub fn as_slice(&self) -> Result<&'a [u8], BerError> {
+ self.content.as_slice()
+ }
+
+ /// Attempt to get the content from a DER object, as a str.
+ /// This can fail if the object does not contain a string type.
+ ///
+ /// Only some string types are considered here. Other
+ /// string types can be read using `as_slice`.
+ pub fn as_str(&self) -> Result<&'a str, BerError> {
+ self.content.as_str()
+ }
+
+ /// Get the BER object header's class.
+ #[inline]
+ pub const fn class(&self) -> Class {
+ self.header.class()
+ }
+
+ /// Get the BER object header's tag.
+ #[inline]
+ pub const fn tag(&self) -> Tag {
+ self.header.tag()
+ }
+
+ /// Get the BER object header's length.
+ #[inline]
+ pub const fn length(&self) -> Length {
+ self.header.length()
+ }
+
+ /// Test if object class is Universal
+ #[inline]
+ pub const fn is_universal(&self) -> bool {
+ self.header.is_universal()
+ }
+ /// Test if object class is Application
+ #[inline]
+ pub const fn is_application(&self) -> bool {
+ self.header.is_application()
+ }
+ /// Test if object class is Context-specific
+ #[inline]
+ pub const fn is_contextspecific(&self) -> bool {
+ self.header.is_contextspecific()
+ }
+ /// Test if object class is Private
+ #[inline]
+ pub fn is_private(&self) -> bool {
+ self.header.is_private()
+ }
+
+ /// Test if object is primitive
+ #[inline]
+ pub const fn is_primitive(&self) -> bool {
+ self.header.is_primitive()
+ }
+ /// Test if object is constructed
+ #[inline]
+ pub const fn is_constructed(&self) -> bool {
+ self.header.is_constructed()
+ }
+
+ /// Return error if `class` is not the expected class
+ #[inline]
+ pub const fn assert_class(&self, class: Class) -> Result<(), BerError> {
+ self.header.assert_class(class)
+ }
+
+ /// Return error if `tag` is not the expected tag
+ #[inline]
+ pub const fn assert_tag(&self, tag: Tag) -> Result<(), BerError> {
+ self.header.assert_tag(tag)
+ }
+
+ /// Return error if object is not constructed
+ #[inline]
+ pub const fn assert_constructed(&self) -> Result<(), BerError> {
+ self.header.assert_constructed()
+ }
+
+ /// Return error if object is not primitive
+ #[inline]
+ pub const fn assert_primitive(&self) -> Result<(), BerError> {
+ self.header.assert_primitive()
+ }
+}
+
+/// Build a DER object from an OID.
+impl<'a> From<Oid<'a>> for BerObject<'a> {
+ fn from(oid: Oid<'a>) -> BerObject<'a> {
+ BerObject::from_obj(BerObjectContent::OID(oid))
+ }
+}
+
+/// Build a DER object from a BerObjectContent.
+impl<'a> From<BerObjectContent<'a>> for BerObject<'a> {
+ fn from(obj: BerObjectContent<'a>) -> BerObject<'a> {
+ BerObject::from_obj(obj)
+ }
+}
+
+impl<'a> BerObjectContent<'a> {
+ /// Attempt to read a signed integer value from this object.
+ ///
+ /// This can fail if the object is not an integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use der_parser::ber::BerObject;
+ /// let der_int = BerObject::from_int_slice(b"\x80");
+ /// assert_eq!(
+ /// der_int.as_i64(),
+ /// Ok(-128)
+ /// );
+ /// ```
+ pub fn as_i64(&self) -> Result<i64, BerError> {
+ if let BerObjectContent::Integer(bytes) = self {
+ let result = if is_highest_bit_set(bytes) {
+ <i64>::from_be_bytes(decode_array_int8(bytes)?)
+ } else {
+ <u64>::from_be_bytes(decode_array_uint8(bytes)?) as i64
+ };
+ Ok(result)
+ } else {
+ Err(BerError::BerValueError)
+ }
+ }
+
+ /// Attempt to read a signed integer value from this object.
+ ///
+ /// This can fail if the object is not an integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use der_parser::ber::BerObject;
+ /// let der_int = BerObject::from_int_slice(b"\x80");
+ /// assert_eq!(
+ /// der_int.as_i32(),
+ /// Ok(-128)
+ /// );
+ /// ```
+ pub fn as_i32(&self) -> Result<i32, BerError> {
+ if let BerObjectContent::Integer(bytes) = self {
+ let result = if is_highest_bit_set(bytes) {
+ <i32>::from_be_bytes(decode_array_int4(bytes)?)
+ } else {
+ <u32>::from_be_bytes(decode_array_uint4(bytes)?) as i32
+ };
+ Ok(result)
+ } else {
+ Err(BerError::BerValueError)
+ }
+ }
+
+ /// Attempt to read integer value from this object.
+ ///
+ /// This can fail if the object is not an unsigned integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use der_parser::ber::BerObject;
+ /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01");
+ /// assert_eq!(
+ /// der_int.as_u64(),
+ /// Ok(0x10001)
+ /// );
+ /// ```
+ pub fn as_u64(&self) -> Result<u64, BerError> {
+ match self {
+ BerObjectContent::Integer(i) => {
+ let result = <u64>::from_be_bytes(decode_array_uint8(i)?);
+ Ok(result)
+ }
+ BerObjectContent::BitString(ignored_bits, data) => {
+ bitstring_to_u64(*ignored_bits as usize, data)
+ }
+ BerObjectContent::Enum(i) => Ok(*i),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ /// Attempt to read integer value from this object.
+ ///
+ /// This can fail if the object is not an unsigned integer, or if it is too large.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # extern crate der_parser;
+ /// # use der_parser::ber::{BerObject,BerObjectContent};
+ /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01"));
+ /// assert_eq!(
+ /// der_int.as_u32(),
+ /// Ok(0x10001)
+ /// );
+ /// ```
+ pub fn as_u32(&self) -> Result<u32, BerError> {
+ match self {
+ BerObjectContent::Integer(i) => {
+ let result = <u32>::from_be_bytes(decode_array_uint4(i)?);
+ Ok(result)
+ }
+ BerObjectContent::BitString(ignored_bits, data) => {
+ bitstring_to_u64(*ignored_bits as usize, data).and_then(|x| {
+ if x > u64::from(core::u32::MAX) {
+ Err(BerError::IntegerTooLarge)
+ } else {
+ Ok(x as u32)
+ }
+ })
+ }
+ BerObjectContent::Enum(i) => {
+ if *i > u64::from(core::u32::MAX) {
+ Err(BerError::IntegerTooLarge)
+ } else {
+ Ok(*i as u32)
+ }
+ }
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_bool(&self) -> Result<bool, BerError> {
+ match *self {
+ BerObjectContent::Boolean(b) => Ok(b),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_oid(&self) -> Result<&Oid<'a>, BerError> {
+ match *self {
+ BerObjectContent::OID(ref o) => Ok(o),
+ BerObjectContent::RelativeOID(ref o) => Ok(o),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_oid_val(&self) -> Result<Oid<'a>, BerError> {
+ self.as_oid().map(|o| o.clone())
+ }
+
+ pub fn as_optional(&self) -> Result<Option<&BerObject<'a>>, BerError> {
+ match *self {
+ BerObjectContent::Optional(Some(ref o)) => Ok(Some(o)),
+ BerObjectContent::Optional(None) => Ok(None),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_tagged(&self) -> Result<(Class, Tag, &BerObject<'a>), BerError> {
+ match *self {
+ BerObjectContent::Tagged(class, tag, ref o) => Ok((class, tag, o.as_ref())),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_bitstring_ref(&self) -> Result<&BitStringObject, BerError> {
+ match *self {
+ BerObjectContent::BitString(_, ref b) => Ok(b),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_bitstring(&self) -> Result<BitStringObject<'a>, BerError> {
+ match *self {
+ BerObjectContent::BitString(_, ref b) => Ok(b.to_owned()),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ /// Constructs a shared `&BitSlice` reference over the object data, if available as slice.
+ #[cfg(feature = "bitvec")]
+ pub fn as_bitslice(&self) -> Result<&BitSlice<Msb0, u8>, BerError> {
+ self.as_slice()
+ .and_then(|s| BitSlice::<Msb0, _>::from_slice(s).map_err(|_| BerError::BerValueError))
+ }
+
+ pub fn as_sequence(&self) -> Result<&Vec<BerObject<'a>>, BerError> {
+ match *self {
+ BerObjectContent::Sequence(ref s) => Ok(s),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ pub fn as_set(&self) -> Result<&Vec<BerObject<'a>>, BerError> {
+ match *self {
+ BerObjectContent::Set(ref s) => Ok(s),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ #[rustfmt::skip]
+ pub fn as_slice(&self) -> Result<&'a [u8],BerError> {
+ match *self {
+ BerObjectContent::NumericString(s) |
+ BerObjectContent::BmpString(s) |
+ BerObjectContent::VisibleString(s) |
+ BerObjectContent::PrintableString(s) |
+ BerObjectContent::GeneralString(s) |
+ BerObjectContent::ObjectDescriptor(s) |
+ BerObjectContent::GraphicString(s) |
+ BerObjectContent::T61String(s) |
+ BerObjectContent::VideotexString(s) |
+ BerObjectContent::UTF8String(s) |
+ BerObjectContent::IA5String(s) => Ok(s.as_ref()),
+ BerObjectContent::Integer(s) |
+ BerObjectContent::BitString(_,BitStringObject{data:s}) |
+ BerObjectContent::OctetString(s) |
+ BerObjectContent::UniversalString(s) => Ok(s),
+ BerObjectContent::Unknown(ref any) => Ok(any.data),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ #[rustfmt::skip]
+ pub fn as_str(&self) -> Result<&'a str,BerError> {
+ match *self {
+ BerObjectContent::NumericString(s) |
+ BerObjectContent::BmpString(s) |
+ BerObjectContent::VisibleString(s) |
+ BerObjectContent::PrintableString(s) |
+ BerObjectContent::GeneralString(s) |
+ BerObjectContent::ObjectDescriptor(s) |
+ BerObjectContent::GraphicString(s) |
+ BerObjectContent::T61String(s) |
+ BerObjectContent::VideotexString(s) |
+ BerObjectContent::UTF8String(s) |
+ BerObjectContent::IA5String(s) => Ok(s),
+ _ => Err(BerError::BerTypeError),
+ }
+ }
+
+ #[rustfmt::skip]
+ const fn tag(&self) -> Tag {
+ match self {
+ BerObjectContent::EndOfContent => Tag::EndOfContent,
+ BerObjectContent::Boolean(_) => Tag::Boolean,
+ BerObjectContent::Integer(_) => Tag::Integer,
+ BerObjectContent::BitString(_,_) => Tag::BitString,
+ BerObjectContent::OctetString(_) => Tag::OctetString,
+ BerObjectContent::Null => Tag::Null,
+ BerObjectContent::Enum(_) => Tag::Enumerated,
+ BerObjectContent::OID(_) => Tag::Oid,
+ BerObjectContent::NumericString(_) => Tag::NumericString,
+ BerObjectContent::VisibleString(_) => Tag::VisibleString,
+ BerObjectContent::PrintableString(_) => Tag::PrintableString,
+ BerObjectContent::IA5String(_) => Tag::Ia5String,
+ BerObjectContent::UTF8String(_) => Tag::Utf8String,
+ BerObjectContent::RelativeOID(_) => Tag::RelativeOid,
+ BerObjectContent::T61String(_) => Tag::T61String,
+ BerObjectContent::VideotexString(_) => Tag::VideotexString,
+ BerObjectContent::BmpString(_) => Tag::BmpString,
+ BerObjectContent::UniversalString(_) => Tag::UniversalString,
+ BerObjectContent::Sequence(_) => Tag::Sequence,
+ BerObjectContent::Set(_) => Tag::Set,
+ BerObjectContent::UTCTime(_) => Tag::UtcTime,
+ BerObjectContent::GeneralizedTime(_) => Tag::GeneralizedTime,
+ BerObjectContent::ObjectDescriptor(_) => Tag::ObjectDescriptor,
+ BerObjectContent::GraphicString(_) => Tag::GraphicString,
+ BerObjectContent::GeneralString(_) => Tag::GeneralString,
+ BerObjectContent::Tagged(_,x,_) => *x,
+ BerObjectContent::Unknown(any) => any.tag(),
+ BerObjectContent::Optional(Some(obj)) => obj.content.tag(),
+ BerObjectContent::Optional(None) => Tag(0x00), // XXX invalid !
+ }
+ }
+}
+
+#[cfg(feature = "bigint")]
+#[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
+use num_bigint::{BigInt, BigUint};
+
+#[cfg(feature = "bigint")]
+#[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
+impl<'a> BerObject<'a> {
+ /// Attempt to read an integer value from this object.
+ ///
+ /// This can fail if the object is not an integer.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use der_parser::ber::*;
+ ///
+ /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01];
+ ///
+ /// let (_, object) = parse_ber_integer(data).expect("parsing failed");
+ /// # #[cfg(feature = "bigint")]
+ /// assert_eq!(object.as_bigint(), Ok(65537.into()))
+ /// ```
+ pub fn as_bigint(&self) -> Result<BigInt, BerError> {
+ match self.content {
+ BerObjectContent::Integer(s) => Ok(BigInt::from_signed_bytes_be(s)),
+ _ => Err(BerError::BerValueError),
+ }
+ }
+
+ /// Attempt to read a positive integer value from this object.
+ ///
+ /// This can fail if the object is not an integer, or is negative.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use der_parser::ber::*;
+ ///
+ /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01];
+ ///
+ /// let (_, object) = parse_ber_integer(data).expect("parsing failed");
+ /// # #[cfg(feature = "bigint")]
+ /// assert_eq!(object.as_biguint(), Ok(65537_u32.into()))
+ /// ```
+ pub fn as_biguint(&self) -> Result<BigUint, BerError> {
+ match self.content {
+ BerObjectContent::Integer(s) => {
+ if is_highest_bit_set(s) {
+ return Err(BerError::IntegerNegative);
+ }
+ Ok(BigUint::from_bytes_be(s))
+ }
+ _ => Err(BerError::BerValueError),
+ }
+ }
+}
+
+// This is a consuming iterator
+impl<'a> IntoIterator for BerObject<'a> {
+ type Item = BerObject<'a>;
+ type IntoIter = BerObjectIntoIterator<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ // match self {
+ // BerObjectContent::Sequence(ref v) => (),
+ // _ => (),
+ // };
+ BerObjectIntoIterator { val: self, idx: 0 }
+ }
+}
+
+#[derive(Debug)]
+pub struct BerObjectIntoIterator<'a> {
+ val: BerObject<'a>,
+ idx: usize,
+}
+
+impl<'a> Iterator for BerObjectIntoIterator<'a> {
+ type Item = BerObject<'a>;
+ fn next(&mut self) -> Option<BerObject<'a>> {
+ // let result = if self.idx < self.vec.len() {
+ // Some(self.vec[self.idx].clone())
+ // } else {
+ // None
+ // };
+ let res = match self.val.content {
+ BerObjectContent::Sequence(ref v) if self.idx < v.len() => Some(v[self.idx].clone()),
+ BerObjectContent::Set(ref v) if self.idx < v.len() => Some(v[self.idx].clone()),
+ _ => {
+ if self.idx == 0 {
+ Some(self.val.clone())
+ } else {
+ None
+ }
+ }
+ };
+ self.idx += 1;
+ res
+ }
+}
+
+// impl<'a> Iterator for BerObjectContent<'a> {
+// type Item = BerObjectContent<'a>;
+//
+// fn next(&mut self) -> Option<BerObjectContent<'a>> {
+// None
+// }
+// }
+
+#[derive(Debug)]
+pub struct BerObjectRefIterator<'a> {
+ obj: &'a BerObject<'a>,
+ idx: usize,
+}
+
+impl<'a> Iterator for BerObjectRefIterator<'a> {
+ type Item = &'a BerObject<'a>;
+ fn next(&mut self) -> Option<&'a BerObject<'a>> {
+ let res = match (self.obj).content {
+ BerObjectContent::Sequence(ref v) if self.idx < v.len() => Some(&v[self.idx]),
+ BerObjectContent::Set(ref v) if self.idx < v.len() => Some(&v[self.idx]),
+ _ => None,
+ };
+ self.idx += 1;
+ res
+ }
+}
+
+impl<'a> BerObject<'a> {
+ pub fn ref_iter(&'a self) -> BerObjectRefIterator<'a> {
+ BerObjectRefIterator { obj: self, idx: 0 }
+ }
+}
+
+impl<'a> Index<usize> for BerObject<'a> {
+ type Output = BerObject<'a>;
+
+ fn index(&self, idx: usize) -> &BerObject<'a> {
+ match (self).content {
+ BerObjectContent::Sequence(ref v) if idx < v.len() => &v[idx],
+ BerObjectContent::Set(ref v) if idx < v.len() => &v[idx],
+ _ => panic!("Try to index BerObjectContent which is not constructed"),
+ }
+ // XXX the following
+ // self.ref_iter().nth(idx).unwrap()
+ // fails with:
+ // error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495]
+ // self.ref_iter().nth(idx).unwrap()
+ }
+}
+
+/// BitString wrapper
+#[derive(Clone, Debug, PartialEq)]
+pub struct BitStringObject<'a> {
+ pub data: &'a [u8],
+}
+
+impl<'a> BitStringObject<'a> {
+ /// Test if bit `bitnum` is set
+ pub fn is_set(&self, bitnum: usize) -> bool {
+ let byte_pos = bitnum / 8;
+ if byte_pos >= self.data.len() {
+ return false;
+ }
+ let b = 7 - (bitnum % 8);
+ (self.data[byte_pos] & (1 << b)) != 0
+ }
+
+ /// Constructs a shared `&BitSlice` reference over the object data.
+ #[cfg(feature = "bitvec")]
+ pub fn as_bitslice(&self) -> Option<&BitSlice<Msb0, u8>> {
+ BitSlice::<Msb0, _>::from_slice(self.data).ok()
+ }
+}
+
+impl<'a> AsRef<[u8]> for BitStringObject<'a> {
+ fn as_ref(&self) -> &[u8] {
+ self.data
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::ber::*;
+ use crate::oid::*;
+
+ #[test]
+ fn test_der_as_u64() {
+ let der_obj = BerObject::from_int_slice(b"\x01\x00\x02");
+ assert_eq!(der_obj.as_u64(), Ok(0x10002));
+ }
+
+ #[test]
+ fn test_ber_as_u64_bitstring() {
+ let (_, ber_obj) = parse_ber_bitstring(b"\x03\x04\x06\x6e\x5d\xc0").unwrap();
+ assert_eq!(ber_obj.as_u64(), Ok(0b011011100101110111));
+
+ let (_, ber_obj_with_nonzero_padding) =
+ parse_ber_bitstring(b"\x03\x04\x06\x6e\x5d\xe0").unwrap();
+ assert_eq!(
+ ber_obj_with_nonzero_padding.as_u64(),
+ Ok(0b011011100101110111)
+ );
+ }
+
+ #[test]
+ fn test_der_seq_iter() {
+ let der_obj = BerObject::from_obj(BerObjectContent::Sequence(vec![
+ BerObject::from_int_slice(b"\x01\x00\x01"),
+ BerObject::from_int_slice(b"\x01\x00\x00"),
+ ]));
+ let expected_values = vec![
+ BerObject::from_int_slice(b"\x01\x00\x01"),
+ BerObject::from_int_slice(b"\x01\x00\x00"),
+ ];
+
+ for (idx, v) in der_obj.ref_iter().enumerate() {
+ // println!("v: {:?}", v);
+ assert_eq!((*v), expected_values[idx]);
+ }
+ }
+
+ #[test]
+ fn test_der_from_oid() {
+ let obj: BerObject = Oid::from(&[1, 2]).unwrap().into();
+ let expected = BerObject::from_obj(BerObjectContent::OID(Oid::from(&[1, 2]).unwrap()));
+
+ assert_eq!(obj, expected);
+ }
+
+ #[test]
+ fn test_der_bitstringobject() {
+ let obj = BitStringObject {
+ data: &[0x0f, 0x00, 0x40],
+ };
+ assert!(!obj.is_set(0));
+ assert!(obj.is_set(7));
+ assert!(!obj.is_set(9));
+ assert!(obj.is_set(17));
+ }
+
+ #[cfg(feature = "bitvec")]
+ #[test]
+ fn test_der_bitslice() {
+ use std::string::String;
+ let obj = BitStringObject {
+ data: &[0x0f, 0x00, 0x40],
+ };
+ let slice = obj.as_bitslice().expect("as_bitslice");
+ assert_eq!(slice.get(0).as_deref(), Some(&false));
+ assert_eq!(slice.get(7).as_deref(), Some(&true));
+ assert_eq!(slice.get(9).as_deref(), Some(&false));
+ assert_eq!(slice.get(17).as_deref(), Some(&true));
+ let s = slice.iter().fold(String::with_capacity(24), |mut acc, b| {
+ acc += if *b { "1" } else { "0" };
+ acc
+ });
+ assert_eq!(&s, "000011110000000001000000");
+ }
+
+ #[test]
+ fn test_der_bistringobject_asref() {
+ fn assert_equal<T: AsRef<[u8]>>(s: T, b: &[u8]) {
+ assert_eq!(s.as_ref(), b);
+ }
+ let b: &[u8] = &[0x0f, 0x00, 0x40];
+ let obj = BitStringObject { data: b };
+ assert_equal(obj, b);
+ }
+
+ #[cfg(feature = "bigint")]
+ #[test]
+ fn test_der_to_bigint() {
+ let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01"));
+ let expected = ::num_bigint::BigInt::from(0x10001);
+
+ assert_eq!(obj.as_bigint(), Ok(expected));
+ }
+
+ #[cfg(feature = "bigint")]
+ #[test]
+ fn test_der_to_biguint() {
+ let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01"));
+ let expected = ::num_bigint::BigUint::from(0x10001_u32);
+
+ assert_eq!(obj.as_biguint(), Ok(expected));
+ }
+}