use crate::bit_string::BitString;
use crate::date::{GeneralizedTime, UTCTime};
use crate::restricted_string::{BmpString, Ia5String, NumericString, PrintableString, Utf8String};
use crate::tag::Tag;
use crate::Asn1Type;
use oid::ObjectIdentifier;
use serde::{de, ser, Deserialize, Serialize};
use std::fmt;
use std::ops::{Deref, DerefMut};
macro_rules! asn1_wrapper {
(struct $wrapper_ty:ident ( $wrapped_ty:ident ), $tag:expr) => {
#[derive(Debug, PartialEq, Clone)]
pub struct $wrapper_ty(pub $wrapped_ty);
impls! { $wrapper_ty ( $wrapped_ty ), $tag }
};
(auto struct $wrapper_ty:ident ( $wrapped_ty:ident ), $tag:expr) => {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct $wrapper_ty(pub $wrapped_ty);
impls! { $wrapper_ty ( $wrapped_ty ), $tag }
};
(special tag struct $wrapper_ty:ident < $generic:ident >, $tag:expr) => {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct $wrapper_ty<$generic>(pub $generic);
impls! { $wrapper_ty < $generic >, $tag }
};
(auto collection struct $wrapper_ty:ident < T >, $tag:expr) => {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct $wrapper_ty<T>(
#[serde(
serialize_with = "serialize_vec",
deserialize_with = "deserialize_vec",
bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")
)]
pub Vec<T>,
);
impl<T> Default for $wrapper_ty<T> {
fn default() -> Self {
Self(Vec::new())
}
}
impls! { $wrapper_ty ( Vec < T > ), $tag }
};
}
macro_rules! impls {
($wrapper_ty:ident ( $wrapped_ty:ident ), $tag:expr) => {
impl $crate::wrapper::Asn1Type for $wrapper_ty {
const TAG: Tag = $tag;
const NAME: &'static str = stringify!($wrapper_ty);
}
impl From<$wrapped_ty> for $wrapper_ty {
fn from(wrapped: $wrapped_ty) -> Self {
Self(wrapped)
}
}
impl From<$wrapper_ty> for $wrapped_ty {
fn from(wrapper: $wrapper_ty) -> $wrapped_ty {
wrapper.0
}
}
impl Deref for $wrapper_ty {
type Target = $wrapped_ty;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for $wrapper_ty {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl PartialEq<$wrapped_ty> for $wrapper_ty {
fn eq(&self, other: &$wrapped_ty) -> bool {
self.0.eq(other)
}
}
};
($wrapper_ty:ident < $generic:ident >, $tag:expr) => {
impl<$generic> $crate::wrapper::Asn1Type for $wrapper_ty<$generic> {
const TAG: Tag = $tag;
const NAME: &'static str = stringify!($wrapper_ty);
}
impl<$generic> Default for $wrapper_ty<$generic>
where
$generic: Default,
{
fn default() -> Self {
Self($generic::default())
}
}
impl<$generic> From<$generic> for $wrapper_ty<$generic> {
fn from(wrapped: $generic) -> Self {
Self(wrapped)
}
}
impl<$generic> Deref for $wrapper_ty<$generic> {
type Target = $generic;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<$generic> DerefMut for $wrapper_ty<$generic> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<$generic> PartialEq<$generic> for $wrapper_ty<$generic>
where
$generic: PartialEq,
{
fn eq(&self, other: &$generic) -> bool {
self.0.eq(other)
}
}
};
($wrapper_ty:ident ( $wrapped_ty:ident < $generic:ident > ), $tag:expr) => {
impl<$generic> $crate::wrapper::Asn1Type for $wrapper_ty<$generic> {
const TAG: Tag = $tag;
const NAME: &'static str = stringify!($wrapper_ty);
}
impl<$generic> From<$wrapped_ty<$generic>> for $wrapper_ty<$generic> {
fn from(wrapped: $wrapped_ty<$generic>) -> Self {
Self(wrapped)
}
}
impl<$generic> From<$wrapper_ty<$generic>> for $wrapped_ty<$generic> {
fn from(wrapper: $wrapper_ty<$generic>) -> Self {
wrapper.0
}
}
impl<$generic> Deref for $wrapper_ty<$generic> {
type Target = $wrapped_ty<$generic>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<$generic> DerefMut for $wrapper_ty<$generic> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<$generic> PartialEq<$wrapped_ty<$generic>> for $wrapper_ty<$generic>
where
$generic: PartialEq,
{
fn eq(&self, other: &$wrapped_ty<$generic>) -> bool {
self.0.eq(other)
}
}
};
}
macro_rules! define_special_tag {
( $name:ident => $tag:expr ) => {
asn1_wrapper! { special tag struct $name<T>, $tag }
};
( $( $name:ident => $tag:expr , )+ ) => {
$( define_special_tag! { $name => $tag } )+
};
}
asn1_wrapper! { auto struct BitStringAsn1(BitString), Tag::BIT_STRING }
asn1_wrapper! { auto struct ObjectIdentifierAsn1(ObjectIdentifier), Tag::OID }
asn1_wrapper! { auto struct Utf8StringAsn1(Utf8String), Tag::UTF8_STRING }
asn1_wrapper! { auto struct NumericStringAsn1(NumericString), Tag::NUMERIC_STRING }
asn1_wrapper! { auto struct PrintableStringAsn1(PrintableString), Tag::PRINTABLE_STRING }
asn1_wrapper! { auto struct Ia5StringAsn1(Ia5String), Tag::IA5_STRING }
asn1_wrapper! { auto struct BmpStringAsn1(BmpString), Tag::BMP_STRING }
asn1_wrapper! { auto struct UtcTimeAsn1(UTCTime), Tag::UTC_TIME }
asn1_wrapper! { auto struct GeneralizedTimeAsn1(GeneralizedTime), Tag::GENERALIZED_TIME }
asn1_wrapper! { auto struct GeneralStringAsn1(Ia5String), Tag::GENERAL_STRING }
#[deprecated = "Use BmpStringAsn1 instead"]
pub use BmpStringAsn1 as BMPStringAsn1;
#[deprecated = "Use Ia5StringAsn1 instead"]
pub use Ia5StringAsn1 as IA5StringAsn1;
#[deprecated = "Use UtcTimeAsn1 instead"]
pub use UtcTimeAsn1 as UTCTimeAsn1;
asn1_wrapper! { auto collection struct Asn1SequenceOf<T>, Tag::SEQUENCE }
asn1_wrapper! { auto collection struct Asn1SetOf<T>, Tag::SET }
define_special_tag! {
ExplicitContextTag0 => Tag::context_specific_constructed(0),
ExplicitContextTag1 => Tag::context_specific_constructed(1),
ExplicitContextTag2 => Tag::context_specific_constructed(2),
ExplicitContextTag3 => Tag::context_specific_constructed(3),
ExplicitContextTag4 => Tag::context_specific_constructed(4),
ExplicitContextTag5 => Tag::context_specific_constructed(5),
ExplicitContextTag6 => Tag::context_specific_constructed(6),
ExplicitContextTag7 => Tag::context_specific_constructed(7),
ExplicitContextTag8 => Tag::context_specific_constructed(8),
ExplicitContextTag9 => Tag::context_specific_constructed(9),
ExplicitContextTag10 => Tag::context_specific_constructed(10),
ExplicitContextTag11 => Tag::context_specific_constructed(11),
ExplicitContextTag12 => Tag::context_specific_constructed(12),
ExplicitContextTag13 => Tag::context_specific_constructed(13),
ExplicitContextTag14 => Tag::context_specific_constructed(14),
ExplicitContextTag15 => Tag::context_specific_constructed(15),
ImplicitContextTag0 => Tag::context_specific_primitive(0),
ImplicitContextTag1 => Tag::context_specific_primitive(1),
ImplicitContextTag2 => Tag::context_specific_primitive(2),
ImplicitContextTag3 => Tag::context_specific_primitive(3),
ImplicitContextTag4 => Tag::context_specific_primitive(4),
ImplicitContextTag5 => Tag::context_specific_primitive(5),
ImplicitContextTag6 => Tag::context_specific_primitive(6),
ImplicitContextTag7 => Tag::context_specific_primitive(7),
ImplicitContextTag8 => Tag::context_specific_primitive(8),
ImplicitContextTag9 => Tag::context_specific_primitive(9),
ImplicitContextTag10 => Tag::context_specific_primitive(10),
ImplicitContextTag11 => Tag::context_specific_primitive(11),
ImplicitContextTag12 => Tag::context_specific_primitive(12),
ImplicitContextTag13 => Tag::context_specific_primitive(13),
ImplicitContextTag14 => Tag::context_specific_primitive(14),
ImplicitContextTag15 => Tag::context_specific_primitive(15),
}
#[allow(clippy::derivable_impls)]
impl Default for BitStringAsn1 {
fn default() -> Self {
BitStringAsn1(BitString::default())
}
}
impl Default for Ia5StringAsn1 {
fn default() -> Self {
Ia5StringAsn1::from(Ia5String::default())
}
}
impl Default for BmpStringAsn1 {
fn default() -> Self {
BmpStringAsn1::from(BmpString::default())
}
}
fn serialize_vec<S, T>(elems: &[T], serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
where
S: ser::Serializer,
T: Serialize,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(elems.len()))?;
for e in elems {
seq.serialize_element(e)?;
}
seq.end()
}
fn deserialize_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: de::Deserializer<'de>,
T: Deserialize<'de>,
{
struct Visitor<T>(std::marker::PhantomData<T>);
impl<'de, T> de::Visitor<'de> for Visitor<T>
where
T: Deserialize<'de>,
{
type Value = Vec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid sequence of T")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(e) = seq.next_element()? {
vec.push(e);
}
Ok(vec)
}
}
deserializer.deserialize_seq(Visitor(std::marker::PhantomData))
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Hash, Clone, Default)]
pub struct OctetStringAsn1(#[serde(with = "serde_bytes")] pub Vec<u8>);
type VecU8 = Vec<u8>;
impls! { OctetStringAsn1(VecU8), Tag::OCTET_STRING }
impl fmt::Debug for OctetStringAsn1 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "OctetString(0x")?;
self.0.iter().try_for_each(|byte| write!(f, "{byte:02X}"))?;
write!(f, ")")?;
Ok(())
}
}
#[derive(Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Hash, Clone)]
pub struct IntegerAsn1(#[serde(with = "serde_bytes")] pub Vec<u8>);
impls! { IntegerAsn1(VecU8), Tag::INTEGER }
fn minimal_encode_start(bytes: &[u8]) -> usize {
let mut start = 0;
while start + 1 < bytes.len() {
if bytes[start] == 0 && (bytes[start + 1] & 0x80) == 0
|| bytes[start] == 0xFF && (bytes[start + 1] & 0x80) == 0x80
{
start += 1;
} else {
break;
}
}
start
}
impl IntegerAsn1 {
pub fn is_positive(&self) -> bool {
if self.0.len() > 1 && self.0[0] == 0x00 || self.0.is_empty() {
true
} else {
self.0[0] & 0x80 == 0
}
}
pub fn is_negative(&self) -> bool {
if self.0.len() > 1 && self.0[0] == 0x00 {
false
} else if self.0.is_empty() {
true
} else {
self.0[0] & 0x80 != 0
}
}
pub fn as_unsigned_bytes_be(&self) -> &[u8] {
if self.0.len() > 1 {
if self.0[0] == 0x00 {
&self.0[1..]
} else {
&self.0
}
} else if self.0.is_empty() {
&[0]
} else {
&self.0
}
}
pub fn as_signed_bytes_be(&self) -> &[u8] {
if self.0.is_empty() {
&[0]
} else {
&self.0
}
}
pub fn from_bytes_be_signed(bytes: Vec<u8>) -> Self {
let start = minimal_encode_start(&bytes);
if start == 0 {
Self(bytes)
} else {
Self(bytes[start..].to_vec())
}
}
pub fn from_bytes_be_unsigned(mut bytes: Vec<u8>) -> Self {
if !bytes.is_empty() && bytes[0] & 0x80 == 0x80 {
bytes.insert(0, 0x00);
}
let start = minimal_encode_start(&bytes);
if start == 0 {
Self(bytes)
} else {
Self(bytes[start..].to_vec())
}
}
}
#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for IntegerAsn1 {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
impl fmt::Debug for IntegerAsn1 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Integer(0x")?;
self.0.iter().try_for_each(|byte| write!(f, "{byte:02X}"))?;
write!(f, ")")?;
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Hash, Clone, Default)]
pub struct HeaderOnly<T: Asn1Type>(
#[serde(
serialize_with = "serialize_header_only",
deserialize_with = "deserialize_header_only",
bound(serialize = "T: Asn1Type", deserialize = "T: Asn1Type")
)]
pub std::marker::PhantomData<T>,
);
impl<T: Asn1Type> Asn1Type for HeaderOnly<T> {
const TAG: Tag = T::TAG;
const NAME: &'static str = "HeaderOnly";
}
#[allow(clippy::trivially_copy_pass_by_ref)]
fn serialize_header_only<S, Phantom>(
_: &std::marker::PhantomData<Phantom>,
serializer: S,
) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
where
S: ser::Serializer,
Phantom: Asn1Type,
{
serializer.serialize_bytes(&[Phantom::TAG.inner(), 0x00][..])
}
fn deserialize_header_only<'de, D, Phantom>(deserializer: D) -> Result<std::marker::PhantomData<Phantom>, D::Error>
where
D: de::Deserializer<'de>,
Phantom: Asn1Type,
{
struct Visitor<T>(std::marker::PhantomData<T>);
impl<'de, T> de::Visitor<'de> for Visitor<T>
where
T: Asn1Type,
{
type Value = std::marker::PhantomData<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid header for empty payload")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
if v.len() != 2 {
return Err(E::invalid_value(
de::Unexpected::Other("invalid ASN.1 header length"),
&"a valid buffer representing an ASN.1 header with empty payload (two bytes)",
));
}
if v[0] != T::TAG.inner() {
return Err(E::invalid_value(
de::Unexpected::Other("invalid ASN.1 header: wrong tag"),
&"a valid buffer representing an empty ASN.1 header (two bytes) with the expected tag",
));
}
if v[1] != 0 {
return Err(E::invalid_value(
de::Unexpected::Other("invalid ASN.1 header: bad payload length"),
&"a valid buffer representing an empty ASN.1 header (two bytes) with no payload",
));
}
Ok(std::marker::PhantomData)
}
}
deserializer.deserialize_bytes(Visitor(std::marker::PhantomData))
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Hash, Clone)]
pub struct BitStringAsn1Container<Encapsulated>(pub Encapsulated);
impls! { BitStringAsn1Container<Encapsulated>, Tag::BIT_STRING }
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Hash, Clone)]
pub struct OctetStringAsn1Container<Encapsulated>(pub Encapsulated);
impls! { OctetStringAsn1Container<Encapsulated>, Tag::OCTET_STRING }
#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Clone)]
pub struct Optional<T>(pub T);
impl<T: Default> Default for Optional<T> {
fn default() -> Self {
Optional(T::default())
}
}
impl<T> Optional<T>
where
T: Default + PartialEq,
{
pub fn is_default(&self) -> bool {
self.0 == T::default()
}
}
impl<T> From<T> for Optional<T> {
fn from(wrapped: T) -> Self {
Self(wrapped)
}
}
impl<T> Deref for Optional<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Optional<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> PartialEq<T> for Optional<T>
where
T: PartialEq,
{
fn eq(&self, other: &T) -> bool {
self.0.eq(other)
}
}
impl<T> Serialize for Optional<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for Optional<T>
where
T: Deserialize<'de> + Default,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor<T>(std::marker::PhantomData<T>);
impl<'de, T> de::Visitor<'de> for Visitor<T>
where
T: Deserialize<'de>,
{
type Value = Optional<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "nothing or a valid DER-encoded T")
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: de::Deserializer<'de>,
{
T::deserialize(deserializer).map(Optional::from)
}
}
match deserializer.deserialize_newtype_struct("Optional", Visitor(std::marker::PhantomData)) {
Err(_) => Ok(Self(T::default())),
result => result,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn integer_from_unsigned_bytes_be_no_panic() {
IntegerAsn1::from_bytes_be_unsigned(vec![]);
}
#[test]
fn minimal_encode_start_positive() {
assert_eq!(minimal_encode_start(b""), 0);
assert_eq!(minimal_encode_start(b"\x00"), 0);
assert_eq!(minimal_encode_start(b"\x00\x00"), 1);
assert_eq!(minimal_encode_start(b"\x00\x00\x00"), 2);
assert_eq!(minimal_encode_start(b"\x00\x00\x80"), 1);
}
#[test]
fn minimal_encode_start_negative() {
assert_eq!(minimal_encode_start(b"\xFF"), 0);
assert_eq!(minimal_encode_start(b"\xFF\x00"), 0);
assert_eq!(minimal_encode_start(b"\xFF\x80"), 1);
assert_eq!(minimal_encode_start(b"\xFF\xFF\x00"), 1);
assert_eq!(minimal_encode_start(b"\xFF\xFF\x80"), 2);
}
}