Code signing no longer working

2

We have a legacy Windows Workflow process that uses SignerSign to apply a digital signature to an EXE. We are migrating away from the Windows Workflow process, and so I have been preparing a tool within the context of our new process to perform the same signing operation. I copy/pasted the code signing code from the Workflow Activity to a class in the new project, but I am encountering an error when I try to run it.

The rough outline of what the code does is:

  • CertOpenStore is used to open the PFX file containing the private key and certificate.
  • A certificate context is obtained by calling CertEnumCertificatesInStore on the resulting certificate store handle.
  • SignerSign is called with a SIGNER_SUBJECT_INFO pointing at the target EXE file, a SIGNER_CERT pointing at the certificate context from the previous step and a SIGNATURE_SIGNER_INFO specifying that the SHA-1 algorithm should be used. (I have tried changing the algorithm to SHA-2 512 with no change in the outcome.) The pProviderInfo parameter is NULL.
  • A separate call is made to SignerTimeStamp to apply a timestamp to the signature. A comment in the code indicates that if the pwszHttpTimeStamp parameter to SignerSign is used, it returns HRESULT 0x80070020 ("File in use"?)

When I try to run this code on Windows 10 64-bit, whether from a 32-bit or 64-bit process, I get error HRESULT 0x80092006 "No provider was specified for the store or object.". I tried supplying a pProviderInfo with the provider name set to "Microsoft Strong Cryptographic Provider" (seen in the API Monitor trace output for when SignTool.exe signs the executable -- this works) but it did not affect the outcome.

Does anyone know what exactly this error means and how to fix it?

c#
windows
digital-signature
signature
cryptoapi

1 Answer

0

I have no idea at all why this worked, but by massaging my code so that does the same thing I see SignTool doing in Rohitab's API Monitor, and then paring bits away to what appears to be the minimal working set, this now signs files again:

  • Instead of CertOpenStore,. PFXImportCertStore is used to open the PFX file and produce an HCERTSTORE. This requires loading the PFX into memory so that it can be passed in as a CRYPT_DATA_BLOB -- no big deal.
  • A certificate context is obtained using CertEnumCertificatesInStore as before.
  • CertGetCertificateChain is used on the resulting certificate context with an unrestrictive CERT_CHAIN_PARA and flags CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING | CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT. No additional store is specified. When I originally wrote this, based on the API Monitor results, I defined CERT_CHAIN_PARA_HAS_EXTRA_FIELDS and populated them the same way the API Monitor capture showed, but I continue to get S_OK from SignerSign with the short CERT_CHAIN_PARA structure as well.
  • SignerSign is called as before, except that a dummy collection-type store is passed in as the hCertStore of the SIGNER_CERT_STORE_INFO struct nested within the SIGNER_CERT. This dummy collection type store is created by calling CertOpenStore twice, once with CERT_STORE_PROV_COLLECTION and flag CERT_STORE_CREATE_NEW_FLAG and once with CERT_STORE_PROV_MEMORY specifying encodings PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, and then adding the memory store to the collection store using CertAddStoreToCollection.

If the dummy collection type store is not specified, then SignerSign complains that it cannot find a path to a trusted root. Note that the certificate I am using in my testing is self-signed, and thus doesn't have a path to a trusted root. Perhaps the dummy collection type store would not be necessary with a code signing certificate that does have a path to a trusted root, I do not presently have the means to test.

In any case, I hope this helps resolve this issue for anybody else who might have bumped into problems with SignerSign. :-)

answered on Stack Overflow Feb 20, 2018 by Jonathan Gilbert • edited Feb 20, 2018 by Jonathan Gilbert

User contributions licensed under CC BY-SA 3.0