#![allow(single_use_lifetimes)]
use der::{asn1, Choice, Decode, Encode, Reader, Sequence, ValueOrd};
use sha1::Digest;
pub use const_oid::db::rfc5911::{
ID_COUNTERSIGNATURE, ID_MESSAGE_DIGEST, ID_SIGNED_DATA, ID_SIGNING_TIME,
};
pub use der::asn1::{
AnyRef, BitStringRef, GeneralizedTime, IntRef, ObjectIdentifier, OctetStringRef, SetOfVec,
UtcTime,
};
use crate::module::hex_encode;
pub const ID_SPC_INDIRECT_DATA: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.1.4");
pub const ID_SPC_SP_OPUS_INFO: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.1.12");
pub const ID_SPC_NESTED_SIGNATURE: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.4.1");
pub const ID_COUNTERSIGN: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.3.3.1");
pub const ID_CT_TSTINFO: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.2.840.113549.1.9.16.1.4");
pub const SHA1_WITH_RSA: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.29");
pub const ECDSA_WITH_SHA_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.1");
pub const JURISDICTION_L: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.60.2.1.1");
pub const JURISDICTION_ST: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.60.2.1.2");
pub const JURISDICTION_C: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.60.2.1.3");
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct ContentInfo<'a> {
pub content_type: ObjectIdentifier,
#[asn1(context_specific = "0", tag_mode = "EXPLICIT")]
pub content: AnyRef<'a>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct SignerInfo<'a> {
pub version: u8,
pub sid: SignerIdentifier<'a>,
pub digest_alg: AlgorithmIdentifierRef<'a>,
#[asn1(
context_specific = "0",
tag_mode = "IMPLICIT",
constructed = "true",
optional = "true"
)]
pub signed_attrs: Option<SignedAttrs<'a>>,
pub signature_algorithm: AlgorithmIdentifierRef<'a>,
pub signature: OctetStringRef<'a>,
#[asn1(
context_specific = "1",
tag_mode = "IMPLICIT",
constructed = "true",
optional = "true"
)]
pub unsigned_attrs: Option<AttributesRef<'a>>,
}
impl<'a> SignerInfo<'a> {
pub fn get_signed_attr(&self, oid: &ObjectIdentifier) -> Option<AnyRef<'a>> {
let attrs = self.signed_attrs.as_ref()?;
let attr = attrs.attrs.iter().find(|attr| &attr.oid == oid)?;
attr.values.iter().next().copied()
}
pub fn get_message_digest(&self) -> Option<&'a [u8]> {
self.get_signed_attr(&ID_MESSAGE_DIGEST).map(AnyRef::value)
}
pub fn get_signing_time(&self) -> Option<Time> {
let value = self.get_signed_attr(&ID_SIGNING_TIME)?;
if let Ok(v) = value.decode_as::<UtcTime>() {
Some(Time::UtcTime(v))
} else if let Ok(v) = value.decode_as::<GeneralizedTime>() {
Some(Time::GeneralTime(v))
} else {
None
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SignedAttrs<'a> {
pub attrs: Vec<AttributeRef<'a>>,
pub value: &'a [u8],
}
impl<'a> der::DecodeValue<'a> for SignedAttrs<'a> {
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
let mut attrs = Vec::new();
decoder.read_nested(header.length, |decoder| {
let value = decoder.read_slice(decoder.remaining_len())?;
let mut decoder = der::SliceReader::new(value)?;
while !decoder.is_finished() {
attrs.push(decoder.decode()?);
}
Ok(Self { attrs, value })
})
}
}
impl der::EncodeValue for SignedAttrs<'_> {
fn value_len(&self) -> der::Result<der::Length> {
self.attrs
.iter()
.try_fold(der::Length::ZERO, |len, elem| len + elem.encoded_len()?)
}
fn encode_value(&self, writer: &mut impl der::Writer) -> der::Result<()> {
for elem in &self.attrs {
elem.encode(writer)?;
}
Ok(())
}
}
impl ValueOrd for SignedAttrs<'_> {
fn value_cmp(&self, other: &Self) -> der::Result<std::cmp::Ordering> {
use der::DerOrd;
let length_ord = self.attrs.len().cmp(&other.attrs.len());
for (value1, value2) in self.attrs.iter().zip(other.attrs.iter()) {
match value1.der_cmp(value2)? {
std::cmp::Ordering::Equal => (),
other => return Ok(other),
}
}
Ok(length_ord)
}
}
impl der::FixedTag for SignedAttrs<'_> {
const TAG: der::Tag = der::Tag::Set;
}
#[derive(Clone, Debug, Eq, PartialEq, Choice)]
pub enum SignerIdentifier<'a> {
IssuerAndSerialNumber(IssuerAndSerialNumber<'a>),
#[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
SubjectKeyIdentifier(OctetStringRef<'a>),
}
impl ValueOrd for SignerIdentifier<'_> {
fn value_cmp(&self, other: &Self) -> der::Result<std::cmp::Ordering> {
use der::DerOrd;
self.to_der()?.der_cmp(&other.to_der()?)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct IssuerAndSerialNumber<'a> {
pub issuer: NameRef<'a>,
pub serial_number: IntRef<'a>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct SpcSpOpusInfo<'a> {
#[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
pub program_name: Option<SpcString<'a>>,
#[asn1(context_specific = "1", tag_mode = "EXPLICIT", optional = "true")]
pub more_info: Option<SpcLink<'a>>,
}
#[derive(Clone, Debug, Eq, PartialEq, Choice)]
pub enum SpcString<'a> {
#[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
Unicode(asn1::BmpString),
#[asn1(context_specific = "1", tag_mode = "IMPLICIT")]
Ascii(asn1::Ia5StringRef<'a>),
}
#[derive(Clone, Debug, Eq, PartialEq, Choice)]
pub enum SpcLink<'a> {
#[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
Url(asn1::Ia5StringRef<'a>),
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct SpcIndirectDataContent<'a> {
pub data: SpcAttributeTypeAndOptionalValue<'a>,
pub message_digest: DigestInfo<'a>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct SpcAttributeTypeAndOptionalValue<'a> {
pub r#type: ObjectIdentifier,
pub value: Option<AnyRef<'a>>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct DigestInfo<'a> {
pub digest_algorithm: AlgorithmIdentifierRef<'a>,
pub digest: OctetStringRef<'a>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TstInfo<'a> {
pub version: &'a [u8],
pub policy: &'a [u8],
pub message_imprint: MessageImprint<'a>,
pub serial_number: IntRef<'a>,
pub gen_time: GeneralizedTimeWithFrac,
pub remaining: &'a [u8],
}
impl<'a> der::DecodeValue<'a> for TstInfo<'a> {
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
decoder.read_nested(header.length, |decoder| {
let version = decoder.tlv_bytes()?;
let policy = decoder.tlv_bytes()?;
let message_imprint = decoder.decode()?;
let serial_number = decoder.decode()?;
let gen_time = decoder.decode()?;
let remaining = decoder.read_slice(decoder.remaining_len())?;
Ok(Self {
version,
policy,
message_imprint,
serial_number,
gen_time,
remaining,
})
})
}
}
impl der::FixedTag for TstInfo<'_> {
const TAG: der::Tag = der::Tag::Sequence;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GeneralizedTimeWithFrac(pub GeneralizedTime);
impl<'a> der::DecodeValue<'a> for GeneralizedTimeWithFrac {
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
use der::FixedTag;
let s = decoder.read_slice(header.length)?;
if s.len() < 15 || s[s.len() - 1] != b'Z' {
return Err(Self::TAG.value_error());
}
let bytes = [
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13],
b'Z',
];
let mut subreader = der::SliceReader::new(&bytes)?;
GeneralizedTime::decode_value(
&mut subreader,
der::Header::new(header.tag, der::Length::new(15))?,
)
.map(Self)
}
}
impl der::FixedTag for GeneralizedTimeWithFrac {
const TAG: der::Tag = der::Tag::GeneralizedTime;
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct MessageImprint<'a> {
pub hash_algorithm: AlgorithmIdentifierRef<'a>,
pub hashed_message: OctetStringRef<'a>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct SignedData<'a> {
pub version: u8,
pub digest_algorithms: SetOfVec<AlgorithmIdentifierRef<'a>>,
pub encap_content_info: EncapsulatedContentInfo<'a>,
#[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")]
pub certificates: Option<Certificates<'a>>,
#[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
pub crls: Option<AnyRef<'a>>,
pub signer_infos: SetOfVec<SignerInfo<'a>>,
}
impl<'a> SignedData<'a> {
pub fn get_spc_indirect_data(&self) -> Option<SpcIndirectDataContent<'a>> {
if self.encap_content_info.econtent_type == ID_SPC_INDIRECT_DATA {
self.encap_content_info.econtent?.decode_as().ok()
} else {
None
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct EncapsulatedContentInfo<'a> {
pub econtent_type: ObjectIdentifier,
#[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
pub econtent: Option<AnyRef<'a>>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Certificates<'a>(pub Vec<CertificateWithThumbprint<'a>>);
impl<'a> der::DecodeValue<'a> for Certificates<'a> {
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
decoder.read_nested(header.length, |decoder| {
let mut res = Vec::new();
while !decoder.is_finished() {
let der = decoder.tlv_bytes()?;
let thumbprint = hex_encode(sha1::Sha1::digest(der));
match Certificate::from_der(der) {
Ok(cert) => res.push(CertificateWithThumbprint { cert, thumbprint }),
Err(_) => break,
}
}
Ok(Self(res))
})
}
}
impl der::EncodeValue for Certificates<'_> {
fn value_len(&self) -> der::Result<der::Length> {
self.0.iter().try_fold(der::Length::ZERO, |len, elem| {
len + elem.cert.encoded_len()?
})
}
fn encode_value(&self, writer: &mut impl der::Writer) -> der::Result<()> {
for elem in &self.0 {
elem.cert.encode(writer)?;
}
Ok(())
}
}
impl der::FixedTag for Certificates<'_> {
const TAG: der::Tag = der::Tag::Set;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CertificateWithThumbprint<'a> {
pub cert: Certificate<'a>,
pub thumbprint: Vec<u8>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct AlgorithmIdentifierRef<'a> {
pub oid: ObjectIdentifier,
pub parameters: Option<AnyRef<'a>>,
}
pub type AttributeType = ObjectIdentifier;
pub type AttributeValueRef<'a> = AnyRef<'a>;
#[derive(Clone, Debug, PartialEq, Eq, Sequence, ValueOrd)]
pub struct AttributeRef<'a> {
pub oid: AttributeType,
pub values: SetOfVec<AttributeValueRef<'a>>,
}
pub type AttributesRef<'a> = SetOfVec<AttributeRef<'a>>;
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Sequence, ValueOrd)]
pub struct AttributeTypeAndValueRef<'a> {
pub oid: AttributeType,
pub value: AttributeValueRef<'a>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct TbsCertificate<'a> {
#[asn1(context_specific = "0", default = "u8::default")]
pub version: u8,
pub serial_number: IntRef<'a>,
pub signature: AlgorithmIdentifierRef<'a>,
pub issuer: NameRef<'a>,
pub validity: Validity,
pub subject: NameRef<'a>,
pub subject_public_key_info: AnyRef<'a>,
#[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")]
pub issuer_unique_id: Option<BitStringRef<'a>>,
#[asn1(context_specific = "2", tag_mode = "IMPLICIT", optional = "true")]
pub subject_unique_id: Option<BitStringRef<'a>>,
#[asn1(context_specific = "3", tag_mode = "EXPLICIT", optional = "true")]
pub extensions: Option<AnyRef<'a>>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Certificate<'a> {
pub tbs_certificate: TbsCertificate<'a>,
pub cert_raw: &'a [u8],
pub signature_algorithm: AlgorithmIdentifierRef<'a>,
pub signature: BitStringRef<'a>,
}
impl<'a> der::DecodeValue<'a> for Certificate<'a> {
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
decoder.read_nested(header.length, |decoder| {
let cert_raw = decoder.tlv_bytes()?;
let tbs_certificate = TbsCertificate::from_der(cert_raw)?;
let signature_algorithm = decoder.decode()?;
let signature = decoder.decode()?;
Ok(Self {
tbs_certificate,
cert_raw,
signature_algorithm,
signature,
})
})
}
}
impl der::EncodeValue for Certificate<'_> {
fn value_len(&self) -> der::Result<der::Length> {
self.tbs_certificate.encoded_len()?
+ self.signature_algorithm.encoded_len()?
+ self.signature.encoded_len()?
}
fn encode_value(&self, writer: &mut impl der::Writer) -> der::Result<()> {
self.tbs_certificate.encode(writer)?;
self.signature_algorithm.encode(writer)?;
self.signature.encode(writer)?;
Ok(())
}
}
impl der::FixedTag for Certificate<'_> {
const TAG: der::Tag = der::Tag::Sequence;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct Validity {
pub not_before: Time,
pub not_after: Time,
}
#[derive(Choice, Copy, Clone, Debug, Eq, PartialEq, ValueOrd)]
pub enum Time {
#[asn1(type = "UTCTime")]
UtcTime(UtcTime),
#[asn1(type = "GeneralizedTime")]
GeneralTime(GeneralizedTime),
}
pub type NameRef<'a> = RdnSequenceRef<'a>;
pub type RdnSequenceRef<'a> = Vec<RelativeDistinguishedNameRef<'a>>;
pub type RelativeDistinguishedNameRef<'a> = SetOfVec<AttributeTypeAndValueRef<'a>>;