use std::borrow::Cow;
use const_oid::ObjectIdentifier;
use const_oid::db::{rfc4519, rfc5912};
use der_parser::asn1_rs::{
Any, FromBer, FromDer, OptTaggedParser, ParseResult,
};
use der_parser::ber::*;
use der_parser::error::Error::BerValueError;
use der_parser::error::{BerError, BerResult};
use der_parser::nom;
use der_parser::nom::Err::Incomplete;
use der_parser::nom::Parser;
use der_parser::nom::branch::alt;
use der_parser::nom::combinator::{consumed, map_res};
use der_parser::num_bigint::BigUint;
use der_parser::{Oid, asn1_rs, parse_ber};
use digest::Digest;
use sha1::Sha1;
use x509_parser::certificate::X509Certificate;
use x509_parser::prelude::{AlgorithmIdentifier, X509CertificateParser};
use x509_parser::x509::X509Name;
#[rustfmt::skip]
#[allow(dead_code)]
pub mod oid {
use const_oid::ObjectIdentifier;
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");
pub const MS_SPC_NESTED_SIGNATURE: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.4.1");
pub const MS_SPC_INDIRECT_DATA_OBJID: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.1.4");
pub const MS_SPC_OPUS_INFO: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.1.12");
pub const MS_COUNTERSIGN: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.3.3.1");
pub const SHA1_WITH_RSA_ENCRYPTION_OBSOLETE: ObjectIdentifier =
ObjectIdentifier::new_unwrap("1.3.14.3.2.29");
}
#[inline]
pub fn oid_to_object_identifier(
oid: &Oid,
) -> Result<ObjectIdentifier, const_oid::Error> {
ObjectIdentifier::from_bytes(oid.as_bytes())
}
pub fn oid_to_str(oid: &Oid) -> Cow<'static, str> {
let oid = match oid_to_object_identifier(oid) {
Ok(oid) => oid,
Err(_) => return Cow::Borrowed("invalid"),
};
match oid {
rfc5912::ID_MD_5 => Cow::Borrowed("md5"),
rfc5912::ID_SHA_1 => Cow::Borrowed("sha1"),
rfc5912::ID_SHA_256 => Cow::Borrowed("sha256"),
rfc5912::ID_SHA_384 => Cow::Borrowed("sha384"),
rfc5912::ID_SHA_512 => Cow::Borrowed("sha512"),
rfc5912::MD_5_WITH_RSA_ENCRYPTION => {
Cow::Borrowed("md5WithRSAEncryption")
}
rfc5912::SHA_1_WITH_RSA_ENCRYPTION
| oid::SHA1_WITH_RSA_ENCRYPTION_OBSOLETE => {
Cow::Borrowed("sha1WithRSAEncryption")
}
rfc5912::SHA_256_WITH_RSA_ENCRYPTION => {
Cow::Borrowed("sha256WithRSAEncryption")
}
rfc5912::SHA_384_WITH_RSA_ENCRYPTION => {
Cow::Borrowed("sha384WithRSAEncryption")
}
rfc5912::SHA_512_WITH_RSA_ENCRYPTION => {
Cow::Borrowed("sha512WithRSAEncryption")
}
rfc5912::DSA_WITH_SHA_1 => Cow::Borrowed("dsaWithSHA1"),
rfc5912::DSA_WITH_SHA_224 => Cow::Borrowed("dsa_with_SHA224"),
rfc5912::DSA_WITH_SHA_256 => Cow::Borrowed("dsa_with_SHA256"),
rfc4519::C => Cow::Borrowed("C"),
rfc4519::COMMON_NAME => Cow::Borrowed("CN"),
rfc4519::O => Cow::Borrowed("O"),
rfc4519::OU => Cow::Borrowed("OU"),
rfc4519::ST => Cow::Borrowed("ST"),
rfc4519::STREET => Cow::Borrowed("street"),
oid::JURISDICTION_C => Cow::Borrowed("jurisdictionC"),
oid::JURISDICTION_L => Cow::Borrowed("jurisdictionL"),
oid::JURISDICTION_ST => Cow::Borrowed("jurisdictionST"),
oid => {
if let Some(name) = const_oid::db::DB.by_oid(&oid) {
Cow::Borrowed(name)
} else {
Cow::Owned(oid.to_string())
}
}
}
}
pub struct ContentInfo<'a> {
pub content_type: ObjectIdentifier,
pub content: Any<'a>,
}
impl<'a> ContentInfo<'a> {
pub fn parse(data: &'a [u8]) -> BerResult<'a, Self> {
parse_ber_sequence_defined_g(|i, _| Self::parse_inner(i))(data)
}
pub fn from_ber(
data: &'a [u8],
) -> Result<Self, nom::Err<der_parser::error::Error>> {
Self::parse(data).map(|(_, content_info)| content_info)
}
fn parse_inner(data: &'a [u8]) -> BerResult<'a, Self> {
let (remainder, content_type) = parse_ber_oid(data)?;
let (remainder, content) =
parse_ber_tagged_explicit_g(0, |content, _| {
parse_ber_any(content)
})(remainder)?;
Ok((
remainder,
Self {
content_type: oid_to_object_identifier(content_type.as_oid()?)
.map_err(|_| BerValueError)?,
content,
},
))
}
}
impl<'a> TryFrom<&Any<'a>> for ContentInfo<'a> {
type Error = asn1_rs::Error;
fn try_from(any: &Any<'a>) -> Result<Self, Self::Error> {
any.tag().assert_eq(asn1_rs::Tag::Sequence)?;
Ok(Self::parse_inner(any.data).map(|(_, ci)| ci)?)
}
}
pub struct Certificate<'a> {
pub x509: X509Certificate<'a>,
pub thumbprint: String,
}
pub struct SignedData<'a> {
pub version: i32,
pub digest_algorithms: Vec<AlgorithmIdentifier<'a>>,
pub content_info: ContentInfo<'a>,
pub certificates: Vec<Certificate<'a>>,
pub signer_infos: Vec<SignerInfo<'a>>,
}
impl<'a> SignedData<'a> {
fn parse_inner(input: &'a [u8]) -> BerResult<'a, Self> {
let (remainder, version) = parse_ber_integer(input)?;
let (remainder, digest_algorithms) =
parse_ber_set_of_v(AlgorithmIdentifier::from_ber)(remainder)
.map_err(|_| BerValueError)?;
let (remainder, content_info) = ContentInfo::parse(remainder)?;
let (remainder, certificates) = OptTaggedParser::from(0)
.parse_ber(remainder, |_, raw_certs| -> ParseResult<'_, Vec<_>> {
Ok(Self::parse_certificates(raw_certs))
})
.map_err(|_| BerValueError)?;
let (remainder, _revocation_info) = OptTaggedParser::from(1)
.parse_ber(remainder, |_, data| parse_ber(data))?;
let (remainder, signer_infos) =
parse_ber_set_of_v(SignerInfo::parse)(remainder)?;
Ok((
remainder,
Self {
version: version.as_i32()?,
certificates: certificates.unwrap_or_default(),
signer_infos,
digest_algorithms,
content_info,
},
))
}
pub fn parse_certificates(input: &[u8]) -> (&[u8], Vec<Certificate<'_>>) {
let mut remainder = input;
let mut certificates = Vec::new();
let mut cert_parser =
consumed(|input| X509CertificateParser::new().parse(input));
loop {
remainder = match cert_parser(remainder) {
Ok((remainder, (cert_bytes, cert))) => {
certificates.push(Certificate {
x509: cert,
thumbprint: hex::encode(Sha1::digest(cert_bytes)),
});
remainder
}
Err(_) => {
return (remainder, certificates);
}
}
}
}
}
impl<'a> TryFrom<Any<'a>> for SignedData<'a> {
type Error = asn1_rs::Error;
fn try_from(any: Any<'a>) -> Result<Self, Self::Error> {
any.tag().assert_eq(asn1_rs::Tag::Sequence)?;
Ok(Self::parse_inner(any.data).map(|(_, ci)| ci)?)
}
}
pub struct SignerInfo<'a> {
pub _version: i32,
pub unsigned_attrs: Vec<Attribute<'a>>,
pub signed_attrs: Vec<Attribute<'a>>,
pub raw_signed_attrs: &'a [u8],
pub issuer: X509Name<'a>,
pub serial_number: BigUint,
pub digest_algorithm: AlgorithmIdentifier<'a>,
pub _signature_algorithm: AlgorithmIdentifier<'a>,
pub signature: &'a [u8],
}
impl<'a> SignerInfo<'a> {
pub fn parse(input: &'a [u8]) -> BerResult<'a, Self> {
parse_ber_sequence_defined_g(|input: &[u8], _| {
Self::parse_inner(input)
})(input)
}
pub fn parse_inner(input: &'a [u8]) -> BerResult<'a, Self> {
let (remainder, version) = parse_ber_integer(input)?;
let (remainder, (issuer, serial_number)) =
Self::parse_issuer_and_serial_number(remainder)?;
let (remainder, digest_algorithm) =
AlgorithmIdentifier::from_ber(remainder)
.map_err(|_| BerValueError)?;
let (remainder, signed_attrs) = OptTaggedParser::from(0).parse_ber(
remainder,
|_, raw_attrs| {
let (remainder, parsed_attrs) =
Self::parse_attributes(raw_attrs)?;
Ok((remainder, (raw_attrs, parsed_attrs)))
},
)?;
let (remainder, _signature_algorithm) =
AlgorithmIdentifier::from_ber(remainder)
.map_err(|_| BerValueError)?;
let (remainder, signature) = parse_ber_octetstring(remainder)?;
let (remainder, unsigned_attrs) = OptTaggedParser::from(1)
.parse_ber(remainder, |_, raw_attrs| {
Self::parse_attributes(raw_attrs)
})?;
let (raw_signed_attrs, signed_attrs) =
signed_attrs.unwrap_or_default();
Ok((
remainder,
Self {
_version: version.as_i32()?,
signed_attrs,
raw_signed_attrs,
unsigned_attrs: unsigned_attrs.unwrap_or_default(),
signature: signature.content.as_slice()?,
issuer,
serial_number,
digest_algorithm,
_signature_algorithm,
},
))
}
pub fn get_signed_attr(&self, oid: &ObjectIdentifier) -> Option<&Any<'a>> {
self.signed_attrs
.iter()
.find(|attr| attr.attr_type.eq(oid))
.and_then(|attr| attr.attr_values.first())
}
fn parse_issuer_and_serial_number(
input: &[u8],
) -> BerResult<'_, (X509Name<'_>, BigUint)> {
parse_ber_sequence_defined_g(|input: &[u8], _| {
let (remainder, issuer) =
X509Name::from_der(input).map_err(|_| BerValueError)?;
let (remainder, serial) = parse_ber_integer(remainder)?;
let serial = BigUint::from_bytes_be(serial.content.as_slice()?);
Ok((remainder, (issuer, serial)))
})(input)
}
fn parse_attributes(input: &[u8]) -> BerResult<'_, Vec<Attribute<'_>>> {
let mut remainder = input;
let mut attributes = Vec::new();
loop {
remainder = match Attribute::parse(remainder) {
Ok((remainder, attr)) => {
attributes.push(attr);
remainder
}
Err(Incomplete(_)) => return Ok((remainder, attributes)),
Err(err) => return Err(err),
}
}
}
}
impl<'a> TryFrom<&Any<'a>> for SignerInfo<'a> {
type Error = asn1_rs::Error;
fn try_from(any: &Any<'a>) -> Result<Self, Self::Error> {
any.tag().assert_eq(asn1_rs::Tag::Sequence)?;
Ok(Self::parse_inner(any.data).map(|(_, si)| si)?)
}
}
pub struct Attribute<'a> {
pub attr_type: ObjectIdentifier,
pub attr_values: Vec<Any<'a>>,
}
impl<'a> Attribute<'a> {
pub fn parse(input: &'a [u8]) -> BerResult<'a, Self> {
parse_ber_sequence_defined_g(|data: &[u8], _| {
let (remainder, attr_type) = parse_ber_oid(data)?;
let (remainder, attr_values) =
parse_ber_set_of_v(parse_ber_any)(remainder)?;
Ok((
remainder,
Self {
attr_type: oid_to_object_identifier(attr_type.as_oid()?)
.map_err(|_| BerValueError)?,
attr_values,
},
))
})(input)
}
}
pub struct SpcIndirectDataContent<'a> {
pub message_digest: DigestInfo<'a>,
}
impl<'a> SpcIndirectDataContent<'a> {
pub fn parse_inner(input: &'a [u8]) -> BerResult<'a, Self> {
let (remainder, _data) = parse_ber(input)?;
let (remainder, message_digest) = DigestInfo::parse(remainder)?;
Ok((remainder, Self { message_digest }))
}
}
impl<'a> TryFrom<Any<'a>> for SpcIndirectDataContent<'a> {
type Error = asn1_rs::Error;
fn try_from(any: Any<'a>) -> Result<Self, Self::Error> {
any.tag().assert_eq(Tag::Sequence)?;
Ok(Self::parse_inner(any.data).map(|(_, ci)| ci)?)
}
}
pub struct DigestInfo<'a> {
pub algorithm: AlgorithmIdentifier<'a>,
pub digest: &'a [u8],
}
impl<'a> DigestInfo<'a> {
pub fn parse(input: &'a [u8]) -> BerResult<'a, Self> {
parse_ber_sequence_defined_g(|input: &[u8], _| {
let (remainder, algorithm) = AlgorithmIdentifier::from_ber(input)
.map_err(|_| BerValueError)?;
let (remainder, digest) = parse_ber_octetstring(remainder)?;
Ok((remainder, Self { algorithm, digest: digest.as_slice()? }))
})(input)
}
}
pub struct SpcSpOpusInfo {
pub program_name: Option<String>,
pub more_info: Option<String>,
}
impl SpcSpOpusInfo {
fn parse_inner(input: &[u8]) -> BerResult<'_, Self> {
let (remainder, program_name) = OptTaggedParser::from(0)
.parse_ber(input, |_, content| Self::parse_spc_string(content))?;
let (remainder, more_info) = OptTaggedParser::from(1)
.parse_ber(remainder, |_, content| Self::parse_spc_link(content))
.unwrap_or_default();
Ok((remainder, Self { program_name, more_info }))
}
fn parse_spc_string(input: &[u8]) -> BerResult<'_, String> {
alt((
parse_ber_tagged_implicit_g(0, |input, _header, _size| {
Ok((&[], string_from_utf16be(input).ok_or(BerValueError)?))
}),
map_res(
parse_ber_tagged_implicit(
1,
parse_ber_content(Tag::Ia5String),
),
|s| Ok::<String, BerError>(String::from(s.as_str()?)),
),
))(input)
}
fn parse_spc_link(input: &[u8]) -> BerResult<'_, String> {
map_res(
parse_ber_tagged_implicit(0, parse_ber_content(Tag::Ia5String)),
|s| Ok::<String, BerError>(String::from(s.as_str()?)),
)(input)
}
}
impl TryFrom<&Any<'_>> for SpcSpOpusInfo {
type Error = asn1_rs::Error;
fn try_from(any: &Any) -> Result<Self, Self::Error> {
Ok(Self::parse_inner(any.data).map(|(_, ci)| ci)?)
}
}
pub struct TstInfo<'a> {
pub hash_algorithm: AlgorithmIdentifier<'a>,
pub hashed_message: &'a [u8],
}
impl<'a> TstInfo<'a> {
pub fn from_ber(
data: &'a [u8],
) -> Result<Self, nom::Err<der_parser::error::Error>> {
Self::parse(data).map(|(_, tst_info)| tst_info)
}
pub fn parse(input: &'a [u8]) -> BerResult<'a, Self> {
parse_ber_sequence_defined_g(|input: &[u8], _| {
let (remainder, _version) = parse_ber_integer(input)?;
let (remainder, _policy) = parse_ber(remainder)?;
let (remainder, (hash_algorithm, hashed_message)) =
Self::parse_message_imprint(remainder)?;
Ok((remainder, Self { hash_algorithm, hashed_message }))
})(input)
}
fn parse_message_imprint(
input: &'a [u8],
) -> BerResult<'a, (AlgorithmIdentifier<'a>, &'a [u8])> {
parse_ber_sequence_defined_g(|input: &[u8], _| {
let (remainder, hash_algorithm) =
AlgorithmIdentifier::from_ber(input)
.map_err(|_| BerValueError)?;
let (remainder, hashed_message) = parse_ber(remainder)?;
Ok((remainder, (hash_algorithm, hashed_message.as_slice()?)))
})(input)
}
}
fn string_from_utf16be(v: &[u8]) -> Option<String> {
if !v.len().is_multiple_of(2) {
return None;
}
let codepoints = v
.chunks_exact(2)
.map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]));
let x: String =
char::decode_utf16(codepoints).collect::<Result<_, _>>().ok()?;
Some(x)
}