Understand why pkcs7 block failed during verification using openssl











up vote
3
down vote

favorite
1












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










share|improve this question




























    up vote
    3
    down vote

    favorite
    1












    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










    share|improve this question


























      up vote
      3
      down vote

      favorite
      1









      up vote
      3
      down vote

      favorite
      1






      1





      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










      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 10 at 22:26

























      asked Nov 10 at 22:12









      Zohar81

      2,0311732




      2,0311732
























          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.






          share|improve this answer























          • 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











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          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

























          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.






          share|improve this answer























          • 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















          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.






          share|improve this answer























          • 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













          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.






          share|improve this answer














          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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


















          • 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


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python