Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .config/codesignpolicy.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<SiPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:schemas-microsoft-com:sipolicy">
<VersionEx>10.4.0.0</VersionEx>
<PolicyTypeID>{A244370E-44C9-4C06-B551-F6016E563076}</PolicyTypeID>
<PlatformID>{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}</PlatformID>
<!-- Do not inherit the default policy: this policy must accept only the signer below. -->
<Rules />
<EKUs>
<EKU ID="ID_EKU_WINDOWS" Value="010A2B0601040182370A0306" FriendlyName="Windows EKU - 1.3.6.1.4.1.311.10.3.6" />
<EKU ID="ID_EKU_WHQL" Value="010A2B0601040182370A0305" FriendlyName="WHQL EKU - 1.3.6.1.4.1.311.10.3.5" />
<EKU ID="ID_EKU_ELAM" Value="010A2B0601040182373D0401" FriendlyName="Early Launch AntiMalware EKU - 1.3.6.1.4.1.311.61.4.1" />
<EKU ID="ID_EKU_HAL_EXT" Value="010A2B0601040182373D0501" FriendlyName="Hardware Abstraction Layer EKU - 1.3.6.1.4.1.311.61.5.1" />
<EKU ID="ID_EKU_RT_EXT" Value="010A2B0601040182370A0315" FriendlyName="Windows RT EKU - 1.3.6.1.4.1.311.10.3.21" />
<EKU ID="ID_EKU_STORE" Value="010A2B0601040182374C0301" FriendlyName="Windows Store EKU - 1.3.6.1.4.1.311.76.3.1" />
<EKU ID="ID_EKU_DCODEGEN" Value="010A2B0601040182374C0501" FriendlyName="Dynamic Code Generation EKU - 1.3.6.1.4.1.311.76.5.1" />
<EKU ID="ID_EKU_AM" Value="010A2B0601040182374C0B01" FriendlyName="AntiMalware EKU - 1.3.6.1.4.1.311.76.11.1" />
<EKU ID="ID_EKU_ENCLAVE" Value="010A2B0601040182370A032A" FriendlyName="Enclave EKU - 1.3.6.1.4.1.311.10.3.42" />
</EKUs>
<FileRules>
<FileAttrib ID="ID_FILEATTRIB_REFRESH_POLICY" FriendlyName="RefreshPolicy.exe FileAttribute" FileName="RefreshPolicy.exe" MinimumFileVersion="10.0.19042.0" />
</FileRules>
<!--
The vPack pipeline signs every .dll, .exe and every signed .ps1/.psm1/.psd1/.ps1xml with the
Windows build tools certificate (windows_build_tools_cert_id / CP-458204). This policy therefore
allows the "Windows Internal Build Tools CodeSign" publisher and nothing else, so that any file
that is not signed with the tools certificate is reported by CodeSign Validation.
CodeSign Validation evaluates these payload files under the user mode (UMCI) scenario.
-->
<Signers>
<Signer Name="Windows Internal Build Tools PCA 2020" ID="ID_SIGNER_S_0">
<CertRoot Type="TBS" Value="0B0692273CF07E96C7A9EC4177E3044368B383CBF8E03BAC215C3E3BC5C203482262169804ACD1F473C57C2831A3F191" />
<CertPublisher Value="Windows Internal Build Tools CodeSign" />
</Signer>
</Signers>
<SigningScenarios>
<SigningScenario ID="ID_SIGNINGSCENARIO_KMCI" FriendlyName="Kernel Mode Signing Scenario" Value="131">
<ProductSigners />
</SigningScenario>
<SigningScenario ID="ID_SIGNINGSCENARIO_UMCI" FriendlyName="User Mode Signing Scenario" Value="12">
<ProductSigners>
<AllowedSigners>
<AllowedSigner SignerId="ID_SIGNER_S_0" />
</AllowedSigners>
</ProductSigners>
</SigningScenario>
</SigningScenarios>
<UpdatePolicySigners />
<CiSigners>
<CiSigner SignerId="ID_SIGNER_S_0" />
</CiSigners>
<HvciOptions>0</HvciOptions>
<Settings>
<Setting Provider="PolicyInfo" Key="Information" ValueName="Name">
<Value>
<String>CodeSignCustomPolicy_2026-08-31</String>
</Value>
</Setting>
<Setting Provider="PolicyInfo" Key="Information" ValueName="Id">
<Value>
<String>2026-08-31</String>
</Value>
</Setting>
</Settings>
</SiPolicy>
1 change: 0 additions & 1 deletion .pipelines/PowerShell-vPack-Official.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ extends:
enabled: false

globalSdl:
useCustomPolicy: true # for signing code
disableLegacyManifest: true
# disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates.
armory:
Expand Down
11 changes: 9 additions & 2 deletions .pipelines/templates/obp-file-signing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ parameters:
binPath: '$(ob_outputDirectory)'
globalTool: 'false'
SigningProfile: 'external_distribution'
ThirdPartySigningProfile: '$(msft_3rd_party_cert_id)'
SignAllBinariesWithThirdPartyProfile: false
OfficialBuild: true
vPackScenario: false

