No description
Find a file
Zepheris 3a5faf63f4 Add MIT License with attribution
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:49:05 -06:00
.gitignore Initial Commit 2026-03-18 00:43:21 -06:00
CLAUDE.md Initial Commit 2026-03-18 00:43:21 -06:00
generate.ps1 Initial Commit 2026-03-18 00:43:21 -06:00
install-cert.ps1 Initial Commit 2026-03-18 00:43:21 -06:00
LICENSE Add MIT License with attribution 2026-03-18 00:49:05 -06:00
openssl-codesign.cnf Initial Commit 2026-03-18 00:43:21 -06:00
README.md Improve README opening description for clarity 2026-03-18 00:45:59 -06:00
sign.ps1 Initial Commit 2026-03-18 00:43:21 -06:00
verify.ps1 Initial Commit 2026-03-18 00:43:21 -06:00

Code Signing Certificate

PowerShell scripts to create, install, and use a self-signed code signing certificate for Windows.

Overview

Code signing attaches a cryptographic signature to your application so that:

  • Windows can verify the file has not been tampered with since it was signed
  • Users see your name instead of "Unknown Publisher" in UAC prompts
  • Antivirus tools are less likely to flag your app as suspicious

This project uses OpenSSL to generate a private key and self-signed certificate, then osslsigncode or signtool (Windows SDK) to sign your binaries.

Note: Self-signed certificates will still trigger Windows SmartScreen warnings for end users unless the certificate is installed in their Trusted Publishers store. For public distribution without warnings, use a certificate from a trusted CA (DigiCert, Sectigo, etc.).


Requirements

Install the following tools before running any scripts:

Tool Required Install (Windows)
OpenSSL Yes winget install FireDaemon.OpenSSL or winget install ShiningLight.OpenSSL.Light
signtool Recommended Included with Windows SDK
osslsigncode Alternative to signtool winget install osslsigncode

Run scripts from PowerShell (5.1 or 7+). Right-click the Start menu → "Windows PowerShell" or "Terminal".


Project Structure

CodeSigningCert/
├── openssl-codesign.cnf   # OpenSSL config — edit CN/O/C before first run
├── generate.ps1           # Step 1: generate key, certificate, and PFX
├── install-cert.ps1       # Step 2: install certificate into Windows trust stores
├── sign.ps1               # Step 3: sign an executable (GUI file picker)
├── verify.ps1             # Step 4: verify a signed executable (GUI file picker)
├── .gitignore             # Prevents private keys from being committed
├── CLAUDE.md              # AI assistant context for this project
└── certs\                 # Created by generate.ps1 (gitignored)
    ├── codesign.key       # Private key — keep secret
    ├── codesign.crt       # Certificate — public
    └── codesign.pfx       # PKCS#12 bundle used for signing

Setup

1. Configure your certificate details

Open openssl-codesign.cnf and update the [ req_distinguished_name ] section:

[ req_distinguished_name ]
CN = My Code Signing Certificate   # Your name or app name
O  = My Organization               # Your company or personal brand
C  = US                            # Two-letter country code

2. Generate the certificate

.\generate.ps1

This creates the certs\ directory and produces three files:

  • certs\codesign.key — your private key (never share or commit this)
  • certs\codesign.crt — your public certificate
  • certs\codesign.pfx — a PKCS#12 bundle used by signing tools

You will be prompted to set a PFX export password during generation. Save it in a password manager.

Optional: Override the certificate validity period (default is 10 years):

.\generate.ps1 -Days 365

Signing a File

# Pass the file directly
.\sign.ps1 -File MyApp.exe

# Or run without arguments — a file picker dialog will open
.\sign.ps1

The signed output is saved as <filename>-signed.exe in the same folder as the original.

Supply the PFX password directly (avoids the interactive prompt):

.\sign.ps1 -File MyApp.exe -PfxPass "yourpassword"

Use a custom timestamp server:

.\sign.ps1 -File MyApp.exe -TimestampUrl "http://timestamp.sectigo.com"

The script automatically uses signtool if available, falling back to osslsigncode.


Verifying a Signature

# Pass the file directly
.\verify.ps1 -File MyApp.exe

# Or run without arguments — a file picker dialog will open
.\verify.ps1

A message box shows whether the signature is valid. The script tries signtool, then osslsigncode, and falls back to PowerShell's built-in Get-AuthenticodeSignature.


Trusting the Certificate Locally (Windows)

To suppress UAC/SmartScreen warnings on your own machine, use the included script to install the certificate into the Windows trust stores:

# Install for all users (requires Administrator)
.\install-cert.ps1

# Install for current user only (no Administrator needed)
.\install-cert.ps1 -Scope CurrentUser

# Remove the certificate later
.\install-cert.ps1 -Uninstall

This installs the certificate into both Trusted Root Certification Authorities and Trusted Publishers, which is required for Windows to fully trust signed executables.

Manual alternative: Double-click certs/codesign.pfx, choose Local Machine, and place it in the Trusted Publishers store.


Security Reminders

  • The certs/ directory is gitignored. Never commit .key, .pfx, or .p12 files.
  • Always use a timestamp server when signing (sign.ps1 does this automatically). This ensures signatures remain valid even after the certificate expires.
  • Store your PFX password in a password manager, not in shell scripts or environment files.

Common Timestamp Servers

Provider URL
DigiCert http://timestamp.digicert.com
Sectigo http://timestamp.sectigo.com
GlobalSign http://timestamp.globalsign.com/scripts/timstamp.dll

The default used by sign.ps1 is DigiCert.