use synta::{Decoder, Encoding, ObjectIdentifier, Tag, TagClass};
use crate::pkcs7_types::ID_SIGNED_DATA;
#[derive(Debug)]
pub enum Pkcs7Error {
Parse(synta::Error),
NotSignedData,
}
impl std::fmt::Display for Pkcs7Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Pkcs7Error::Parse(e) => write!(f, "PKCS#7 ASN.1 parse error: {}", e),
Pkcs7Error::NotSignedData => f.write_str("PKCS#7 ContentInfo is not id-signedData"),
}
}
}
impl std::error::Error for Pkcs7Error {}
impl From<synta::Error> for Pkcs7Error {
fn from(e: synta::Error) -> Self {
Pkcs7Error::Parse(e)
}
}
pub fn certs_from_pkcs7(data: &[u8]) -> Result<Vec<Vec<u8>>, Pkcs7Error> {
let mut decoder = Decoder::new(data, Encoding::Ber);
let seq_tag = Tag::universal_constructed(16); let mut outer = decoder
.enter_constructed(seq_tag)
.map_err(Pkcs7Error::Parse)?;
let content_type: ObjectIdentifier = outer.decode().map_err(Pkcs7Error::Parse)?;
if content_type.components() != ID_SIGNED_DATA {
return Err(Pkcs7Error::NotSignedData);
}
let ctx0_tag = Tag::new(TagClass::ContextSpecific, true, 0);
let mut content = outer
.enter_constructed(ctx0_tag)
.map_err(Pkcs7Error::Parse)?;
parse_signed_data_certs(&mut content)
}
fn parse_signed_data_certs(dec: &mut Decoder<'_>) -> Result<Vec<Vec<u8>>, Pkcs7Error> {
let seq_tag = Tag::universal_constructed(16); let mut inner = dec.enter_constructed(seq_tag).map_err(Pkcs7Error::Parse)?;
skip_tlv(&mut inner)?;
skip_tlv(&mut inner)?;
skip_tlv(&mut inner)?;
if inner.is_empty() {
return Ok(Vec::new());
}
let next = inner.peek_tag().map_err(Pkcs7Error::Parse)?;
if next.class() != TagClass::ContextSpecific || next.number() != 0 {
return Ok(Vec::new());
}
let ctx0_tag = Tag::new(TagClass::ContextSpecific, true, 0);
let mut cert_set = inner
.enter_constructed(ctx0_tag)
.map_err(Pkcs7Error::Parse)?;
let mut certs = Vec::new();
while !cert_set.is_empty() {
let tag = cert_set.peek_tag().map_err(Pkcs7Error::Parse)?;
if tag.class() == TagClass::Universal && tag.number() == 16 && tag.is_constructed() {
let raw: synta::RawDer = cert_set.decode().map_err(Pkcs7Error::Parse)?;
certs.push(raw.as_bytes().to_vec());
} else {
let _: synta::RawDer = cert_set.decode().map_err(Pkcs7Error::Parse)?;
}
}
Ok(certs)
}
fn skip_tlv(dec: &mut Decoder<'_>) -> Result<(), Pkcs7Error> {
let _: synta::RawDer = dec.decode().map_err(Pkcs7Error::Parse)?;
Ok(())
}