Home/Blog/Code Signing Certificate Setup Guide: Secure Software Distribution
Security

Code Signing Certificate Setup Guide: Secure Software Distribution

Learn how to obtain and use code signing certificates for Windows Authenticode, macOS, Linux packages, and CI/CD pipelines, including 2025 regulatory changes and HSM requirements.

By InventiveHQ Team
Code Signing Certificate Setup Guide: Secure Software Distribution

Code Signing Certificate Setup Guide: Secure Software Distribution

Code signing digitally signs software to prove authenticity and integrity. When users download signed applications, they can verify the software comes from the claimed publisher and hasn't been modified since signing. Operating systems increasingly require code signing—Windows SmartScreen warns users about unsigned software, macOS Gatekeeper blocks it, and mobile platforms require it for app store distribution.

This guide covers obtaining code signing certificates, signing on Windows, macOS, and Linux, CI/CD integration, and the 2025 regulatory changes requiring HSM-based key storage.

2025 Code Signing Requirements

The CA/Browser Forum has mandated significant changes effective in 2025:

┌─────────────────────────────────────────────────────────────────────────┐
│              2025 Code Signing Certificate Changes                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  EFFECTIVE FEBRUARY 1, 2025                                             │
│  ─────────────────────────────────────────────────────────────────────  │
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  MANDATORY HSM STORAGE                                           │   │
│  │  • All code signing private keys MUST be stored in:             │   │
│  │    - Hardware Security Module (HSM)                              │   │
│  │    - Hardware token (USB, smart card)                            │   │
│  │  • FIPS 140-2 Level 2 minimum certification required             │   │
│  │  • Software key storage NO LONGER PERMITTED                      │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  SHORTER VALIDITY PERIODS                                        │   │
│  │  • Maximum certificate validity: 460 days (was 3 years)          │   │
│  │  • More frequent renewals required                               │   │
│  │  • Automation becomes essential                                   │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  STRONGER KEY REQUIREMENTS                                       │   │
│  │  • Minimum RSA key size: 3072 bits (was 2048)                   │   │
│  │  • ECDSA P-256 or P-384 also acceptable                         │   │
│  │  • SHA-256 or stronger hash algorithm required                   │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│  WHY THESE CHANGES?                                                     │
│  • High-profile key theft incidents (Nvidia, Samsung, Microsoft)        │
│  • Software-stored keys too easily compromised                          │
│  • Shorter validity limits exposure from compromised certificates       │
│  • Stronger cryptography for long-term security                         │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Action required: If you currently store code signing keys in software (PFX file, certificate store), you must transition to HSM or hardware token before your next certificate renewal.

Code Signing Certificate Types

Standard vs EV Code Signing

FeatureStandard Code SigningEV Code Signing
Identity VerificationOrganization verifiedExtended verification (like EV SSL)
SmartScreen ReputationBuilds over timeImmediate trusted reputation
User ExperienceMay show warnings initiallyNo SmartScreen warnings
Key StorageHSM required (2025+)HSM required (always)
Price Range$200-500/year$400-700/year
Best ForInternal/limited distributionCommercial software distribution

Recommendation: For commercial software, EV code signing is worth the premium to avoid SmartScreen warnings that significantly reduce download completion rates.

Certificate Providers

ProviderStandard CSEV CSHSM Options
DigiCert$474/year$619/yearCloud, Token, Network HSM
Sectigo$329/year$399/yearCloud, Token
GlobalSign$249/year$419/yearCloud, Token
SSL.com$229/year$319/yearCloud, Token
Microsoft Trusted SigningPay per signatureN/AManaged HSM

Microsoft Trusted Signing (Preview)

Microsoft's managed code signing service provides EV-equivalent reputation without managing certificates:

# Azure CLI setup
az extension add --name trustedsigning

# Create Trusted Signing account
az trustedsigning account create \
    --resource-group myRG \
    --name mySigningAccount \
    --location eastus

# Create certificate profile
az trustedsigning certificate-profile create \
    --account-name mySigningAccount \
    --profile-name Production \
    --profile-type PublicTrust \
    --include-street true \
    --include-city true

# Sign using SignTool with Trusted Signing
signtool sign /v /debug /fd SHA256 \
    /tr http://timestamp.acs.microsoft.com \
    /td SHA256 \
    /dlib "C:\Program Files\Azure\TrustedSigning\bin\Azure.CodeSigning.Dlib.dll" \
    /dmdf metadata.json \
    myapp.exe

