use std::hash::Hash;
pub use {DerWrite, FromBer, ToDer};
pub use yasna::models::ObjectIdentifier;
pub use yasna::{
construct_der, ASN1Error, ASN1ErrorKind, ASN1Result, BERReader, BERReaderSeq, DERWriter,
DERWriterSeq, BERDecodable, Tag,
};
pub trait BerDecodableSubSequence: Sized + Eq + Hash {
fn decode_ber<'a, 'b>(reader: &mut BERReaderSeq<'a, 'b>) -> ASN1Result<Self>;
}
pub trait SubSequenceDerWrite {
fn write(&self, writer: &mut DERWriterSeq);
}
#[macro_export]
macro_rules! enum_oid {
($name:ident {
$($variant:ident = $val:expr),*,
}) => {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[allow(non_camel_case_types)]
pub enum $name {
$($variant),*
}
impl $name {
#[allow(unused)]
fn try_from_oid(oid: ObjectIdentifier) -> Result<Self, ASN1Error> {
$(if oid == *$val {
return Ok($name::$variant);
}
)*
return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
}
}
impl <'a>From<&'a $name> for &'static ObjectIdentifier {
fn from(item : &'a $name) -> &'static ObjectIdentifier {
match item {
$(&$name::$variant => &$val),*
}
}
}
impl DerWrite for $name {
fn write(&self, writer: DERWriter) {
writer.write_oid(self.into())
}
}
impl BERDecodable for $name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
reader.read_oid().and_then(|oid| {$name::try_from_oid(oid)})
}
}
}
}
#[macro_export]
macro_rules! define_content_with_associated_type {
($name:ident => $Ty:ident {
$($variant:ident),*,
}) => {
define_content_with_associated_type! {
$name => $Ty {
$($variant = $variant),*,
}
}
};
($name:ident => $Ty:ident {
$($variant:ident = $typeVariant:ident),*,
}) => {
define_content_with_associated_type! {
$name => $Ty {
$($variant($variant) = $variant),*,
}
}
$(impl From<$variant> for $name {
fn from(var : $variant) -> $name {
$name::$variant{0: var}
}
})*
};
($name:ident => $Ty:ident {
$($variant:ident($innerVariant:ty) = $typeVariant:ident),*,
}) => {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[allow(non_camel_case_types, non_snake_case)]
pub enum $name {
$($variant($innerVariant)),*
}
impl $name {
pub fn get_type(&self) -> $Ty {
match self {
$(&$name::$variant(_) => $Ty::$typeVariant),*
}
}
}
}
}
#[macro_export]
macro_rules! impl_content_with_associated_type {
($name:ident : Sequence TypeEmbedded => $Ty:ident {
$($tail:tt)*
}) => {
impl_content_with_associated_type! {
$name => $Ty SubSequenceDerWrite, BerDecodableSubSequence, &mut BERReaderSeq {
$($tail)*
}
}
impl DerWrite for $name {
fn write(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
self.get_type().write(writer.next());
self.content_writer().write(writer);
})
}
}
impl BERDecodable for $name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
reader.read_sequence(|seq_reader| {
let content_type = <$Ty as BERDecodable>::decode_ber(seq_reader.next())?;
$name::content_reader(content_type, seq_reader)
})
}
}
};
($name:ident : Sequence => $Ty:ident {
$($tail:tt)*
}) => {
impl_content_with_associated_type!($name => $Ty {
$($tail)*
});
impl DerWrite for $name {
fn write(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
self.get_type().write(writer.next());
self.content_writer().write(writer.next());
})
}
}
impl BERDecodable for $name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
reader.read_sequence(|seq_reader| {
let content_type = <$Ty as BERDecodable>::decode_ber(seq_reader.next())?;
$name::content_reader(content_type, seq_reader.next())
})
}
}
};
($name:ident => $Ty:ident {
$($tail:tt)*
}) => {
impl_content_with_associated_type! {
$name => $Ty DerWrite,BERDecodable,BERReader {
$($tail)*
}
}
};
($name:ident => $Ty:ident $writeTrait:ident, $readTrait:ident, $readerType:ty {
$($variant:ident),*,
}) => {
impl_content_with_associated_type! {
$name => $Ty $writeTrait, $readTrait, $readerType {
$($variant = $variant),*,
}
}
};
($name:ident => $Ty:ident $writeTrait:ident, $readTrait:ident,$readerType:ty {
$($variant:ident($innerVariant:ty)),*,
}) => {
impl_content_with_associated_type! {
$name => $Ty $writeTrait, $readTrait, $readerType {
$($variant($innerVariant) = $variant),*,
}
}
};
($name:ident => $Ty:ident $writeTrait:ident, $readTrait:ident,$readerType:ty {
$($variant:ident = $typeVariant:ident),*,
}) => {
impl_content_with_associated_type! {
$name => $Ty $writeTrait, $readTrait, $readerType {
$($variant($variant) = $typeVariant),*,
}
}
$(impl From<$variant> for $name {
fn from(var : $variant) -> $name {
$name::$variant{0: var}
}
})*
};
($name:ident => $Ty:ident $writeTrait:ident, $readTrait:ident,$readerType:ty {
$($variant:ident($innerVariant:ty) = $typeVariant:ident),*,
}) => {
define_content_with_associated_type! {
$name => $Ty {
$($variant($innerVariant) = $typeVariant),*,
}
}
impl $name {
fn content_writer<'a>(&'a self) -> Box<&'a dyn $writeTrait> {
match self {
$(&$name::$variant(ref var) => Box::new(var)),*
}
}
fn content_reader(content_type: $Ty, reader : $readerType)-> ASN1Result<Self> {
#[allow(unreachable_patterns)]
match content_type {
$($Ty::$typeVariant => <$innerVariant as $readTrait>::decode_ber(reader).and_then(|v| Ok($name::$variant(v)))),*,
_ => Err(ASN1Error::new(ASN1ErrorKind::Invalid))
}
}
}
}
}
#[macro_export]
macro_rules! enum_subtype {
($name:ident => $super:ident {
$($variant:ident),*,
}) => {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[allow(non_camel_case_types)]
pub enum $name {
$($variant($variant)),*
}
impl $name {
#[allow(unused)]
pub fn try_from_super(sup: $super) -> Result<Self, ASN1Error> {
match sup {
$($super::$variant(var) => Ok($name::$variant{0: var}))*,
_ => Err(ASN1Error::new(ASN1ErrorKind::Invalid))
}
}
}
$(
impl From<$variant> for $name {
fn from(item : $variant) -> $name {
$name::$variant{0: item}
}
}
)*
impl DerWrite for $name {
fn write(&self, writer: DERWriter) {
match self {
$(&$name::$variant{0: ref var} => {
$super::$variant{0: var.clone()}.write(writer);
}
),*
}
}
}
impl BERDecodable for $name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
<$super as BERDecodable>::decode_ber(reader).and_then(|s| $name::try_from_super(s))
}
}
}
}
#[macro_export]
macro_rules! derive_set {
($elem_name:ty => $set_name:ident) => {
#[derive(Clone, Debug, Eq, PartialEq, Hash, Default)]
#[allow(non_camel_case_types, non_snake_case)]
pub struct $set_name {
elements: Vec<$elem_name>,
}
impl DerWrite for $set_name {
fn write(&self, writer: DERWriter) {
writer.write_set(|w| {
for element in &self.elements {
element.write(w.next());
}
})
}
}
impl BERDecodable for $set_name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
let mut elements = Vec::<$elem_name>::new();
reader.read_set_of(|r| {
let info = <$elem_name as BERDecodable>::decode_ber(r)?;
elements.push(info);
Ok(())
})?;
Ok($set_name { elements })
}
}
impl From<Vec<$elem_name>> for $set_name {
fn from(elements: Vec<$elem_name>) -> $set_name {
$set_name { elements }
}
}
impl $set_name {
#[allow(unused)]
pub fn push<T: Into<$elem_name>>(&mut self, elem: T) {
self.elements.push(elem.into());
}
}
impl From<$set_name> for Vec<$elem_name> {
fn from(set_name : $set_name) -> Vec<$elem_name> {
set_name.elements
}
}
};
}
#[macro_export]
macro_rules! derive_set_of {
($elem_name:ty => $set_name:ident) => {
#[derive(Clone, Debug, Eq, PartialEq, Hash, Default)]
#[allow(non_camel_case_types, non_snake_case)]
pub struct $set_name {
elements: Vec<$elem_name>,
}
impl DerWrite for $set_name {
fn write(&self, writer: DERWriter) {
writer.write_set_of(|w| {
for element in &self.elements {
element.write(w.next());
}
})
}
}
impl BERDecodable for $set_name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
let mut elements = Vec::<$elem_name>::new();
reader.read_set_of(|r| {
let info = <$elem_name as BERDecodable>::decode_ber(r)?;
elements.push(info);
Ok(())
})?;
Ok($set_name { elements })
}
}
impl From<Vec<$elem_name>> for $set_name {
fn from(elements: Vec<$elem_name>) -> $set_name {
$set_name { elements }
}
}
impl $set_name {
#[allow(unused)]
pub fn push<T: Into<$elem_name>>(&mut self, elem: T) {
self.elements.push(elem.into());
}
}
impl From<$set_name> for Vec<$elem_name> {
fn from(set_name : $set_name) -> Vec<$elem_name> {
set_name.elements
}
}
};
}
#[macro_export]
macro_rules! derive_sequence_of {
($(#[$outer:meta])* $elem_name:ident$(<$ele_lt:lifetime>)? => $sequence_name:ident$(<$seq_lt:lifetime>)?) => {
$(#[$outer])*
#[derive(Clone, Debug, Eq, PartialEq, Hash, Default)]
#[allow(non_camel_case_types, non_snake_case)]
pub struct $sequence_name$(<$seq_lt>)?(pub Vec<$elem_name$(<$ele_lt>)?>);
impl$(<$seq_lt>)? DerWrite for $sequence_name$(<$seq_lt>)? {
fn write(&self, writer: DERWriter) {
writer.write_sequence_of(|w| {
for element in &self.0 {
element.write(w.next());
}
})
}
}
impl$(<$seq_lt>)? BERDecodable for $sequence_name$(<$seq_lt>)? {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
Ok($sequence_name(reader.collect_sequence_of($elem_name::decode_ber)?))
}
}
impl$(<$seq_lt>)? From<Vec<$elem_name$(<$ele_lt>)?>> for $sequence_name$(<$seq_lt>)? {
fn from(elements: Vec<$elem_name$(<$ele_lt>)?>) -> Self {
Self(elements)
}
}
impl$(<$seq_lt>)? $sequence_name$(<$seq_lt>)? {
#[allow(unused)]
pub fn push<T: Into<$elem_name$(<$ele_lt>)?>>(&mut self, elem: T) {
self.0.push(elem.into());
}
}
impl$(<$seq_lt>)? From<$sequence_name$(<$seq_lt>)?> for Vec<$elem_name$(<$ele_lt>)?> {
fn from(sequence_name: $sequence_name$(<$seq_lt>)?) -> Self {
sequence_name.0
}
}
};
}
#[macro_export]
macro_rules! derive_sequence {
(
$(#[$outer:meta])*
$name:ident$(<$name_lt:lifetime>)? {
$($item:ident : [$tag:tt] $tag_type:ident $optional:ident: $item_type:ty),*$(,)*
}) => {
$(#[$outer])*
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[allow(non_camel_case_types, non_snake_case)]
pub struct $name$(<$name_lt>)? {
$(pub $item : $item_type),*,
}
impl$(<$name_lt>)? DerWrite for $name$(<$name_lt>)? {
fn write(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
derive_sequence! {
$name deriveDerWr(self, writer.next()) {
$($item : [$tag] $tag_type $optional : $item_type),*,
}
}
})
}
}
impl$(<$name_lt>)? BERDecodable for $name$(<$name_lt>)? {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
reader.read_sequence(|reader| {
derive_sequence! {
$name deriveBerRd(reader, reader.next()) {
$($item : [$tag] $tag_type $optional : $item_type),*,
}
}
let obj = $name {
$($item),*,
};
Ok(obj)
})
}
}
};
(
$(#[$outer:meta])*
$name:ident$(<$name_lt:lifetime>)? {
$($item:ident : [$tag:tt] $tag_type:ident : $item_type:ty),*$(,)*
}) => {
derive_sequence! {
$(#[$outer])*
$name$(<$name_lt>)? {
$($item : [$tag] $tag_type REQUIRED : $item_type),*,
}
}
};
(
$(#[$outer:meta])*
$name:ident$(<$name_lt:lifetime>)? {
$($item:ident : $item_type:ty),*$(,)*
}) => {
derive_sequence! {
$(#[$outer])*
$name$(<$name_lt>)? {
$($item : [_] UNTAGGED REQUIRED : $item_type),*,
}
}
};
(
$(#[$outer:meta])*
$name:ident : Subsequence {
$($item:ident : [$tag:tt] $tag_type:ident $optional:ident : $item_type:ty),*$(,)*
}) => {
$(#[$outer])*
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[allow(non_camel_case_types, non_snake_case)]
pub struct $name {
$(pub $item : $item_type),*,
}
impl SubSequenceDerWrite for $name {
fn write(&self, writer: &mut DERWriterSeq) {
derive_sequence! {
$name deriveDerWr(self, writer.next()) {
$($item : [$tag] $tag_type $optional : $item_type),*,
}
}
}
}
impl BerDecodableSubSequence for $name {
fn decode_ber<'a, 'b>(reader: &mut BERReaderSeq<'a, 'b>) -> ASN1Result<Self> {
derive_sequence! {
$name deriveBerRd(reader, reader.next()) {
$($item : [$tag] $tag_type $optional : $item_type),*,
}
}
let obj = $name {
$($item),*,
};
Ok(obj)
}
}
};
(
$(#[$outer:meta])*
$name:ident : Subsequence {
$($item:ident : [$tag:tt] $tag_type:ident : $item_type:ty),*$(,)*
}) => {
derive_sequence! {
$(#[$outer])*
$name :Subsequence {
$($item : [$tag] $tag_type REQUIRED : $item_type),*,
}
}
};
(
$(#[$outer:meta])*
$name:ident : Subsequence {
$($item:ident : $item_type:ty),*$(,)*
}) => {
derive_sequence! {
$(#[$outer])*
$name :Subsequence {
$($item : [_] UNTAGGED REQUIRED : $item_type),*,
}
}
};
($name:ident deriveDerWr($written:ident, $writer:expr) { }) => {};
($name:ident deriveDerWr($written:ident, $writer:expr) {
$item:ident : [$tag:tt] EXPLICIT REQUIRED : $item_type:ty,
$($tail:tt)*
}) => {
$writer.write_tagged(Tag::context($tag), |writer| {
$written.$item.write(writer)
});
derive_sequence! {
$name deriveDerWr($written, $writer) {
$($tail)*
}
}
};
($name:ident deriveDerWr($written:ident, $writer:expr) {
$item:ident : [$tag:tt] IMPLICIT REQUIRED : $item_type:ty,
$($tail:tt)*
}) => {
$writer.write_tagged_implicit(Tag::context($tag), |writer| {
$written.$item.write(writer)
});
derive_sequence! {
$name deriveDerWr($written, $writer) {
$($tail)*
}
}
};
($name:ident deriveDerWr($written:ident, $writer:expr) {
$item:ident : [$tag:tt] UNTAGGED REQUIRED : $item_type:ty,
$($tail:tt)*
}) => {
$written.$item.write($writer);
derive_sequence! {
$name deriveDerWr($written, $writer) {
$($tail)*
}
}
};
($name:ident deriveDerWr($written:ident, $writer:expr) {
$item:ident : [$tag:tt] EXPLICIT OPTIONAL : $item_type:ty,
$($tail:tt)*
}) => {
if let Some($item) = $written.$item.as_ref() {
$writer.write_tagged(Tag::context($tag), |writer| {
$item.write(writer)
});
};
derive_sequence! {
$name deriveDerWr($written, $writer) {
$($tail)*
}
}
};
($name:ident deriveDerWr($written:ident, $writer:expr) {
$item:ident : [$tag:tt] IMPLICIT OPTIONAL : $item_type:ty,
$($tail:tt)*
}) => {
if let Some($item) = $written.$item.as_ref() {
$writer.write_tagged_implicit(Tag::context($tag), |writer| {
$item.write(writer)
});
}
derive_sequence! {
$name deriveDerWr($written, $writer) {
$($tail)*
}
}
};
($name:ident deriveDerWr($written:ident, $writer:expr) {
$item:ident : [$tag:tt] UNTAGGED OPTIONAL : $item_type:ty,
$($tail:tt)*
}) => {
if let Some($item) = $written.$item.as_ref() {
$item.write($writer);
}
derive_sequence! {
$name deriveDerWr($written, $writer) {
$($tail)*
}
}
};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) { }) => {};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) {
$item:ident : [$tag:tt] EXPLICIT REQUIRED : $item_type:ty,
$($tail:tt)*
}) => {
#[allow(non_camel_case_types, non_snake_case)]
let $item = $next_reader.read_tagged(Tag::context($tag), |reader| {
<$item_type as BERDecodable>::decode_ber(reader)
})?;
derive_sequence! {
$name deriveBerRd($reader, $next_reader) {
$($tail)*
}
}
};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) {
$item:ident : [$tag:tt] IMPLICIT REQUIRED : $item_type:ty,
$($tail:tt)*
}) => {
#[allow(non_camel_case_types, non_snake_case)]
let $item= $next_reader.read_tagged_implicit(Tag::context($tag), |reader| {
<$item_type as BERDecodable>::decode_ber(reader)
})?;
derive_sequence! {
$name deriveBerRd($reader, $next_reader) {
$($tail)*
}
}
};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) {
$item:ident : [$tag:tt] UNTAGGED REQUIRED : $item_type:ty,
$($tail:tt)*
}) => {
#[allow(non_camel_case_types, non_snake_case)]
let $item = <$item_type as BERDecodable>::decode_ber($next_reader)?;
derive_sequence! {
$name deriveBerRd($reader, $next_reader) {
$($tail)*
}
}
};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) {
$item:ident : [$tag:tt] EXPLICIT OPTIONAL : $item_type:ty,
$($tail:tt)*
}) => {
#[allow(non_camel_case_types, non_snake_case)]
let $item: $item_type = $reader.read_optional(|reader_optional| {
reader_optional.read_tagged(Tag::context($tag), |reader| {
<_ as BERDecodable>::decode_ber(reader)
})
})?;
derive_sequence! {
$name deriveBerRd($reader, $next_reader) {
$($tail)*
}
}
};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) {
$item:ident : [$tag:tt] IMPLICIT OPTIONAL : $item_type:ty,
$($tail:tt)*
}) => {
#[allow(non_camel_case_types, non_snake_case)]
let $item: $item_type = $reader.read_optional(|reader_optional| {
reader_optional.read_tagged_implicit(Tag::context($tag), |reader| {
<_ as BERDecodable>::decode_ber(reader)
})
})?;
derive_sequence! {
$name deriveBerRd($reader, $next_reader) {
$($tail)*
}
}
};
($name:ident deriveBerRd($reader:ident, $next_reader:expr) {
$item:ident : [$tag:tt] UNTAGGED OPTIONAL : $item_type:ty,
$($tail:tt)*
}) => {
#[allow(non_camel_case_types, non_snake_case)]
let $item: $item_type = $reader.read_optional(|reader_optional| {
<_ as BERDecodable>::decode_ber(reader_optional)
})?;
derive_sequence! {
$name deriveBerRd($reader, $next_reader) {
$($tail)*
}
}
};
}
#[macro_export]
macro_rules! define_version {
(
$(#[$outer:meta])*
$name:ident {
$($ver:ident = $n:expr),*,
}) => {
$(#[$outer])*
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum $name {
$($ver = $n),*,
}
impl DerWrite for $name {
fn write(&self, writer: DERWriter) {
((*self).clone() as u32).write(writer)
}
}
impl BERDecodable for $name {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
reader.read_u32().and_then(|n| {
match n {
$($n => Ok($name::$ver)),*,
_ => Err(ASN1Error::new(ASN1ErrorKind::Invalid))
}
})
}
}
}
}