Skip to content

Commit

Permalink
Add support for 128 bit OID arcs
Browse files Browse the repository at this point in the history
  • Loading branch information
robby-cornelissen committed Oct 17, 2024
1 parent efe033d commit 22109d7
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 22 deletions.
8 changes: 4 additions & 4 deletions asn1_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ fn generate_enum_write_block(name: &syn::Ident, data: &syn::DataEnum) -> proc_ma

// TODO: Duplicate of this function in src/object_identifier.rs, can we
// de-dupe?
fn _write_base128_int(data: &mut Vec<u8>, n: u32) {
fn _write_base128_int(data: &mut Vec<u8>, n: u128) {
if n == 0 {
data.push(0);
return;
Expand Down Expand Up @@ -709,11 +709,11 @@ pub fn oid(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut arcs = p_arcs.iter();

let mut der_encoded = vec![];
let first = arcs.next().unwrap().base10_parse::<u32>().unwrap();
let second = arcs.next().unwrap().base10_parse::<u32>().unwrap();
let first = arcs.next().unwrap().base10_parse::<u128>().unwrap();
let second = arcs.next().unwrap().base10_parse::<u128>().unwrap();
_write_base128_int(&mut der_encoded, 40 * first + second);
for arc in arcs {
_write_base128_int(&mut der_encoded, arc.base10_parse().unwrap());
_write_base128_int(&mut der_encoded, arc.base10_parse::<u128>().unwrap());
}

let der_len = der_encoded.len();
Expand Down
29 changes: 17 additions & 12 deletions src/base128.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use crate::parser::{ParseError, ParseErrorKind, ParseResult};

pub(crate) fn read_base128_int(mut data: &[u8]) -> ParseResult<(u32, &[u8])> {
let mut ret = 0u32;
for i in 0..5 {
const INT_MAX_BYTES: u32 = (u128::BITS + 6) / 7;

pub(crate) fn read_base128_int(mut data: &[u8]) -> ParseResult<(u128, &[u8])> {
let mut ret = 0u128;
for i in 0..INT_MAX_BYTES {
let b = match data.first() {
Some(b) => *b,
None => return Err(ParseError::new(ParseErrorKind::ShortData { needed: 1 })),
};
data = &data[1..];
if ret > u32::MAX >> 7 {
if ret > u128::MAX >> 7 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
ret <<= 7;
ret |= u32::from(b & 0x7f);
ret |= u128::from(b & 0x7f);
// Integers must be minimally encoded. `i == 0 && 0x80` would mean
// that the first byte had a value of 0, which is non-minimal.
if i == 0 && b == 0x80 {
Expand All @@ -25,14 +27,14 @@ pub(crate) fn read_base128_int(mut data: &[u8]) -> ParseResult<(u32, &[u8])> {
Err(ParseError::new(ParseErrorKind::InvalidValue))
}

pub(crate) fn base128_length(n: u32) -> usize {
// Equivalent to: let bits = if n != 0 { 32 - n.leading_zeros() } else { 1 };
let bits = u32::BITS - (n | 1).leading_zeros();
pub(crate) fn base128_length(n: u128) -> usize {
// Equivalent to: let bits = if n != 0 { 128 - n.leading_zeros() } else { 1 };
let bits = u128::BITS - (n | 1).leading_zeros();
let bytes = (bits + 6) / 7;
bytes as usize
}

pub(crate) fn write_base128_int(mut data: &mut [u8], n: u32) -> Option<usize> {
pub(crate) fn write_base128_int(mut data: &mut [u8], n: u128) -> Option<usize> {
let length = base128_length(n);

if data.len() < length {
Expand Down Expand Up @@ -63,15 +65,18 @@ mod tests {

#[test]
fn test_read_overflow() {
let buf = [0x90, 0x80, 0x80, 0x80, 0x0];
let buf = [
0x90, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x0,
];
let result = read_base128_int(&buf);
assert!(result.is_err());
}

#[test]
fn test_roundtrip() {
for i in [0, 10, u32::MAX] {
let mut buf = [0; 16];
for i in [0, 10, u128::MAX] {
let mut buf = [0; 32];
let length = write_base128_int(&mut buf, i).unwrap();
let (val, remainder) = read_base128_int(&buf[..length]).unwrap();
assert_eq!(i, val);
Expand Down
11 changes: 8 additions & 3 deletions src/object_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ impl ObjectIdentifier {
pub fn from_string(oid: &str) -> Option<ObjectIdentifier> {
let mut parts = oid.split('.');

let first = parts.next()?.parse::<u32>().ok()?;
let second = parts.next()?.parse::<u32>().ok()?;
let first = parts.next()?.parse::<u128>().ok()?;
let second = parts.next()?.parse::<u128>().ok()?;
if first > 2 || (first < 2 && second >= 40) {
return None;
}
Expand All @@ -43,7 +43,7 @@ impl ObjectIdentifier {
for part in parts {
der_data_len += base128::write_base128_int(
&mut der_data[der_data_len..],
part.parse::<u32>().ok()?,
part.parse::<u128>().ok()?,
)?;
}
Some(ObjectIdentifier {
Expand Down Expand Up @@ -165,6 +165,9 @@ mod tests {
"1.2.3.4",
"1.2.840.133549.1.1.5",
"2.100.3",
"2.1.750304883",
"2.25.223663413560230117710484359924050447509",
"2.25.340282366920938463463374607431768211455",
] {
assert!(ObjectIdentifier::from_string(val).is_some());
}
Expand Down Expand Up @@ -204,6 +207,8 @@ mod tests {
"1.2.840.133549.1.1.5",
"2.100.3",
"2.1.750304883",
"2.25.223663413560230117710484359924050447509",
"2.25.340282366920938463463374607431768211455",
] {
assert_eq!(
&ObjectIdentifier::from_string(val).unwrap().to_string(),
Expand Down
9 changes: 6 additions & 3 deletions src/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ impl Tag {
}
})?;
// MSRV of 1.59 required for `(value, data) = ...;`
value = result.0;
value = result
.0
.try_into()
.map_err(|_| ParseError::new(ParseErrorKind::InvalidTag))?;
data = result.1;
// Tags must be encoded in minimal form.
if value < 0x1f {
Expand Down Expand Up @@ -109,12 +112,12 @@ impl Tag {
if self.value >= 0x1f {
b |= 0x1f;
dest.push_byte(b)?;
let len = base128::base128_length(self.value);
let len = base128::base128_length(self.value.into());
let orig_len = dest.len();
for _ in 0..len {
dest.push_byte(0)?;
}
base128::write_base128_int(&mut dest.as_mut_slice()[orig_len..], self.value);
base128::write_base128_int(&mut dest.as_mut_slice()[orig_len..], self.value.into());
} else {
b |= self.value as u8;
dest.push_byte(b)?;
Expand Down
9 changes: 9 additions & 0 deletions tests/oid_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ fn test_oid_value() {
);
}

#[test]
fn test_oid_with_uuid() {
assert_eq!(
asn1::oid!(2, 25, 223663413560230117710484359924050447509),
asn1::ObjectIdentifier::from_string("2.25.223663413560230117710484359924050447509")
.unwrap()
);
}

#[test]
fn test_match_statement() {
const OID1: asn1::ObjectIdentifier = asn1::oid!(1, 2, 3, 4);
Expand Down

0 comments on commit 22109d7

Please sign in to comment.