#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::vec;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::mem;
use core::num::{
NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8,
};
use crate::writer::Writer;
use crate::{
parse, parse_single, BitString, ObjectIdentifier, OwnedBitString, ParseError, ParseErrorKind,
ParseLocation, ParseResult, Parser, Tag, WriteBuf, WriteError, WriteResult,
};
pub trait Asn1Readable<'a>: Sized {
fn parse(parser: &mut Parser<'a>) -> ParseResult<Self>;
fn can_parse(tag: Tag) -> bool;
}
pub trait SimpleAsn1Readable<'a>: Sized {
const TAG: Tag;
fn parse_data(data: &'a [u8]) -> ParseResult<Self>;
}
impl<'a, T: SimpleAsn1Readable<'a>> Asn1Readable<'a> for T {
#[inline]
fn parse(parser: &mut Parser<'a>) -> ParseResult<Self> {
let tlv = parser.read_tlv()?;
if !Self::can_parse(tlv.tag) {
return Err(ParseError::new(ParseErrorKind::UnexpectedTag {
actual: tlv.tag,
}));
}
Self::parse_data(tlv.data)
}
#[inline]
fn can_parse(tag: Tag) -> bool {
tag == Self::TAG
}
}
impl<'a, T: SimpleAsn1Readable<'a>> SimpleAsn1Readable<'a> for Box<T> {
const TAG: Tag = T::TAG;
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
Ok(Box::new(T::parse_data(data)?))
}
}
pub trait Asn1Writable: Sized {
type Error: From<WriteError>;
fn write(&self, dest: &mut Writer<'_>) -> Result<(), Self::Error>;
fn encoded_length(&self) -> Option<usize>;
}
pub trait SimpleAsn1Writable: Sized {
type Error: From<WriteError>;
const TAG: Tag;
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error>;
fn data_length(&self) -> Option<usize>;
}
pub trait Asn1DefinedByReadable<'a, T: Asn1Readable<'a>>: Sized {
fn parse(item: T, parser: &mut Parser<'a>) -> ParseResult<Self>;
}
pub trait Asn1DefinedByWritable<T: Asn1Writable>: Sized {
type Error: From<WriteError>;
fn item(&self) -> &T;
fn write(&self, dest: &mut Writer<'_>) -> Result<(), Self::Error>;
fn encoded_length(&self) -> Option<usize>;
}
impl<T: SimpleAsn1Writable> Asn1Writable for T {
type Error = T::Error;
#[inline]
fn write(&self, w: &mut Writer<'_>) -> Result<(), Self::Error> {
w.write_tlv(Self::TAG, self.data_length(), move |dest| {
self.write_data(dest)
})
}
fn encoded_length(&self) -> Option<usize> {
Some(Tlv::full_length(Self::TAG, self.data_length()?))
}
}
impl<T: SimpleAsn1Writable> SimpleAsn1Writable for &T {
type Error = T::Error;
const TAG: Tag = T::TAG;
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
T::write_data(self, dest)
}
fn data_length(&self) -> Option<usize> {
T::data_length(self)
}
}
impl<T: SimpleAsn1Writable> SimpleAsn1Writable for Box<T> {
type Error = T::Error;
const TAG: Tag = T::TAG;
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
T::write_data(self, dest)
}
fn data_length(&self) -> Option<usize> {
T::data_length(self)
}
}
#[derive(Debug, PartialEq, Hash, Clone, Copy, Eq)]
pub struct Tlv<'a> {
pub(crate) tag: Tag,
pub(crate) data: &'a [u8],
pub(crate) full_data: &'a [u8],
}
impl<'a> Tlv<'a> {
pub(crate) fn full_length(t: Tag, inner_length: usize) -> usize {
t.encoded_length() + crate::writer::length_encoding_size(inner_length) + inner_length
}
pub fn tag(&self) -> Tag {
self.tag
}
pub fn tag_bytes(&self) -> &'a [u8] {
&self.full_data[..self.tag.encoded_length()]
}
pub fn data(&self) -> &'a [u8] {
self.data
}
pub fn full_data(&self) -> &'a [u8] {
self.full_data
}
pub fn parse<T: Asn1Readable<'a>>(&self) -> ParseResult<T> {
parse_single::<T>(self.full_data)
}
}
impl<'a> Asn1Readable<'a> for Tlv<'a> {
#[inline]
fn parse(parser: &mut Parser<'a>) -> ParseResult<Self> {
parser.read_tlv()
}
#[inline]
fn can_parse(_tag: Tag) -> bool {
true
}
}
impl Asn1Writable for Tlv<'_> {
type Error = WriteError;
#[inline]
fn write(&self, w: &mut Writer<'_>) -> WriteResult {
w.write_tlv(self.tag, Some(self.data.len()), move |dest| {
dest.push_slice(self.data)
})
}
fn encoded_length(&self) -> Option<usize> {
Some(Tlv::full_length(self.tag, self.data.len()))
}
}
impl Asn1Writable for &Tlv<'_> {
type Error = WriteError;
#[inline]
fn write(&self, w: &mut Writer<'_>) -> WriteResult {
Tlv::write(self, w)
}
fn encoded_length(&self) -> Option<usize> {
Tlv::encoded_length(self)
}
}
pub type Null = ();
impl SimpleAsn1Readable<'_> for Null {
const TAG: Tag = Tag::primitive(0x05);
#[inline]
fn parse_data(data: &[u8]) -> ParseResult<Null> {
if data.is_empty() {
Ok(())
} else {
Err(ParseError::new(ParseErrorKind::InvalidValue))
}
}
}
impl SimpleAsn1Writable for Null {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x05);
#[inline]
fn write_data(&self, _dest: &mut WriteBuf) -> WriteResult {
Ok(())
}
fn data_length(&self) -> Option<usize> {
Some(0)
}
}
impl SimpleAsn1Readable<'_> for bool {
const TAG: Tag = Tag::primitive(0x1);
fn parse_data(data: &[u8]) -> ParseResult<bool> {
match data {
b"\x00" => Ok(false),
b"\xff" => Ok(true),
_ => Err(ParseError::new(ParseErrorKind::InvalidValue)),
}
}
}
impl SimpleAsn1Writable for bool {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x1);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
if *self {
dest.push_byte(0xff)
} else {
dest.push_byte(0x00)
}
}
fn data_length(&self) -> Option<usize> {
Some(1)
}
}
impl<'a> SimpleAsn1Readable<'a> for &'a [u8] {
const TAG: Tag = Tag::primitive(0x04);
fn parse_data(data: &'a [u8]) -> ParseResult<&'a [u8]> {
Ok(data)
}
}
impl SimpleAsn1Writable for &[u8] {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x04);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self)
}
fn data_length(&self) -> Option<usize> {
Some(self.len())
}
}
impl<const N: usize> SimpleAsn1Readable<'_> for [u8; N] {
const TAG: Tag = Tag::primitive(0x04);
fn parse_data(data: &[u8]) -> ParseResult<[u8; N]> {
data.try_into()
.map_err(|_| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl<const N: usize> SimpleAsn1Writable for [u8; N] {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x04);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self)
}
fn data_length(&self) -> Option<usize> {
Some(N)
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct OctetStringEncoded<T>(T);
impl<T> OctetStringEncoded<T> {
pub fn new(v: T) -> OctetStringEncoded<T> {
OctetStringEncoded(v)
}
pub fn get(&self) -> &T {
&self.0
}
pub fn into_inner(self) -> T {
self.0
}
}
impl<'a, T: Asn1Readable<'a>> SimpleAsn1Readable<'a> for OctetStringEncoded<T> {
const TAG: Tag = Tag::primitive(0x04);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
Ok(OctetStringEncoded::new(parse_single(data)?))
}
}
impl<T: Asn1Writable> SimpleAsn1Writable for OctetStringEncoded<T> {
type Error = T::Error;
const TAG: Tag = Tag::primitive(0x04);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
self.0.write(&mut Writer::new(dest))
}
fn data_length(&self) -> Option<usize> {
self.0.encoded_length()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PrintableString<'a>(&'a str);
impl<'a> PrintableString<'a> {
pub fn new(s: &'a str) -> Option<PrintableString<'a>> {
if PrintableString::verify(s.as_bytes()) {
Some(PrintableString(s))
} else {
None
}
}
fn new_from_bytes(s: &'a [u8]) -> Option<PrintableString<'a>> {
if PrintableString::verify(s) {
Some(PrintableString(core::str::from_utf8(s).unwrap()))
} else {
None
}
}
pub fn as_str(&self) -> &'a str {
self.0
}
fn verify(data: &[u8]) -> bool {
for b in data {
match b {
b'A'..=b'Z'
| b'a'..=b'z'
| b'0'..=b'9'
| b' '
| b'\''
| b'('
| b')'
| b'+'
| b','
| b'-'
| b'.'
| b'/'
| b':'
| b'='
| b'?' => {}
_ => return false,
};
}
true
}
}
impl<'a> SimpleAsn1Readable<'a> for PrintableString<'a> {
const TAG: Tag = Tag::primitive(0x13);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
PrintableString::new_from_bytes(data)
.ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for PrintableString<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x13);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.0.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.0.len())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IA5String<'a>(&'a str);
impl<'a> IA5String<'a> {
pub fn new(s: &'a str) -> Option<IA5String<'a>> {
if IA5String::verify(s.as_bytes()) {
Some(IA5String(s))
} else {
None
}
}
fn new_from_bytes(s: &'a [u8]) -> Option<IA5String<'a>> {
if IA5String::verify(s) {
Some(IA5String(core::str::from_utf8(s).unwrap()))
} else {
None
}
}
fn verify(s: &[u8]) -> bool {
s.is_ascii()
}
pub fn as_str(&self) -> &'a str {
self.0
}
}
impl<'a> SimpleAsn1Readable<'a> for IA5String<'a> {
const TAG: Tag = Tag::primitive(0x16);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
IA5String::new_from_bytes(data).ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for IA5String<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x16);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.0.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.0.len())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Utf8String<'a>(&'a str);
impl<'a> Utf8String<'a> {
pub fn new(s: &'a str) -> Utf8String<'a> {
Utf8String(s)
}
fn new_from_bytes(s: &'a [u8]) -> Option<Utf8String<'a>> {
Some(Utf8String(core::str::from_utf8(s).ok()?))
}
pub fn as_str(&self) -> &'a str {
self.0
}
}
impl<'a> SimpleAsn1Readable<'a> for Utf8String<'a> {
const TAG: Tag = Tag::primitive(0x0c);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
Utf8String::new_from_bytes(data)
.ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for Utf8String<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x0c);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.0.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.0.len())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VisibleString<'a>(&'a str);
impl<'a> VisibleString<'a> {
pub fn new(s: &'a str) -> Option<VisibleString<'a>> {
if VisibleString::verify(s.as_bytes()) {
Some(VisibleString(s))
} else {
None
}
}
fn new_from_bytes(s: &'a [u8]) -> Option<VisibleString<'a>> {
if VisibleString::verify(s) {
Some(VisibleString(core::str::from_utf8(s).unwrap()))
} else {
None
}
}
fn verify(s: &[u8]) -> bool {
for b in s {
if !(b.is_ascii_graphic() || *b == b' ') {
return false;
}
}
true
}
pub fn as_str(&self) -> &'a str {
self.0
}
}
impl<'a> SimpleAsn1Readable<'a> for VisibleString<'a> {
const TAG: Tag = Tag::primitive(0x1a);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
VisibleString::new_from_bytes(data)
.ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for VisibleString<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x1a);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.0.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.0.len())
}
}
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub struct BMPString<'a>(&'a [u8]);
impl<'a> BMPString<'a> {
pub fn new(b: &'a [u8]) -> Option<BMPString<'a>> {
if BMPString::verify(b) {
Some(BMPString(b))
} else {
None
}
}
fn verify(b: &[u8]) -> bool {
if b.len() % 2 == 1 {
return false;
}
for r in core::char::decode_utf16(
b.chunks_exact(2)
.map(|v| u16::from_be_bytes(v.try_into().unwrap())),
) {
if r.is_err() {
return false;
}
}
true
}
pub fn as_utf16_be_bytes(&self) -> &'a [u8] {
self.0
}
}
impl<'a> SimpleAsn1Readable<'a> for BMPString<'a> {
const TAG: Tag = Tag::primitive(0x1e);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
BMPString::new(data).ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for BMPString<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x1e);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_utf16_be_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_utf16_be_bytes().len())
}
}
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub struct UniversalString<'a>(&'a [u8]);
impl<'a> UniversalString<'a> {
pub fn new(b: &'a [u8]) -> Option<UniversalString<'a>> {
if UniversalString::verify(b) {
Some(UniversalString(b))
} else {
None
}
}
fn verify(b: &[u8]) -> bool {
if b.len() % 4 != 0 {
return false;
}
for r in b
.chunks_exact(4)
.map(|v| u32::from_be_bytes(v.try_into().unwrap()))
{
if core::char::from_u32(r).is_none() {
return false;
}
}
true
}
pub fn as_utf32_be_bytes(&self) -> &'a [u8] {
self.0
}
}
impl<'a> SimpleAsn1Readable<'a> for UniversalString<'a> {
const TAG: Tag = Tag::primitive(0x1c);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
UniversalString::new(data).ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for UniversalString<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x1c);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_utf32_be_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_utf32_be_bytes().len())
}
}
fn bigint_bit_length(data: &[u8]) -> usize {
if data[0] & 0x80 == 0 {
let data = if data[0] == 0x00 { &data[1..] } else { data };
match data.first() {
None => 0,
Some(&b) => (data.len() - 1) * 8 + (8 - b.leading_zeros() as usize),
}
} else {
let skip = data.iter().take_while(|&&b| b == 0xff).count();
if skip == data.len() {
return 1; }
let inv = !data[skip];
let bits = (data.len() - skip - 1) * 8 + (8 - inv.leading_zeros() as usize);
let pow2 =
inv.count_zeros() == inv.leading_zeros() && data[skip + 1..].iter().all(|&b| b == 0x00);
bits + pow2 as usize
}
}
const fn validate_integer(data: &[u8], signed: bool) -> ParseResult<()> {
if data.is_empty() {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
if data.len() > 1
&& ((data[0] == 0 && data[1] & 0x80 == 0) || (data[0] == 0xff && data[1] & 0x80 == 0x80))
{
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
if !signed && data[0] & 0x80 == 0x80 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
Ok(())
}
macro_rules! impl_asn1_element_for_int {
($t:ty; $signed:expr) => {
impl SimpleAsn1Readable<'_> for $t {
const TAG: Tag = Tag::primitive(0x02);
#[inline]
fn parse_data(mut data: &[u8]) -> ParseResult<Self> {
validate_integer(data, $signed)?;
if !$signed && data.len() == mem::size_of::<Self>() + 1 && data[0] == 0 {
data = &data[1..];
}
if data.len() > mem::size_of::<Self>() {
return Err(ParseError::new(ParseErrorKind::IntegerOverflow));
}
let mut fixed_data = [0; mem::size_of::<$t>()];
fixed_data[mem::size_of::<Self>() - data.len()..].copy_from_slice(data);
let mut ret = Self::from_be_bytes(fixed_data);
ret <<= (8 * mem::size_of::<Self>()) - data.len() * 8;
ret >>= (8 * mem::size_of::<Self>()) - data.len() * 8;
Ok(ret)
}
}
impl SimpleAsn1Writable for $t {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x02);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
let num_bytes = self.data_length().unwrap() as u32;
for i in (1..=num_bytes).rev() {
let digit = self.checked_shr((i - 1) * 8).unwrap_or(0);
dest.push_byte(digit as u8)?;
}
Ok(())
}
fn data_length(&self) -> Option<usize> {
let mut num_bytes = 1;
let mut v: $t = *self;
#[allow(unused_comparisons)]
while v > 127 || ($signed && v < (-128i64) as $t) {
num_bytes += 1;
v = v.checked_shr(8).unwrap_or(0);
}
Some(num_bytes)
}
}
};
}
macro_rules! impl_asn1_write_for_nonzero_int {
($t:ty, $inner_type:ty) => {
impl SimpleAsn1Writable for $t {
type Error = WriteError;
const TAG: Tag = <$inner_type as SimpleAsn1Writable>::TAG;
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
<$inner_type>::from(*self).write_data(dest)
}
fn data_length(&self) -> Option<usize> {
<$inner_type>::from(*self).data_length()
}
}
};
}
impl_asn1_element_for_int!(i8; true);
impl_asn1_element_for_int!(u8; false);
impl_asn1_element_for_int!(i16; true);
impl_asn1_element_for_int!(u16; false);
impl_asn1_element_for_int!(i32; true);
impl_asn1_element_for_int!(u32; false);
impl_asn1_element_for_int!(i64; true);
impl_asn1_element_for_int!(u64; false);
impl_asn1_write_for_nonzero_int!(NonZeroI8, i8);
impl_asn1_write_for_nonzero_int!(NonZeroI16, i16);
impl_asn1_write_for_nonzero_int!(NonZeroI32, i32);
impl_asn1_write_for_nonzero_int!(NonZeroI64, i64);
impl_asn1_write_for_nonzero_int!(NonZeroU8, u8);
impl_asn1_write_for_nonzero_int!(NonZeroU16, u16);
impl_asn1_write_for_nonzero_int!(NonZeroU32, u32);
impl_asn1_write_for_nonzero_int!(NonZeroU64, u64);
#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)]
pub struct BigUint<'a> {
data: &'a [u8],
}
impl<'a> BigUint<'a> {
pub const fn new(data: &'a [u8]) -> Option<Self> {
match validate_integer(data, false) {
Ok(()) => Some(BigUint { data }),
Err(_) => None,
}
}
pub fn as_bytes(&self) -> &'a [u8] {
self.data
}
}
impl<'a> SimpleAsn1Readable<'a> for BigUint<'a> {
const TAG: Tag = Tag::primitive(0x02);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
BigUint::new(data).ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for BigUint<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x02);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_bytes().len())
}
}
#[derive(PartialEq, Clone, Debug, Hash, Eq)]
pub struct OwnedBigUint {
data: Vec<u8>,
}
impl OwnedBigUint {
pub fn new(data: Vec<u8>) -> Option<Self> {
validate_integer(&data, false).ok()?;
Some(OwnedBigUint { data })
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
}
impl SimpleAsn1Readable<'_> for OwnedBigUint {
const TAG: Tag = Tag::primitive(0x02);
fn parse_data(data: &[u8]) -> ParseResult<Self> {
OwnedBigUint::new(data.to_vec())
.ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for OwnedBigUint {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x02);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_bytes().len())
}
}
#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)]
pub struct BigInt<'a> {
data: &'a [u8],
}
impl<'a> BigInt<'a> {
pub const fn new(data: &'a [u8]) -> Option<Self> {
match validate_integer(data, true) {
Ok(()) => Some(BigInt { data }),
Err(_) => None,
}
}
pub fn as_bytes(&self) -> &'a [u8] {
self.data
}
pub fn is_negative(&self) -> bool {
self.data[0] & 0x80 == 0x80
}
pub fn bit_length(&self) -> usize {
bigint_bit_length(self.data)
}
}
impl<'a> SimpleAsn1Readable<'a> for BigInt<'a> {
const TAG: Tag = Tag::primitive(0x02);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
BigInt::new(data).ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for BigInt<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x02);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_bytes().len())
}
}
#[derive(PartialEq, Clone, Debug, Hash, Eq)]
pub struct OwnedBigInt {
data: Vec<u8>,
}
impl OwnedBigInt {
pub fn new(data: Vec<u8>) -> Option<Self> {
validate_integer(&data, true).ok()?;
Some(OwnedBigInt { data })
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
pub fn is_negative(&self) -> bool {
self.data[0] & 0x80 == 0x80
}
pub fn bit_length(&self) -> usize {
bigint_bit_length(&self.data)
}
}
impl SimpleAsn1Readable<'_> for OwnedBigInt {
const TAG: Tag = Tag::primitive(0x02);
fn parse_data(data: &[u8]) -> ParseResult<Self> {
OwnedBigInt::new(data.to_vec()).ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for OwnedBigInt {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x02);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_bytes().len())
}
}
impl<'a> SimpleAsn1Readable<'a> for ObjectIdentifier {
const TAG: Tag = Tag::primitive(0x06);
fn parse_data(data: &'a [u8]) -> ParseResult<ObjectIdentifier> {
ObjectIdentifier::from_der(data)
}
}
impl SimpleAsn1Writable for ObjectIdentifier {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x06);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_slice(self.as_der())
}
fn data_length(&self) -> Option<usize> {
Some(self.as_der().len())
}
}
impl<'a> SimpleAsn1Readable<'a> for BitString<'a> {
const TAG: Tag = Tag::primitive(0x03);
fn parse_data(data: &'a [u8]) -> ParseResult<BitString<'a>> {
if data.is_empty() {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
BitString::new(&data[1..], data[0])
.ok_or_else(|| ParseError::new(ParseErrorKind::InvalidValue))
}
}
impl SimpleAsn1Writable for BitString<'_> {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x03);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
dest.push_byte(self.padding_bits())?;
dest.push_slice(self.as_bytes())
}
fn data_length(&self) -> Option<usize> {
Some(1 + self.as_bytes().len())
}
}
impl<'a> SimpleAsn1Readable<'a> for OwnedBitString {
const TAG: Tag = Tag::primitive(0x03);
fn parse_data(data: &'a [u8]) -> ParseResult<OwnedBitString> {
let bs = BitString::parse_data(data)?;
Ok(OwnedBitString::new(bs.as_bytes().to_vec(), bs.padding_bits()).unwrap())
}
}
impl SimpleAsn1Writable for OwnedBitString {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x03);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
self.as_bitstring().write_data(dest)
}
fn data_length(&self) -> Option<usize> {
self.as_bitstring().data_length()
}
}
fn read_byte(data: &mut &[u8]) -> ParseResult<u8> {
if data.is_empty() {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
let result = Ok(data[0]);
*data = &data[1..];
result
}
fn read_digit(data: &mut &[u8]) -> ParseResult<u8> {
let b = read_byte(data)?;
if !b.is_ascii_digit() {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
Ok(b - b'0')
}
fn read_2_digits(data: &mut &[u8]) -> ParseResult<u8> {
Ok(read_digit(data)? * 10 + read_digit(data)?)
}
fn read_4_digits(data: &mut &[u8]) -> ParseResult<u16> {
Ok(u16::from(read_digit(data)?) * 1000
+ u16::from(read_digit(data)?) * 100
+ u16::from(read_digit(data)?) * 10
+ u16::from(read_digit(data)?))
}
const fn validate_date(year: u16, month: u8, day: u8) -> ParseResult<()> {
if day < 1 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
let days_in_month = match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => {
if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 {
29
} else {
28
}
}
_ => return Err(ParseError::new(ParseErrorKind::InvalidValue)),
};
if day > days_in_month {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
Ok(())
}
fn read_tz_and_finish(data: &mut &[u8]) -> ParseResult<()> {
if read_byte(data)? != b'Z' {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
if !data.is_empty() {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
Ok(())
}
fn push_two_digits(dest: &mut WriteBuf, val: u8) -> WriteResult {
dest.push_byte(b'0' + ((val / 10) % 10))?;
dest.push_byte(b'0' + (val % 10))
}
fn push_four_digits(dest: &mut WriteBuf, val: u16) -> WriteResult {
dest.push_byte(b'0' + ((val / 1000) % 10) as u8)?;
dest.push_byte(b'0' + ((val / 100) % 10) as u8)?;
dest.push_byte(b'0' + ((val / 10) % 10) as u8)?;
dest.push_byte(b'0' + (val % 10) as u8)
}
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd)]
pub struct DateTime {
year: u16,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
}
impl DateTime {
pub const fn new(
year: u16,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
) -> ParseResult<DateTime> {
if hour > 23 || minute > 59 || second > 59 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
match validate_date(year, month, day) {
Ok(()) => Ok(DateTime {
year,
month,
day,
hour,
minute,
second,
}),
Err(e) => Err(e),
}
}
pub fn year(&self) -> u16 {
self.year
}
pub fn month(&self) -> u8 {
self.month
}
pub fn day(&self) -> u8 {
self.day
}
pub fn hour(&self) -> u8 {
self.hour
}
pub fn minute(&self) -> u8 {
self.minute
}
pub fn second(&self) -> u8 {
self.second
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
pub struct UtcTime(DateTime);
impl UtcTime {
pub fn new(dt: DateTime) -> ParseResult<UtcTime> {
if dt.year() < 1950 || dt.year() >= 2050 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
Ok(UtcTime(dt))
}
pub fn as_datetime(&self) -> &DateTime {
&self.0
}
}
impl SimpleAsn1Readable<'_> for UtcTime {
const TAG: Tag = Tag::primitive(0x17);
fn parse_data(mut data: &[u8]) -> ParseResult<Self> {
let year = u16::from(read_2_digits(&mut data)?);
let month = read_2_digits(&mut data)?;
let day = read_2_digits(&mut data)?;
let year = if year >= 50 { 1900 + year } else { 2000 + year };
let hour = read_2_digits(&mut data)?;
let minute = read_2_digits(&mut data)?;
let second = read_2_digits(&mut data)?;
read_tz_and_finish(&mut data)?;
UtcTime::new(DateTime::new(year, month, day, hour, minute, second)?)
}
}
impl SimpleAsn1Writable for UtcTime {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x17);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
let dt = self.as_datetime();
let year = if 1950 <= dt.year() && dt.year() < 2000 {
dt.year() - 1900
} else {
assert!(2000 <= dt.year() && dt.year() < 2050);
dt.year() - 2000
};
push_two_digits(dest, year.try_into().unwrap())?;
push_two_digits(dest, dt.month())?;
push_two_digits(dest, dt.day())?;
push_two_digits(dest, dt.hour())?;
push_two_digits(dest, dt.minute())?;
push_two_digits(dest, dt.second())?;
dest.push_byte(b'Z')
}
fn data_length(&self) -> Option<usize> {
Some(13)
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
pub struct X509GeneralizedTime(DateTime);
impl X509GeneralizedTime {
pub fn new(dt: DateTime) -> ParseResult<X509GeneralizedTime> {
Ok(X509GeneralizedTime(dt))
}
pub fn as_datetime(&self) -> &DateTime {
&self.0
}
}
impl SimpleAsn1Readable<'_> for X509GeneralizedTime {
const TAG: Tag = Tag::primitive(0x18);
fn parse_data(mut data: &[u8]) -> ParseResult<X509GeneralizedTime> {
let year = read_4_digits(&mut data)?;
let month = read_2_digits(&mut data)?;
let day = read_2_digits(&mut data)?;
let hour = read_2_digits(&mut data)?;
let minute = read_2_digits(&mut data)?;
let second = read_2_digits(&mut data)?;
read_tz_and_finish(&mut data)?;
X509GeneralizedTime::new(DateTime::new(year, month, day, hour, minute, second)?)
}
}
impl SimpleAsn1Writable for X509GeneralizedTime {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x18);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
let dt = self.as_datetime();
push_four_digits(dest, dt.year())?;
push_two_digits(dest, dt.month())?;
push_two_digits(dest, dt.day())?;
push_two_digits(dest, dt.hour())?;
push_two_digits(dest, dt.minute())?;
push_two_digits(dest, dt.second())?;
dest.push_byte(b'Z')
}
fn data_length(&self) -> Option<usize> {
Some(15) }
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash, Eq)]
pub struct GeneralizedTime {
datetime: DateTime,
nanoseconds: Option<u32>,
}
impl GeneralizedTime {
pub fn new(dt: DateTime, nanoseconds: Option<u32>) -> ParseResult<GeneralizedTime> {
if let Some(val) = nanoseconds {
if val < 1 || val >= 1e9 as u32 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
}
Ok(GeneralizedTime {
datetime: dt,
nanoseconds,
})
}
pub fn as_datetime(&self) -> &DateTime {
&self.datetime
}
pub fn nanoseconds(&self) -> Option<u32> {
self.nanoseconds
}
}
fn read_fractional_time(data: &mut &[u8]) -> ParseResult<Option<u32>> {
if data.first() == Some(&b'.') {
*data = &data[1..];
let mut fraction = 0u32;
let mut digits = 0;
for b in data.iter().take(9) {
if !b.is_ascii_digit() {
if digits == 0 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
break;
}
fraction = fraction * 10 + (b - b'0') as u32;
digits += 1;
}
*data = &data[digits..];
if fraction % 10 == 0 {
return Err(ParseError::new(ParseErrorKind::InvalidValue));
}
let nanoseconds: u32 = fraction * 10u32.pow(9 - digits as u32);
Ok(Some(nanoseconds))
} else {
Ok(None)
}
}
impl SimpleAsn1Readable<'_> for GeneralizedTime {
const TAG: Tag = Tag::primitive(0x18);
fn parse_data(mut data: &[u8]) -> ParseResult<GeneralizedTime> {
let year = read_4_digits(&mut data)?;
let month = read_2_digits(&mut data)?;
let day = read_2_digits(&mut data)?;
let hour = read_2_digits(&mut data)?;
let minute = read_2_digits(&mut data)?;
let second = read_2_digits(&mut data)?;
let fraction = read_fractional_time(&mut data)?;
read_tz_and_finish(&mut data)?;
GeneralizedTime::new(
DateTime::new(year, month, day, hour, minute, second)?,
fraction,
)
}
}
impl SimpleAsn1Writable for GeneralizedTime {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0x18);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
let dt = self.as_datetime();
push_four_digits(dest, dt.year())?;
push_two_digits(dest, dt.month())?;
push_two_digits(dest, dt.day())?;
push_two_digits(dest, dt.hour())?;
push_two_digits(dest, dt.minute())?;
push_two_digits(dest, dt.second())?;
if let Some(nanoseconds) = self.nanoseconds() {
dest.push_byte(b'.')?;
let mut buf = itoa::Buffer::new();
let nanos = buf.format(nanoseconds);
let pad = 9 - nanos.len();
let nanos = nanos.trim_end_matches('0');
for _ in 0..pad {
dest.push_byte(b'0')?;
}
dest.push_slice(nanos.as_bytes())?;
}
dest.push_byte(b'Z')
}
fn data_length(&self) -> Option<usize> {
let base_len = 15; if let Some(nanoseconds) = self.nanoseconds() {
let mut buf = itoa::Buffer::new();
let nanos = buf.format(nanoseconds);
let pad = 9 - nanos.len();
let nanos = nanos.trim_end_matches('0');
Some(base_len + 1 + pad + nanos.len()) } else {
Some(base_len)
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Enumerated(u32);
impl Enumerated {
pub fn new(v: u32) -> Enumerated {
Enumerated(v)
}
pub fn value(&self) -> u32 {
self.0
}
}
impl<'a> SimpleAsn1Readable<'a> for Enumerated {
const TAG: Tag = Tag::primitive(0xa);
fn parse_data(data: &'a [u8]) -> ParseResult<Enumerated> {
Ok(Enumerated::new(u32::parse_data(data)?))
}
}
impl SimpleAsn1Writable for Enumerated {
type Error = WriteError;
const TAG: Tag = Tag::primitive(0xa);
fn write_data(&self, dest: &mut WriteBuf) -> WriteResult {
u32::write_data(&self.value(), dest)
}
fn data_length(&self) -> Option<usize> {
self.value().data_length()
}
}
impl<'a, T: Asn1Readable<'a>> Asn1Readable<'a> for Option<T> {
fn parse(parser: &mut Parser<'a>) -> ParseResult<Self> {
match parser.peek_tag() {
Some(tag) if Self::can_parse(tag) => Ok(Some(parser.read_element::<T>()?)),
Some(_) | None => Ok(None),
}
}
#[inline]
fn can_parse(tag: Tag) -> bool {
T::can_parse(tag)
}
}
impl<T: Asn1Writable> Asn1Writable for Option<T> {
type Error = T::Error;
#[inline]
fn write(&self, w: &mut Writer<'_>) -> Result<(), Self::Error> {
if let Some(v) = self {
w.write_element(v)
} else {
Ok(())
}
}
fn encoded_length(&self) -> Option<usize> {
match self {
Some(v) => v.encoded_length(),
None => Some(0),
}
}
}
macro_rules! declare_choice {
($count:ident => $(($number:ident $name:ident)),+) => {
#[derive(Debug, PartialEq, Eq)]
pub enum $count<
$($number,)+
> {
$(
$name($number),
)*
}
impl<
'a,
$(
$number: Asn1Readable<'a>,
)*
> Asn1Readable<'a> for $count<$($number,)+> {
fn parse(parser: &mut Parser<'a>) -> ParseResult<Self> {
let tlv = parser.read_tlv()?;
$(
if $number::can_parse(tlv.tag()) {
return Ok($count::$name(tlv.parse::<$number>()?));
}
)+
Err(ParseError::new(ParseErrorKind::UnexpectedTag{actual: tlv.tag()}))
}
fn can_parse(tag: Tag) -> bool {
$(
if $number::can_parse(tag) {
return true;
}
)+
false
}
}
impl<
$(
$number: Asn1Writable<Error = WriteError>,
)+
> Asn1Writable for $count<$($number,)+> {
type Error = WriteError;
fn write(&self, w: &mut Writer<'_>) -> WriteResult {
match self {
$(
$count::$name(v) => w.write_element(v),
)+
}
}
fn encoded_length(&self) -> Option<usize> {
match self {
$(
$count::$name(v) => Asn1Writable::encoded_length(v),
)+
}
}
}
}
}
declare_choice!(Choice1 => (T1 ChoiceA));
declare_choice!(Choice2 => (T1 ChoiceA), (T2 ChoiceB));
declare_choice!(Choice3 => (T1 ChoiceA), (T2 ChoiceB), (T3 ChoiceC));
#[derive(Debug, PartialEq, Hash, Clone, Eq)]
pub struct Sequence<'a> {
data: &'a [u8],
}
impl<'a> Sequence<'a> {
#[inline]
pub(crate) fn new(data: &'a [u8]) -> Sequence<'a> {
Sequence { data }
}
pub fn parse<T, E: From<ParseError>, F: Fn(&mut Parser<'a>) -> Result<T, E>>(
self,
f: F,
) -> Result<T, E> {
parse(self.data, f)
}
}
impl<'a> SimpleAsn1Readable<'a> for Sequence<'a> {
const TAG: Tag = Tag::constructed(0x10);
#[inline]
fn parse_data(data: &'a [u8]) -> ParseResult<Sequence<'a>> {
Ok(Sequence::new(data))
}
}
impl SimpleAsn1Writable for Sequence<'_> {
type Error = WriteError;
const TAG: Tag = Tag::constructed(0x10);
#[inline]
fn write_data(&self, data: &mut WriteBuf) -> WriteResult {
data.push_slice(self.data)
}
fn data_length(&self) -> Option<usize> {
Some(self.data.len())
}
}
pub struct SequenceWriter<'a, E: From<WriteError> = WriteError> {
f: &'a dyn Fn(&mut Writer<'_>) -> Result<(), E>,
}
impl<'a, E: From<WriteError>> SequenceWriter<'a, E> {
#[inline]
pub fn new(f: &'a dyn Fn(&mut Writer<'_>) -> Result<(), E>) -> Self {
SequenceWriter { f }
}
}
impl<E: From<WriteError>> SimpleAsn1Writable for SequenceWriter<'_, E> {
type Error = E;
const TAG: Tag = Tag::constructed(0x10);
#[inline]
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), E> {
(self.f)(&mut Writer::new(dest))
}
fn data_length(&self) -> Option<usize> {
None
}
}
pub struct SequenceOf<
'a,
T,
const MINIMUM_LEN: usize = 0,
const MAXIMUM_LEN: usize = { usize::MAX },
> {
parser: Parser<'a>,
length: usize,
_phantom: PhantomData<T>,
}
impl<'a, T: Asn1Readable<'a>, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize>
SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
#[inline]
pub(crate) fn new(data: &'a [u8]) -> ParseResult<SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>> {
let length = parse(data, |p| {
let mut i = 0;
while !p.is_empty() {
p.read_element::<T>()
.map_err(|e| e.add_location(ParseLocation::Index(i)))?;
i += 1;
}
Ok(i)
})?;
if length < MINIMUM_LEN || length > MAXIMUM_LEN {
return Err(ParseError::new(ParseErrorKind::InvalidSize {
min: MINIMUM_LEN,
max: MAXIMUM_LEN,
actual: length,
}));
}
Ok(Self {
length,
parser: Parser::new(data),
_phantom: PhantomData,
})
}
pub fn len(&self) -> usize {
self.length
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a, T: Asn1Readable<'a>, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize> Clone
for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
fn clone(&self) -> SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN> {
SequenceOf {
parser: self.parser.clone_internal(),
length: self.length,
_phantom: PhantomData,
}
}
}
impl<'a, T: Asn1Readable<'a> + PartialEq, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize>
PartialEq for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
fn eq(&self, other: &Self) -> bool {
let mut it1 = self.clone();
let mut it2 = other.clone();
loop {
match (it1.next(), it2.next()) {
(Some(v1), Some(v2)) => {
if v1 != v2 {
return false;
}
}
(None, None) => return true,
_ => return false,
}
}
}
}
impl<'a, T: Asn1Readable<'a> + Eq, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize> Eq
for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
}
impl<'a, T: Asn1Readable<'a> + Hash, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize> Hash
for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
fn hash<H: Hasher>(&self, state: &mut H) {
for val in self.clone() {
val.hash(state);
}
}
}
impl<'a, T: Asn1Readable<'a> + 'a, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize>
SimpleAsn1Readable<'a> for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
const TAG: Tag = Tag::constructed(0x10);
#[inline]
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
SequenceOf::new(data)
}
}
impl<'a, T: Asn1Readable<'a>, const MINIMUM_LEN: usize, const MAXIMUM_LEN: usize> Iterator
for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.is_empty() {
return None;
}
self.length -= 1;
Some(
self.parser
.read_element::<T>()
.expect("Should always succeed"),
)
}
}
impl<
'a,
T: Asn1Readable<'a> + Asn1Writable,
const MINIMUM_LEN: usize,
const MAXIMUM_LEN: usize,
> SimpleAsn1Writable for SequenceOf<'a, T, MINIMUM_LEN, MAXIMUM_LEN>
{
type Error = <T as Asn1Writable>::Error;
const TAG: Tag = Tag::constructed(0x10);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
let mut w = Writer::new(dest);
for el in self.clone() {
w.write_element(&el)?;
}
Ok(())
}
fn data_length(&self) -> Option<usize> {
let iter = self.clone();
iter.map(|el| el.encoded_length()).sum()
}
}
#[derive(Hash, PartialEq, Eq, Clone)]
pub struct SequenceOfWriter<'a, T, V: Borrow<[T]> = &'a [T]> {
vals: V,
_phantom: PhantomData<&'a T>,
}
impl<T, V: Borrow<[T]>> SequenceOfWriter<'_, T, V> {
pub fn new(vals: V) -> Self {
SequenceOfWriter {
vals,
_phantom: PhantomData,
}
}
}
impl<T: Asn1Writable, V: Borrow<[T]>> SimpleAsn1Writable for SequenceOfWriter<'_, T, V> {
type Error = T::Error;
const TAG: Tag = Tag::constructed(0x10);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
let mut w = Writer::new(dest);
for el in self.vals.borrow() {
w.write_element(el)?;
}
Ok(())
}
fn data_length(&self) -> Option<usize> {
let vals = self.vals.borrow();
vals.iter().map(|v| v.encoded_length()).sum()
}
}
fn validate_set_ordering<'a>(
p: &mut Parser<'a>,
mut per_element: impl FnMut(Tlv<'a>, usize) -> ParseResult<()>,
) -> ParseResult<()> {
let mut last_element: Option<Tlv<'a>> = None;
let mut i = 0;
while !p.is_empty() {
let el = p
.read_tlv()
.map_err(|e| e.add_location(ParseLocation::Index(i)))?;
if let Some(last_el) = last_element {
if el.full_data < last_el.full_data {
return Err(ParseError::new(ParseErrorKind::InvalidSetOrdering)
.add_location(ParseLocation::Index(i)));
}
}
last_element = Some(el);
per_element(el, i)?;
i += 1;
}
Ok(())
}
#[derive(Debug, PartialEq, Hash, Clone, Eq)]
pub struct Set<'a> {
data: &'a [u8],
}
impl<'a> Set<'a> {
#[inline]
pub(crate) fn new(data: &'a [u8]) -> Set<'a> {
Set { data }
}
pub fn parse<T, E: From<ParseError>, F: Fn(&mut Parser<'a>) -> Result<T, E>>(
self,
f: F,
) -> Result<T, E> {
parse(self.data, f)
}
}
impl<'a> SimpleAsn1Readable<'a> for Set<'a> {
const TAG: Tag = Tag::constructed(0x11);
#[inline]
fn parse_data(data: &'a [u8]) -> ParseResult<Set<'a>> {
parse(data, |p| validate_set_ordering(p, |_, _| Ok(())))?;
Ok(Set::new(data))
}
}
impl SimpleAsn1Writable for Set<'_> {
type Error = WriteError;
const TAG: Tag = Tag::constructed(0x11);
#[inline]
fn write_data(&self, data: &mut WriteBuf) -> WriteResult {
data.push_slice(self.data)
}
fn data_length(&self) -> Option<usize> {
Some(self.data.len())
}
}
pub struct SetWriter<'a, E: From<WriteError> = WriteError> {
f: &'a dyn Fn(&mut SetElementWriter<'_>) -> Result<(), E>,
}
impl<'a, E: From<WriteError>> SetWriter<'a, E> {
#[inline]
pub fn new(f: &'a dyn Fn(&mut SetElementWriter<'_>) -> Result<(), E>) -> Self {
SetWriter { f }
}
}
impl<E: From<WriteError>> SimpleAsn1Writable for SetWriter<'_, E> {
type Error = E;
const TAG: Tag = Tag::constructed(0x11);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), E> {
(self.f)(&mut SetElementWriter::new(dest))
}
fn data_length(&self) -> Option<usize> {
None
}
}
pub struct SetElementWriter<'a> {
writer: Writer<'a>,
prev_start: Option<usize>,
}
impl<'a> SetElementWriter<'a> {
fn new(buf: &'a mut WriteBuf) -> Self {
SetElementWriter {
writer: Writer::new(buf),
prev_start: None,
}
}
pub fn write_element<T: Asn1Writable>(&mut self, val: &T) -> Result<(), T::Error> {
let start = self.writer.buf.len();
self.writer.write_element(val)?;
let end = self.writer.buf.len();
if start == end {
return Ok(());
}
if let Some(prev_start) = self.prev_start {
let prev = &self.writer.buf.as_slice()[prev_start..start];
let curr = &self.writer.buf.as_slice()[start..end];
if curr < prev {
return Err(WriteError::InvalidSetOrdering.into());
}
}
self.prev_start = Some(start);
Ok(())
}
}
pub struct SetOf<'a, T> {
parser: Parser<'a>,
_phantom: PhantomData<T>,
}
impl<'a, T: Asn1Readable<'a>> SetOf<'a, T> {
#[inline]
pub(crate) fn new(data: &'a [u8]) -> SetOf<'a, T> {
SetOf {
parser: Parser::new(data),
_phantom: PhantomData,
}
}
}
impl<'a, T: Asn1Readable<'a>> Clone for SetOf<'a, T> {
fn clone(&self) -> SetOf<'a, T> {
SetOf {
parser: self.parser.clone_internal(),
_phantom: PhantomData,
}
}
}
impl<'a, T: Asn1Readable<'a> + PartialEq> PartialEq for SetOf<'a, T> {
fn eq(&self, other: &Self) -> bool {
let mut it1 = self.clone();
let mut it2 = other.clone();
loop {
match (it1.next(), it2.next()) {
(Some(v1), Some(v2)) => {
if v1 != v2 {
return false;
}
}
(None, None) => return true,
_ => return false,
}
}
}
}
impl<'a, T: Asn1Readable<'a> + Eq> Eq for SetOf<'a, T> {}
impl<'a, T: Asn1Readable<'a> + Hash> Hash for SetOf<'a, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
for val in self.clone() {
val.hash(state);
}
}
}
impl<'a, T: Asn1Readable<'a> + 'a> SimpleAsn1Readable<'a> for SetOf<'a, T> {
const TAG: Tag = Tag::constructed(0x11);
#[inline]
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
parse(data, |p| {
validate_set_ordering(p, |el, i| {
el.parse::<T>()
.map_err(|e| e.add_location(ParseLocation::Index(i)))?;
Ok(())
})
})?;
Ok(SetOf::new(data))
}
}
impl<'a, T: Asn1Readable<'a>> Iterator for SetOf<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.parser.is_empty() {
return None;
}
Some(
self.parser
.read_element::<T>()
.expect("Should always succeed"),
)
}
}
impl<'a, T: Asn1Readable<'a> + Asn1Writable> SimpleAsn1Writable for SetOf<'a, T> {
type Error = <T as Asn1Writable>::Error;
const TAG: Tag = Tag::constructed(0x11);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
let mut w = Writer::new(dest);
for el in self.clone() {
w.write_element(&el)?;
}
Ok(())
}
fn data_length(&self) -> Option<usize> {
let iter = self.clone();
iter.map(|el| el.encoded_length()).sum()
}
}
#[derive(Hash, PartialEq, Eq, Clone)]
pub struct SetOfWriter<'a, T, V: Borrow<[T]> = &'a [T]> {
vals: V,
_phantom: PhantomData<&'a T>,
}
impl<T: Asn1Writable, V: Borrow<[T]>> SetOfWriter<'_, T, V> {
pub fn new(vals: V) -> Self {
SetOfWriter {
vals,
_phantom: PhantomData,
}
}
}
impl<T: Asn1Writable, V: Borrow<[T]>> SimpleAsn1Writable for SetOfWriter<'_, T, V> {
type Error = T::Error;
const TAG: Tag = Tag::constructed(0x11);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
let vals = self.vals.borrow();
if vals.is_empty() {
return Ok(());
} else if vals.len() == 1 {
let mut w = Writer::new(dest);
w.write_element(&vals[0])?;
return Ok(());
}
let mut data = WriteBuf::new(vec![]);
let mut w = Writer::new(&mut data);
let mut spans = vec![];
let mut pos = 0;
for el in vals {
w.write_element(el)?;
let l = w.buf.len();
spans.push(pos..l);
pos = l;
}
let data = data.as_slice();
spans.sort_by_key(|v| &data[v.clone()]);
for span in spans {
dest.push_slice(&data[span])?;
}
Ok(())
}
fn data_length(&self) -> Option<usize> {
let vals = self.vals.borrow();
vals.iter().map(|v| v.encoded_length()).sum()
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct Implicit<T, const TAG: u32> {
inner: T,
}
impl<T, const TAG: u32> Implicit<T, { TAG }> {
pub fn new(v: T) -> Self {
Implicit { inner: v }
}
pub fn as_inner(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T, const TAG: u32> From<T> for Implicit<T, { TAG }> {
fn from(v: T) -> Self {
Implicit::new(v)
}
}
impl<'a, T: SimpleAsn1Readable<'a>, const TAG: u32> SimpleAsn1Readable<'a>
for Implicit<T, { TAG }>
{
const TAG: Tag = crate::implicit_tag(TAG, T::TAG);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
Ok(Implicit::new(T::parse_data(data)?))
}
}
impl<T: SimpleAsn1Writable, const TAG: u32> SimpleAsn1Writable for Implicit<T, { TAG }> {
type Error = T::Error;
const TAG: Tag = crate::implicit_tag(TAG, T::TAG);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
self.inner.write_data(dest)
}
fn data_length(&self) -> Option<usize> {
self.inner.data_length()
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct Explicit<T, const TAG: u32> {
inner: T,
}
impl<T, const TAG: u32> Explicit<T, { TAG }> {
pub fn new(v: T) -> Self {
Explicit { inner: v }
}
pub fn as_inner(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T, const TAG: u32> From<T> for Explicit<T, { TAG }> {
fn from(v: T) -> Self {
Explicit::new(v)
}
}
impl<'a, T: Asn1Readable<'a>, const TAG: u32> SimpleAsn1Readable<'a> for Explicit<T, { TAG }> {
const TAG: Tag = crate::explicit_tag(TAG);
fn parse_data(data: &'a [u8]) -> ParseResult<Self> {
Ok(Explicit::new(parse(data, Parser::read_element::<T>)?))
}
}
impl<T: Asn1Writable, const TAG: u32> SimpleAsn1Writable for Explicit<T, { TAG }> {
type Error = T::Error;
const TAG: Tag = crate::explicit_tag(TAG);
fn write_data(&self, dest: &mut WriteBuf) -> Result<(), Self::Error> {
Writer::new(dest).write_element(&self.inner)
}
fn data_length(&self) -> Option<usize> {
self.inner.encoded_length()
}
}
impl<'a, T: Asn1Readable<'a>, U: Asn1DefinedByReadable<'a, T>, const TAG: u32>
Asn1DefinedByReadable<'a, T> for Explicit<U, { TAG }>
{
fn parse(item: T, parser: &mut Parser<'a>) -> ParseResult<Self> {
let tlv = parser.read_element::<Explicit<Tlv<'_>, TAG>>()?;
Ok(Explicit::new(parse(tlv.as_inner().full_data(), |p| {
U::parse(item, p)
})?))
}
}
impl<T: Asn1Writable, U: Asn1DefinedByWritable<T>, const TAG: u32> Asn1DefinedByWritable<T>
for Explicit<U, { TAG }>
{
type Error = U::Error;
fn item(&self) -> &T {
self.as_inner().item()
}
fn write(&self, dest: &mut Writer<'_>) -> Result<(), Self::Error> {
dest.write_tlv(
crate::explicit_tag(TAG),
self.as_inner().encoded_length(),
|dest| self.as_inner().write(&mut Writer::new(dest)),
)
}
fn encoded_length(&self) -> Option<usize> {
let inner_len = self.as_inner().encoded_length()?;
Some(Tlv::full_length(crate::explicit_tag(TAG), inner_len))
}
}
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
pub struct DefinedByMarker<T>(core::marker::PhantomData<T>);
impl<T> DefinedByMarker<T> {
pub const fn marker() -> DefinedByMarker<T> {
DefinedByMarker(core::marker::PhantomData)
}
}
impl<'a, T: Asn1Readable<'a>> Asn1Readable<'a> for DefinedByMarker<T> {
fn parse(_: &mut Parser<'a>) -> ParseResult<Self> {
panic!("parse() should never be called on a DefinedByMarker")
}
fn can_parse(_: Tag) -> bool {
panic!("can_parse() should never be called on a DefinedByMarker")
}
}
impl<T: Asn1Writable> Asn1Writable for DefinedByMarker<T> {
type Error = WriteError;
fn write(&self, _: &mut Writer<'_>) -> WriteResult {
panic!("write() should never be called on a DefinedByMarker")
}
fn encoded_length(&self) -> Option<usize> {
panic!("encoded_length() should never be called on a DefinedByMarker")
}
}
#[cfg(test)]
mod tests {
use crate::{
parse_single, Asn1Readable, Asn1Writable, BigInt, BigUint, DateTime, DefinedByMarker,
Enumerated, GeneralizedTime, IA5String, ObjectIdentifier, OctetStringEncoded, OwnedBigInt,
OwnedBigUint, ParseError, ParseErrorKind, PrintableString, SequenceOf, SequenceOfWriter,
SetOf, SetOfWriter, Tag, Tlv, UtcTime, Utf8String, VisibleString, X509GeneralizedTime,
};
use crate::{Explicit, Implicit};
#[cfg(not(feature = "std"))]
use alloc::vec;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use core::hash::{Hash, Hasher};
#[cfg(feature = "std")]
use std::collections::hash_map::DefaultHasher;
#[test]
fn test_octet_string_encoded() {
assert_eq!(OctetStringEncoded::new(12).get(), &12);
assert_eq!(OctetStringEncoded::new(12).into_inner(), 12);
}
#[test]
fn test_printable_string_new() {
assert!(PrintableString::new("abc").is_some());
assert!(PrintableString::new("").is_some());
assert!(PrintableString::new(" ").is_some());
assert!(PrintableString::new("%").is_none());
assert!(PrintableString::new("\x00").is_none());
}
#[test]
fn test_printable_string_as_str() {
assert_eq!(PrintableString::new("abc").unwrap().as_str(), "abc");
}
#[test]
fn test_ia5string_new() {
assert!(IA5String::new("abc").is_some());
assert!(IA5String::new("").is_some());
assert!(IA5String::new(" ").is_some());
assert!(IA5String::new("%").is_some());
assert!(IA5String::new("😄").is_none());
}
#[test]
fn test_ia5string_as_str() {
assert_eq!(IA5String::new("abc").unwrap().as_str(), "abc");
}
#[test]
fn test_utf8string_as_str() {
assert_eq!(Utf8String::new("abc").as_str(), "abc");
}
#[test]
fn test_visiblestring_new() {
assert!(VisibleString::new("").is_some());
assert!(VisibleString::new("abc").is_some());
assert!(VisibleString::new("\n").is_none());
}
#[test]
fn test_visiblestring_as_str() {
assert_eq!(VisibleString::new("abc").unwrap().as_str(), "abc");
}
#[test]
fn test_tlv_tag_bytes() {
let tlv = parse_single::<Tlv<'_>>(b"\x01\x03abc").unwrap();
assert_eq!(tlv.tag_bytes(), b"\x01");
let tlv_long = parse_single::<Tlv<'_>>(b"\x1f\x1f\x03abc").unwrap();
assert_eq!(tlv_long.tag_bytes(), b"\x1f\x1f");
}
#[test]
fn test_tlv_data() {
let tlv = parse_single::<Tlv<'_>>(b"\x01\x03abc").unwrap();
assert_eq!(tlv.data(), b"abc");
}
#[test]
fn test_tlv_full_data() {
let tlv = parse_single::<Tlv<'_>>(b"\x01\x03abc").unwrap();
assert_eq!(tlv.full_data(), b"\x01\x03abc");
}
#[test]
fn test_tlv_parse() {
let tlv = Tlv {
tag: Tag::primitive(0x2),
data: b"\x03",
full_data: b"\x02\x01\x03",
};
assert_eq!(tlv.parse::<u64>(), Ok(3));
assert_eq!(
tlv.parse::<&[u8]>(),
Err(ParseError::new(ParseErrorKind::UnexpectedTag {
actual: Tag::primitive(0x2)
}))
);
}
#[test]
fn test_biguint_as_bytes() {
assert_eq!(BigUint::new(b"\x01").unwrap().as_bytes(), b"\x01");
assert_eq!(
OwnedBigUint::new(b"\x01".to_vec()).unwrap().as_bytes(),
b"\x01"
);
}
#[test]
fn test_bigint_as_bytes() {
assert_eq!(BigInt::new(b"\x01").unwrap().as_bytes(), b"\x01");
assert_eq!(
OwnedBigInt::new(b"\x01".to_vec()).unwrap().as_bytes(),
b"\x01"
);
}
#[test]
fn test_bigint_bit_length() {
for (value, expected) in [
(0, 0),
(1, 1),
(2, 2),
(3, 2),
(127, 7),
(128, 8),
(255, 8),
(256, 9),
(65535, 16),
(65536, 17),
(-1, 1),
(-2, 2),
(-3, 2),
(-127, 7),
(-128, 8),
(-129, 8),
(-255, 8),
(-256, 9),
(-65535, 16),
(-65536, 17),
] {
let der = crate::write_single(&value).unwrap();
let bigint: BigInt<'_> = parse_single(&der).unwrap();
assert_eq!(bigint.bit_length(), expected);
let owned: OwnedBigInt = parse_single(&der).unwrap();
assert_eq!(owned.bit_length(), expected);
}
}
#[test]
fn test_bigint_is_negative() {
assert!(!BigInt::new(b"\x01").unwrap().is_negative()); assert!(!BigInt::new(b"\x00").unwrap().is_negative()); assert!(BigInt::new(b"\xff").unwrap().is_negative());
assert!(!OwnedBigInt::new(b"\x01".to_vec()).unwrap().is_negative()); assert!(!OwnedBigInt::new(b"\x00".to_vec()).unwrap().is_negative()); assert!(OwnedBigInt::new(b"\xff".to_vec()).unwrap().is_negative()); }
#[test]
fn test_sequence_of_clone() {
let mut seq1 =
parse_single::<SequenceOf<'_, u64>>(b"\x30\x09\x02\x01\x01\x02\x01\x02\x02\x01\x03")
.unwrap();
assert_eq!(seq1.next(), Some(1));
let seq2 = seq1.clone();
assert_eq!(seq1.collect::<Vec<_>>(), vec![2, 3]);
assert_eq!(seq2.collect::<Vec<_>>(), vec![2, 3]);
}
#[test]
fn test_sequence_of_len() {
let mut seq1 =
parse_single::<SequenceOf<'_, u64>>(b"\x30\x09\x02\x01\x01\x02\x01\x02\x02\x01\x03")
.unwrap();
let seq2 = seq1.clone();
assert_eq!(seq1.len(), 3);
assert!(seq1.next().is_some());
assert_eq!(seq1.len(), 2);
assert_eq!(seq2.len(), 3);
assert!(seq1.next().is_some());
assert!(seq1.next().is_some());
assert_eq!(seq1.len(), 0);
assert!(seq1.next().is_none());
assert_eq!(seq1.len(), 0);
assert!(seq1.is_empty());
assert_eq!(seq2.len(), 3);
assert!(!seq2.is_empty());
}
#[cfg(feature = "std")]
fn hash<T: Hash>(v: &T) -> u64 {
let mut h = DefaultHasher::new();
v.hash(&mut h);
h.finish()
}
#[test]
fn test_set_of_eq() {
let s1 = SetOf::<bool>::new(b"");
let s2 = SetOf::<bool>::new(b"");
let s3 = SetOf::<bool>::new(b"\x01\x01\x00");
let s4 = SetOf::<bool>::new(b"\x01\x01\xff");
assert!(s1 == s2);
assert!(s2 != s3);
assert!(s3 == s3);
assert!(s3 != s4);
}
#[cfg(feature = "std")]
#[test]
fn test_set_of_hash() {
let s1 = SetOf::<bool>::new(b"");
let s2 = SetOf::<bool>::new(b"");
let s3 = SetOf::<bool>::new(b"\x01\x01\x00");
let s4 = SetOf::<bool>::new(b"\x01\x01\xff");
assert_eq!(hash(&s1), hash(&s2));
assert_ne!(hash(&s2), hash(&s3));
assert_ne!(hash(&s3), hash(&s4));
}
#[test]
fn test_sequence_of_eq() {
let s1 = SequenceOf::<bool>::new(b"").unwrap();
let s2 = SequenceOf::<bool>::new(b"").unwrap();
let s3 = SequenceOf::<bool>::new(b"\x01\x01\x00").unwrap();
let s4 = SequenceOf::<bool>::new(b"\x01\x01\xff").unwrap();
assert!(s1 == s2);
assert!(s2 != s3);
assert!(s3 == s3);
assert!(s3 != s4);
}
#[cfg(feature = "std")]
#[test]
fn test_sequence_of_hash() {
let s1 = SequenceOf::<bool>::new(b"").unwrap();
let s2 = SequenceOf::<bool>::new(b"").unwrap();
let s3 = SequenceOf::<bool>::new(b"\x01\x01\x00").unwrap();
let s4 = SequenceOf::<bool>::new(b"\x01\x01\xff").unwrap();
assert_eq!(hash(&s1), hash(&s2));
assert_ne!(hash(&s2), hash(&s3));
assert_ne!(hash(&s3), hash(&s4));
}
#[test]
fn test_sequence_of_writer_clone() {
let s1 = SequenceOfWriter::new([1, 2, 3]);
let s2 = s1.clone();
assert!(s1 == s2);
}
#[test]
fn test_set_of_writer_clone() {
let s1 = SetOfWriter::new([1, 2, 3]);
let s2 = s1.clone();
assert!(s1 == s2);
}
#[test]
fn test_datetime_new() {
assert!(DateTime::new(2038, 13, 1, 12, 0, 0).is_err());
assert!(DateTime::new(2000, 1, 1, 12, 60, 0).is_err());
assert!(DateTime::new(2000, 1, 1, 12, 0, 60).is_err());
assert!(DateTime::new(2000, 1, 1, 24, 0, 0).is_err());
}
#[test]
fn test_datetime_partialord() {
let point = DateTime::new(2023, 6, 15, 14, 26, 5).unwrap();
assert!(point < DateTime::new(2023, 6, 15, 14, 26, 6).unwrap());
assert!(point < DateTime::new(2023, 6, 15, 14, 27, 5).unwrap());
assert!(point < DateTime::new(2023, 6, 15, 15, 26, 5).unwrap());
assert!(point < DateTime::new(2023, 6, 16, 14, 26, 5).unwrap());
assert!(point < DateTime::new(2023, 7, 15, 14, 26, 5).unwrap());
assert!(point < DateTime::new(2024, 6, 15, 14, 26, 5).unwrap());
assert!(point > DateTime::new(2023, 6, 15, 14, 26, 4).unwrap());
assert!(point > DateTime::new(2023, 6, 15, 14, 25, 5).unwrap());
assert!(point > DateTime::new(2023, 6, 15, 13, 26, 5).unwrap());
assert!(point > DateTime::new(2023, 6, 14, 14, 26, 5).unwrap());
assert!(point > DateTime::new(2023, 5, 15, 14, 26, 5).unwrap());
assert!(point > DateTime::new(2022, 6, 15, 14, 26, 5).unwrap());
}
#[test]
fn test_utctime_new() {
assert!(UtcTime::new(DateTime::new(1950, 1, 1, 12, 0, 0).unwrap()).is_ok());
assert!(UtcTime::new(DateTime::new(1949, 1, 1, 12, 0, 0).unwrap()).is_err());
assert!(UtcTime::new(DateTime::new(2050, 1, 1, 12, 0, 0).unwrap()).is_err());
assert!(UtcTime::new(DateTime::new(2100, 1, 1, 12, 0, 0).unwrap()).is_err());
}
#[test]
fn test_x509_generalizedtime_new() {
assert!(X509GeneralizedTime::new(DateTime::new(2015, 6, 30, 23, 59, 59).unwrap()).is_ok());
}
#[test]
fn test_generalized_time_new() {
assert!(
GeneralizedTime::new(DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(), Some(1234))
.is_ok()
);
assert!(
GeneralizedTime::new(DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(), None).is_ok()
);
assert!(GeneralizedTime::new(
DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(),
Some(999_999_999_u32)
)
.is_ok());
assert!(GeneralizedTime::new(
DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(),
Some(1e9 as u32)
)
.is_err());
assert!(GeneralizedTime::new(
DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(),
Some(1e9 as u32 + 1)
)
.is_err());
}
#[test]
fn test_generalized_time_partial_ord() {
let point =
GeneralizedTime::new(DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(), Some(1234))
.unwrap();
assert!(
point
< GeneralizedTime::new(DateTime::new(2023, 6, 30, 23, 59, 59).unwrap(), Some(1234))
.unwrap()
);
assert!(
point
< GeneralizedTime::new(DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(), Some(1235))
.unwrap()
);
assert!(
point
> GeneralizedTime::new(DateTime::new(2015, 6, 30, 23, 59, 59).unwrap(), None)
.unwrap()
);
}
#[test]
fn test_enumerated_value() {
assert_eq!(Enumerated::new(4).value(), 4);
}
#[test]
fn test_implicit_as_inner() {
assert_eq!(Implicit::<i32, 0>::new(12).as_inner(), &12);
}
#[test]
fn test_explicit_as_inner() {
assert_eq!(Explicit::<i32, 0>::new(12).as_inner(), &12);
}
#[test]
fn test_const() {
const _: DefinedByMarker<ObjectIdentifier> = DefinedByMarker::marker();
}
#[test]
#[should_panic]
fn test_defined_by_marker_parse() {
crate::parse(b"", DefinedByMarker::<ObjectIdentifier>::parse).unwrap();
}
#[test]
#[should_panic]
fn test_defined_by_marker_can_parse() {
DefinedByMarker::<ObjectIdentifier>::can_parse(Tag::primitive(2));
}
#[test]
#[should_panic]
fn test_defined_by_marker_write() {
crate::write(|w| DefinedByMarker::<ObjectIdentifier>::marker().write(w)).unwrap();
}
#[test]
#[should_panic]
fn test_defined_by_marker_encoded_length() {
DefinedByMarker::<ObjectIdentifier>::marker().encoded_length();
}
}