-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathAssert-AuthenticodeSignature.ps1
More file actions
77 lines (63 loc) · 2.74 KB
/
Copy pathAssert-AuthenticodeSignature.ps1
File metadata and controls
77 lines (63 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<#
.SYNOPSIS
Verifies that every assembly under the given path is Authenticode signed by an approved certificate.
.DESCRIPTION
A valid Authenticode signature only proves that *someone* signed the file. This script additionally
requires the signer certificate's SHA-256 fingerprint to appear in a list pinned in the repository,
so a signature produced with any other certificate is rejected rather than trusted.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string[]]$Path,
[Parameter(Mandatory)]
[string]$ExpectedCertificateSha256Path,
[string]$SummaryPath = $env:GITHUB_STEP_SUMMARY
)
$ErrorActionPreference = 'Stop'
if (-not (Test-Path -LiteralPath $ExpectedCertificateSha256Path -PathType Leaf)) {
throw "Pinned certificate fingerprint file not found: $ExpectedCertificateSha256Path"
}
$allowedFingerprints = @(
Get-Content -LiteralPath $ExpectedCertificateSha256Path |
ForEach-Object { $_.Trim().ToUpperInvariant() } |
Where-Object { $_ -and -not $_.StartsWith('#') }
)
# A blank or malformed pin must fail loudly; otherwise the whole check silently becomes a no-op.
if ($allowedFingerprints.Count -eq 0 -or @($allowedFingerprints | Where-Object { $_ -notmatch '^[0-9A-F]{64}$' }).Count -gt 0) {
throw "$ExpectedCertificateSha256Path must contain at least one valid SHA-256 certificate fingerprint."
}
$assemblies = @(Get-ChildItem -Path $Path -Filter '*.dll' -Recurse -File)
if ($assemblies.Count -eq 0) {
throw "No DLLs were found under '$($Path -join ', ')'. Refusing to report success."
}
$problems = @()
$fingerprints = @{}
$signerNames = @{}
foreach ($assembly in $assemblies) {
$signature = Get-AuthenticodeSignature -LiteralPath $assembly.FullName
if ($signature.Status -ne 'Valid') {
$problems += "$($assembly.FullName): signature status $($signature.Status)."
continue
}
$fingerprint = [Convert]::ToHexString(
[System.Security.Cryptography.SHA256]::HashData($signature.SignerCertificate.RawData)
)
if ($fingerprint -notin $allowedFingerprints) {
$problems += "$($assembly.FullName): certificate SHA-256 fingerprint $fingerprint is not approved by '$ExpectedCertificateSha256Path'."
continue
}
$fingerprints[$fingerprint] = $true
$signerNames[$signature.SignerCertificate.GetNameInfo('SimpleName', $false)] = $true
}
if ($problems.Count -gt 0) {
throw "Authenticode validation failed:`n$($problems -join "`n")"
}
Write-Host "All $($assemblies.Count) DLLs signed by an approved certificate."
if ($SummaryPath) {
@(
'### Authenticode signer',
"- Subject CN: $($signerNames.Keys -join ', ')",
"- SHA-256 fingerprint: $($fingerprints.Keys -join ', ')"
) | Add-Content -LiteralPath $SummaryPath
}