Extract certificate from pkcs7


I am new to Rust and I am currently working on an application which handles PKCS7 sign and verify. This is how I verify signedData from an PKCS7:

    let mut content = Vec::new();
    let pkcs7_vec = base64::decode(&content).unwrap();
    let pkcs7 = openssl::pkcs7::Pkcs7::from_der(&pkcs7_vec).expect("Unable to convert from DER");
    let _ = pkcs7
        .verify(&certs, &store, None, Some(&mut content), flags)
        .expect("Unable to verify PKCS7 file");

in content I have the raw data which works without any problem. But how can I extract the inner certificates? In openssl the command would be:

openssl pkcs7 -in file.pem -print_certs -out certs.pem

How can I achieve this with Rust?

Thank you in advance

Best regards,

You could parse the content using whatever parser most appropriate for the content? If it's certificates you probably want to use X509's from_pem or from_der.

Or what exactly do you mean by "inner certificates"?

Thank you for your reply!

For example, my PEM encoded pkcs7 looks like this:

-----BEGIN PKCS7-----
-----END PKCS7-----

If I open up the PKCS7 data, I have this in it:

    Signature Algorithm: ecdsa-with-SHA256

Now I need only to extract the certificate from signedData so to say.


From the docs, openssl::pkcs7 crate doesn't implement decoding the wrapped content, which makes some sense, as the RFC initially describes the format:

This document describes a general syntax for data that may have cryptography applied to it

and only at the end of the introduction notes:

A degenerate case of the syntax provides a means for disseminating certificates and certificate-revocation lists.

The degenerate case seems to be described in section 9, which describes the "Signed Data" content type, and notes:

the syntax has a degenerate case in which there are no signers on the content. The degenerate case provides a means for disseminating certificates and certificate-revocation lists.

and goes on to describe the encoded data with the ASN.1 schema:

   SignedData ::= SEQUENCE {
     version Version,
     digestAlgorithms DigestAlgorithmIdentifiers,
     contentInfo ContentInfo,
        [0] IMPLICIT ExtendedCertificatesAndCertificates
       [1] IMPLICIT CertificateRevocationLists OPTIONAL,
     signerInfos SignerInfos }

which means it definitely is defined by PKCS #7, and not imported from some other ASN.1 module.

Since neither openssl nor the pkcs7 crate (written by the Rust Crypto team) implement the SignedData type, you'll probably have to give it a go yourself.

I suggest grabbing the der crate and start implementing Decode from the RFC syntax. I've found it's generally not too tough when I've messed with this before, for example, the above should look like (completely untested!):

struct SignedData {
  pub version: Version,
  pub digest_algorithms: DigestAlgorithmIdentifiers,
  pub content_info: ContentInfo,
  #[asn1(context_specific = "0")]
  pub certificates: Option<ExtendedCertificatesAndCertificates>,
  #[asn1(context_specific = "1")]
  pub crls: Option<CertificateRevocationLists>,

enum Version { V1 = 1 };

// Or you can define `AlgorithmIdentifier` yourself, it's even the `der` crate example!
type DigestAlgorithmIdentifiers = der::asn1::SetOfVec<spki::AlgorithmIdentifier>;

// This is presumably what "content" you get out of openssl::pkcs7::Pkcs7::verify(),
// which the docs imply is probably empty!
struct ContentInfo {
  pub content_type: der::asn1::ObjectIdentifier,
  #[asn1(context_specific = "0")]
  pub content: Option<der::asn1::Any>,

type ExtendedCertificatesAndCertificates = der::asn1::SetOfVec<ExtendedCertificateOrCertificate>;

enum ExtendedCertificateOrCertificate {
  // ExtendedCertificate(pkcs6::Certificate), // not implemented... 

Thank you very much! I'll go through it and report afterwards

One thing to remember here, is this is the whole PKCS#7 file, not the content. It's not clear that this SignedData payload is what you're getting, so you might have to start poking at the openssl asn1parse output to see what you're getting.

On the other hand, since this "degenerate case" has no signers, you probably can drop the openssl crate completely then.

1 Like