From 622afc2c324906f376e89e5fe050c0678fbf8af4 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Wed, 29 Jul 2026 09:40:35 +0200 Subject: [PATCH] docs(packaging/windows): fix the driver-cert runbook's RNG and secret scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get-Random is System.Random — not a cryptographic RNG, and it had no business generating the passphrase protecting a signing key. Uses RandomNumberGenerator instead (.Create()/.GetBytes() spelling works on both PS 5.1 and PS 7). Scope corrected to repo-level, matching MSIX_CERT_PFX_B64 next door: only unom/punktfunk builds drivers, so there is nothing for an org-level secret to reach. RPM_GPG_PRIVATE_KEY is org-level because other repos publish RPMs. Also records where to run it — interactive logon only (New-SelfSignedCertificate fails NTE_PERM over SSH, no key container on a network logon), and not on the CI runner, which is the one machine that executes build code. Co-Authored-By: Claude Opus 5 (1M context) --- packaging/windows/README.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packaging/windows/README.md b/packaging/windows/README.md index 84e8bd41..4514ad83 100644 --- a/packaging/windows/README.md +++ b/packaging/windows/README.md @@ -181,19 +181,29 @@ $c = New-SelfSignedCertificate -Type CodeSigningCert -Subject 'CN=punktfunk-driv -NotAfter (Get-Date).AddYears(10) $c.Thumbprint # <- publish this: paste into the "Current fingerprint" line above + SECURITY.md -# 2. Export it, protected by a strong random password. -$pw = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 32 | % { [char]$_ }) +# 2. Export it, protected by a strong random password. RandomNumberGenerator, NOT Get-Random — +# Get-Random is System.Random, which is not a cryptographic RNG and has no business generating +# the passphrase on a signing key. (.Create()/.GetBytes() works on both PS 5.1 and PS 7.) +$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create() +$bytes = [byte[]]::new(24); $rng.GetBytes($bytes); $pw = [Convert]::ToBase64String($bytes) $sec = ConvertTo-SecureString $pw -AsPlainText -Force Export-PfxCertificate -Cert "Cert:\CurrentUser\My\$($c.Thumbprint)" -FilePath .\driver.pfx -Password $sec | Out-Null [Convert]::ToBase64String([IO.File]::ReadAllBytes('.\driver.pfx')) | Set-Clipboard # -> DRIVER_CERT_PFX_B64 $pw # -> DRIVER_CERT_PASSWORD -# 3. Add BOTH as Gitea Actions secrets (org level on `unom`, like RPM_GPG_PRIVATE_KEY, so any repo -# that builds drivers inherits them), then destroy the local copies: +# 3. Add BOTH as **repo**-level Gitea Actions secrets on unom/punktfunk — same scope as the +# MSIX_CERT_PFX_B64 signing cert next door, and only this repo builds drivers. (RPM_GPG_PRIVATE_KEY +# is org-level because other repos publish RPMs; nothing else needs this one.) Then destroy the +# local copies — the .pfx must not linger on the machine that generated it: Remove-Item .\driver.pfx -Force Remove-Item "Cert:\CurrentUser\My\$($c.Thumbprint)" -Force ``` +Generate it on a machine you would trust with a signing key, at an **interactive** logon (physical +console or RDP). Over SSH, `New-SelfSignedCertificate` fails with `NTE_PERM 0x80090010`: a network +logon has no access to the user's key container. Avoid generating it on the CI runner — that box +executes build code, which is the one place a signing key should not be sitting. + Keep an offline backup of the .pfx + password somewhere you'd keep a signing key. Losing it means the next release ships a cert nobody has trusted before, and every user's installer adds a second root — recoverable, but only by re-running the install.