Windows Code Signing (Authenticode)

Prerequisites

# Install Windows SDK (includes signtool.exe)
# Download from: https://developer.microsoft.com/windows/downloads/windows-sdk/

# Or install via winget
winget install Microsoft.WindowsSDK

# Verify signtool is available
& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe" /?

Signing with Hardware Token (EV Certificate)

# EV certificate on SafeNet token (automatic detection)
signtool sign /v /fd SHA256 `
    /tr http://timestamp.digicert.com `
    /td SHA256 `
    /sha1 ABC123DEF456... `
    MyApplication.exe

# For unattended signing, some tokens support PIN caching
# Or use SafeNet Authentication Client with stored PIN

# Sign multiple files
Get-ChildItem -Recurse -Include *.exe, *.dll | ForEach-Object {
    signtool sign /v /fd SHA256 `
        /tr http://timestamp.digicert.com `
        /td SHA256 `
        /sha1 ABC123DEF456... `
        $_.FullName
}

Signing with Cloud HSM (Azure Key Vault)

# Install Azure Sign Tool
dotnet tool install --global AzureSignTool

# Sign using Azure Key Vault
AzureSignTool sign `
    --azure-key-vault-url "https://myvault.vault.azure.net" `
    --azure-key-vault-client-id "client-id" `
    --azure-key-vault-client-secret "client-secret" `
    --azure-key-vault-tenant-id "tenant-id" `
    --azure-key-vault-certificate "code-signing-cert" `
    --timestamp-rfc3161 "http://timestamp.digicert.com" `
    --timestamp-digest sha256 `
    --file-digest sha256 `
    --verbose `
    MyApplication.exe

Signing Windows Drivers

Kernel-mode drivers have additional requirements:

# Drivers require EV certificate and cross-certificate
# Microsoft attestation signing for Windows 10 1607+

