How can i extract the public certificate from an smime message (pkcs7-signature) with OpenSSL?
3 Answers
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).

- 72,986
- 14
- 147
- 189
-
1how 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 ? – Ashish Jun 28 '11 at 19:46
-
@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? – Stanislav Serdiuk Nov 09 '21 at 12:38
-
Is there an easy way to get specifically the signerʼs cert and not others, *without* going through the `smime -verify` route which can fail even with `-noverify` if the signature doesnʼt match the message? I could probably figure out how to process the output of `openssl pkcs7` to get it but that sounds fragile – Daniel H Aug 19 '23 at 03:55
-
Ah, right after I asked that I found the `-nosigs` option to `openssl smime` which when paired with `-noverify` looks like itʼll extract the signer no matter what as long as `openssl` can read the signature file. – Daniel H Aug 19 '23 at 04:01
Or just:
cat message.eml | openssl smime -pk7out | openssl pkcs7 -print_certs > senders-cert.pem

- 7,547
- 1
- 17
- 8
-
1I 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` – Liam Nov 15 '13 at 18:49
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;
}

- 602
- 2
- 7
- 22