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.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
.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?
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:
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.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
. :-)
User contributions licensed under CC BY-SA 3.0