# Sign with EV certificate (includes cross-cert)
signtool sign /v /fd SHA256 `
    /ac "DigiCert High Assurance EV Root CA.crt" `
    /tr http://timestamp.digicert.com `
    /td SHA256 `
    /sha1 ABC123DEF456... `
    /ph `
    MyDriver.sys

# Submit to Microsoft Partner Center for attestation signing
# (Required for Windows 10 version 1607 and later)

Verify Signatures

# Verify signature
signtool verify /pa /v MyApplication.exe

# Verify with detailed output
signtool verify /pa /v /debug MyApplication.exe

# Check timestamp
signtool verify /pa /v /tw MyApplication.exe

# Expected output for valid signature:
# Successfully verified: MyApplication.exe
# Signing Certificate Chain:
#     Issued to: Example Corp
#     Issued by: DigiCert Code Signing CA
# The signature is timestamped: [date]

macOS Code Signing

Prerequisites

# Requires Apple Developer Program membership ($99/year)
# Obtain Developer ID certificate from Apple Developer portal

# List available signing identities
security find-identity -v -p codesigning

# Expected output:
# 1) ABC123... "Developer ID Application: Example Corp (TEAM123)"
# 2) DEF456... "Developer ID Installer: Example Corp (TEAM123)"

Sign Applications

# Sign application bundle
codesign --sign "Developer ID Application: Example Corp (TEAM123)" \
    --timestamp \
    --options runtime \
    --force \
    --deep \
    MyApp.app

# Verify signature
codesign --verify --verbose=4 MyApp.app
spctl --assess --verbose=4 --type execute MyApp.app

Notarization (Required for macOS 10.15+)

# Create ZIP for notarization
ditto -c -k --keepParent MyApp.app MyApp.zip

# Submit for notarization
xcrun notarytool submit MyApp.zip \
    --apple-id "[email protected]" \
    --team-id "TEAM123" \
    --password "@keychain:AC_PASSWORD" \
    --wait

# Check status
xcrun notarytool log <submission-id> \
    --apple-id "[email protected]" \
    --team-id "TEAM123" \
    --password "@keychain:AC_PASSWORD"

# Staple notarization ticket to app
xcrun stapler staple MyApp.app

# Verify notarization
spctl --assess --verbose=4 --type execute MyApp.app
# Should show: source=Notarized Developer ID

Sign Disk Images (DMG)

# Sign the DMG
codesign --sign "Developer ID Application: Example Corp (TEAM123)" \
    --timestamp \
    MyApp.dmg

# Notarize the DMG
xcrun notarytool submit MyApp.dmg \
    --apple-id "[email protected]" \
    --team-id "TEAM123" \
    --password "@keychain:AC_PASSWORD" \
    --wait

# Staple
xcrun stapler staple MyApp.dmg

Sign Installer Packages (PKG)

# Sign package
productsign --sign "Developer ID Installer: Example Corp (TEAM123)" \
    --timestamp \
    unsigned.pkg \
    signed.pkg

# Notarize
xcrun notarytool submit signed.pkg \
    --apple-id "[email protected]" \
    --team-id "TEAM123" \
    --password "@keychain:AC_PASSWORD" \
    --wait

# Staple
xcrun stapler staple signed.pkg

Linux Package Signing

GPG Signing for DEB Packages

# Generate GPG key (if not exists)
gpg --full-generate-key

# Export public key for repository
gpg --armor --export [email protected] > public.gpg

# Sign .deb package
dpkg-sig --sign builder mypackage.deb

# Verify signature
dpkg-sig --verify mypackage.deb

RPM Package Signing

# Configure RPM macros
cat >> ~/.rpmmacros << 'EOF'
%_signature gpg
%_gpg_name Developer <[email protected]>
%_gpg_path /home/developer/.gnupg
EOF

# Sign RPM
rpm --addsign mypackage.rpm

# Verify signature
rpm --checksig mypackage.rpm
rpm -K mypackage.rpm

Sign AppImage

# Sign with GPG
gpg --detach-sign --armor MyApp.AppImage

# Users verify with
gpg --verify MyApp.AppImage.asc MyApp.AppImage

CI/CD Integration

GitHub Actions (Windows)

name: Build and Sign

on:
  push:
    tags:
      - 'v*'

jobs:
  build-and-sign:
    runs-on: windows-latest

    steps:
      - uses: actions/checkout@v4

      - name: Build Application
        run: dotnet build -c Release

      - name: Decode Certificate
        run: |
          $certBytes = [Convert]::FromBase64String("${{ secrets.CODE_SIGNING_CERT }}")
          [IO.File]::WriteAllBytes("cert.pfx", $certBytes)

      - name: Sign Application
        run: |
          & "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe" sign `
            /f cert.pfx `
            /p "${{ secrets.CERT_PASSWORD }}" `
            /fd SHA256 `
            /tr http://timestamp.digicert.com `
            /td SHA256 `
            .\bin\Release\MyApp.exe

      - name: Clean Up Certificate
        if: always()
        run: Remove-Item cert.pfx -ErrorAction SilentlyContinue

GitHub Actions (Azure Key Vault)

name: Build and Sign with Azure Key Vault

on:
  push:
    tags:
      - 'v*'

jobs:
  build-and-sign:
    runs-on: windows-latest

    steps:
      - uses: actions/checkout@v4

      - name: Azure Login
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Build Application
        run: dotnet build -c Release

      - name: Install Azure Sign Tool
        run: dotnet tool install --global AzureSignTool

      - name: Sign Application
        run: |
          AzureSignTool sign `
            --azure-key-vault-url "${{ secrets.AZURE_KEY_VAULT_URL }}" `
            --azure-key-vault-client-id "${{ secrets.AZURE_CLIENT_ID }}" `
            --azure-key-vault-client-secret "${{ secrets.AZURE_CLIENT_SECRET }}" `
            --azure-key-vault-tenant-id "${{ secrets.AZURE_TENANT_ID }}" `
            --azure-key-vault-certificate "${{ secrets.CERT_NAME }}" `
            --timestamp-rfc3161 "http://timestamp.digicert.com" `
            --timestamp-digest sha256 `
            --file-digest sha256 `
            .\bin\Release\MyApp.exe

Azure DevOps Pipeline

trigger:
  tags:
    include:
      - v*

pool:
  vmImage: 'windows-latest'

