-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Setup Basic Encoding Rules with DER flavor
- Loading branch information
1 parent
8a40e78
commit dc10bc4
Showing
8 changed files
with
574 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
use crate::protocol::basic::err::Error; | ||
use crate::protocol::basic::{BasicRead, BasicWrite}; | ||
use crate::rw::{BasicReader, BasicWriter}; | ||
use asn1rs_model::asn::Tag; | ||
use std::io::{Read, Write}; | ||
|
||
pub type DER = DistinguishedEncodingRules; | ||
pub struct DistinguishedEncodingRules; | ||
|
||
impl DistinguishedEncodingRules { | ||
#[inline] | ||
pub fn writer<W: BasicWrite<Flavor = Self>>(write: W) -> BasicWriter<W> { | ||
BasicWriter::from(write) | ||
} | ||
|
||
#[inline] | ||
pub fn reader<W: BasicRead<Flavor = Self>>(read: W) -> BasicReader<W> { | ||
BasicReader::from(read) | ||
} | ||
} | ||
|
||
const CLASS_BITS_MASK: u8 = 0b_11_000000; | ||
const CLASS_BITS_UNIVERSAL: u8 = 0b_00_000000; | ||
const CLASS_BITS_APPLICATION: u8 = 0b_01_000000; | ||
const CLASS_BITS_CONTEXT_SPECIFIC: u8 = 0b_10_000000; | ||
const CLASS_BITS_PRIVATE: u8 = 0b_11_000000; | ||
|
||
const LENGTH_MASK: u8 = 0b_11_000000; | ||
const LENGTH_SHORT_FORM: u8 = 0b_01_000000; | ||
|
||
impl<T: Read> BasicRead for T { | ||
type Flavor = DistinguishedEncodingRules; | ||
|
||
fn read_identifier(&mut self) -> Result<Tag, Error> { | ||
let mut byte = [0x00]; | ||
self.read_exact(&mut byte[..])?; | ||
let class = byte[0] & CLASS_BITS_MASK; | ||
let value = byte[0] & !CLASS_BITS_MASK; | ||
// TODO assumption: number contains the primitive / constructed flag | ||
// TODO assumption: number not greater than the octets remaining bits | ||
Ok(match class { | ||
CLASS_BITS_UNIVERSAL => Tag::Universal(usize::from(value)), | ||
CLASS_BITS_APPLICATION => Tag::Application(usize::from(value)), | ||
CLASS_BITS_CONTEXT_SPECIFIC => Tag::ContextSpecific(usize::from(value)), | ||
CLASS_BITS_PRIVATE => Tag::Private(usize::from(value)), | ||
_ => unreachable!(), | ||
}) | ||
} | ||
|
||
#[inline] | ||
fn read_length(&mut self) -> Result<usize, Error> { | ||
let mut bytes = [0u8; 1]; | ||
self.read_exact(&mut bytes[..])?; | ||
if bytes[0] & LENGTH_MASK == LENGTH_SHORT_FORM { | ||
Ok(usize::from(bytes[0] & !LENGTH_MASK)) | ||
} else { | ||
todo!() | ||
} | ||
} | ||
|
||
#[inline] | ||
fn read_boolean(&mut self) -> Result<bool, Error> { | ||
let mut byte = [0u8; 1]; | ||
self.read_exact(&mut byte[..])?; | ||
Ok(byte[0] != 0x00) | ||
} | ||
} | ||
|
||
impl<T: Write> BasicWrite for T { | ||
type Flavor = DistinguishedEncodingRules; | ||
|
||
fn write_identifier(&mut self, tag: Tag) -> Result<(), Error> { | ||
let mut identifier_octet: u8 = match tag { | ||
Tag::Universal(_) => CLASS_BITS_UNIVERSAL, | ||
Tag::Application(_) => CLASS_BITS_APPLICATION, | ||
Tag::ContextSpecific(_) => CLASS_BITS_CONTEXT_SPECIFIC, | ||
Tag::Private(_) => CLASS_BITS_PRIVATE, | ||
}; | ||
// TODO assumption: number contains the primitive / constructed flag | ||
// TODO assumption: number not greater than the octets remaining bits | ||
identifier_octet |= tag.value() as u8; | ||
Ok(self.write_all(&[identifier_octet])?) | ||
} | ||
|
||
#[inline] | ||
fn write_length(&mut self, length: usize) -> Result<(), Error> { | ||
let byte = if length < 64 { | ||
// short form 8.1.3.4 | ||
LENGTH_SHORT_FORM | (length as u8) | ||
} else { | ||
// long form 8.1.3.5 | ||
todo!() | ||
}; | ||
Ok(self.write_all(&[byte])?) | ||
} | ||
|
||
#[inline] | ||
fn write_boolean(&mut self, value: bool) -> Result<(), Error> { | ||
Ok(self.write_all(&[if value { 0x01 } else { 0x00 }])?) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use asn1rs_model::asn::Tag; | ||
use backtrace::Backtrace; | ||
use std::fmt::{Debug, Display, Formatter}; | ||
use std::ops::Range; | ||
|
||
pub struct Error(pub(crate) Box<Inner>); | ||
|
||
impl Error { | ||
#[inline] | ||
pub fn kind(&self) -> &ErrorKind { | ||
&self.0.kind | ||
} | ||
|
||
#[cold] | ||
#[inline(never)] | ||
pub fn unexpected_tag(expected: Tag, got: Tag) -> Self { | ||
Self::from(ErrorKind::UnexpectedTypeTag { expected, got }) | ||
} | ||
|
||
#[cold] | ||
#[inline(never)] | ||
pub fn unexpected_length(expected: Range<usize>, got: usize) -> Self { | ||
Self::from(ErrorKind::UnexpectedTypeLength { expected, got }) | ||
} | ||
} | ||
|
||
impl From<ErrorKind> for Error { | ||
#[inline] | ||
fn from(kind: ErrorKind) -> Self { | ||
Error(Box::new(Inner::from(kind))) | ||
} | ||
} | ||
|
||
impl From<std::io::Error> for Error { | ||
#[inline] | ||
fn from(e: std::io::Error) -> Self { | ||
Self::from(ErrorKind::IoError(e)) | ||
} | ||
} | ||
|
||
impl Debug for Error { | ||
#[inline] | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
Display::fmt(self, f) | ||
} | ||
} | ||
|
||
impl Display for Error { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
writeln!(f, "{}", self.0.kind)?; | ||
let mut backtrace = self.0.backtrace.clone(); | ||
backtrace.resolve(); | ||
writeln!(f, "{backtrace:?}") | ||
} | ||
} | ||
|
||
impl std::error::Error for Error { | ||
fn description(&self) -> &str { | ||
"encoding or decoding with basic rules failed" | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub(crate) struct Inner { | ||
pub(crate) kind: ErrorKind, | ||
pub(crate) backtrace: Backtrace, | ||
} | ||
|
||
impl From<ErrorKind> for Inner { | ||
#[inline] | ||
fn from(kind: ErrorKind) -> Self { | ||
Self { | ||
kind, | ||
backtrace: Backtrace::new_unresolved(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum ErrorKind { | ||
UnexpectedTypeTag { expected: Tag, got: Tag }, | ||
UnexpectedTypeLength { expected: Range<usize>, got: usize }, | ||
IoError(std::io::Error), | ||
} | ||
|
||
impl Display for ErrorKind { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
ErrorKind::UnexpectedTypeTag { expected, got } => { | ||
write!(f, "Expected tag {expected:?} but got {got:?}") | ||
} | ||
ErrorKind::UnexpectedTypeLength { expected, got } => { | ||
write!(f, "Expected length in range {expected:?} but got {got:?}") | ||
} | ||
ErrorKind::IoError(e) => { | ||
write!(f, "Experienced underlying IO error: {e:?}") | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
//! This module contains defines traits to encode and decode basic ASN.1 primitives and types of | ||
//! the basic family (BER, DER, CER). | ||
|
||
mod distinguished; | ||
mod err; | ||
|
||
pub use distinguished::*; | ||
pub use err::Error; | ||
|
||
use asn1rs_model::asn::Tag; | ||
|
||
/// According to ITU-T X.690 | ||
pub trait BasicRead { | ||
type Flavor; | ||
|
||
/// According to ITU-T X.690, chapter 8.1.2, an identifier octet contains the class and number | ||
/// of the type. | ||
fn read_identifier(&mut self) -> Result<Tag, Error>; | ||
|
||
/// According to ITU-T X.690, chapter 8.1.3, the length is encoded in at least one byte, in | ||
/// either the short (8.1.3.4) or long (8.1.3.5) form | ||
fn read_length(&mut self) -> Result<usize, Error>; | ||
|
||
/// According to ITU-T X.690, chapter 8.2, the boolean type is represented in a single byte, | ||
/// where 0 represents `false` and any other value represents `true`. | ||
fn read_boolean(&mut self) -> Result<bool, Error>; | ||
} | ||
|
||
/// According to ITU-T X.690 | ||
pub trait BasicWrite { | ||
type Flavor; | ||
|
||
/// According to ITU-T X.690, chapter 8.1.2, an identifier octet contains the class and number | ||
/// of the type. | ||
fn write_identifier(&mut self, tag: Tag) -> Result<(), Error>; | ||
|
||
/// According to ITU-T X.690, chapter 8.1.3, the length is encoded in at least one byte, in | ||
/// either the short (8.1.3.4) or long (8.1.3.5) form | ||
fn write_length(&mut self, length: usize) -> Result<(), Error>; | ||
|
||
/// According to ITU-T X.690, chapter 8.2, the boolean type is represented in a single byte, | ||
/// where 0 represents `false` and any other value represents `true`. | ||
fn write_boolean(&mut self, value: bool) -> Result<(), Error>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.