Skip to content

Commit

Permalink
const-oid: handle repeated dot characters in input
Browse files Browse the repository at this point in the history
Adds an `Error::RepeatedDot` case and handles it within the parser
  • Loading branch information
tarcieri committed Nov 1, 2024
1 parent c872bb3 commit a5dac2b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 20 deletions.
5 changes: 5 additions & 0 deletions const-oid/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ pub enum Error {
/// OID length is invalid (too short or too long).
Length,

/// Repeated `..` characters in input data.
RepeatedDot,

/// Trailing `.` character at end of input.
TrailingDot,
}
Expand All @@ -53,6 +56,7 @@ impl Error {
Error::DigitExpected { .. } => panic!("OID expected to start with digit"),
Error::Empty => panic!("OID value is empty"),
Error::Length => panic!("OID length invalid"),
Error::RepeatedDot => panic!("repeated consecutive '..' characters in OID"),
Error::TrailingDot => panic!("OID ends with invalid trailing '.'"),
}
}
Expand All @@ -69,6 +73,7 @@ impl fmt::Display for Error {
}
Error::Empty => f.write_str("OID value is empty"),
Error::Length => f.write_str("OID length invalid"),
Error::RepeatedDot => f.write_str("repeated consecutive '..' characters in OID"),
Error::TrailingDot => f.write_str("OID ends with invalid trailing '.'"),
}
}
Expand Down
53 changes: 33 additions & 20 deletions const-oid/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{encoder::Encoder, Arc, Error, ObjectIdentifier, Result};
#[derive(Debug)]
pub(crate) struct Parser {
/// Current arc in progress
current_arc: Arc,
current_arc: Option<Arc>,

/// BER/DER encoder
encoder: Encoder<{ ObjectIdentifier::MAX_SIZE }>,
Expand All @@ -25,7 +25,7 @@ impl Parser {

match bytes[0] {
b'0'..=b'9' => Self {
current_arc: 0,
current_arc: None,
encoder: Encoder::new(),
}
.parse_bytes(bytes),
Expand All @@ -42,37 +42,50 @@ impl Parser {
const fn parse_bytes(mut self, bytes: &[u8]) -> Result<Self> {
match bytes {
// TODO(tarcieri): use `?` when stable in `const fn`
[] => match self.encoder.arc(self.current_arc) {
Ok(encoder) => {
self.encoder = encoder;
Ok(self)
}
Err(err) => Err(err),
[] => match self.current_arc {
Some(arc) => match self.encoder.arc(arc) {
Ok(encoder) => {
self.encoder = encoder;
Ok(self)
}
Err(err) => Err(err),
},
None => Err(Error::TrailingDot),
},
[byte @ b'0'..=b'9', remaining @ ..] => {
let digit = byte.saturating_sub(b'0');
self.current_arc = match self.current_arc.checked_mul(10) {
let arc = match self.current_arc {
Some(arc) => arc,
None => 0,
};

self.current_arc = match arc.checked_mul(10) {
Some(arc) => match arc.checked_add(digit as Arc) {
Some(arc) => arc,
None => return Err(Error::ArcTooBig),
arc => arc,
},
None => return Err(Error::ArcTooBig),
};
self.parse_bytes(remaining)
}
[b'.', remaining @ ..] => {
if remaining.is_empty() {
return Err(Error::TrailingDot);
}
match self.current_arc {
Some(arc) => {
if remaining.is_empty() {
return Err(Error::TrailingDot);
}

// TODO(tarcieri): use `?` when stable in `const fn`
match self.encoder.arc(self.current_arc) {
Ok(encoder) => {
self.encoder = encoder;
self.current_arc = 0;
self.parse_bytes(remaining)
// TODO(tarcieri): use `?` when stable in `const fn`
match self.encoder.arc(arc) {
Ok(encoder) => {
self.encoder = encoder;
self.current_arc = None;
self.parse_bytes(remaining)
}
Err(err) => Err(err),
}
}
Err(err) => Err(err),
None => Err(Error::RepeatedDot),
}
}
[byte, ..] => Err(Error::DigitExpected { actual: *byte }),
Expand Down
5 changes: 5 additions & 0 deletions const-oid/tests/oid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ fn parse_invalid_second_arc() {
);
}

#[test]
fn parse_invalid_repeat_dots() {
assert_eq!(ObjectIdentifier::new("1.2..3.4"), Err(Error::RepeatedDot))
}

#[test]
fn parent() {
let child = oid("1.2.3.4");
Expand Down

0 comments on commit a5dac2b

Please sign in to comment.