steps:
  - task: DotNetCoreCLI@2
    inputs:
      command: 'build'
      configuration: 'Release'

  - task: AzureKeyVault@2
    inputs:
      azureSubscription: 'Azure-Connection'
      KeyVaultName: 'MyKeyVault'
      SecretsFilter: 'CodeSigningCert'

  - task: DotNetCoreCLI@2
    displayName: 'Install AzureSignTool'
    inputs:
      command: 'custom'
      custom: 'tool'
      arguments: 'install --global AzureSignTool'

  - script: |
      AzureSignTool sign ^
        --azure-key-vault-url "$(KeyVaultUrl)" ^
        --azure-key-vault-managed-identity ^
        --azure-key-vault-certificate "CodeSigningCert" ^
        --timestamp-rfc3161 "http://timestamp.digicert.com" ^
        --file-digest sha256 ^
        "$(Build.ArtifactStagingDirectory)\MyApp.exe"
    displayName: 'Sign Application'

Jenkins Pipeline

pipeline {
    agent { label 'windows' }

    environment {
        AZURE_CLIENT_ID = credentials('azure-client-id')
        AZURE_CLIENT_SECRET = credentials('azure-client-secret')
        AZURE_TENANT_ID = credentials('azure-tenant-id')
    }

    stages {
        stage('Build') {
            steps {
                bat 'dotnet build -c Release'
            }
        }

        stage('Sign') {
            steps {
                bat '''
                    AzureSignTool sign ^
                        --azure-key-vault-url "https://myvault.vault.azure.net" ^
                        --azure-key-vault-client-id "%AZURE_CLIENT_ID%" ^
                        --azure-key-vault-client-secret "%AZURE_CLIENT_SECRET%" ^
                        --azure-key-vault-tenant-id "%AZURE_TENANT_ID%" ^
                        --azure-key-vault-certificate "code-signing-cert" ^
                        --timestamp-rfc3161 "http://timestamp.digicert.com" ^
                        --file-digest sha256 ^
                        bin\\Release\\MyApp.exe
                '''
            }
        }
    }
}

Security Best Practices

Pre-Signing Verification

┌─────────────────────────────────────────────────────────────────────────┐
│                Code Signing Security Workflow                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. BUILD                                                               │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ • Build from verified source control                              │  │
│  │ • Use reproducible builds                                         │  │
│  │ • Lock dependency versions                                        │  │
│  │ • Scan dependencies for vulnerabilities                           │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                              │                                          │
│                              ▼                                          │
│  2. PRE-SIGN VERIFICATION                                              │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ • Static analysis (SAST)                                          │  │
│  │ • Malware scan (multiple engines)                                 │  │
│  │ • License compliance check                                        │  │
│  │ • Binary verification (no unexpected changes)                     │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                              │                                          │
│                              ▼                                          │
│  3. SIGNING                                                            │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ • HSM-protected signing key                                       │  │
│  │ • Multi-party authorization for production                        │  │
│  │ • Timestamp from multiple TSAs                                    │  │
│  │ • Audit logging of all signatures                                 │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                              │                                          │
│                              ▼                                          │
│  4. POST-SIGN VERIFICATION                                             │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ • Verify signature is valid                                       │  │
│  │ • Verify timestamp is present                                     │  │
│  │ • Test on clean system                                            │  │
│  │ • Record hash for future verification                             │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Malware Scanning Before Signing

# Scan with multiple engines before signing
# Example: VirusTotal API

#!/bin/bash
FILE="$1"
API_KEY="${VIRUSTOTAL_API_KEY}"

# Upload file
RESPONSE=$(curl -s --request POST \
    --url 'https://www.virustotal.com/api/v3/files' \
    --header "x-apikey: ${API_KEY}" \
    --form "file=@${FILE}")

ANALYSIS_ID=$(echo "$RESPONSE" | jq -r '.data.id')

# Wait for analysis
sleep 60

# Get results
RESULT=$(curl -s --request GET \
    --url "https://www.virustotal.com/api/v3/analyses/${ANALYSIS_ID}" \
    --header "x-apikey: ${API_KEY}")

MALICIOUS=$(echo "$RESULT" | jq '.data.attributes.stats.malicious')

if [ "$MALICIOUS" -gt 0 ]; then
    echo "WARNING: $MALICIOUS engines detected malware!"
    exit 1
fi

echo "Clean: proceeding with signing"

Timestamping Best Practices

# Use multiple timestamp servers for redundancy
$timestampServers = @(
    "http://timestamp.digicert.com",
    "http://timestamp.sectigo.com",
    "http://timestamp.globalsign.com",
    "http://tsa.starfieldtech.com"
)

