diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3625734..a24530b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,10 +15,13 @@ permissions: env: CARGO_TERM_COLOR: always # The bundled Virtual Display Driver (VirtualDrivers/Virtual-Display-Driver, - # MIT). Pinned: the installer's scheduled tasks and lifecycle handling are - # verified against this exact version. + # MIT). Pinned by tag AND by the asset's SHA-256: upstream ships this setup + # wrapper unsigned (the driver files inside are the signed part), so exact- + # bytes pinning is the supply-chain gate — a re-tagged or replaced asset + # fails the build loudly. VDD_RELEASE_TAG: "25.5.2" VDD_ASSET: "Virtual.Display.Driver-v25.05.03-setup-x64.exe" + VDD_SHA256: "ca10b85babecfb636c85b3f04d2306968d4f940dd3dd35767f866207bfba846e" jobs: windows-installer: @@ -64,22 +67,29 @@ jobs: Invoke-WebRequest -Uri "https://raw.githubusercontent.com/VirtualDrivers/Virtual-Display-Driver/$env:VDD_RELEASE_TAG/LICENSE" ` -OutFile (Join-Path $dest "LICENSE-VirtualDisplayDriver.txt") - - name: Verify the driver's Authenticode signature + - name: Verify the driver against the pinned SHA-256 shell: pwsh run: | - $sig = Get-AuthenticodeSignature "installer\vendor\vdd\$env:VDD_ASSET" - Write-Host "Signature status: $($sig.Status) Signer: $($sig.SignerCertificate.Subject)" - if ($sig.Status -ne "Valid") { - throw "Driver signature is '$($sig.Status)' — refusing to release an unverified driver." + $path = "installer\vendor\vdd\$env:VDD_ASSET" + $hash = (Get-FileHash $path -Algorithm SHA256).Hash.ToLower() + Write-Host "Downloaded: $hash" + Write-Host "Pinned: $env:VDD_SHA256" + if ($hash -ne $env:VDD_SHA256) { + throw "Driver asset hash mismatch — upstream bytes changed; re-vet the driver before updating the pin." } + # Informational: upstream's setup wrapper is unsigned today (the + # driver files inside are the signed part). If this ever reports + # Valid, tighten this step into a hard signature check too. + $sig = Get-AuthenticodeSignature $path + Write-Host "Authenticode status (informational): $($sig.Status)" - name: Install Inno Setup shell: pwsh run: choco install innosetup -y --no-progress - - name: Build the installer (strict driver signature) + - name: Build the installer shell: pwsh - run: .\scripts\build-installer.ps1 -StrictSignature + run: .\scripts\build-installer.ps1 - name: Compute SHA-256 id: hash diff --git a/DECISIONS.md b/DECISIONS.md index 9103d21..5f97765 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -143,10 +143,13 @@ multi-monitor and virtual-display layouts land clicks on the right screen. - One version, single-sourced from `host/Cargo.toml` (`env!` into the banner and the mDNS TXT), matched by the iOS `MARKETING_VERSION`. -- CI builds releases from a `v*` tag: pinned FFmpeg, pinned driver version, - hard-fail Authenticode verification on the bundled driver, and the - installer's SHA-256 published in the release body, where the website - reads it. +- CI builds releases from a `v*` tag: pinned FFmpeg, and the bundled driver + pinned by tag AND by the asset's SHA-256 with a hard fail on mismatch. + (Upstream ships the setup wrapper unsigned — the driver files inside are + the signed part — so exact-bytes pinning is the supply-chain gate, and + the workflow reports the Authenticode status informationally in case + upstream starts signing.) The installer's SHA-256 is published in the + release body, where the website reads it. ## Deferred diff --git a/installer/vendor/vdd/README.txt b/installer/vendor/vdd/README.txt index 1c830c6..c36422e 100644 --- a/installer/vendor/vdd/README.txt +++ b/installer/vendor/vdd/README.txt @@ -31,9 +31,13 @@ license on its repository before public distribution. VERIFY BEFORE BUNDLING ---------------------- -After downloading, confirm the file is signed: - Get-AuthenticodeSignature .\Virtual.Display.Driver-v25.05.03-setup-x64.exe -The Status should be "Valid". +Upstream ships this setup wrapper UNSIGNED (Get-AuthenticodeSignature +reports NotSigned) — the signed part is the driver package inside it, which +Windows itself validates at install time. Verify the download by hash +instead; the vetted 25.5.2 asset is: + SHA-256: ca10b85babecfb636c85b3f04d2306968d4f940dd3dd35767f866207bfba846e + (Get-FileHash .\Virtual.Display.Driver-v25.05.03-setup-x64.exe) +The release workflow pins this same hash and fails the build on mismatch. NOTE: files in this folder (other than this README) are git-ignored so the binary is not committed to the repository. diff --git a/scripts/build-installer.ps1 b/scripts/build-installer.ps1 index 77a14e6..a0996e0 100644 --- a/scripts/build-installer.ps1 +++ b/scripts/build-installer.ps1 @@ -9,9 +9,10 @@ # Without it, the build still succeeds and produces an app-only installer. param( - # Release builds (CI) pass this: an unsigned or invalidly-signed bundled - # driver then FAILS the build instead of warning. Local developer builds - # keep the warning so an unsigned test driver doesn't block iteration. + # Fail the build on a driver whose Authenticode signature isn't Valid. + # Today's upstream setup wrapper is unsigned (CI pins its SHA-256 in + # release.yml instead), so leave this off unless you are bundling a + # signed driver build and want the signature enforced. [switch]$StrictSignature )