Sign a PE File with Mono signcode and Verify the Result
You will finish with an Authenticode signature on a copy of a PE file, such as a managed assembly, Windows executable or DLL, and a separate verification check. The examples use Mono SignCode 6.8.0.105 from the installed mono-devel package, as reported by signcode itself and package version 6.8.0.105+dfsg-3.6ubuntu2.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 20 minutes if your certificate files already exist. You need signcode, an X.509 publisher certificate in an SPC file, the matching private key in a PVK file, and a PE input file. Creating or importing a real code-signing certificate is a separate security process. Do not use a test certificate to establish production trust.
Safety checkpoint
Signing changes the file named on the command line. Work in a temporary directory or sign a deliberate copy. Keep the PVK private, and do not paste it into a shared command, log or issue.
1. Confirm the installed tool
Start with read-only checks. These commands need no elevated privileges:
$ command -v signcode
/usr/bin/signcode
$ signcode
Mono SignCode - version 6.8.0.105
Sign assemblies and PE files using Authenticode(tm).
The short usage line in the manual is signcode [options] filename. The filename is the PE file to sign. There is no separate output-file option in this interface, so treat the input path as the file that will be changed.
Checkpoint: if your version is not 6.8.0.105, stop and read that installation's help or manual page before copying these options. Version differences matter for old Mono security tools.
2. Put the inputs in a controlled workspace
Make a private working directory and copy only the executable you intend to sign. Replace the obvious placeholders with real paths. This changes only the new workspace and does not need root:
umask 077
workdir="$(mktemp -d)"
cp -- /path/to/application.exe "$workdir/application.exe"
cp -- /secure/path/publisher.spc "$workdir/publisher.spc"
cp -- /secure/path/publisher.pvk "$workdir/publisher.pvk"
cd "$workdir"
ls -l -- application.exe publisher.spc publisher.pvk
Do not use a glob for the input. A surprising second executable or a similarly named key file is an easy way to sign the wrong thing. The private key should be readable only by the account performing the signing. If you copied it into a temporary directory, remove that copy after the operation.
Checkpoint: compare the copied executable with the original before signing if you need a reproducible audit trail:
$ sha256sum /path/to/application.exe application.exe
<hash> /path/to/application.exe
<hash> application.exe
3. Sign the copied PE file
Pass the publisher certificate chain with -spc and the matching private key with -v. Select a current digest explicitly rather than relying on the documented default of SHA1:
$ signcode \
-spc publisher.spc \
-v publisher.pvk \
-a sha256 \
-n "Example application" \
-i "https://example.invalid/software" \
application.exe
The manual lists sha1, md5, sha2, sha256, sha384 and sha512; it also says the default is SHA1. SHA1 and MD5 are legacy choices. Use the digest required by your compatibility policy, and test that choice with the systems that will consume the file. Do not assume that an option accepted by this old tool is accepted by every verifier.
The -n value becomes the file description. -i records an associated URL. Both are metadata, not a trust decision. The certificate and its private key must match: -spc supplies the public certificate chain and -v supplies the key used to create the signature.
A successful run may produce little or no useful standard output. Check the exit status immediately:
$ printf 'signcode exit status: %s\n' "$?"
signcode exit status: 0
If the status is non-zero, do not distribute the file. Common causes are a missing input, an unreadable key, a certificate and key mismatch, or an unsupported option. Keep the diagnostic, fix the input, and sign a fresh copy rather than repeatedly modifying an uncertain artefact.
4. Add a timestamp when the certificate must outlive its validity
A publisher certificate can expire after release. The manual describes -t as a timestamp-service URL and says the countersignature records that the certificate was valid when the file was signed. Use the service URL supplied by your certificate or release process:
$ signcode \
-spc publisher.spc \
-v publisher.pvk \
-a sha256 \
-t "https://timestamp.example.invalid/service" \
-tr 3 \
-tw 10 \
application.exe
-tr sets the number of timestamp retries and -tw sets the delay between retries in seconds. These options do not make an unavailable service reliable, and they do not replace checking the timestamp in your verification environment. A timestamp URL is security-sensitive input: use one you trust, and review the resulting signature before release.
5. Verify the signed file
Mono's companion chktrust utility checks PE Authenticode signatures. Run it against the signed copy:
$ chktrust application.exe
Mono CheckTrust - version 6.8.0.105
Verifying file application.exe for Authenticode(tm) signatures...
The remaining lines depend on the certificate chain, trust store and whether the file was timestamped. A valid signature is not the same as a trusted publisher on every machine. A test or private certificate can verify cryptographic structure while still failing trust-chain validation for recipients. If chktrust reports no digital signature, stop and inspect the signing command, the file path and its exit status.
For a basic release check, retain the signed file's checksum and the exact certificate identifier used by your build records:
$ sha256sum application.exe
<signed-file-hash> application.exe
$ chktrust application.exe
<review the complete verification report before publishing>
6. Recover safely from a failed or unwanted signing
There is no undo option in signcode. If the result is wrong, delete only the disposable signed copy and restore the original from your trusted build output or backup. Do not overwrite the original with an unverified file:
$ rm -- "$workdir/application.exe"
$ cp -- /path/to/application.exe "$workdir/application.exe"
This removes the signed copy, not the source file. If the private key was copied into the temporary directory, remove that copy after confirming the operation is complete:
$ rm -- "$workdir/publisher.pvk"
$ rmdir -- "$workdir"
If the key may have been exposed to an unauthorised person, treat it as compromised and follow your certificate revocation and replacement procedure. That is an operational security incident, not a command-line error.
Done means
- You signed a deliberate copy of a PE file with the matching SPC and PVK files.
- You selected and recorded the digest and any timestamp settings.
signcodereturned status 0.chktrustproduced a verification report that you reviewed for signature, timestamp and trust-chain results.- The original executable and private key remain protected and unchanged.