$signed = $false
foreach ($ts in $timestampServers) {
    try {
        signtool sign /v /fd SHA256 `
            /tr $ts `
            /td SHA256 `
            /sha1 ABC123... `
            MyApp.exe

        $signed = $true
        Write-Host "Signed with timestamp from: $ts"
        break
    }
    catch {
        Write-Host "Timestamp failed from $ts, trying next..."
    }
}

if (-not $signed) {
    throw "All timestamp servers failed!"
}

Separation of Test and Production

┌─────────────────────────────────────────────────────────────────────────┐
│              Test vs Production Signing                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  TEST ENVIRONMENT                  PRODUCTION ENVIRONMENT               │
│  ─────────────────────────────────────────────────────────────────────  │
│                                                                          │
│  ┌─────────────────────┐          ┌─────────────────────┐              │
│  │ Self-Signed Cert    │          │ EV Code Signing     │              │
│  │ or Test CA          │          │ Certificate         │              │
│  └─────────────────────┘          └─────────────────────┘              │
│                                                                          │
│  • Different key from prod        • HSM-protected key                   │
│  • No SmartScreen impact          • Multi-person authorization          │
│  • Automated in CI                • Approval gate required              │
│  • Short validity                 • Full audit logging                  │
│  • Test systems only              • Customer-facing releases            │
│                                                                          │
│  NEVER use production signing key for:                                  │
│  • Development builds                                                   │
│  • Testing/QA builds                                                    │
│  • Internal tools not for distribution                                  │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Internal Code Signing (Private PKI)

For internal enterprise deployment:

# Create code signing CA (using private PKI)
# See: PKI Certificate Authority Setup Guide

# OpenSSL config for code signing template
cat > codesigning.cnf << 'EOF'
[req]
distinguished_name = req_dn
x509_extensions = v3_code

[req_dn]
CN = Internal Code Signing

[v3_code]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, codeSigning
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
EOF

# Generate code signing certificate
openssl req -new -nodes \
    -keyout codesigning.key \
    -out codesigning.csr \
    -subj "/CN=Internal Code Signing/O=Example Corp"

openssl ca -config /etc/pki/issuing-ca/openssl.cnf \
    -extensions v3_code \
    -in codesigning.csr \
    -out codesigning.crt

# Create PFX for Windows
openssl pkcs12 -export \
    -inkey codesigning.key \
    -in codesigning.crt \
    -certfile ca-chain.crt \
    -out codesigning.pfx

Deploy internal CA trust:

# Windows: Deploy via Group Policy
# Import to Trusted Publishers and Root

# PowerShell deployment
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("root-ca.crt")
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Root", "LocalMachine")
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()

$signingCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("codesigning.crt")
$pubStore = New-Object System.Security.Cryptography.X509Certificates.X509Store("TrustedPublisher", "LocalMachine")
$pubStore.Open("ReadWrite")
$pubStore.Add($signingCert)
$pubStore.Close()

Common Pitfalls

PitfallImpactPrevention
Missing timestampSignatures invalid after cert expiresAlways use timestamping with redundant TSAs
Software key storageKey theft, signing malwareHSM or hardware token (required 2025+)
Signing without scanningSigning malware as legitimatePre-sign malware scanning pipeline
Single person authorizationInsider threatMulti-person approval for production
Using prod key for testKey exposure, SmartScreen contaminationSeparate test and production keys
Weak algorithmsFuture signature invalidationSHA-256+, RSA 3072+ or ECDSA
Missing chain certificatesVerification failuresInclude full certificate chain
Delayed revocation responseExtended malware trustIncident response plan, CA communication
No signature verificationShip unsigned buildsPost-sign verification in CI
Hardcoded credentialsKey exposure in source controlSecrets management (Key Vault, etc.)

Conclusion

Code signing is essential for secure software distribution, building user trust, and meeting platform requirements. The 2025 regulatory changes requiring HSM storage and stronger keys reflect the industry's recognition that code signing key protection is critical—stolen keys have been used to sign malware impersonating major vendors.

Key takeaways:

  • Transition to HSM before your next certificate renewal (required February 2025)
  • Use EV certificates for commercial software to avoid SmartScreen warnings
  • Always timestamp signatures with multiple TSA servers
  • Integrate scanning into CI/CD to prevent signing compromised builds
  • Separate test and production signing keys and processes
  • Implement multi-person authorization for production signing

