Code Signing Certificate Validation After Root CA Expiration: Timestamp Impact and Trust Chain Considerations


40 views

When dealing with code signing certificates, the expiration dynamics become particularly interesting when examining CA hierarchy expiration. Let's break down the technical reality:

// Example of timestamp verification in C#
var signedCms = new SignedCms();
signedCms.Decode(signedData);
var signerInfo = signedCms.SignerInfos[0];

// Critical timestamp verification
if (signerInfo.UnsignedAttributes[Pkcs9AttributeTypes.SigningTime] == null)
{
    throw new CryptographicException("Missing timestamp - vulnerable to cert expiration");
}

The presence of a RFC 3161-compliant timestamp becomes absolutely critical when the entire CA chain expires. Here's what happens at verification time:

  • Timestamped code: Verification succeeds indefinitely because the trust is anchored to the timestamp server's validity period
  • Non-timestamped code: Verification fails immediately upon any certificate in the chain expiring

Contrary to some assumptions, expired root and intermediate CAs must

openssl verify -CAfile expired_root.pem -untrusted expired_intermediate.pem code_sign_cert.pem

The verification will succeed for timestamped signatures even with expired CAs, provided:

1. The entire chain remains in trust stores

2. The timestamp was applied when all certificates were valid

3. The timestamp itself remains valid

While expiration affects different aspects than revocation, some subtle behaviors emerge:

Scenario Impact
Expired CA with missing CRL Generally acceptable as expiration supersedes revocation checks
Expired CA with revoked status Behavior varies by platform - Windows may still accept if timestamped

For developers maintaining long-term signed applications:

# PowerShell example for adding expired CA to store
Import-Certificate -FilePath "expired_root.cer" -CertStoreLocation Cert:\LocalMachine\Root
Import-Certificate -FilePath "expired_intermediate.cer" -CertStoreLocation Cert:\LocalMachine\CA

Key takeaways:

- Always use timestamping for long-lived code signatures

- Never remove expired CA certificates from trust stores

- Monitor for platform-specific behavior changes (particularly macOS Gatekeeper)


When examining code signing certificates after CA expiration, we must consider the complete trust chain. The root CA's expiration affects all subordinate certificates in the hierarchy, but timestamping creates an exception scenario.

Timestamped signatures maintain validity even after CA expiration. The verification process checks the signature's validity at the time of timestamping, not during execution. For example:


// PowerShell verification example
Get-AuthenticodeSignature -FilePath "app.exe" | 
Where-Object {$_.Status -eq "Valid" -and $_.TimeStamperCertificate -ne $null}

Your assumption is correct - expired root and intermediate CA certificates must remain in trust stores. The complete chain must validate against the signing time's trust anchor. Modern systems typically:

  • Maintain historical trust anchors
  • Support multiple trust store versions
  • Preserve CRLs for historical verification

Missing CRLs/AIAs can create problems for strict validation scenarios. However, timestamped signatures often bypass online revocation checks. Key points:


// Sample OpenSSL verification command showing revocation check
openssl verify -crl_check -CAfile root.pem -untrusted intermediate.pem codecert.pem

For Windows systems, you might need to explicitly trust expired CAs for legacy code:


certutil -addstore -f "Root" expired_root.cer
certutil -addstore -f "CA" expired_intermediate.cer

In managed environments, consider:

  • Pre-deploying historical CA bundles
  • Configuring GPOs for trust store management
  • Implementing custom validation policies for legacy code
  1. Always timestamp code signatures
  2. Maintain historical CA certificates in trust stores
  3. Preserve CRL distribution points when possible
  4. Document validation policies for legacy systems