Understand why pkcs7 block failed during verification using openssl
up vote
3
down vote
favorite
I've got PKCS#7 Der formatted file called p7
and an x509 certificate file called mroot.der.cer
which matches the root certificate of p7 chain.
I'd like to verify my p7 certificate chain using openssl using the following commands :
First - convert my mroot trusted cert file to pem format.
openssl x509 -in mroot.der.cer -inform der -outform PEM -out mroot.pem.cer
Second - verify the root chain using mroot.pem.cer
openssl smime -verify -CAfile mroot.pem.cer -in p7 -inform DER -out blabla
However, I got the following error :
Verification failure
140735569544136:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:343:Verify error:unable to get local issuer certificate
I also tried to add the last command, the -noverify
flag but got a different error.
Verification failure
140735569544136:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_doit.c:1084:
140735569544136:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:412:
The pkcs7 structure should be fine as I've extracted it from the PE file iexlorer.exe
and from its chain I've extracted the root certificate, and refer to it as a trusted one.
What am I doing wrong here ?
P.s.
To observe the same failures I did, I've uploaded the files to the following links :
https://ufile.io/vrqpt
https://ufile.io/ajgex
openssl x509certificate pkcs#7
add a comment |
up vote
3
down vote
favorite
I've got PKCS#7 Der formatted file called p7
and an x509 certificate file called mroot.der.cer
which matches the root certificate of p7 chain.
I'd like to verify my p7 certificate chain using openssl using the following commands :
First - convert my mroot trusted cert file to pem format.
openssl x509 -in mroot.der.cer -inform der -outform PEM -out mroot.pem.cer
Second - verify the root chain using mroot.pem.cer
openssl smime -verify -CAfile mroot.pem.cer -in p7 -inform DER -out blabla
However, I got the following error :
Verification failure
140735569544136:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:343:Verify error:unable to get local issuer certificate
I also tried to add the last command, the -noverify
flag but got a different error.
Verification failure
140735569544136:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_doit.c:1084:
140735569544136:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:412:
The pkcs7 structure should be fine as I've extracted it from the PE file iexlorer.exe
and from its chain I've extracted the root certificate, and refer to it as a trusted one.
What am I doing wrong here ?
P.s.
To observe the same failures I did, I've uploaded the files to the following links :
https://ufile.io/vrqpt
https://ufile.io/ajgex
openssl x509certificate pkcs#7
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I've got PKCS#7 Der formatted file called p7
and an x509 certificate file called mroot.der.cer
which matches the root certificate of p7 chain.
I'd like to verify my p7 certificate chain using openssl using the following commands :
First - convert my mroot trusted cert file to pem format.
openssl x509 -in mroot.der.cer -inform der -outform PEM -out mroot.pem.cer
Second - verify the root chain using mroot.pem.cer
openssl smime -verify -CAfile mroot.pem.cer -in p7 -inform DER -out blabla
However, I got the following error :
Verification failure
140735569544136:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:343:Verify error:unable to get local issuer certificate
I also tried to add the last command, the -noverify
flag but got a different error.
Verification failure
140735569544136:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_doit.c:1084:
140735569544136:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:412:
The pkcs7 structure should be fine as I've extracted it from the PE file iexlorer.exe
and from its chain I've extracted the root certificate, and refer to it as a trusted one.
What am I doing wrong here ?
P.s.
To observe the same failures I did, I've uploaded the files to the following links :
https://ufile.io/vrqpt
https://ufile.io/ajgex
openssl x509certificate pkcs#7
I've got PKCS#7 Der formatted file called p7
and an x509 certificate file called mroot.der.cer
which matches the root certificate of p7 chain.
I'd like to verify my p7 certificate chain using openssl using the following commands :
First - convert my mroot trusted cert file to pem format.
openssl x509 -in mroot.der.cer -inform der -outform PEM -out mroot.pem.cer
Second - verify the root chain using mroot.pem.cer
openssl smime -verify -CAfile mroot.pem.cer -in p7 -inform DER -out blabla
However, I got the following error :
Verification failure
140735569544136:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:343:Verify error:unable to get local issuer certificate
I also tried to add the last command, the -noverify
flag but got a different error.
Verification failure
140735569544136:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_doit.c:1084:
140735569544136:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pkcs7/pk7_smime.c:412:
The pkcs7 structure should be fine as I've extracted it from the PE file iexlorer.exe
and from its chain I've extracted the root certificate, and refer to it as a trusted one.
What am I doing wrong here ?
P.s.
To observe the same failures I did, I've uploaded the files to the following links :
https://ufile.io/vrqpt
https://ufile.io/ajgex
openssl x509certificate pkcs#7
openssl x509certificate pkcs#7
edited Nov 10 at 22:26
asked Nov 10 at 22:12
Zohar81
2,0311732
2,0311732
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
Your uploaded example files have a few properties which prevent it from being verified.
First, the certificate of the signer in the p7
file has expired on Apr 24 22:33:39 2014 GMT
. You will have to disable checking of the expiration date if you want to verify the chain. This is programmatically done with the verify flag X509_V_FLAG_NO_CHECK_TIME
, or the option -no_check_time
for the OpenSSL smime -verify
tool.
Then, your "root of trust", found in the mroot.pem.cer
file is not the right one. You extracted the Microsoft Time-Stamp PCA
certificate whereas the signer of the p7
file chains up to the Microsoft Code Signing PCA
certificate.
Let's say that you extract that correct certificate to a file called trust.pem.cer
. That certificate is not self-signed: its issuer is the Microsoft Root Certificate Authority
. You will have to indicate that you are using a so-called partial chain if you want such a certificate to be at the end of the chain. This is programmatically done with the verify flag X509_V_FLAG_PARTIAL_CHAIN
, or the option -partial_chain
for the OpenSSL smime -verify
tool.
Also, it looks like the OpenSSL implementation of the PKCS7 verification requires your certificate to include the extended key usage of S/MIME signing, which your certificate does not include. It looks like this can be worked around by setting a code-signing purpose for the OpenSSL X509_STORE
. The OpenSSL smime -verify
tool does not expose this kind of setting so you will have to do this programmatically by setting the XKU_CODE_SIGN
purpose. XKU
stands for eXtended Key Usage and, as a caveat, the OpenSSL documentation around that is virtually non-existent. You have to thoroughly test this if you decide to use it.
The piece of code below (return code checking omitted) successfully verifies the certificate chain in your p7
file, but not the signature:
BIO *bio_p7 = BIO_new_file("p7", "r");
PKCS7 *p7 = d2i_PKCS7_bio(bio_p7, NULL);
X509_STORE *store = X509_STORE_new();
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
X509_LOOKUP_load_file(lookup, "trust.pem.cer", X509_FILETYPE_PEM);
X509_STORE_set_purpose(store, XKU_CODE_SIGN); /* see caveat above */
X509_VERIFY_PARAM_set_flags(
X509_STORE_get0_param(store),
X509_V_FLAG_NO_CHECK_TIME | X509_V_FLAG_PARTIAL_CHAIN);
int retcode = PKCS7_verify(p7, NULL, store, NULL, NULL, PKCS7_NOSIGS);
For a verification of the signature itself: the function verify_pe_pkcs7() in osslsigncode.c
gives example code to do that. Its PKCS7_verify()
invocation does not verify the certificate chain, but it does check the signature. This requires extraction of a hash which is stored in a Microsoft-specific element in the p7 of a type called SpcIndirectDataContent
, as pointed out by @dave_thompson_085 below. It is possible to verify the signature that was taken over that hash. For a complete verification, you will also need to re-calculate the hash over the PE file itself and compare it to the hash value found in the p7.
This answer is based on OpenSSL 1.1.1. Just now, I realize that you are using libressl, which is based on a (much) older version of OpenSSL. It might not work in your case. For example, for my version of libressl, the smime -verify
tool does not support the partial_chain
and no_time_check
options because those were introduced in the OpenSSL 1.1.0 branch.
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using-content
to specify the value part of the contents does verify the signature (with-noverify
to avoid the problems with verifying the cert chain, especially EKU).
– dave_thompson_085
Nov 12 at 0:17
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
|
show 1 more comment
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Your uploaded example files have a few properties which prevent it from being verified.
First, the certificate of the signer in the p7
file has expired on Apr 24 22:33:39 2014 GMT
. You will have to disable checking of the expiration date if you want to verify the chain. This is programmatically done with the verify flag X509_V_FLAG_NO_CHECK_TIME
, or the option -no_check_time
for the OpenSSL smime -verify
tool.
Then, your "root of trust", found in the mroot.pem.cer
file is not the right one. You extracted the Microsoft Time-Stamp PCA
certificate whereas the signer of the p7
file chains up to the Microsoft Code Signing PCA
certificate.
Let's say that you extract that correct certificate to a file called trust.pem.cer
. That certificate is not self-signed: its issuer is the Microsoft Root Certificate Authority
. You will have to indicate that you are using a so-called partial chain if you want such a certificate to be at the end of the chain. This is programmatically done with the verify flag X509_V_FLAG_PARTIAL_CHAIN
, or the option -partial_chain
for the OpenSSL smime -verify
tool.
Also, it looks like the OpenSSL implementation of the PKCS7 verification requires your certificate to include the extended key usage of S/MIME signing, which your certificate does not include. It looks like this can be worked around by setting a code-signing purpose for the OpenSSL X509_STORE
. The OpenSSL smime -verify
tool does not expose this kind of setting so you will have to do this programmatically by setting the XKU_CODE_SIGN
purpose. XKU
stands for eXtended Key Usage and, as a caveat, the OpenSSL documentation around that is virtually non-existent. You have to thoroughly test this if you decide to use it.
The piece of code below (return code checking omitted) successfully verifies the certificate chain in your p7
file, but not the signature:
BIO *bio_p7 = BIO_new_file("p7", "r");
PKCS7 *p7 = d2i_PKCS7_bio(bio_p7, NULL);
X509_STORE *store = X509_STORE_new();
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
X509_LOOKUP_load_file(lookup, "trust.pem.cer", X509_FILETYPE_PEM);
X509_STORE_set_purpose(store, XKU_CODE_SIGN); /* see caveat above */
X509_VERIFY_PARAM_set_flags(
X509_STORE_get0_param(store),
X509_V_FLAG_NO_CHECK_TIME | X509_V_FLAG_PARTIAL_CHAIN);
int retcode = PKCS7_verify(p7, NULL, store, NULL, NULL, PKCS7_NOSIGS);
For a verification of the signature itself: the function verify_pe_pkcs7() in osslsigncode.c
gives example code to do that. Its PKCS7_verify()
invocation does not verify the certificate chain, but it does check the signature. This requires extraction of a hash which is stored in a Microsoft-specific element in the p7 of a type called SpcIndirectDataContent
, as pointed out by @dave_thompson_085 below. It is possible to verify the signature that was taken over that hash. For a complete verification, you will also need to re-calculate the hash over the PE file itself and compare it to the hash value found in the p7.
This answer is based on OpenSSL 1.1.1. Just now, I realize that you are using libressl, which is based on a (much) older version of OpenSSL. It might not work in your case. For example, for my version of libressl, the smime -verify
tool does not support the partial_chain
and no_time_check
options because those were introduced in the OpenSSL 1.1.0 branch.
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using-content
to specify the value part of the contents does verify the signature (with-noverify
to avoid the problems with verifying the cert chain, especially EKU).
– dave_thompson_085
Nov 12 at 0:17
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
|
show 1 more comment
up vote
2
down vote
accepted
Your uploaded example files have a few properties which prevent it from being verified.
First, the certificate of the signer in the p7
file has expired on Apr 24 22:33:39 2014 GMT
. You will have to disable checking of the expiration date if you want to verify the chain. This is programmatically done with the verify flag X509_V_FLAG_NO_CHECK_TIME
, or the option -no_check_time
for the OpenSSL smime -verify
tool.
Then, your "root of trust", found in the mroot.pem.cer
file is not the right one. You extracted the Microsoft Time-Stamp PCA
certificate whereas the signer of the p7
file chains up to the Microsoft Code Signing PCA
certificate.
Let's say that you extract that correct certificate to a file called trust.pem.cer
. That certificate is not self-signed: its issuer is the Microsoft Root Certificate Authority
. You will have to indicate that you are using a so-called partial chain if you want such a certificate to be at the end of the chain. This is programmatically done with the verify flag X509_V_FLAG_PARTIAL_CHAIN
, or the option -partial_chain
for the OpenSSL smime -verify
tool.
Also, it looks like the OpenSSL implementation of the PKCS7 verification requires your certificate to include the extended key usage of S/MIME signing, which your certificate does not include. It looks like this can be worked around by setting a code-signing purpose for the OpenSSL X509_STORE
. The OpenSSL smime -verify
tool does not expose this kind of setting so you will have to do this programmatically by setting the XKU_CODE_SIGN
purpose. XKU
stands for eXtended Key Usage and, as a caveat, the OpenSSL documentation around that is virtually non-existent. You have to thoroughly test this if you decide to use it.
The piece of code below (return code checking omitted) successfully verifies the certificate chain in your p7
file, but not the signature:
BIO *bio_p7 = BIO_new_file("p7", "r");
PKCS7 *p7 = d2i_PKCS7_bio(bio_p7, NULL);
X509_STORE *store = X509_STORE_new();
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
X509_LOOKUP_load_file(lookup, "trust.pem.cer", X509_FILETYPE_PEM);
X509_STORE_set_purpose(store, XKU_CODE_SIGN); /* see caveat above */
X509_VERIFY_PARAM_set_flags(
X509_STORE_get0_param(store),
X509_V_FLAG_NO_CHECK_TIME | X509_V_FLAG_PARTIAL_CHAIN);
int retcode = PKCS7_verify(p7, NULL, store, NULL, NULL, PKCS7_NOSIGS);
For a verification of the signature itself: the function verify_pe_pkcs7() in osslsigncode.c
gives example code to do that. Its PKCS7_verify()
invocation does not verify the certificate chain, but it does check the signature. This requires extraction of a hash which is stored in a Microsoft-specific element in the p7 of a type called SpcIndirectDataContent
, as pointed out by @dave_thompson_085 below. It is possible to verify the signature that was taken over that hash. For a complete verification, you will also need to re-calculate the hash over the PE file itself and compare it to the hash value found in the p7.
This answer is based on OpenSSL 1.1.1. Just now, I realize that you are using libressl, which is based on a (much) older version of OpenSSL. It might not work in your case. For example, for my version of libressl, the smime -verify
tool does not support the partial_chain
and no_time_check
options because those were introduced in the OpenSSL 1.1.0 branch.
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using-content
to specify the value part of the contents does verify the signature (with-noverify
to avoid the problems with verifying the cert chain, especially EKU).
– dave_thompson_085
Nov 12 at 0:17
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
|
show 1 more comment
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Your uploaded example files have a few properties which prevent it from being verified.
First, the certificate of the signer in the p7
file has expired on Apr 24 22:33:39 2014 GMT
. You will have to disable checking of the expiration date if you want to verify the chain. This is programmatically done with the verify flag X509_V_FLAG_NO_CHECK_TIME
, or the option -no_check_time
for the OpenSSL smime -verify
tool.
Then, your "root of trust", found in the mroot.pem.cer
file is not the right one. You extracted the Microsoft Time-Stamp PCA
certificate whereas the signer of the p7
file chains up to the Microsoft Code Signing PCA
certificate.
Let's say that you extract that correct certificate to a file called trust.pem.cer
. That certificate is not self-signed: its issuer is the Microsoft Root Certificate Authority
. You will have to indicate that you are using a so-called partial chain if you want such a certificate to be at the end of the chain. This is programmatically done with the verify flag X509_V_FLAG_PARTIAL_CHAIN
, or the option -partial_chain
for the OpenSSL smime -verify
tool.
Also, it looks like the OpenSSL implementation of the PKCS7 verification requires your certificate to include the extended key usage of S/MIME signing, which your certificate does not include. It looks like this can be worked around by setting a code-signing purpose for the OpenSSL X509_STORE
. The OpenSSL smime -verify
tool does not expose this kind of setting so you will have to do this programmatically by setting the XKU_CODE_SIGN
purpose. XKU
stands for eXtended Key Usage and, as a caveat, the OpenSSL documentation around that is virtually non-existent. You have to thoroughly test this if you decide to use it.
The piece of code below (return code checking omitted) successfully verifies the certificate chain in your p7
file, but not the signature:
BIO *bio_p7 = BIO_new_file("p7", "r");
PKCS7 *p7 = d2i_PKCS7_bio(bio_p7, NULL);
X509_STORE *store = X509_STORE_new();
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
X509_LOOKUP_load_file(lookup, "trust.pem.cer", X509_FILETYPE_PEM);
X509_STORE_set_purpose(store, XKU_CODE_SIGN); /* see caveat above */
X509_VERIFY_PARAM_set_flags(
X509_STORE_get0_param(store),
X509_V_FLAG_NO_CHECK_TIME | X509_V_FLAG_PARTIAL_CHAIN);
int retcode = PKCS7_verify(p7, NULL, store, NULL, NULL, PKCS7_NOSIGS);
For a verification of the signature itself: the function verify_pe_pkcs7() in osslsigncode.c
gives example code to do that. Its PKCS7_verify()
invocation does not verify the certificate chain, but it does check the signature. This requires extraction of a hash which is stored in a Microsoft-specific element in the p7 of a type called SpcIndirectDataContent
, as pointed out by @dave_thompson_085 below. It is possible to verify the signature that was taken over that hash. For a complete verification, you will also need to re-calculate the hash over the PE file itself and compare it to the hash value found in the p7.
This answer is based on OpenSSL 1.1.1. Just now, I realize that you are using libressl, which is based on a (much) older version of OpenSSL. It might not work in your case. For example, for my version of libressl, the smime -verify
tool does not support the partial_chain
and no_time_check
options because those were introduced in the OpenSSL 1.1.0 branch.
Your uploaded example files have a few properties which prevent it from being verified.
First, the certificate of the signer in the p7
file has expired on Apr 24 22:33:39 2014 GMT
. You will have to disable checking of the expiration date if you want to verify the chain. This is programmatically done with the verify flag X509_V_FLAG_NO_CHECK_TIME
, or the option -no_check_time
for the OpenSSL smime -verify
tool.
Then, your "root of trust", found in the mroot.pem.cer
file is not the right one. You extracted the Microsoft Time-Stamp PCA
certificate whereas the signer of the p7
file chains up to the Microsoft Code Signing PCA
certificate.
Let's say that you extract that correct certificate to a file called trust.pem.cer
. That certificate is not self-signed: its issuer is the Microsoft Root Certificate Authority
. You will have to indicate that you are using a so-called partial chain if you want such a certificate to be at the end of the chain. This is programmatically done with the verify flag X509_V_FLAG_PARTIAL_CHAIN
, or the option -partial_chain
for the OpenSSL smime -verify
tool.
Also, it looks like the OpenSSL implementation of the PKCS7 verification requires your certificate to include the extended key usage of S/MIME signing, which your certificate does not include. It looks like this can be worked around by setting a code-signing purpose for the OpenSSL X509_STORE
. The OpenSSL smime -verify
tool does not expose this kind of setting so you will have to do this programmatically by setting the XKU_CODE_SIGN
purpose. XKU
stands for eXtended Key Usage and, as a caveat, the OpenSSL documentation around that is virtually non-existent. You have to thoroughly test this if you decide to use it.
The piece of code below (return code checking omitted) successfully verifies the certificate chain in your p7
file, but not the signature:
BIO *bio_p7 = BIO_new_file("p7", "r");
PKCS7 *p7 = d2i_PKCS7_bio(bio_p7, NULL);
X509_STORE *store = X509_STORE_new();
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
X509_LOOKUP_load_file(lookup, "trust.pem.cer", X509_FILETYPE_PEM);
X509_STORE_set_purpose(store, XKU_CODE_SIGN); /* see caveat above */
X509_VERIFY_PARAM_set_flags(
X509_STORE_get0_param(store),
X509_V_FLAG_NO_CHECK_TIME | X509_V_FLAG_PARTIAL_CHAIN);
int retcode = PKCS7_verify(p7, NULL, store, NULL, NULL, PKCS7_NOSIGS);
For a verification of the signature itself: the function verify_pe_pkcs7() in osslsigncode.c
gives example code to do that. Its PKCS7_verify()
invocation does not verify the certificate chain, but it does check the signature. This requires extraction of a hash which is stored in a Microsoft-specific element in the p7 of a type called SpcIndirectDataContent
, as pointed out by @dave_thompson_085 below. It is possible to verify the signature that was taken over that hash. For a complete verification, you will also need to re-calculate the hash over the PE file itself and compare it to the hash value found in the p7.
This answer is based on OpenSSL 1.1.1. Just now, I realize that you are using libressl, which is based on a (much) older version of OpenSSL. It might not work in your case. For example, for my version of libressl, the smime -verify
tool does not support the partial_chain
and no_time_check
options because those were introduced in the OpenSSL 1.1.0 branch.
edited Nov 13 at 3:05
answered Nov 11 at 8:16
Reinier Torenbeek
8,95222845
8,95222845
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using-content
to specify the value part of the contents does verify the signature (with-noverify
to avoid the problems with verifying the cert chain, especially EKU).
– dave_thompson_085
Nov 12 at 0:17
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
|
show 1 more comment
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using-content
to specify the value part of the contents does verify the signature (with-noverify
to avoid the problems with verifying the cert chain, especially EKU).
– dave_thompson_085
Nov 12 at 0:17
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
Hi and thanks for the help again. The main misconception I had is that the root certificate reside inside the pkcs7 block of the PE file where in fact it I should get it somewhere else (like in windows root certificate list). Now, it's working, but I wonder if it's also possible that the root certificate will be part of the chain as the last one, and sign itself ?
– Zohar81
Nov 11 at 19:56
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
For verification of a certificate chain to have any value, you have to end with a certificate that you (or the OS) somehow know and trust -- self-signed or not. By the way, looking at the chain that you uploaded, it has a field called "Authority Information Access" that points to the certificate of the root: microsoft.com/pki/certs/MicrosoftRootCert.crt .
– Reinier Torenbeek
Nov 11 at 21:12
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using
-content
to specify the value part of the contents does verify the signature (with -noverify
to avoid the problems with verifying the cert chain, especially EKU).– dave_thompson_085
Nov 12 at 0:17
Actually the Authenticode p7 signature is on data that is embedded, but it has MS-defined structure SpcIndirectDataContent. OpenSSL doesn't handle the case where embedded data is not type pkcs7-data and not encoded as OCTET STRING, which is presumably why the code you point to makes its own memBIO to feed to PKCS7_verify. At commandline using
-content
to specify the value part of the contents does verify the signature (with -noverify
to avoid the problems with verifying the cert chain, especially EKU).– dave_thompson_085
Nov 12 at 0:17
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
@dave_thompson_085 Thanks for weighing in. My conclusion was also that the signature is on data that is embedded, but that that data is a hash of the actual PE contents. So to do a complete verification, that hash over the PE contents would have to be calculated for verification as well. Is that in line with your understanding?
– Reinier Torenbeek
Nov 12 at 0:45
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
Yes. But I took this Q to be only about the part of the process that involves the p7; doing or checking the file hash is a different problem (though also important).
– dave_thompson_085
Nov 13 at 2:38
|
show 1 more comment
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53243943%2funderstand-why-pkcs7-block-failed-during-verification-using-openssl%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown