Files
openp2p/.github/scripts/sign-windows.ps1
Pikachu Ren e9e4cd6b3c add(ci): support core build & signing by cert (#166)
* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* add(ci): github action & signing

* chore: update signature CI

* fix(ci): sign windows binaries with direct CERTUM SHA1

* fix(ci): replace cert-store wait with simplysign readiness check

* feat(ci): refactor certum signing flow for release

* fix(ci): fail certum auth when session not ready

* fix(ci): retry certum auth and fail critical steps

* fix(ci): add cert preflight checks before signtool

* fix(install): update SimplySign Desktop MSI download link to version 9.4.3.90

* fix(ci): mask totp and certificate identifiers in scripts

* fix(ci): remove certificate inventory logs from release

* add(ci): CHANGE beta release

* feat(ci): resolve certum msi url dynamically from download page

* add(ci): github action & signing

* add(ci): github action & signing

* revert(ci): app/app/build.gradle for build

* add(ci): github action & signing

* add(ci): github action & signing

* Update default URLs for binary file downloads

---------

Co-authored-by: Suyunmeng <Susus0175@proton.me>
Co-authored-by: OpenP2P <89245779+TenderIronh@users.noreply.github.com>
2026-06-03 15:39:14 +08:00

182 lines
6.6 KiB
PowerShell

# Sign-Windows.ps1
# Signs Windows EasyTier executables and libraries with a Certum SimplySign cloud certificate.
param(
[string]$TargetDirectory = "sign_binaries",
[string]$CertificateSHA1 = $env:CERTUM_CERTIFICATE_SHA1,
[string]$TimestampServer = "http://time.certum.pl"
)
function Get-LatestSignToolPath {
$windowsKitsBin = Join-Path ${env:ProgramFiles(x86)} "Windows Kits\10\bin"
if (Test-Path $windowsKitsBin) {
$candidate = (
Get-ChildItem -Path $windowsKitsBin -Recurse -File -Filter "signtool.exe" -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -match "\\x64\\signtool\.exe$" } |
ForEach-Object {
$version = [version]"0.0"
if ($_.FullName -match "\\bin\\([^\\]+)\\x64\\signtool\.exe$") {
try {
$version = [version]$matches[1]
} catch {
$version = [version]"0.0"
}
}
[PSCustomObject]@{
Path = $_.FullName
Version = $version
}
} |
Sort-Object -Property Version -Descending |
Select-Object -First 1
)
if ($candidate) {
return $candidate.Path
}
}
$cmd = Get-Command "signtool.exe" -ErrorAction SilentlyContinue
if ($cmd) {
return $cmd.Source
}
return $null
}
function Find-TargetCertificate {
param([string]$Thumbprint)
$all = Get-ChildItem -Path "Cert:\CurrentUser\My", "Cert:\LocalMachine\My" -ErrorAction SilentlyContinue
# 对证书库中的 Thumbprint 同样做规范化(去除不可见字符、统一大写),避免 BOM 或格式差异导致匹配失败
return @($all | Where-Object {
$normalizedStoreThumprint = ($_.Thumbprint -replace "[^a-fA-F0-9]", "").ToUpperInvariant()
$normalizedStoreThumprint -eq $Thumbprint
})
}
function Show-PrivateKeyCertificateHints {
$candidates = Get-ChildItem -Path "Cert:\CurrentUser\My", "Cert:\LocalMachine\My" -ErrorAction SilentlyContinue |
Where-Object { $_.HasPrivateKey }
if (($null -eq $candidates) -or ($candidates.Count -eq 0)) {
Write-Host "No certificates with private keys were found in Personal stores"
return
}
Write-Host "Certificates with private keys are present in Personal stores, but details are hidden for security"
}
Write-Host "=== WINDOWS BINARY SIGNING (CERTUM SIMPLYSIGN) ==="
Write-Host "Target directory: $TargetDirectory"
if (-not (Test-Path $TargetDirectory)) {
Write-Host "ERROR: Target directory not found: $TargetDirectory"
exit 1
}
if (-not $CertificateSHA1) {
Write-Host "ERROR: CERTUM_CERTIFICATE_SHA1 environment variable not provided"
exit 1
}
$normalizedSha1 = ($CertificateSHA1 -replace "[^a-fA-F0-9]", "").ToUpperInvariant()
if ($normalizedSha1.Length -ne 40) {
Write-Host "ERROR: CERTUM_CERTIFICATE_SHA1 is invalid after normalization"
Write-Host "Raw length: $($CertificateSHA1.Length), normalized length: $($normalizedSha1.Length)"
exit 1
}
Write-Host "Expected signing certificate thumbprint has been received (masked)"
$targetCerts = Find-TargetCertificate -Thumbprint $normalizedSha1
if (($null -eq $targetCerts) -or ($targetCerts.Count -eq 0)) {
Write-Host "ERROR: Target certificate not found in Cert:\CurrentUser\My or Cert:\LocalMachine\My"
Write-Host "Authentication likely failed or CERTUM_CERTIFICATE_SHA1 is incorrect"
Show-PrivateKeyCertificateHints
exit 1
}
$targetWithPrivateKey = @($targetCerts | Where-Object { $_.HasPrivateKey })
if (($null -eq $targetWithPrivateKey) -or ($targetWithPrivateKey.Count -eq 0)) {
Write-Host "ERROR: Target certificate exists but has no available private key"
Write-Host "Signing cannot continue without private key access"
Show-PrivateKeyCertificateHints
exit 1
}
Write-Host "Locating signtool..."
$signTool = Get-LatestSignToolPath
if (-not $signTool) {
Write-Host "ERROR: signtool.exe not found"
exit 1
}
Write-Host "Found signtool: $signTool"
Write-Host "Scanning for Windows binaries to sign (.exe, .dll)..."
$filesToSign = Get-ChildItem -Path $TargetDirectory -Recurse -File |
Where-Object { $_.Extension -iin @(".exe", ".dll") }
if (($null -eq $filesToSign) -or ($filesToSign.Count -eq 0)) {
Write-Host "WARNING: No signable files (.exe, .dll) found to sign"
exit 0
}
Write-Host "Found $($filesToSign.Count) files to sign"
$signedCount = 0
$failedCount = 0
foreach ($file in $filesToSign) {
Write-Host "=== Signing: $($file.Name) ==="
Write-Host "Path: $($file.FullName)"
$attempts = @(
@{ Name = "SHA1 thumbprint + /td SHA256"; Args = @("sign", "/sha1", $normalizedSha1, "/tr", $TimestampServer, "/td", "SHA256", "/fd", "SHA256", "/v", $file.FullName) },
@{ Name = "SHA1 thumbprint in CurrentUser\\My"; Args = @("sign", "/sha1", $normalizedSha1, "/s", "My", "/tr", $TimestampServer, "/td", "SHA256", "/fd", "SHA256", "/v", $file.FullName) },
@{ Name = "SHA1 thumbprint in LocalMachine\\My"; Args = @("sign", "/sha1", $normalizedSha1, "/sm", "/s", "My", "/tr", $TimestampServer, "/td", "SHA256", "/fd", "SHA256", "/v", $file.FullName) },
@{ Name = "Auto-select cert (fallback)"; Args = @("sign", "/a", "/tr", $TimestampServer, "/td", "SHA256", "/fd", "SHA256", "/v", $file.FullName) }
)
$signed = $false
foreach ($attempt in $attempts) {
Write-Host "Attempt: $($attempt.Name)"
$signOutput = & $signTool @($attempt.Args) 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "SUCCESS: $($attempt.Name)"
$signed = $true
break
}
Write-Host "FAILED: $($attempt.Name)"
Write-Host "signtool returned a non-zero exit code; detailed output is hidden for security"
}
if ($signed) {
$signedCount++
$verifyOutput = & $signTool verify /pa /v $file.FullName 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "VERIFIED: Signature verification successful"
} else {
Write-Host "WARNING: Signature verification failed"
Write-Host "Detailed verification output is hidden for security"
}
} else {
$failedCount++
}
Write-Host ""
}
Write-Host "=== SIGNING SUMMARY ==="
Write-Host "Total files: $($filesToSign.Count)"
Write-Host "Successfully signed: $signedCount"
Write-Host "Failed to sign: $failedCount"
if ($failedCount -eq 0) {
Write-Host "ALL WINDOWS BINARIES SIGNED SUCCESSFULLY"
exit 0
}
Write-Host "SOME WINDOWS BINARIES FAILED TO SIGN"
exit 1