Files
esengine 579c59da70 ci(release-studio): sign and verify every PE file in the Windows tree
The Windows release signed only the three executables Studio builds. The
installed tree also ships Electron's ffmpeg.dll, dxcompiler.dll,
vk_swiftshader.dll and vulkan-1.dll unsigned, and Smart App Control / WDAC
can refuse to load an unsigned low-reputation DLL, so the app may not start.

Every PE file the Windows bundle may hold is now declared in
scripts/windows-signing-lib.ps1: seven the release signs, and
d3dcompiler_47.dll and dxil.dll, which Electron ships signed by Microsoft
and which are kept that way and verified as Microsoft-signed. A bundle with
an undeclared or missing PE file (.exe, .dll, .node, or any MZ header) fails
until a person updates the list.

windows-sign-payload signs the declared files, verifies all nine, and
records a SHA-256 digest of the whole signed tree as a job output. The
signed tree is the payload artifact; windows-package packages it as it
came. A new job, windows-verify-package, with no secrets and no
environment, checks the payload against that digest, unpacks the zip and
the installer's app-64.7z, requires both trees to equal the payload file
for file (plus resources/elevate.exe, pinned by SHA-256), and outputs the
SHA-256 of both packages. windows-sign-installer only requires the packages
to hash to those values before signing, and afterwards only runs SignTool
verification, so no archive is parsed in a job holding the Certum
credentials and Certum never signs an installer whose contents did not
match.

Signatures are read from the file itself through SignTool and the embedded
signer certificate. Get-AuthenticodeSignature answers from the OS catalog
for d3dcompiler_47.dll and reports a catalog signature whatever the file
carries.

The contract pins the new scripts, and validate now refuses a fingerprint
file that runs a script under scripts/ which is not pinned.
2026-09-27 09:09:45 -07:00

41 lines
1.7 KiB
PowerShell

param(
[Parameter(Mandatory = $true, ParameterSetName = 'Payload')]
[string]$PayloadDirectory,
[Parameter(Mandatory = $true, ParameterSetName = 'File')]
[string]$FilePath
)
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
$thumbprint = $env:CERTUM_KEY_ID
if ($thumbprint -notmatch '^[0-9a-fA-F]{40}$') { throw 'Invalid CERTUM_KEY_ID' }
. (Join-Path $PSScriptRoot 'windows-signing-lib.ps1')
$tool = Get-SignTool
if ($PSCmdlet.ParameterSetName -eq 'Payload') {
$root = (Resolve-Path -LiteralPath $PayloadDirectory).Path
$prefix = $root.TrimEnd('\', '/') + [IO.Path]::DirectorySeparatorChar
$entries = @(Get-Content -LiteralPath (Join-Path $root 'signing-files.txt') |
ForEach-Object { $_.Trim() } | Where-Object { $_ -and -not $_.StartsWith('#') })
if ($entries.Count -eq 0) { throw 'Empty signing manifest' }
$files = @($entries | ForEach-Object {
$candidate = [IO.Path]::GetFullPath((Join-Path $root $_))
if (-not $candidate.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase)) {
throw 'Signing manifest path escapes payload directory'
}
$candidate
})
} else {
$files = @((Resolve-Path -LiteralPath $FilePath).Path)
}
# Validate the entire manifest before the first signing operation.
foreach ($file in $files) {
if (-not (Test-Path -LiteralPath $file -PathType Leaf)) { throw "Missing signing input: $file" }
}
foreach ($file in $files) {
& $tool sign /sha1 $thumbprint /fd SHA256 /tr http://timestamp.certum.pl /td SHA256 $file
if ($LASTEXITCODE -ne 0) { throw "Authenticode signing failed: $file" }
Assert-EmbeddedSignature -Path $file -Thumbprint $thumbprint
}