From a5dac2b1fe409d5261e08b9e0ff9c31069f134c5 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 1 Nov 2024 15:53:40 -0600 Subject: [PATCH] const-oid: handle repeated dot characters in input Adds an `Error::RepeatedDot` case and handles it within the parser --- const-oid/src/error.rs | 5 ++++ const-oid/src/parser.rs | 53 +++++++++++++++++++++++++---------------- const-oid/tests/oid.rs | 5 ++++ 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/const-oid/src/error.rs b/const-oid/src/error.rs index faa01769b..39a70e8a4 100644 --- a/const-oid/src/error.rs +++ b/const-oid/src/error.rs @@ -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, } @@ -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 '.'"), } } @@ -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 '.'"), } } diff --git a/const-oid/src/parser.rs b/const-oid/src/parser.rs index 1df2335a6..fe687e39a 100644 --- a/const-oid/src/parser.rs +++ b/const-oid/src/parser.rs @@ -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, /// BER/DER encoder encoder: Encoder<{ ObjectIdentifier::MAX_SIZE }>, @@ -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), @@ -42,37 +42,50 @@ impl Parser { const fn parse_bytes(mut self, bytes: &[u8]) -> Result { 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 }), diff --git a/const-oid/tests/oid.rs b/const-oid/tests/oid.rs index 374a127f7..ad7a0f8e9 100644 --- a/const-oid/tests/oid.rs +++ b/const-oid/tests/oid.rs @@ -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");