Skip to content

AD2022: SignSecurely

Summary

Property Value
ID AD2022
Name SignSecurely
Category Security
Severity Error
Applies to PE (Windows)

Description

Binaries should be signed using secure cryptographic algorithms. This rule verifies that if a binary is signed, it uses modern, secure signing algorithms rather than deprecated ones like SHA-1.

How It Works

The rule examines:

  1. Authenticode signature presence and validity
  2. Hash algorithm used (SHA-256 or better required)
  3. Certificate chain and timestamp validity
  4. Dual-signing for compatibility when needed

Why This Matters

Code signing with weak algorithms provides false security assurance and may be bypassable by attackers.

Algorithm Security

Algorithm Status Recommendation
MD5 Broken Never use
SHA-1 Deprecated Do not use
SHA-256 Secure Required minimum
SHA-384/512 Secure Acceptable

SHA-1 Deprecation Timeline

Date Event
2017 First practical SHA-1 collision (SHAttered)
2019 Windows stops trusting SHA-1 for new certs
2020 Chosen-prefix collision demonstrated
2021+ SHA-1 signed binaries increasingly blocked

The Collision Attack

SHA-1 collision allows:
1. Attacker creates malicious binary
2. Crafts it to have same SHA-1 hash as legitimate binary
3. Signature validates for malicious binary
4. Users trust malicious code

Signing Best Practices

Practice Reason
SHA-256 or better Collision resistant
Timestamp signature Remains valid after cert expiry
EV certificates Higher trust, SmartScreen reputation
HSM key storage Protects signing key

Dual Signing for Compatibility

# Sign with both SHA-1 (legacy) and SHA-256 (secure)
signtool sign /sha1 THUMBPRINT /fd sha256 /tr http://timestamp.url /td sha256 binary.exe
signtool sign /sha1 THUMBPRINT /as /fd sha1 /tr http://timestamp.url /td sha1 binary.exe

Performance and Resolution

Performance Considerations

Secure code signing has minimal performance impact:

Operation Impact
Signature verification (OS loader) ~5-10ms at load time
SHA-256 vs SHA-1 verification Negligible difference
Timestamping overhead Build-time only
Binary size increase ~2-5KB for signature

The security benefits far outweigh the minimal overhead. Windows caches signature verification results, so subsequent loads are faster.

Resolution Steps

1. Re-sign with SHA-256

Using Windows SDK signtool:

# Sign with SHA-256 using certificate from store
signtool sign /sha1 <CERT_THUMBPRINT> /fd sha256 /tr http://timestamp.digicert.com /td sha256 binary.exe

# Or using PFX file
signtool sign /f certificate.pfx /p <password> /fd sha256 /tr http://timestamp.digicert.com /td sha256 binary.exe

2. Dual-Sign for Legacy Compatibility

If you must support Windows Vista/7 without updates:

# First signature: SHA-256 (primary, for modern systems)
signtool sign /sha1 <CERT_THUMBPRINT> /fd sha256 /tr http://timestamp.digicert.com /td sha256 binary.exe

# Second signature: SHA-1 (appended, for legacy systems)
signtool sign /sha1 <CERT_THUMBPRINT> /as /fd sha1 /t http://timestamp.digicert.com binary.exe

3. Verify Signature Algorithm

# Check signature details
signtool verify /pa /v binary.exe

# Look for "Hash of file (sha256):" in output
# PowerShell verification
Get-AuthenticodeSignature binary.exe | Select-Object -ExpandProperty SignerCertificate | Format-List

Timestamp Server URLs

Always timestamp signatures to ensure validity after certificate expiration:

Provider SHA-256 Timestamp URL
DigiCert http://timestamp.digicert.com
Sectigo http://timestamp.sectigo.com
GlobalSign http://timestamp.globalsign.com/tsa/r6advanced1
SSL.com http://ts.ssl.com

HSM and Secure Key Storage

For production signing, use Hardware Security Modules:

# Sign using HSM-stored certificate (Azure Key Vault example)
AzureSignTool sign -kvu https://myvault.vault.azure.net `
  -kvc MyCertificateName `
  -fd sha256 `
  -tr http://timestamp.digicert.com `
  binary.exe

Certificate Best Practices

Practice Implementation
EV Certificate Higher SmartScreen trust, protected key
HSM Storage Azure Key Vault, AWS CloudHSM, on-prem HSM
Key Rotation New certificate before expiry
Access Control Limit signing key access to CI/CD only

CI/CD Integration

Azure DevOps:

- task: DotNetCoreCLI@2
  displayName: 'Sign binaries'
  inputs:
    command: 'custom'
    custom: 'tool'
    arguments: 'run sign --file-digest sha256 --timestamp-url http://timestamp.digicert.com'

GitHub Actions with Azure Key Vault:

- name: Sign binaries
  uses: azure/azure-code-signing-action@v0.3.0
  with:
    azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
    azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
    azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
    endpoint: https://wus.codesigning.azure.net/
    code-signing-account-name: my-signing-account
    certificate-profile-name: my-cert-profile
    files-folder: ./build/output
    files-folder-filter: exe,dll
    file-digest: SHA256
    timestamp-rfc3161: http://timestamp.digicert.com

Verification Script

# Batch verify all signed binaries
Get-ChildItem -Path .\build\output -Include *.exe,*.dll -Recurse | ForEach-Object {
    $sig = Get-AuthenticodeSignature $_.FullName
    if ($sig.Status -ne 'Valid') {
        Write-Error "Invalid signature: $($_.Name)"
        exit 1
    }
    if ($sig.SignerCertificate.SignatureAlgorithm.FriendlyName -match 'sha1') {
        Write-Warning "SHA-1 signature detected: $($_.Name)"
    }
}