Skip to content

Commit

Permalink
const-oid: add ObjectIdentifierRef
Browse files Browse the repository at this point in the history
Adds a `repr(transparent)` newtype for a `[u8]` which is guaranteed to
contain a valid BER serialization of an OID. This is a similar approach
to how `Path`/`PathBuf` or `OsStr`/`OsString` work (except with
`ObjectIdentifier` being stack-allocated instead of heap allocated).

An unsafe pointer cast is required to go from `&[u8]` to
`&ObjectIdentifierRef`, so unfortunately this means the crate is no
longer `forbid(unsafe_code)`, however it's been lowered to
`deny(unsafe_code)` to ensure contributors think twice before adding
more.

`Borrow` and `Deref` impls have been added to the owned
`ObjectIdentifier` type, allowing common functionality to be moved to
`ObjectIdentifierRef`, allowing both types to exist while eliminating
code duplication.

A `PartialEq` impl allows them to be compared.

The `db` module continues to use `ObjectIdentifier` for now, however
hopefully this approach would allow #1212 to be reinstated and for
`ObjectIdentifierRef`s to be used for the database eventually (i.e.
revert the revert in #1299)
  • Loading branch information
tarcieri committed Jan 5, 2024
1 parent 12820eb commit d5fd54f
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 111 deletions.
3 changes: 2 additions & 1 deletion const-oid/src/arcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ impl<'a> Arcs<'a> {
match self.cursor {
// Indicates we're on the root arc
None => {
let root = RootArcs::try_from(self.bytes[0])?;
let root_byte = *self.bytes.first().ok_or(Error::Empty)?;
let root = RootArcs::try_from(root_byte)?;
self.cursor = Some(0);
Ok(Some(root.first_arc()))
}
Expand Down
4 changes: 2 additions & 2 deletions const-oid/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'a> Database<'a> {
while i < self.0.len() {
let lhs = self.0[i].0;

if lhs.buffer.eq(&oid.buffer) {
if lhs.ber.eq(&oid.ber) {
return Some(self.0[i].1);
}

Expand Down Expand Up @@ -110,7 +110,7 @@ impl<'a> Iterator for Names<'a> {
while i < self.database.0.len() {
let lhs = self.database.0[i].0;

if lhs.buffer.eq(&self.oid.buffer) {
if lhs.ber.eq(&self.oid.ber) {
self.position = i + 1;
return Some(self.database.0[i].1);
}
Expand Down
38 changes: 19 additions & 19 deletions const-oid/src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,29 @@ use crate::{
Arc, Buffer, Error, ObjectIdentifier, Result,
};

/// BER/DER encoder
/// BER/DER encoder.
#[derive(Debug)]
pub(crate) struct Encoder<const MAX_SIZE: usize> {
/// Current state
/// Current state.
state: State,

/// Bytes of the OID being encoded in-progress
/// Bytes of the OID being BER-encoded in-progress.
bytes: [u8; MAX_SIZE],

/// Current position within the byte buffer
/// Current position within the byte buffer.
cursor: usize,
}

/// Current state of the encoder
/// Current state of the encoder.
#[derive(Debug)]
enum State {
/// Initial state - no arcs yet encoded
/// Initial state - no arcs yet encoded.
Initial,

/// First arc parsed
/// First arc parsed.
FirstArc(Arc),

/// Encoding base 128 body of the OID
/// Encoding base 128 body of the OID.
Body,
}

Expand All @@ -45,8 +45,8 @@ impl<const MAX_SIZE: usize> Encoder<MAX_SIZE> {
pub(crate) const fn extend(oid: ObjectIdentifier<MAX_SIZE>) -> Self {
Self {
state: State::Body,
bytes: oid.buffer.bytes,
cursor: oid.buffer.length as usize,
bytes: oid.ber.bytes,
cursor: oid.ber.length as usize,
}
}

Expand Down Expand Up @@ -100,16 +100,16 @@ impl<const MAX_SIZE: usize> Encoder<MAX_SIZE> {

/// Finish encoding an OID.
pub(crate) const fn finish(self) -> Result<ObjectIdentifier<MAX_SIZE>> {
if self.cursor >= 2 {
let bytes = Buffer {
bytes: self.bytes,
length: self.cursor as u8,
};

Ok(ObjectIdentifier { buffer: bytes })
} else {
Err(Error::NotEnoughArcs)
if self.cursor == 0 {
return Err(Error::Empty);
}

let ber = Buffer {
bytes: self.bytes,
length: self.cursor as u8,
};

Ok(ObjectIdentifier { ber })
}

/// Encode a single byte of a Base 128 value.
Expand Down
5 changes: 0 additions & 5 deletions const-oid/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ pub enum Error {
/// OID length is invalid (too short or too long).
Length,

/// Minimum 3 arcs required.
NotEnoughArcs,

/// Trailing `.` character at end of input.
TrailingDot,
}
Expand All @@ -56,7 +53,6 @@ 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::NotEnoughArcs => panic!("OID requires minimum of 3 arcs"),
Error::TrailingDot => panic!("OID ends with invalid trailing '.'"),
}
}
Expand All @@ -73,7 +69,6 @@ impl fmt::Display for Error {
}
Error::Empty => f.write_str("OID value is empty"),
Error::Length => f.write_str("OID length invalid"),
Error::NotEnoughArcs => f.write_str("OID requires minimum of 3 arcs"),
Error::TrailingDot => f.write_str("OID ends with invalid trailing '.'"),
}
}
Expand Down
Loading

0 comments on commit d5fd54f

Please sign in to comment.