For related topics, see our guides on HSM Certificate Storage and PKI Certificate Authority Setup.

Frequently Asked Questions

Find answers to common questions

Code signing is the process of digitally signing software to verify its authenticity and integrity. When users download signed software, they can confirm it comes from the stated publisher and hasn't been tampered with. Operating systems like Windows, macOS, and mobile platforms display warnings or block unsigned code. Code signing builds trust, prevents malware distribution through your identity, and is increasingly required for enterprise software deployment and app store distribution.

Standard code signing certificates verify the organization's identity and provide SmartScreen reputation over time. EV (Extended Validation) code signing certificates undergo rigorous identity verification and provide immediate Microsoft SmartScreen reputation—no warning dialogs from day one. EV certificates must be stored on HSM or hardware token (FIPS 140-2 Level 2+). For commercial software distribution, EV certificates are strongly recommended to avoid SmartScreen warnings that reduce user trust.

Starting February 1, 2025, CA/Browser Forum requirements mandate all code signing private keys be stored in HSM or hardware tokens (FIPS 140-2 Level 2+)—software storage is no longer permitted. Maximum certificate validity reduced to 460 days (from 3 years). Minimum RSA key size increased to 3072 bits (from 2048). These changes address key theft incidents and align with industry security improvements. Plan for HSM deployment before your next certificate renewal.

Timestamping proves your signature was created while the certificate was valid. Without timestamps, signatures become invalid when the certificate expires. Always use multiple timestamp servers for redundancy. For Windows Authenticode, use RFC 3161 timestamps (/tr flag with /td SHA256). For macOS, timestamps are automatic with --timestamp flag. Timestamp servers are free—DigiCert, Sectigo, and GlobalSign provide public services. Code signed with timestamps remains valid indefinitely, even after certificate expiration.

Yes, for internal enterprise deployment. Internal code signing works when you control the trust stores of target machines (via Group Policy, MDM, or configuration management). Internal signing is ideal for internal tools, scripts, and applications that never leave your organization. For publicly distributed software, you must use a publicly-trusted code signing certificate from a commercial CA—browsers and operating systems won't trust internal CA signatures.

Use Microsoft's signtool.exe (included in Windows SDK) or open-source alternatives like osslsigncode. Basic command: signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /sha1 file.exe. For EV certificates on HSM, the tool automatically uses the hardware token. For multiple files, use batch signing. Always verify signatures with signtool verify /pa /v file.exe. Include page hash signing (/ph) for drivers.

Use Apple's codesign utility with a Developer ID certificate from Apple Developer Program ($99/year). Basic command: codesign --sign "Developer ID Application: Company Name" --timestamp --options runtime MyApp.app. For distribution, also notarize with Apple: xcrun notarytool submit MyApp.zip --apple-id [email protected] --team-id TEAMID. Notarization is required for macOS 10.15+ to avoid Gatekeeper warnings. The --options runtime enables Hardened Runtime, required for notarization.

Store signing credentials securely—never in source control. Use secrets management (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault) for certificate access. For HSM-based signing, use cloud HSM services or network HSM accessed from CI runners. In GitHub Actions, use signtool with certificate from secrets; in Azure DevOps, use built-in code signing tasks with Azure Key Vault. Run malware scans before signing to avoid signing compromised builds. Implement approval gates for production signing.

Microsoft Trusted Signing is a managed code signing service that eliminates the need to manage certificates and HSMs. It provides instant SmartScreen reputation (like EV certificates), HSM-backed key storage, and integration with Azure DevOps and GitHub Actions. Keys never leave Microsoft's HSM infrastructure. Pricing is per-signature. It's ideal for organizations wanting EV-equivalent signing without HSM management complexity. Currently requires Azure subscription and is in public preview.

Contact your CA immediately if your private key is compromised. The CA will revoke the certificate and publish to CRL/OCSP. However, revocation doesn't automatically invalidate existing signatures—timestamped code remains trusted. For complete invalidation, request your CA add the certificate to blocklists (SmartScreen, etc.). After revocation: generate new key (never reuse), obtain new certificate, re-sign all distributed software, notify users to update. Document the incident for compliance purposes.

Don't wait for a breach to act

Get a free security assessment. Our experts will identify your vulnerabilities and create a protection plan tailored to your business.