# Description of Changes <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: James Brunton <james@stirlingpdf.com> Co-authored-by: James Brunton <jbrunton96@gmail.com>
7.6 KiB
Windows Code Signing Setup Guide
This guide explains how to set up Windows code signing for Stirling-PDF desktop application builds.
Overview
Windows code signing is essential for:
- Preventing Windows SmartScreen warnings
- Building trust with users
- Enabling Microsoft Store distribution
- Professional application distribution
Certificate Types
OV Certificate (Organization Validated)
- More affordable option
- Requires business verification
- May trigger SmartScreen warnings initially until reputation builds
- Suitable for most independent software vendors
EV Certificate (Extended Validation)
- Premium option with immediate SmartScreen reputation
- Requires hardware security module (HSM) or cloud-based signing
- Higher cost but provides immediate trust
- Required since June 2023 for new certificates
Obtaining a Certificate
Certificate Authorities
Popular certificate authorities for Windows code signing:
- DigiCert
- Sectigo (formerly Comodo)
- GlobalSign
- SSL.com
Certificate Format
You'll receive a certificate in one of these formats:
.pfxor.p12(preferred - contains both certificate and private key).cer+ private key (needs conversion to .pfx)
Converting to PFX (if needed)
If you have separate certificate and private key files:
openssl pkcs12 -export -out certificate.pfx -inkey private-key.key -in certificate.cer
Setting Up GitHub Secrets
Required Secrets
Navigate to your GitHub repository → Settings → Secrets and variables → Actions
Add the following secrets:
1. WINDOWS_CERTIFICATE
- Description: Base64-encoded .pfx certificate file
- How to create:
On macOS/Linux:
base64 -i certificate.pfx | pbcopy # Copies to clipboard
On Windows (PowerShell):
[Convert]::ToBase64String([IO.File]::ReadAllBytes("certificate.pfx")) | Set-Clipboard
Paste the entire base64 string into the GitHub secret.
2. WINDOWS_CERTIFICATE_PASSWORD
- Description: Password for the .pfx certificate
- Value: The password you set when creating/exporting the .pfx file
Optional Secrets for Tauri Updater
If you're using Tauri's built-in updater feature:
TAURI_SIGNING_PRIVATE_KEY
- Generated using Tauri CLI:
npm run tauri signer generate - Used for update package verification
TAURI_SIGNING_PRIVATE_KEY_PASSWORD
- Password for the Tauri signing key
Configuration Files
1. Tauri Configuration (frontend/src-tauri/tauri.conf.json)
The Windows signing configuration is already set up:
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
Configuration Options:
certificateThumbprint: Automatically extracted from imported certificate (leave asnull)digestAlgorithm: Hashing algorithm -sha256is recommendedtimestampUrl: Timestamp server to prove signing time (survives certificate expiration)
Alternative Timestamp Servers:
- DigiCert:
http://timestamp.digicert.com - Sectigo:
http://timestamp.sectigo.com - GlobalSign:
http://timestamp.globalsign.com
2. GitHub Workflow (.github/workflows/tauri-build.yml)
The workflow includes three Windows signing steps:
- Import Certificate: Decodes and imports the .pfx certificate into Windows certificate store
- Build Tauri App: Builds and signs the application using the imported certificate
- Verify Signature: Validates that both .exe and .msi files are properly signed
Testing the Setup
1. Local Testing (Windows Only)
Before pushing to GitHub, test locally:
# Set environment variables
$env:WINDOWS_CERTIFICATE = [Convert]::ToBase64String([IO.File]::ReadAllBytes("certificate.pfx"))
$env:WINDOWS_CERTIFICATE_PASSWORD = "your-certificate-password"
# Build the application
cd frontend
npm run tauri build
# Verify the signature
Get-AuthenticodeSignature "./src-tauri/target/release/bundle/msi/Stirling-PDF_*.msi"
2. GitHub Actions Testing
- Push your changes to a branch
- Manually trigger the workflow:
- Go to Actions → Build Tauri Applications
- Click "Run workflow"
- Select "windows" platform
- Check the build logs for:
- ✅ Certificate import success
- ✅ Build completion
- ✅ Signature verification
3. Verifying Signed Binaries
After downloading the built artifacts:
Windows (PowerShell):
Get-AuthenticodeSignature "Stirling-PDF-windows-x86_64.exe"
Get-AuthenticodeSignature "Stirling-PDF-windows-x86_64.msi"
Look for:
- Status:
Valid - Signer: Your organization name
- Timestamp: Recent date/time
Windows (GUI):
- Right-click the .exe or .msi file
- Select "Properties"
- Go to "Digital Signatures" tab
- Verify signature details
Troubleshooting
"HashMismatch" Status
- Certificate doesn't match the binary
- Possible file corruption during download
- Re-download and verify
"NotSigned" Status
- Certificate wasn't imported correctly
- Check GitHub secrets are set correctly
- Verify base64 encoding is complete (no truncation)
"UnknownError" Status
- Timestamp server unreachable
- Try alternative timestamp URL in tauri.conf.json
- Check network connectivity in GitHub Actions
SmartScreen Still Shows Warnings
- Normal for OV certificates initially
- Reputation builds over time with user downloads
- Consider EV certificate for immediate reputation
Certificate Not Found During Build
- Verify
WINDOWS_CERTIFICATEsecret is set - Check base64 encoding is correct (no extra whitespace)
- Ensure password is correct
Security Best Practices
-
Never commit certificates to version control
- Keep .pfx files secure and backed up
- Use GitHub secrets for CI/CD
-
Rotate certificates before expiration
- Set calendar reminders
- Update GitHub secrets with new certificate
-
Use strong passwords
- Certificate password should be complex
- Store securely (password manager)
-
Monitor certificate usage
- Review GitHub Actions logs
- Set up notifications for failed builds
-
Limit access to secrets
- Only repository admins should access secrets
- Audit secret access regularly
Certificate Lifecycle
Before Expiration
- Obtain new certificate from CA (typically annual renewal)
- Convert to .pfx format if needed
- Update
WINDOWS_CERTIFICATEsecret with new base64-encoded certificate - Update
WINDOWS_CERTIFICATE_PASSWORDif password changed - Test build to verify new certificate works
Expired Certificates
- Signed binaries remain valid (timestamp proves signing time)
- New builds will fail until certificate is renewed
- Users can still install previously signed versions
Cost Considerations
Certificate Costs (Annual, as of 2024)
- OV Certificate: $100-400/year
- EV Certificate: $400-1000/year
Choosing the Right Certificate
- Open source / early stage: Start with OV
- Commercial / enterprise: Consider EV for better trust
- Microsoft Store: EV certificate required
Additional Resources
- Tauri Windows Signing Documentation
- Microsoft Code Signing Overview
- DigiCert Code Signing Guide
- Windows SmartScreen FAQ
Support
If you encounter issues with Windows code signing:
- Check GitHub Actions logs for detailed error messages
- Verify all secrets are set correctly
- Test certificate locally first (Windows environment required)
- Open an issue in the repository with relevant logs (remove sensitive data)