Extract public Certificate from SMIME Message (pkcs7-signature) with OpenSSL

26,420

Solution 1

With the command-line tool, assuming the S/MIME message itself is in file message:

openssl smime -verify -in message -noverify -signer cert.pem -out textdata

This writes the signer certificate (as embedded in the signature blob) into cert.pem, and the message text data in the textdata file.

Alternatively, you can save the signature blob as an independent file (it is just a kind of attachment, so any mailer application or library should be able to do that. Then, assuming that the said blob is in a file named smime.p7s, use:

openssl pkcs7 -in smime.p7s -inform DER -print_certs

which will print out all certificates which are embedded in the PKCS#7 signature. Note that there can be several: the signer's certificate itself, and any extra certificates that the signer found fit to include (e.g. intermediate CA certificates which may help in validating his certificate).

Solution 2

Or just:

cat message.eml | openssl smime -pk7out | openssl pkcs7 -print_certs > senders-cert.pem

Solution 3

If you are writing C/C++, this code snippet would help

    //...assuming you have valid pkcs7, st1, m_store etc......

    verifyResult = PKCS7_verify( pkcs7, st1, m_store, content, out, flags);
    if(verifyResult != 1) {
        goto exit_free;
    }

    //Obtain the signers of this message. Certificates from st1 as well as any found included
    //in the message will be returned.
    signers = PKCS7_get0_signers(pkcs7, st1, flags);
    if (!save_certs(env, signerFilePath, signers)) {
        //Error log
    }

//This method will write the signer certificates into a file provided
int save_certs(JNIEnv *env, jstring signerFilePath, STACK_OF(X509) *signers)
{
    int result = 0;
    int i;
    BIO *tmp;
    int num_certificates = 0;

    if (signerFilePath == NULL) {
        return 0;
    }

    const char *signerfile = (const char *)env->GetStringUTFChars(signerFilePath, 0);
    tmp = BIO_new_file(signerfile, "w");
    if (!tmp) {
        //error. return
    }
    num_certificates = sk_X509_num(signers);
    for(i = 0; i < num_certificates; i++) {
        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
    }
    result = 1;

    exit_free:
    BIO_free(tmp);
    if (signerfile) {
        env->ReleaseStringUTFChars(signerFilePath, signerfile);
        signerfile = 0;
    }
    return result;
}
Share:
26,420

Related videos on Youtube

x2on
Author by

x2on

Team leader, Mobile Evangelist &amp; IT specialist

Updated on July 09, 2022

Comments

  • x2on
    x2on almost 2 years

    How can i extract the public certificate from an smime message (pkcs7-signature) with OpenSSL?

  • Ashish
    Ashish almost 13 years
    how can i verify and extract data from huge pkcs7 singed envelop ? Is there any option in openssl so that it can processing chunk-wise rather than no loading whole file ?
  • Liam
    Liam over 10 years
    I was looking for a way to get certificate information without creating files (just pipes and filters), and this is it. Since I'm not interested in the certificate itself, I make the last command openssl pkcs7 -print_certs -noout
  • Stanislav Serdiuk
    Stanislav Serdiuk over 2 years
    @Ashish Did you find any options? My task is verifying the digital signatures using nodeJS. I am newer in nodeJS and securing by certificates and just want to understand how it has to work properly. The question was ten years ago but maybe you remember some aspects of that issue?