Code Signing — Authenticode Signing of Distributables

Runbook for Authenticode-signing the project's own binaries (FindMyFiles.exe and others) in the distribution zip with SSL.com eSigner (cloud HSM signing). For the decision rationale and rejected alternatives, see ADR-0020.

Current state

The signing step in .github/workflows/release.yml is wired up but dormant. Signing is non-blocking: until the repository Secrets (ES_USERNAME / CREDENTIAL_ID) are in place, cutting a tag still completes, leaving the binaries unsigned and emitting a ::warning::. Signing activates automatically from the next tag after you obtain a certificate and register the 4 Secrets below. No other CI changes are needed.

Only the project's own PE files are signed — FindMyFiles.exe (the executable the user launches = the main target of SmartScreen evaluation), fmf.exe, fmf-service.exe, fmf_engine.dll. The bundled .NET / WindowsAppSDK runtime DLLs are already Microsoft-signed and are not re-signed (to avoid wasting the signing quota and signing others' copyrighted works).

Background (why this setup)

  • An individual residing in Japan is not eligible for the individual tier of Azure Artifact Signing (formerly Trusted Signing) (US/CA/EU/UK only).
  • EV signing no longer grants immediate SmartScreen trust (Microsoft changed this in March 2024). This app ships no kernel driver, so taking EV brings almost no practical benefit. Therefore individual-name IV (Individual Validation) is sufficient.
  • SmartScreen is reputation-based. Even when signed, a warning may appear on first run and disappears as download history accumulates. The immediate effect of signing is that "unknown publisher" disappears and your name appears in the properties.

Activation procedure (when you want a certificate)

A. Obtain the certificate (SSL.com)

  1. Create an account at SSL.com.
  2. Purchase a Code Signing certificate. Choose Individual Validation (IV) with eSigner (cloud signing) support (the cloud version, not the USB token version). Expect roughly $130–250 per year.
    • Only if you want the EV title, you may choose Sole Proprietor EV (no corporate registration required). No changes to this repository's CI (same Action, same 4 Secrets). But SmartScreen behavior is the same as IV.

B. Identity verification (IV validation)

  1. Government-issued ID + identity verification (documents/video). No corporate registration required. There is a track record of Japanese individuals / sole proprietors obtaining it.

C. Configure eSigner for automated signing

  1. In the SSL.com dashboard:
    • Note the Credential ID of the signing certificate.
    • Issue and note the TOTP (2FA) secret for automated signing (a Base32 string).
    • The account username / password.

D. Register 4 GitHub Secrets

  1. In the repository → Settings → Secrets and variables → Actions → New repository secret:

    Secret nameValue
    ES_USERNAMESSL.com username
    ES_PASSWORDSSL.com password
    CREDENTIAL_IDCredential ID of the signing certificate
    ES_TOTP_SECRETTOTP secret for eSigner automated signing (Base32)

    → On the next vX.Y.Z tag (or release via workflow_dispatch), HAVE_SIGNING becomes true and signing runs.

E. Verification

  1. Dry run (possible right now, even before obtaining a certificate): with Secrets unset, run Actions → release via workflow_dispatch → confirm that the signing step is skipped, a ::warning:: is emitted, and the zip / checksum / Release creation complete without failure (= the dormant wiring does not break the pipeline).
  2. Real signing (after registering Secrets): cut a test tag (e.g. v0.0.1-rc1) and run. Confirm that "Sign staged binaries" runs and "Verify signatures" turns green with all 4 files showing signed: ... - CN=<your name>.
  3. Local confirmation: extract the Release zip and on Windows:
    signtool verify /pa /v build\dist\FindMyFiles\FindMyFiles.exe   # → Successfully verified
    Get-AuthenticodeSignature build\dist\FindMyFiles\FindMyFiles.exe # → Status: Valid
    
    In the properties of FindMyFiles.exe → "Digital Signatures" tab, your name and a timestamp appear.

Renewal (handling expiry)

  • The validity period of a publicly trusted code signing certificate is, per CA/Browser Forum rules, at most ~460 days (about 15 months). Renew at SSL.com before expiry.
  • Only if the Credential ID / TOTP change on renewal, update the corresponding Secret.

Troubleshooting

  • Verify signatures fails: batch_sign may have written the signed files to a separate folder instead of override. Check the output location in the Action log and, if needed, specify output_path in the signing step of release.yml so the copy source for "Copy signed binaries back" matches it.
  • Get-AuthenticodeSignature returns UnknownError: the public trust chain is unresolved. Check details with signtool verify /pa.
  • A SmartScreen warning still appears on first launch: expected (reputation is shallow). It disappears as downloads accumulate. Same with EV.