Sign with Self-Signed Certificate #44
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sign with Self-Signed Certificate | |
| on: | |
| workflow_dispatch: | |
| push: | |
| tags: | |
| - 'v*' | |
| permissions: | |
| id-token: write # Required for OIDC authentication with Sigstore | |
| contents: read # Required to read repository contents | |
| jobs: | |
| sign-binaries: | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup certificate from secrets | |
| env: | |
| CERTIFICATE_BASE64: ${{ secrets.CERTIFICATE_BASE64 }} | |
| CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} | |
| run: | | |
| if ([string]::IsNullOrEmpty($env:CERTIFICATE_BASE64)) { | |
| Write-Host "Certificate not found in secrets. Skipping Windows signing." -ForegroundColor Yellow | |
| echo "SKIP_WINDOWS_SIGNING=true" >> $env:GITHUB_ENV | |
| } else { | |
| Write-Host "Setting up certificate for Windows signing..." -ForegroundColor Cyan | |
| $certBytes = [Convert]::FromBase64String($env:CERTIFICATE_BASE64) | |
| [IO.File]::WriteAllBytes("wfdiag-signing-cert.pfx", $certBytes) | |
| Write-Host "Certificate ready" -ForegroundColor Green | |
| echo "SKIP_WINDOWS_SIGNING=false" >> $env:GITHUB_ENV | |
| } | |
| - name: Install Cosign for Sigstore | |
| uses: sigstore/cosign-installer@v3 | |
| with: | |
| cosign-release: 'v2.2.4' | |
| - name: Sign with Windows Certificate and Sigstore | |
| env: | |
| CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} | |
| run: | | |
| Write-Host "Finding binaries to sign..." -ForegroundColor Cyan | |
| $signedCount = 0 | |
| $files = Get-ChildItem -Recurse -Include "*.exe", "*.msi", "*.msix" | Where-Object { $_.Name -notlike "*build*" -and $_.Name -notlike "*temp*" } | |
| foreach ($file in $files) { | |
| $filePath = $file.FullName | |
| Write-Host "Processing: $($file.Name)" -ForegroundColor Yellow | |
| if ($env:SKIP_WINDOWS_SIGNING -eq "false") { | |
| Write-Host "Signing with Windows certificate..." -ForegroundColor Cyan | |
| $signtoolPaths = @( | |
| "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe", | |
| "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe", | |
| "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" | |
| ) | |
| $signtool = $null | |
| foreach ($path in $signtoolPaths) { | |
| if (Test-Path $path) { | |
| $signtool = $path | |
| break | |
| } | |
| } | |
| if ($signtool) { | |
| Write-Host "Using signtool: $signtool" -ForegroundColor Gray | |
| & $signtool sign /f "wfdiag-signing-cert.pfx" /p $env:CERTIFICATE_PASSWORD /fd sha256 /tr "http://timestamp.digicert.com" /td sha256 /d "WindowsForum Diagnostic Tool" /du "https://windowsforum.com" $filePath | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "Windows signature applied" -ForegroundColor Green | |
| } else { | |
| & $signtool sign /f "wfdiag-signing-cert.pfx" /p $env:CERTIFICATE_PASSWORD /fd sha256 /d "WindowsForum Diagnostic Tool" $filePath | |
| } | |
| } | |
| } | |
| Write-Host "Signing with Sigstore..." -ForegroundColor Cyan | |
| cosign sign-blob --yes $filePath --output-signature "$filePath.sig" --output-certificate "$filePath.crt" | |
| $signedCount++ | |
| } | |
| Write-Host "Processed $signedCount files" -ForegroundColor Cyan | |
| - name: Verify signatures | |
| run: | | |
| Write-Host "Verifying signatures..." -ForegroundColor Cyan | |
| $files = Get-ChildItem -Recurse -Include "*.exe", "*.msi", "*.msix" | Where-Object { $_.Name -notlike "*build*" -and $_.Name -notlike "*temp*" } | |
| foreach ($file in $files) { | |
| Write-Host "Verifying: $($file.Name)" -ForegroundColor Yellow | |
| $sig = Get-AuthenticodeSignature $file.FullName | |
| Write-Host "Status: $($sig.Status)" -ForegroundColor $(if ($sig.Status -eq "Valid") { "Green" } else { "Yellow" }) | |
| } | |
| - name: Create signing report | |
| env: | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_SHA: ${{ github.sha }} | |
| run: | | |
| Write-Host "Creating signing report..." -ForegroundColor Cyan | |
| $reportLines = @( | |
| "# Digital Signing Report", | |
| "Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss UTC')", | |
| "Repository: $env:GITHUB_REPOSITORY", | |
| "Commit: $env:GITHUB_SHA", | |
| "", | |
| "## Signed Files", | |
| "" | |
| ) | |
| $files = Get-ChildItem -Recurse -Include "*.exe", "*.msi", "*.msix" | Where-Object { $_.Name -notlike "*build*" -and $_.Name -notlike "*temp*" } | |
| foreach ($file in $files) { | |
| $reportLines += "### $($file.Name)" | |
| $reportLines += "- **Size**: $([math]::Round($file.Length / 1MB, 2)) MB" | |
| $reportLines += "- **SHA256**: $(Get-FileHash $file.FullName -Algorithm SHA256 | Select-Object -ExpandProperty Hash)" | |
| $sig = Get-AuthenticodeSignature $file.FullName | |
| $reportLines += "- **Windows Signature**: $($sig.Status)" | |
| $sigFile = "$($file.FullName).sig" | |
| if (Test-Path $sigFile) { | |
| $reportLines += "- **Sigstore Signature**: Present" | |
| } | |
| $reportLines += "" | |
| } | |
| $reportLines | Out-File -FilePath "SIGNING_REPORT.md" -Encoding UTF8 | |
| Write-Host "Report saved to SIGNING_REPORT.md" -ForegroundColor Green | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: signed-binaries-with-certificates | |
| path: | | |
| **/*.exe | |
| **/*.msi | |
| **/*.msix | |
| **/*.sig | |
| **/*.crt | |
| SIGNING_REPORT.md | |
| retention-days: 90 |