How to Sign Software With a Code Signing Certificate
Signing is not the act of attaching a certificate to a file. The signing tool hashes the artifact, obtains a signing operation from the private key, constructs a platform-specific signature, optionally obtains trusted timestamp evidence, and embeds the resulting signature in the file format.
VERIFYcryptographic workflow
What Actually Happens When You Sign a File?
For a typical public-key code-signing workflow, the signing tool does not encrypt the entire executable with the private key. It calculates a digest over the portions of the artifact covered by the signature, then uses the private key to produce a cryptographic signature over that digest or over a structured signature object.
The certificate is used to carry the public key and signer identity information. The verifier uses the public key from the certificate to validate the signature, recomputes the digest from the received artifact, and checks that the digest represented by the signature matches the artifact. This is why changing signed content after signing can invalidate the signature.
The Certificate Is Not the Signing Operation
A code-signing certificate contains the public key and identity information needed by a verifier. It does not give the signing tool the ability to create a signature. That capability comes from the corresponding private key.
Public evidence
The certificate binds a public key to the subject identified by the certificate and carries extensions such as key usage and extended key usage. It can be distributed with the signature.
Signing capability
The private key performs the cryptographic operation. Depending on the environment, it may be in a PFX, Windows key store/provider, HSM, smart-card-like provider, or remote signing service.
Artifact evidence
The signature binds the signer identity and public key to the signed artifact. A verifier can detect when the covered data no longer matches the signature.
Determine the Artifact and Its Signature Format
Before choosing a command, identify the actual artifact format. A Windows PE executable, a Java JAR, and a macOS application bundle do not use the same signature container or verification mechanism. The signing tool must understand the file format because it needs to place signature metadata where the platform expects it.
| Artifact | Signing mechanism | What the tool is doing |
|---|---|---|
| Windows EXE / DLL | Authenticode / PE signature | Creates a Windows-compatible signature associated with the PE image and certificate. |
| Windows MSI / package | Windows package signing | Signs the package according to the package format and verification rules. |
| PowerShell script | Authenticode | Adds a script signature that PowerShell can inspect and enforce according to execution policy. |
| Java JAR | JAR signature files and signature block | Creates manifest digests, an .SF file, and a cryptographic signature block. |
| macOS app | Apple Code Signing | Signs the bundle's code and associated signing data using an Apple signing identity. |
Android and iOS use platform-specific application signing systems and should be treated as separate workflows rather than as another PFX-to-file signing command.
Check the Certificate's Key Usage and Private-Key Association
A certificate can be structurally valid and still be unsuitable for a signing operation. For public code signing, inspect the certificate's Extended Key Usage and Key Usage extensions, its validity dates, issuer, subject, and the presence of the corresponding private key.
| Property | Why it matters during signing |
|---|---|
| Private key association | The signing provider needs access to the private key corresponding to the certificate's public key. |
| Extended Key Usage | The certificate should be appropriate for code signing where the platform/profile requires that purpose. |
| Key Usage | The key must be permitted for the digital-signature operation expected by the signing environment. |
| Validity period | The certificate must be valid according to the relevant signing and verification rules. |
| Issuer and chain | The verifier needs a trust path appropriate to the target environment. |
| Algorithm and key size | The certificate's public-key algorithm must be compatible with the signing tool and target verifier. |
On Windows, Microsoft documents that SignTool can select certificates by file, subject name, issuer, or certificate hash, and that the certificate store can be searched when the private key is available through the configured cryptographic provider.
Windows EXE/DLL: Sign With SignTool and Understand the Parameters
For Windows PE files, SignTool is the most useful concrete example because its parameters expose the important pieces of the signing operation. The command below uses a password-protected PFX and requests an RFC 3161 timestamp.
signtool sign ^ /f "C:\signing\publisher.pfx" ^ /p "PFX_PASSWORD" ^ /fd SHA256 ^ /tr "TIMESTAMP_URL" ^ /td SHA256 ^ "C:\release\ExampleApp.exe"
| Option | What SignTool actually uses it for |
|---|---|
/f | Loads the signing certificate from a file. For a PFX, this can provide the certificate and private key to the signing operation. |
/p | Supplies the password needed to open the password-protected PFX. In automation, do not expose this value in source control, command history, or build logs. |
/fd SHA256 | Sets the file digest algorithm used when generating the signature. Current Microsoft documentation requires an explicit file digest option when signing. |
/tr | Specifies the RFC 3161 timestamp server endpoint. |
/td SHA256 | Sets the digest algorithm requested for the RFC 3161 timestamp operation. |
| File path | Identifies the exact artifact whose signature is being created. |
Microsoft's current SignTool documentation explicitly distinguishes /fd for the file digest from /td used with /tr for the timestamp digest. The timestamp URL must be supplied separately through /tr.
PFX_PASSWORD and TIMESTAMP_URL.Selecting the Certificate From the Windows Store
Using a certificate store changes certificate selection, but it does not eliminate the private-key requirement. SignTool can search the certificate store and select an appropriate certificate based on subject, issuer, certificate hash, or other selection criteria.
signtool sign ^ /sha1 CERTIFICATE_THUMBPRINT ^ /fd SHA256 ^ /tr "TIMESTAMP_URL" ^ /td SHA256 ^ "C:\release\ExampleApp.exe"
The thumbprint is useful when several certificates have similar subjects or when automation needs deterministic selection. A production pipeline should not rely on whichever certificate happens to be selected first from a store containing multiple candidates.
For machine-level certificates, the store scope also matters. SignTool exposes options for choosing the certificate store and machine store, while the cryptographic provider controls access to the corresponding private key.
What SignTool Is Doing to the Windows File
For an Authenticode-signed PE file, the signature is not simply appended as arbitrary text. Windows has a security directory in the PE format that can point to the certificate table containing the signature information. The signing operation therefore changes the file in a format-aware way.
Hash the covered image
The signing process calculates a digest over the portions of the PE image covered by Authenticode. The signature data itself is handled separately so adding the signature does not create a circular hash dependency.
Sign with the private key
The signer creates the cryptographic signature associated with the digest and the signing certificate. The private key does not become part of the public signature data.
Store signature evidence
The resulting signature and certificate information are embedded according to the PE signing format so Windows verification tools can locate and process them.
The exact internal structure matters when diagnosing why a file verifies before a build step but fails afterward: if a later operation changes covered bytes, the verifier recomputes a different digest.
PFX/P12 Signing: What Is Actually Inside the File?
A PFX is a PKCS#12 container. In a common code-signing setup, it can carry the certificate chain and the private key protected by a password. That makes it portable, which is useful for controlled local signing but dangerous when the file is copied broadly.
Microsoft's documentation describes the PFX signing path and specifically warns that private-key files must be protected. A PFX that contains only the public certificate is not sufficient for signing unless the corresponding private key is made available through another supported provider.
Add an RFC 3161 Timestamp as Part of the Signature Operation
A timestamp is a second cryptographic relationship layered onto the signing evidence. SignTool's /tr option requests an RFC 3161 timestamp, and /td specifies the digest algorithm requested for that timestamp operation. The TSA returns a timestamp token that the signing tool incorporates into the signature evidence.
signtool sign ^ /f "C:\signing\publisher.pfx" ^ /fd SHA256 ^ /tr "TIMESTAMP_URL" ^ /td SHA256 ^ "C:\release\ExampleApp.exe"
File signature
Answers the cryptographic question: does the signature correspond to the signed artifact and the certificate's public key?
Timestamp token
Provides signed time evidence from the TSA for the data represented by the timestamp request.
Certificate validity
Lets the verifier evaluate the signing certificate in the context of the timestamp and the applicable revocation/trust rules.
Microsoft documents /tr as the RFC 3161 timestamp option and /td as its associated timestamp digest option.
Verify the Windows Signature at Multiple Levels
A successful signing command only proves that the signing operation completed. Verification tells you whether the resulting artifact can actually be validated under a chosen Windows policy.
signtool verify /pa /v "C:\release\ExampleApp.exe"
/pa selects the default Authenticode verification policy. /v requests verbose information, which is useful for seeing the signer and diagnostic details. Microsoft notes that SignTool's default verification behavior can otherwise use the Windows driver policy, so explicitly using /pa is important when you are testing ordinary Authenticode software.
| Verification layer | Question | Failure meaning |
|---|---|---|
| Signature presence | Can the verifier find signature evidence? | The file may be unsigned or the signature structure may be unreadable. |
| Digest/integrity | Does the file still produce the expected digest? | The signed content may have changed. |
| Certificate | Does the certificate validate and identify the signer? | Certificate, key, validity, or identity problem. |
| Chain | Can the certificate chain be built to an accepted trust anchor? | Chain or trust-store problem. |
| Timestamp | Does the timestamp evidence validate? | TSA, token, chain, algorithm, or embedding problem. |
| Policy | Does the chosen verification policy accept it? | Platform or trust-policy problem. |
A File Can Be Cryptographically Signed but Still Fail Trust
Signature validity and trust are separate checks. A verifier can mathematically validate a signature with the public key in a certificate and still reject the certificate because its chain is not trusted, its purpose is wrong, its status is unacceptable, or the target policy does not recognize the issuing hierarchy.
This distinction is especially useful when a file “works on my machine.” A development machine may contain an intermediate or root certificate that is absent from another machine. That does not prove that the signed artifact itself changed.
What Happens If the Signed Artifact Changes?
The signature is tied to the data covered by the signing format. If a build or packaging operation modifies that data after signing, the verifier can recompute the digest and discover that it no longer matches the signed value.
Finalize → Sign → Verify → Release
The exact bytes that were signed are the bytes that users receive.
Finalize → Sign → Modify → Release
The release artifact can fail integrity validation because it is no longer the same signed content.
Common causes include editing executable resources, changing installer contents, rebuilding, repacking, applying a post-signing optimization, or modifying a signed script. The correct fix is usually to perform the modification before signing and sign the resulting artifact again.
PowerShell: Inspect the Certificate and Signature, Not Just the Command
PowerShell uses Authenticode for script signatures. The useful technical distinction is that the certificate selection and the script's signature status are inspectable independently.
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert Set-AuthenticodeSignature -FilePath .\deploy.ps1 -Certificate $cert Get-AuthenticodeSignature .\deploy.ps1 | Format-List Status, StatusMessage, SignerCertificate, TimeStamperCertificate
The first command searches the current user's personal certificate store for certificates marked for code signing. The signing cmdlet applies the certificate to the script. The verification cmdlet exposes the signature status, signer certificate, and timestamp certificate information that can be used during troubleshooting.
If the script changes after signing, the signature no longer corresponds to the current script contents. Re-sign the final version instead of treating the previous signature as reusable evidence.
Java JAR Signing Is a Different Cryptographic Workflow
A signed JAR is not simply a ZIP file with a certificate attached. Java's signing model uses manifest digests, a signature file, and a signature block containing the cryptographic signature and certificate chain. jarsigner performs this packaging work and can add a timestamp using an RFC 3161 TSA.
jarsigner -keystore signing.p12 -storetype PKCS12 -tsa TIMESTAMP_URL app.jar signingAlias jarsigner -verify -verbose -certs app.jar
| JAR component | Technical role |
|---|---|
| Manifest | Contains digests for JAR entries that are covered by the signing process. |
.SF file | Contains signature-related digest information for the manifest. |
| Signature block | Contains the cryptographic signature and certificate information for the signer. |
| Timestamp token | When requested, provides signed time evidence associated with the JAR signature. |
Oracle's current jarsigner documentation states that -tsa causes the tool to communicate with a TSA using the RFC 3161 TSP and store the returned timestamp token with the signature. Verification checks the signature and detects changes to signed entries.
macOS: Sign the Bundle, Then Verify the Bundle
Apple code signing is bundle-aware. The signing identity is associated with the Keychain, and the signing system can validate static code objects such as applications, tools, frameworks, plug-ins, and scripts. A macOS application can contain nested signed code, so signing order and bundle structure matter.
codesign --force --verbose --sign "Developer ID Application: Example Company" "Example.app" codesign --verify --deep --strict --verbose=2 "Example.app"
The verification stage should be performed against the final application bundle. Apple's documentation describes code signing as a mechanism that allows the system to detect changes to signed code and also exposes signing information and requirements for evaluation.
Do not treat notarization as the signing command itself. Code signing establishes the application's signing evidence; notarization is a separate Apple distribution/security process.
HSM and Remote Signing Change the Key Operation, Not the Verification Model
The most important architectural difference between local, HSM-backed, and remote signing is where the private-key operation happens. The resulting software still needs a certificate, signature, timestamp where applicable, and verification.
Signer → local private key
The signing process can directly invoke the private key through the operating system or a local provider. PFX files are one common implementation, but they are not the only model.
Signer → crypto provider → HSM
The application requests a signing operation from the protected key. The private key remains inside the HSM boundary according to the HSM's capabilities and configuration.
Signer → API/service → protected key
The build system authenticates and submits a signing request. The service performs the key operation and returns signature output without exposing the production private key as a file.
This is why a PFX-based command should not simply be copied into an HSM or cloud-signing environment. The cryptographic provider interface and authorization model are different even though the resulting signature is ultimately verified with the public key.
Local key
The signing host can access the private key directly through a local certificate/key provider.
HSM-backed key
The signing application requests a cryptographic operation while the private key remains within the protected hardware boundary.
Remote key
A service authenticates the request, applies signing policy, performs the key operation, and returns signing output.
Protect the signing key without slowing releases
For teams that need tighter control over production credentials, compare protected signing options that keep private-key operations separate from ordinary build agents.
Explore Cloud Code SigningCI/CD: Put the Cryptographic Boundary After Testing
A secure release pipeline should treat the signing step as a controlled boundary around a finalized artifact. The pipeline builds and tests first, freezes the release candidate, invokes the signing mechanism, validates the signature and timestamp, and only then publishes the artifact.
source ↓ build ↓ test ↓ final artifact ↓ authenticated signing request ↓ protected private-key operation ↓ timestamp ↓ verification ↓ release
What should not happen
Do not store production PFX files in Git, bake private keys into container images, print PFX passwords in CI logs, or let every build agent retain a reusable production signing credential.
What the pipeline should prove
It should know which artifact was signed, which signing identity was used, whether timestamping succeeded, whether verification passed, and whether the exact verified artifact was published.
Diagnose Signing Failures by the Layer That Failed
Instead of treating every signing error as a certificate problem, classify the failure first.
| Layer | Technical question | Typical evidence |
|---|---|---|
| Artifact | Is this the exact file that should be signed? | Wrong path, wrong build, post-build modification. |
| Certificate | Did the tool select the intended certificate? | Subject, issuer, thumbprint, validity, EKU. |
| Private key | Can the provider perform the private-key operation? | Missing key, inaccessible key container, provider error. |
| Signing | Was a valid signature generated? | SignTool or provider error. |
| Timestamp | Was the TSA response accepted and embedded? | Timeout, token error, TSA chain error. |
| Integrity | Did the artifact change after signing? | Invalid digest/signature after packaging. |
| Trust | Can the certificate chain be trusted? | Unknown issuer, missing intermediate, policy rejection. |
| Platform | Does the target verifier accept the signature? | Works on signer machine but fails on clean target. |
A Reproducible Windows Signing Test
When a production pipeline fails, reduce the problem to one known artifact and one known certificate. The objective is to separate key access from timestamping and verification.
If step 3 fails, investigate certificate/private-key/provider access. If step 3 succeeds but step 4 fails, investigate the generated signature and verification policy. If the signature verifies locally but the published copy fails, compare the exact bytes of the local and published artifacts before changing certificate settings.
The Complete Technical Release Path
For a Windows desktop release, the complete path can be reduced to one chain of evidence. Every stage should preserve the relationship between the artifact, the signing identity, the private-key operation, timestamp evidence, and the published file.
ExampleApp.exe
│
├── finalize build
│
├── calculate signed-data digest
│
├── private-key signature operation
│
├── attach certificate / signature structure
│
├── request RFC 3161 timestamp
│
├── embed timestamp evidence
│
├── SignTool verify /pa /v
│
├── publish exact verified bytes
│
└── verify downloaded artifact again
This is the useful mental model for the page: signing is not a button that changes a file's status. It is a sequence of cryptographic and trust operations whose output must survive verification on the system that will actually consume the software.
Release Checklist With Technical Acceptance Criteria
| Area | Acceptance criterion |
|---|---|
| Artifact | The exact final release artifact is identified and will not be modified after signing. |
| Certificate | The selected certificate has the expected subject, issuer, validity, usage, and public key. |
| Private key | The signing provider can perform the private-key operation corresponding to the certificate. |
| Signature | The platform-specific verifier validates the signature and artifact integrity. |
| Timestamp | The timestamp token is present and accepted by the target verification environment where required. |
| Trust | The certificate chain and applicable trust policy validate on a clean target environment. |
| Pipeline | The published bytes are the same verified bytes produced by the signing stage. |
| Audit | Required signing events and release identity information are retained without exposing private key material. |
Platform-Specific Next Steps
Windows / Authenticode
Continue with SignTool certificate selection, PE signing, timestamping, certificate-chain validation, and Windows trust diagnostics.
Read Windows Code Signing →Java / JAR
Continue with keystore entries, manifest digests, signature files, signature blocks, TSA tokens, and jarsigner verification.
macOS
Continue with Keychain identities, bundle signing, nested code, entitlements, requirements, and codesign verification.
Sign, inspect, verify, then release
A production signing workflow is complete only when the exact artifact users receive passes the target platform's signature, integrity, certificate, trust, and timestamp checks.
Explore Code Signing Solutions