Skip to content

Commit

Permalink
ber: split OID codec functionality to be usable by other codecs (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicceboy authored Aug 28, 2023
1 parent b676f5c commit db2ab2f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 48 deletions.
17 changes: 17 additions & 0 deletions src/ber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ pub use identifier::Identifier;
pub(crate) use rules::EncodingRules;

/// Attempts to decode `T` from `input` using BER.
/// # Errors
/// Returns error specific to BER decoder if decoding is not possible.
pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, de::Error> {
T::decode(&mut de::Decoder::new(input, de::DecoderOptions::ber()))
}

/// Attempts to encode `value` to BER.
/// # Errors
/// Returns error specific to BER encoder if encoding is not possible.
pub fn encode<T: crate::Encode>(value: &T) -> Result<alloc::vec::Vec<u8>, enc::Error> {
let mut enc = enc::Encoder::new(enc::EncoderOptions::ber());

Expand All @@ -22,6 +26,19 @@ pub fn encode<T: crate::Encode>(value: &T) -> Result<alloc::vec::Vec<u8>, enc::E
Ok(enc.output())
}

/// Creates a new BER encoder that can be used to encode any value.
/// # Errors
/// Returns error specific to BER encoder if encoding is not possible.
pub fn encode_scope(
encode_fn: impl FnOnce(&mut crate::ber::enc::Encoder) -> Result<(), crate::ber::enc::Error>,
) -> Result<alloc::vec::Vec<u8>, crate::ber::enc::Error> {
let mut enc = crate::ber::enc::Encoder::new(crate::ber::enc::EncoderOptions::ber());

(encode_fn)(&mut enc)?;

Ok(enc.output())
}

#[cfg(test)]
mod tests {
use alloc::borrow::ToOwned;
Expand Down
64 changes: 35 additions & 29 deletions src/ber/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,40 @@ impl<'input> Decoder<'input> {

Ok(result)
}
/// Decode an object identifier from a byte slice in BER format.
/// Function is public to be used by other codecs.
pub fn decode_object_identifier_from_bytes(
data: &[u8],
) -> Result<crate::types::ObjectIdentifier, Error> {
use num_traits::ToPrimitive;
let (mut contents, root_octets) =
parser::parse_base128_number(data).map_err(error::map_nom_err)?;
let the_number = root_octets
.to_u32()
.context(error::IntegerOverflowSnafu { max_width: 32u32 })?;
let first: u32;
let second: u32;
const MAX_OID_THRESHOLD: u32 = MAX_OID_SECOND_OCTET + 1;
if the_number > MAX_OID_FIRST_OCTET * MAX_OID_THRESHOLD + MAX_OID_SECOND_OCTET {
first = MAX_OID_FIRST_OCTET;
second = the_number - MAX_OID_FIRST_OCTET * MAX_OID_THRESHOLD;
} else {
second = the_number % MAX_OID_THRESHOLD;
first = (the_number - second) / MAX_OID_THRESHOLD;
}
let mut buffer = alloc::vec![first, second];

while !contents.is_empty() {
let (c, number) = parser::parse_base128_number(contents).map_err(error::map_nom_err)?;
contents = c;
buffer.push(
number
.to_u32()
.context(error::IntegerOverflowSnafu { max_width: 32u32 })?,
);
}
crate::types::ObjectIdentifier::new(buffer).context(error::InvalidObjectIdentifierSnafu)
}
/// Parse any GeneralizedTime string, allowing for any from ASN.1 definition
/// TODO, move to type itself?
pub fn parse_any_generalized_time_string(
Expand Down Expand Up @@ -330,36 +364,8 @@ impl<'input> crate::Decoder for Decoder<'input> {
}

fn decode_object_identifier(&mut self, tag: Tag) -> Result<crate::types::ObjectIdentifier> {
use num_traits::ToPrimitive;
let contents = self.parse_primitive_value(tag)?.1;
let (mut contents, root_octets) =
parser::parse_base128_number(contents).map_err(error::map_nom_err)?;
let the_number = root_octets
.to_u32()
.context(error::IntegerOverflowSnafu { max_width: 32u32 })?;
let first: u32;
let second: u32;
const MAX_OID_THRESHOLD: u32 = MAX_OID_SECOND_OCTET + 1;
if the_number > MAX_OID_FIRST_OCTET * MAX_OID_THRESHOLD + MAX_OID_SECOND_OCTET {
first = MAX_OID_FIRST_OCTET;
second = the_number - MAX_OID_FIRST_OCTET * MAX_OID_THRESHOLD;
} else {
second = the_number % MAX_OID_THRESHOLD;
first = (the_number - second) / MAX_OID_THRESHOLD;
}
let mut buffer = alloc::vec![first, second];

while !contents.is_empty() {
let (c, number) = parser::parse_base128_number(contents).map_err(error::map_nom_err)?;
contents = c;
buffer.push(
number
.to_u32()
.context(error::IntegerOverflowSnafu { max_width: 32u32 })?,
);
}

crate::types::ObjectIdentifier::new(buffer).context(error::InvalidObjectIdentifierSnafu)
Self::decode_object_identifier_from_bytes(contents)
}

fn decode_bit_string(&mut self, tag: Tag, _: Constraints) -> Result<types::BitString> {
Expand Down
40 changes: 21 additions & 19 deletions src/ber/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,26 @@ impl Encoder {
.insert(tag, core::mem::take(&mut self.output));
}
}
/// Converts an object identifier into a byte vector in BER format.
/// Reusable function by other codecs.
pub fn object_identifier_as_bytes(&mut self, oid: &[u32]) -> Result<Vec<u8>, error::Error> {
if oid.len() < 2 {
return Err(error::Error::InvalidObjectIdentifier);
}
let mut bytes = Vec::new();

let first = oid[0];
let second = oid[1];

if first > MAX_OID_FIRST_OCTET {
return Err(error::Error::InvalidObjectIdentifier);
}
self.encode_as_base128((first * (MAX_OID_SECOND_OCTET + 1)) + second, &mut bytes);
for component in oid.iter().skip(2) {
self.encode_as_base128(*component, &mut bytes);
}
Ok(bytes)
}
#[must_use]
/// Canonical byte presentation for CER/DER as defined in X.690 section 11.7.
/// Also used for BER on this crate.
Expand Down Expand Up @@ -343,26 +363,8 @@ impl crate::Encoder for Encoder {
}

fn encode_object_identifier(&mut self, tag: Tag, oid: &[u32]) -> Result<Self::Ok, Self::Error> {
if oid.len() < 2 {
return Err(error::Error::InvalidObjectIdentifier);
}
let mut bytes = Vec::new();

let first = oid[0];
let second = oid[1];

if first > MAX_OID_FIRST_OCTET {
return Err(error::Error::InvalidObjectIdentifier);
}

self.encode_as_base128((first * (MAX_OID_SECOND_OCTET + 1)) + second, &mut bytes);

for component in oid.iter().skip(2) {
self.encode_as_base128(*component, &mut bytes);
}

let bytes = self.object_identifier_as_bytes(oid)?;
self.encode_primitive(tag, &bytes);

Ok(())
}

Expand Down

0 comments on commit db2ab2f

Please sign in to comment.