Skip to content
Open
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
8 changes: 6 additions & 2 deletions eng/Signing.props
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@
<MacOSPkg Include="$(ArtifactsPackagesDir)**/dotnet-runtime*.pkg" Exclude="$(ArtifactsPackagesDir)**/dotnet-runtime-internal*.pkg" />
<FileSignInfo Include="@(MacOSPkg->'%(Filename)%(Extension)')" CertificateName="MacDeveloperWithNotarization" />

<!-- We don't need to code sign .js files because they are not used in Windows Script Host. -->
<!-- WARNING: Needs to happed outside of any target -->
<!-- JS files are customer-modifiable runtime/toolchain files. They cannot be
Authenticode-signed because modifying a signed file breaks the signature.
Instead, a catalog file (.cat) is generated and signed to provide integrity
verification. See the GenerateCatalogFiles target in eng/mono.proj. -->
<FileExtensionSignInfo Update=".js" CertificateName="None" />
<FileExtensionSignInfo Include=".cab" CertificateName="Microsoft400" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is for correctness, can we instead add this in dotnet/arcade? Then everyone that builds MSIs will get it (SDK as well).

<FileExtensionSignInfo Include=".cat" CertificateName="Microsoft400" />

<!-- Third-party components which should be signed. -->
<FileSignInfo Include="Antlr4.Runtime.Standard.dll" CertificateName="3PartySHA2" />
Expand Down
93 changes: 93 additions & 0 deletions eng/generate-catalog.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<#
.SYNOPSIS
Generates a catalog definition file (.cdf) and catalog file (.cat) for all .js files
in the specified root directory. Used for VS signing compliance - the .js files are
customer-modifiable and cannot be directly Authenticode-signed.

.PARAMETER RootPath
Root directory to search for .js files recursively.

.PARAMETER CatOutputPath
Full path for the output .cat file.
#>
param(
[Parameter(Mandatory)][string]$RootPath,
[Parameter(Mandatory)][string]$CatOutputPath,
[string]$WindowsSdkDir = '',
[switch]$ErrorIfMakecatNotFound
)

$ErrorActionPreference = 'Stop'

$cdfPath = [System.IO.Path]::ChangeExtension($CatOutputPath, '.cdf')

$files = Get-ChildItem -Path $RootPath -Recurse -Filter '*.js' -File
if ($files.Count -eq 0) {
Write-Warning "No .js files found under $RootPath - skipping catalog generation."
exit 0
}

$cdf = @()
$cdf += '[CatalogHeader]'
$cdf += "Name=$CatOutputPath"
$cdf += 'CatalogVersion=2'
$cdf += 'HashAlgorithms=SHA256'
$cdf += ''
$cdf += '[CatalogFiles]'

$i = 0
foreach ($f in $files) {
$label = "js_${i}_" + ($f.Name -replace '[^\w\.-]', '_')
$cdf += "<hash>$label=$($f.FullName)"
$i++
}

$cdf | Set-Content -Path $cdfPath -Encoding ASCII
Write-Host "Generated CDF with $($files.Count) .js files at $cdfPath"

$catDir = [System.IO.Path]::GetDirectoryName($CatOutputPath)
if (-not (Test-Path $catDir)) {
New-Item -ItemType Directory -Path $catDir -Force | Out-Null
}

# Find makecat.exe - it ships with the Windows SDK and may not be on PATH.
$makecat = $null
if ($WindowsSdkDir -and (Test-Path $WindowsSdkDir)) {
$makecat = Get-ChildItem -Path (Join-Path $WindowsSdkDir 'bin') -Recurse -Filter 'makecat.exe' -File |
Where-Object { $_.DirectoryName -match 'x64' } |
Sort-Object DirectoryName -Descending |
Select-Object -First 1
}

if (-not $makecat) {
$makecat = Get-Command makecat.exe -ErrorAction SilentlyContinue
}

if (-not $makecat) {
# Fallback: search common Windows SDK locations
$sdkRoot = "${env:ProgramFiles(x86)}\Windows Kits\10\bin"
if (Test-Path $sdkRoot) {
$makecat = Get-ChildItem -Path $sdkRoot -Recurse -Filter 'makecat.exe' -File |
Where-Object { $_.DirectoryName -match 'x64' } |
Sort-Object DirectoryName -Descending |
Select-Object -First 1
}
}

if (-not $makecat) {
if ($ErrorIfMakecatNotFound) {
throw "makecat.exe not found. Catalog signing requires the Windows SDK which must be available in CI builds."
}
Write-Warning "makecat.exe not found - skipping catalog generation. Catalog signing requires the Windows SDK."
exit 0
}

$makecatPath = if ($makecat -is [System.Management.Automation.CommandInfo]) { $makecat.Source } else { $makecat.FullName }
Write-Host "Using makecat.exe at: $makecatPath"

& $makecatPath $cdfPath
if ($LASTEXITCODE -ne 0) {
throw "makecat.exe failed with exit code $LASTEXITCODE"
}

Write-Host "Generated catalog file: $CatOutputPath"
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,29 @@
<ReferenceCopyLocalPaths Include="@(MonoRuntimeFiles)" />
</ItemGroup>
</Target>

<!--
Generate a catalog (.cat) file covering all .js files in the runtime pack.
The .js files are customer-modifiable runtime/toolchain files that cannot be
directly Authenticode-signed. The .cat provides integrity verification without
preventing modification. Only runs on Windows (makecat.exe is a Windows SDK tool)
and only for browser-wasm packs which contain .js files.
-->
<Target Name="GenerateCatalogFiles" AfterTargets="AddMonoRuntimeFiles"
Condition="$([MSBuild]::IsOSPlatform('Windows')) and '$(RuntimeIdentifier)' == 'browser-wasm'">
<PropertyGroup>
<_CatOutputPath>$(ArtifactsObjDir)mono-pack\mono-runtime-js.cat</_CatOutputPath>
<_ErrorIfMakecatNotFound Condition="'$(ContinuousIntegrationBuild)' == 'true' or '$(OfficialBuild)' == 'true'">-ErrorIfMakecatNotFound</_ErrorIfMakecatNotFound>
</PropertyGroup>

<Exec Command="powershell.exe -NoProfile -ExecutionPolicy Bypass -Command &quot;&amp; '$(RepoRoot)eng\generate-catalog.ps1' -RootPath '$(MonoObjDir)' -CatOutputPath '$(_CatOutputPath)' -WindowsSdkDir '$(WindowsSdkDir)' $(_ErrorIfMakecatNotFound)&quot;" StandardOutputImportance="High" />

<ItemGroup Condition="Exists('$(_CatOutputPath)')">
<ReferenceCopyLocalPaths Include="$(_CatOutputPath)">
<TargetPath>runtimes/$(RuntimeIdentifier)/native/mono-runtime-js.cat</TargetPath>
<ExcludeFromDataFiles>true</ExcludeFromDataFiles>
</ReferenceCopyLocalPaths>
</ItemGroup>
<Message Condition="Exists('$(_CatOutputPath)')" Importance="High" Text="Generated catalog file: $(_CatOutputPath)" />
</Target>
</Project>
Loading