The short answer
Most SignTool failures are not failures of SignTool. Since June 1, 2023, CA/Browser Forum ballot CSC-17 has required the private key of every publicly trusted code signing certificate to be generated and held in hardware meeting FIPS 140-2 Level 2 or Common Criteria EAL 4+, so the two error classes that now dominate are SignTool cannot reach the key and the timestamp step failed. Read the hex code rather than the sentence: SignerSign() failed is a wrapper, and the HRESULT printed after it is what identifies the cause.
On this page
Why are most SignTool errors not really about SignTool?
Because SignTool never touches your private key. It asks Windows for a certificate, then asks a cryptographic provider to produce a signature with the key behind that certificate. The provider is separate software — token middleware, or a library supplied by a cloud signing service — and it is where the failure normally happens. SignTool only reports what came back.
This is a fairly recent shift in what goes wrong. Before June 2023 you could import a PFX file, point /f at it, and the whole provider layer was a file on disk that either existed or did not. Ballot CSC-17 ended that for publicly trusted certificates: the key must now be generated inside hardware meeting FIPS 140-2 Level 2 or Common Criteria EAL 4+, and marked non-exportable. A USB token, an HSM you run, or a CA cloud signing service are the three legitimate homes for it.
Most of the advice you will find for these errors predates that change, which is why so much of it does not work. Guidance that begins “re-import the PFX with the private key” is answering a question about a world that no longer exists for public code signing. The certificate you are trying to use cannot be re-imported, because it was never exportable in the first place. Whatever is wrong sits in the path between SignTool and the hardware.
There is a second thing worth knowing before you start. The timestamp request is a separate network call to the certificate authority, made after the signature is produced. It fails for entirely different reasons than signing does, it fails far more often, and its failures are recoverable without re-signing. Half of the confusion in SignTool troubleshooting comes from treating those two steps as one.
How do you diagnose a SignTool error quickly?
Run the command again with /debug placed directly after sign, and read what it prints before changing anything. SignTool then lists every certificate it considered and why each one was skipped, which sorts the problem into one of four buckets: nothing was found, something was found but filtered out, a certificate was chosen and the signing call failed, or the file was signed and only the timestamp failed.
Those four buckets have almost nothing in common, and three of them are fixed somewhere other than the command line. Working out which one you are in takes about thirty seconds and saves the far more common approach of editing flags at random until something changes.
One detail that catches people repeatedly: run the diagnostic as the same account that will run the real command. A certificate in your desktop user’s Personal store is invisible to a build service running as NT AUTHORITY\SYSTEM or a dedicated service account, and a command that works perfectly in your own shell will fail in the pipeline for that reason alone. If you are debugging a CI failure, reproduce it under the CI account before you conclude anything.
What does “No certificates were found that met all the given criteria” mean?
It means SignTool searched and came back empty. The search is narrower than most people assume: it looks in the Personal certificate store of the account running the command, for certificates that carry the Code Signing extended key usage, have an associated private key, and match whatever selection flag you passed. Failing any one of those conditions produces this message, with no indication of which one failed.
Work through them in this order, because they get progressively less likely:
- Is the key reachable at all? For a USB token, that means plugged in and its middleware installed — without the card software, Windows cannot see the certificate, never mind the key. Our guide to SafeNet Authentication Client walks through the four checks that isolate a token-not- detected error. For a cloud signing service, it means the desktop client or provider library is running and authenticated.
- Is it the right account? Open
certmgr.mscas the account that runs SignTool and look under Personal → Certificates. If the certificate is not there, nothing else you do to the command will help. - Is your selection filter too tight?
/nmatches on subject name and is fussy about it. Selecting by thumbprint with/sha1removes that whole class of problem: copy the value from the certificate’s Details tab, Thumbprint field, and strip the spaces. - Is it actually a code signing certificate? A TLS certificate, a document signing certificate, or a self-signed test certificate without the Code Signing EKU will be filtered out. So will an expired one.
In a reseller support queue this error is overwhelmingly the first one a new customer hits, and the cause is nearly always the first bullet rather than the last: the token arrived, the certificate was collected, and the middleware was never installed. It is worth ruling out before you touch the command at all.
What does “SignerSign() failed” actually tell you?
On its own, nothing. SignerSign() is the Windows API that SignTool calls to produce the signature, so this line appears whenever that call returns an error — which covers dozens of unrelated causes. The information is in the two numbers printed after it. They are the same value twice: a signed decimal, and the standard Windows HRESULT in hex. The hex is the part to search for.
Three HRESULTs cover most of what you will see. 0x80090016 means the key set does not exist — the certificate is visible but the private key behind it is not, which on a token means it is unplugged or its middleware is not loaded. 0x80070520 says a specified logon session does not exist, which is the same problem seen from the other side: the key is there, but not reachable from the session the command is running in. 0x8007000B is a format error, and for MSIX or Appx packages it almost always means the publisher name in the manifest does not match the certificate’s subject.
That last one deserves a note, because the fix is not on the signing side. The manifest’s Publisher attribute has to match the certificate subject exactly, field for field, including the country code — not approximately, and not just the common name. Either edit the manifest to match the certificate, or accept that the certificate you bought decides what your package’s publisher string has to be. Microsoft’s own MSIX troubleshooting guidance points at the same mismatch, and suggests the AppxPackaging operational log in Event Viewer when the message alone is not enough.
What if SignTool finds the certificate but not the private key?
Then the certificate and the key have become separated, and you need to tell SignTool which provider holds the key. A certificate in the Windows store is just a public document; the link to the key is a provider reference stored alongside it. If that reference is missing, stale, or points at a provider that is not currently running, you get a key set or logon session error rather than a certificate error.
For a physical token, the fix is normally to reinstall or restart the token middleware, then re-import the certificate through the vendor’s own tool rather than by double-clicking the file. Importing a .cer by hand creates exactly this situation: the certificate lands in the store with no key association at all.
For cloud signing, you usually have to name the provider explicitly. The pattern is /csp "<provider name>" /kc <key alias>, where the provider name is the CSP or KSP the service installs and the alias identifies the key inside it — DigiCert KeyLocker documents this shape for its KSP, and Certum’s SimplySign takes the related route of presenting the cloud key as a virtual card reader so that ordinary thumbprint selection works. Which of the two styles applies to you is a property of the service, not of SignTool, so the vendor’s own signing document is the authority.
If you are hitting this repeatedly on a build server, the real answer is probably a change of delivery model rather than a better command. Physical tokens were designed for a person at a desk, and every workaround for using one unattended is worse than the problem. Cloud signing services and networked HSMs exist precisely because build agents cannot plug anything in; our code signing certificates are available with cloud key storage for that reason. The trade-offs between the two are laid out in our comparison of cloud signing and USB tokens.
Why does the timestamp server keep failing?
Nine times out of ten, because the flag and the protocol do not match. SignTool has two timestamp options that are not interchangeable: /tr speaks RFC 3161 and expects /td SHA256 alongside it, while /t speaks the older Authenticode timestamp protocol. Point either one at the other’s endpoint and you get “could not be reached or returned an invalid response”, even though the URL is perfectly reachable in a browser.
The second cause is the network rather than the command. Timestamp endpoints are plain HTTP, not HTTPS, which is correct — RFC 3161 responses are signed, so the transport does not need to be — but it means outbound filters that allow only port 443 will silently break timestamping while everything else on the build agent works. Public timestamp servers are also genuinely busy at times, and a request that fails now may succeed a minute later.
The practical response is to stop coupling the two steps. If signtool sign reported a timestamp failure, the file on disk is already signed; adding the timestamp afterwards with signtool timestamp /tr <url> /td SHA256 app.exe gives an identical result. In a pipeline, retrying the timestamp alone — with a short backoff, and a fallback server on the second attempt — is both faster and cheaper than repeating a signing call against a rate-limited cloud key.
Do not be tempted to drop the timestamp to make a red build go green. An untimestamped signature stops validating the day the certificate expires, and what our guide to code signing timestamping describes as a formality is the thing keeping every release you have ever shipped verifiable.
What happens when the certificate has expired or been revoked?
An expired certificate cannot sign anything new, and SignTool reports it as “no certificates were found” rather than saying so — the expiry check is part of the selection filter, so the certificate is simply excluded. Files you signed earlier are unaffected as long as they were timestamped: the timestamp records that the signature existed while the certificate was valid, and Windows keeps honouring it.
Revocation behaves differently, and worse. Where expiry is a clean line in time that a timestamp protects you from, a revocation can be dated to cover signatures made before it, in which case the timestamp does not save them. This is the scenario that makes key compromise so expensive: it is not the next release that is at risk, it is every release still in the field.
Expiry is also arriving more often than it used to. Under CA/Browser Forum ballot CSC-31, code signing certificates issued on or after March 1, 2026 are capped at 460 days, down from the previous 39-month maximum, so the three-year cycle many teams built their release process around is gone. If your certificate is approaching that line, plan the replacement certificate before the last release of the cycle rather than after the first failed build — validation on a new organisation takes days, not minutes, and a token still has to be shipped if that is your delivery model.
SignTool error code reference
These are the HRESULTs that account for most SignTool failures in a hardware-key setup, with what each one means and where the cause usually sits. Match the hex value from your error line against the first column; the message text on its own is not specific enough to go on.
| HRESULT | Windows meaning | What it usually is when signing |
|---|---|---|
0x8007000B | ERROR_BAD_FORMAT | The file or its manifest is not in the shape the signer expects. For MSIX and Appx packages the usual cause is a publisher name in the manifest that does not match the certificate subject, field for field. |
0x80090016 | Keyset does not exist | The certificate is visible but its private key is not. Token unplugged, middleware not loaded, or the key belongs to a different user profile than the one running SignTool. |
0x80070520 | A specified logon session does not exist | The private key cannot be reached from the current logon session. Classic on build agents and service accounts, and on certificates imported into the wrong certificate context. |
0x80092009 | CRYPT_E_NO_MATCH — cannot find the requested object | The object being asked for is not there. On a verify run it usually means the file carries no signature of the type being checked. |
0x80004005 | E_FAIL — unspecified error | Carries no information at all. Re-run with /debug, and check the provider's own log if you are signing through a cloud service. |
Two named errors do not carry a hex code and are worth listing alongside them. “No file digest algorithm specified” means you are on a SignTool version where /fd is mandatory; add /fd SHA256. “The specified timestamp server either could not be reached or returned an invalid response” is the flag and protocol mismatch covered above, not usually a dead server.
If your error is not here, the command that resolves it is almost always the same one: signtool sign /debug …. Step by step instructions for a working command, including the flags that changed in recent SDK versions, are in our guide to signing an EXE with SignTool.
When the fix is the certificate rather than the command
Some of these errors are not solvable at the command line: an expired certificate, a key stranded on a token nobody can plug into a build agent, or a delivery model that never suited the pipeline it ended up in. Our code signing certificates are issued by Certum and available with cloud key storage as well as a physical token, so unattended signing does not depend on hardware being present at the machine doing the work.
Related reading
- How to sign an EXE with SignTool — the working command, flag by flag, before anything goes wrong with it.
- Code signing in CI/CD — how signing works on a build agent that has no token and no person attached to it.
- Timestamping explained — why the step that fails most often is also the one you cannot skip.