Expand Down Expand Up @@ -106,7 +108,12 @@ steps:
$signatures = $dlls | Get-AuthenticodeSignature
$officialIssuerPattern = '^CN=(Microsoft Code Signing PCA|Microsoft Root Certificate Authority|Microsoft Corporation).*'
$testCert = '^CN=(Microsoft|TestAzureEngBuildCodeSign).*'
$missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch $testCert -or $_.SignerCertificate.Issuer -notmatch $officialIssuerPattern} | select-object -ExpandProperty Path
$signAllBinaries = [System.Convert]::ToBoolean('${{ parameters.SignAllBinariesWithThirdPartyProfile }}')
if ($signAllBinaries) {
$missingSignatures = $signatures | Select-Object -ExpandProperty Path
} else {
$missingSignatures = $signatures | Where-Object { $_.status -eq 'notsigned' -or $_.SignerCertificate.Issuer -notmatch $testCert -or $_.SignerCertificate.Issuer -notmatch $officialIssuerPattern} | Select-Object -ExpandProperty Path
}
Comment on lines +111 to +116

Write-Verbose -verbose "to be signed:`r`n $($missingSignatures | Out-String)"

Expand Down Expand Up @@ -134,7 +141,7 @@ steps:
displayName: Sign 3rd Party files
inputs:
command: 'sign'
signing_profile: $(msft_3rd_party_cert_id)
signing_profile: ${{ parameters.ThirdPartySigningProfile }}
files_to_sign: '**\*.dll;**\*.exe'
search_root: $(Pipeline.Workspace)/thirdPartyToBeSigned

Expand Down
72 changes: 72 additions & 0 deletions .pipelines/templates/stages/PowerShell-vPack-Stages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ stages:
pool:
type: windows

templateContext:
sdl:
codeSignValidation:
enabled: false
justificationForDisabling: >-
This job validates the signed payload with the repository-managed
tools-only policy.

strategy:
matrix:
x86:
Expand All @@ -33,6 +41,9 @@ stages:
ob_createvpack_verbose: true
ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)'
ob_createvpack_description: PowerShell $(architecture) $(version)
# Some official-build adapters force the injected validator on despite templateContext.
# Exclude this payload from that validator; it is validated below with the tools-only policy.
ob_sdl_codeSignValidation_excludes: '-|**\*.ps1;-|**\*.psm1;-|**\*.ps1xml;-|**\*.psd1;-|**\*.exe;-|**\*.dll'
# I think the variables reload after we transition back to the host so this works. 🤷‍♂️
ob_createvpack_majorVer: $(pwshMajorVersion)
ob_createvpack_minorVer: $(pwshMinorVersion)
Expand Down Expand Up @@ -209,9 +220,70 @@ stages:
parameters:
binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)'
SigningProfile: $(windows_build_tools_cert_id)
ThirdPartySigningProfile: $(windows_build_tools_cert_id)
SignAllBinariesWithThirdPartyProfile: true
OfficialBuild: false
vPackScenario: true
Comment on lines 220 to 226

# obp-file-signing.yml signs only the scripts and manifests selected for normal PowerShell
# packages. The validation below intentionally covers every potentially signed file in the
# vPack, so overwrite every matching signature with the tools certificate first.
- task: onebranch.pipeline.signing@1
displayName: Sign all vPack files with Windows build tools certificate
inputs:
command: sign
signing_profile: $(windows_build_tools_cert_id)
files_to_sign: '**\*.ps1;**\*.psm1;**\*.ps1xml;**\*.psd1;**\*.exe;**\*.dll'
search_root: $(ob_outputDirectory)

# The injected CodeSign validation is disabled for this job, so validate the signed payload
# here against the repository policy, which allows only the Windows build tools certificate.
- task: securedevelopmentteam.vss-secure-development-tools.build-task-codesignvalidation.CodeSign@1
displayName: Validate signed files with PowerShell CodeSign policy
inputs:
Path: $(ob_outputDirectory)
PolicyType: Custom
PolicyFile: $(Build.SourcesDirectory)\.config\codesignpolicy.xml
MaxThreads: 16
FailIfNoTargetsFound: true
ExcludePassesFromLog: false
Targets: '**\*.ps1;**\*.psm1;**\*.ps1xml;**\*.psd1;**\*.exe;**\*.dll'

- pwsh: |
$codesignResultsRoot = Join-Path '$(Pipeline.Workspace)' '.gdn\.r\codesign'
if (-not (Test-Path -LiteralPath $codesignResultsRoot -PathType Container)) {
throw "CodeSign Validation did not produce its expected results directory: $codesignResultsRoot"
}

$sarifFile = Get-ChildItem -LiteralPath $codesignResultsRoot -Recurse -File -Filter 'Phalanx.Plugins.CodeSignValidation.dll.sarif' |
Sort-Object -Property LastWriteTimeUtc -Descending |
Select-Object -First 1
if (-not $sarifFile) {
throw "CodeSign Validation did not produce its expected SARIF file under: $codesignResultsRoot"
}

$sarif = Get-Content -LiteralPath $sarifFile.FullName -Raw | ConvertFrom-Json -Depth 100
$failures = @(
foreach ($run in $sarif.runs) {
foreach ($result in $run.results) {
if ($result.ruleId -ne 'CodeSign.MatchingPolicy') {
$result
}
}
}
)

if ($failures.Count -gt 0) {
$failures |
ForEach-Object {
Write-Host "##vso[task.logissue type=error]$($_.ruleId): $($_.locations.physicalLocation.artifactLocation.uri -join ', ') - $($_.message.text)"
}
throw "CodeSign Validation found $($failures.Count) policy violation(s)."
}

Write-Verbose -Verbose 'All signed files matched the PowerShell CodeSign policy.'
displayName: Check PowerShell CodeSign validation results

### END OF BUILD ###

- pwsh: |
Expand Down
Loading