|
@@ -4,43 +4,103 @@
|
|
#
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
#
|
|
#
|
|
-#
|
|
|
|
|
|
|
|
param (
|
|
param (
|
|
[String[]] $exePath,
|
|
[String[]] $exePath,
|
|
[String[]] $packagePath,
|
|
[String[]] $packagePath,
|
|
[String[]] $bootstrapPath,
|
|
[String[]] $bootstrapPath,
|
|
- [String[]] $certificate
|
|
|
|
|
|
+ [String[]] $certificate,
|
|
|
|
+ [String] $MSDlibPath,
|
|
|
|
+ [String] $MetadataFilePath,
|
|
|
|
+ [switch] $Verbose
|
|
)
|
|
)
|
|
|
|
|
|
# Get prerequisites, certs, and paths ready
|
|
# Get prerequisites, certs, and paths ready
|
|
$tempPath = [System.IO.Path]::GetTempPath() # Order of operations defined here: https://docs.microsoft.com/en-us/dotnet/api/system.io.path.gettemppath?view=net-5.0&tabs=windows#remarks
|
|
$tempPath = [System.IO.Path]::GetTempPath() # Order of operations defined here: https://docs.microsoft.com/en-us/dotnet/api/system.io.path.gettemppath?view=net-5.0&tabs=windows#remarks
|
|
-$certThumbprint = Get-ChildItem -Path Cert:LocalMachine\MY -CodeSigningCert -ErrorAction Stop | Select-Object -ExpandProperty Thumbprint # Grab first certificate from local machine store
|
|
|
|
|
|
|
|
-if ($certificate) {
|
|
|
|
- Write-Output "Checking certificate thumbprint $certificate"
|
|
|
|
- Get-ChildItem -Path Cert:LocalMachine\MY -ErrorAction SilentlyContinue | Where-Object {$_.Thumbprint -eq $certificate} # Prints certificate Thumbprint and Subject if found
|
|
|
|
- if($?) {
|
|
|
|
- $certThumbprint = $certificate
|
|
|
|
|
|
+# Function to detect MS Trusted Signing availability
|
|
|
|
+function Test-TrustedSigningAvailable {
|
|
|
|
+ $dlibFound = $false
|
|
|
|
+ $metadataFound = $false
|
|
|
|
+
|
|
|
|
+ # Check for MS DLib - prioritize environment variable, then parameter
|
|
|
|
+ if ($env:O3DE_MS_DLIB_PATH -and (Test-Path $env:O3DE_MS_DLIB_PATH)) {
|
|
|
|
+ # Verify the DLib file contains the expected name pattern
|
|
|
|
+ if ($env:O3DE_MS_DLIB_PATH -match "CodeSigning\.Dlib\.dll") {
|
|
|
|
+ $script:MSDlibPath = $env:O3DE_MS_DLIB_PATH
|
|
|
|
+ $dlibFound = $true
|
|
|
|
+ } else {
|
|
|
|
+ Write-Warning "DLib path does not contain 'CodeSigning.Dlib.dll'. Please check the path."
|
|
|
|
+ }
|
|
|
|
+ } elseif ($MSDlibPath -and (Test-Path $MSDlibPath)) {
|
|
|
|
+ # Verify the DLib file contains the expected name pattern
|
|
|
|
+ if ($MSDlibPath -match "CodeSigning\.Dlib\.dll") {
|
|
|
|
+ $dlibFound = $true
|
|
|
|
+ } else {
|
|
|
|
+ Write-Warning "DLib path does not contain 'CodeSigning.Dlib.dll'. Please check the path."
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- else {
|
|
|
|
- Write-Error "$certificate thumbprint not found, using $certThumbprint thumbprint instead"
|
|
|
|
|
|
+
|
|
|
|
+ # Check for metadata file - prioritize environment variable, then parameter
|
|
|
|
+ if ($env:O3DE_MS_METADATA_PATH -and (Test-Path $env:O3DE_MS_METADATA_PATH)) {
|
|
|
|
+ $script:MetadataFilePath = $env:O3DE_MS_METADATA_PATH
|
|
|
|
+ $metadataFound = $true
|
|
|
|
+ } elseif ($MetadataFilePath -and (Test-Path $MetadataFilePath)) {
|
|
|
|
+ $metadataFound = $true
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return ($dlibFound -and $metadataFound)
|
|
}
|
|
}
|
|
|
|
|
|
-Try {
|
|
|
|
- $signtoolPath = Resolve-Path "C:\Program Files*\Windows Kits\10\bin\*\x64\signtool.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path
|
|
|
|
- $insigniaPath = Resolve-Path "C:\Program Files*\WiX*\bin\insignia.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path
|
|
|
|
-}
|
|
|
|
-Catch {
|
|
|
|
- Write-Error "Signtool or Wix insignia not found! Exiting."
|
|
|
|
|
|
+# Function to check signtool version
|
|
|
|
+function Test-SignToolVersion {
|
|
|
|
+ param($signtoolPath)
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ Write-Output "SignTool path: $signtoolPath"
|
|
|
|
+ if (-not (Test-Path $signtoolPath)) {
|
|
|
|
+ Write-Warning "SignTool path does not exist"
|
|
|
|
+ return $false
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # Get the file version directly from the executable
|
|
|
|
+ $fileVersion = (Get-Item $signtoolPath).VersionInfo.FileVersion
|
|
|
|
+ if ($fileVersion) {
|
|
|
|
+ $requiredVersion = [Version]"10.0.22621.0"
|
|
|
|
+
|
|
|
|
+ # Try to extract version numbers from the file version string
|
|
|
|
+ if ($fileVersion -match "(\d+\.\d+\.\d+\.\d+)") {
|
|
|
|
+ $version = [Version]$matches[1]
|
|
|
|
+
|
|
|
|
+ if ($version -lt $requiredVersion) {
|
|
|
|
+ Write-Warning "SignTool version $version is below the required version $requiredVersion for Trusted Signing"
|
|
|
|
+ return $false
|
|
|
|
+ }
|
|
|
|
+ return $true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # If we got here, we couldn't determine the version, but we'll assume it's OK if the path contains the required version
|
|
|
|
+ if ($signtoolPath -match "10\.0\.22621\.0|10\.0\.2[3-9]|10\.0\.[3-9]\d") {
|
|
|
|
+ return $true
|
|
|
|
+ } else {
|
|
|
|
+ Write-Warning "Could not determine SignTool version. Trusted Signing may not work correctly."
|
|
|
|
+ return $false
|
|
|
|
+ }
|
|
|
|
+ } catch {
|
|
|
|
+ Write-Warning "Error checking SignTool version: $($_.Exception.Message)"
|
|
|
|
+ return $false
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
function Write-Signature {
|
|
function Write-Signature {
|
|
param (
|
|
param (
|
|
$signtool,
|
|
$signtool,
|
|
- $thumbprint,
|
|
|
|
- $filename
|
|
|
|
|
|
+ $filename,
|
|
|
|
+ [switch]$UseTrustedSigning,
|
|
|
|
+ $thumbprint = $null,
|
|
|
|
+ $dlibPath = $null,
|
|
|
|
+ $metadataPath = $null,
|
|
|
|
+ [switch]$Verbose
|
|
)
|
|
)
|
|
|
|
|
|
$attempts = 2
|
|
$attempts = 2
|
|
@@ -49,51 +109,178 @@ function Write-Signature {
|
|
Do {
|
|
Do {
|
|
$attempts--
|
|
$attempts--
|
|
Try {
|
|
Try {
|
|
- & $signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 $thumbprint /sm $filename
|
|
|
|
- & $signtool verify /pa /v $filename
|
|
|
|
- return
|
|
|
|
|
|
+ if ($UseTrustedSigning) {
|
|
|
|
+ # MS Trusted Signing command
|
|
|
|
+ if ($Verbose) {
|
|
|
|
+ # Verbose output for trusted signing
|
|
|
|
+ Write-Host "Signing: $filename"
|
|
|
|
+ & $signtool sign /v /debug /fd SHA256 /tr "http://timestamp.acs.microsoft.com" /td SHA256 /dlib $dlibPath /dmdf $metadataPath $filename
|
|
|
|
+ } else {
|
|
|
|
+ # Quiet output for trusted signing (default)
|
|
|
|
+ $result = & $signtool sign /fd SHA256 /tr "http://timestamp.acs.microsoft.com" /td SHA256 /dlib $dlibPath /dmdf $metadataPath $filename 2>&1
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ # Traditional certificate signing
|
|
|
|
+ if ($Verbose) {
|
|
|
|
+ # Verbose output for certificate signing
|
|
|
|
+ Write-Host "Signing: $filename"
|
|
|
|
+ & $signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 $thumbprint /sm $filename
|
|
|
|
+ } else {
|
|
|
|
+ # Quiet output for certificate signing (default)
|
|
|
|
+ $result = & $signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 $thumbprint /sm $filename 2>&1
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # Check if signing was successful
|
|
|
|
+ if ($LASTEXITCODE -ne 0) {
|
|
|
|
+ Write-Error "Signed: $filename - Failed with exit code $LASTEXITCODE"
|
|
|
|
+ Start-Sleep -Seconds $sleepSec
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # Show success message in a single line
|
|
|
|
+ Write-Host "Signed: $filename - Success"
|
|
|
|
+
|
|
|
|
+ # Don't verify immediately - we'll do that later
|
|
|
|
+ return $true
|
|
}
|
|
}
|
|
Catch {
|
|
Catch {
|
|
Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
|
|
Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
|
|
Start-Sleep -Seconds $sleepSec
|
|
Start-Sleep -Seconds $sleepSec
|
|
}
|
|
}
|
|
- } while ($attempts -lt 0)
|
|
|
|
|
|
+ } while ($attempts -gt 0)
|
|
|
|
|
|
- throw "Failed to sign $filename" # Bypassed in try block if the command is successful
|
|
|
|
|
|
+ Write-Error "Signed: $filename - Failed after multiple attempts"
|
|
|
|
+ return $false
|
|
}
|
|
}
|
|
|
|
|
|
-# Looping through each path insteaad of globbing to prevent hitting maximum command string length limit
|
|
|
|
|
|
+function Verify-Signature {
|
|
|
|
+ param (
|
|
|
|
+ $signtool,
|
|
|
|
+ $filename,
|
|
|
|
+ [switch]$Verbose
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ if ($Verbose) {
|
|
|
|
+ # Verbose verification output
|
|
|
|
+ Write-Host "`nVerifying: $filename"
|
|
|
|
+ & $signtool verify /pa /v $filename
|
|
|
|
+ } else {
|
|
|
|
+ # Quiet verification output - still capture the result
|
|
|
|
+ $result = & $signtool verify /pa $filename 2>&1
|
|
|
|
+ if ($LASTEXITCODE -eq 0) {
|
|
|
|
+ Write-Host "Verified: $filename - Success"
|
|
|
|
+ } else {
|
|
|
|
+ Write-Error "Verified: $filename - Failed"
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# Main Function
|
|
|
|
+
|
|
|
|
+# Find required tools first
|
|
|
|
+Try {
|
|
|
|
+ $signtoolPath = Resolve-Path "C:\Program Files*\Windows Kits\10\bin\*\x64\signtool.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path
|
|
|
|
+ $insigniaPath = Resolve-Path "C:\Program Files*\WiX*\bin\insignia.exe" -ErrorAction Stop | Select-Object -Last 1 -ExpandProperty Path
|
|
|
|
+}
|
|
|
|
+Catch {
|
|
|
|
+ Write-Error "Signtool or Wix insignia not found! Exiting."
|
|
|
|
+ exit 1
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# Determine signing method - use Trusted Signing if dlib and metadata are available
|
|
|
|
+$useTrustedSigning = $false
|
|
|
|
+if (Test-TrustedSigningAvailable) {
|
|
|
|
+ $useTrustedSigning = $true
|
|
|
|
+ Write-Host "### Using Trusted Signing ###"
|
|
|
|
+ Write-Host "SignTool Path: $signtoolPath"
|
|
|
|
+ Write-Host "DLib Path: $script:MSDlibPath"
|
|
|
|
+ Write-Host "Metadata Path: $script:MetadataFilePath"
|
|
|
|
+
|
|
|
|
+ # Check signtool version if we're planning to use Trusted Signing
|
|
|
|
+ if ($useTrustedSigning) {
|
|
|
|
+ $null = Test-SignToolVersion -signtoolPath $signtoolPath
|
|
|
|
+ }
|
|
|
|
+} else {
|
|
|
|
+ Write-Host "### Using certificate-based signing ###"
|
|
|
|
+ Write-Host "SignTool Path: $signtoolPath"
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# Set up certificate-based signing if not using Trusted Signing
|
|
|
|
+$certThumbprint = $null
|
|
|
|
+if (-not $useTrustedSigning) {
|
|
|
|
+ $certThumbprint = Get-ChildItem -Path Cert:LocalMachine\MY -CodeSigningCert -ErrorAction Stop | Select-Object -ExpandProperty Thumbprint # Grab first certificate from local machine store
|
|
|
|
+
|
|
|
|
+ if ($certificate) {
|
|
|
|
+ Write-Output "Checking certificate thumbprint $certificate"
|
|
|
|
+ Get-ChildItem -Path Cert:LocalMachine\MY -ErrorAction SilentlyContinue | Where-Object {$_.Thumbprint -eq $certificate} # Prints certificate Thumbprint and Subject if found
|
|
|
|
+ if($?) {
|
|
|
|
+ $certThumbprint = $certificate
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ Write-Error "$certificate thumbprint not found, using $certThumbprint thumbprint instead"
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# Looping through each path instead of globbing to prevent hitting maximum command string length limit
|
|
|
|
+$allSignedFiles = @()
|
|
|
|
+
|
|
if ($exePath) {
|
|
if ($exePath) {
|
|
- Write-Output "### Signing EXE files ###"
|
|
|
|
|
|
+ Write-Host "### Signing EXE files ###"
|
|
$files = @(Get-ChildItem $exePath -Recurse *.exe | % { $_.FullName })
|
|
$files = @(Get-ChildItem $exePath -Recurse *.exe | % { $_.FullName })
|
|
foreach ($file in $files) {
|
|
foreach ($file in $files) {
|
|
- Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file
|
|
|
|
|
|
+ $success = Write-Signature -signtool $signtoolPath -filename $file -UseTrustedSigning:$useTrustedSigning -thumbprint $certThumbprint -dlibPath $script:MSDlibPath -metadataPath $script:MetadataFilePath -Verbose:$Verbose
|
|
|
|
+ if ($success) {
|
|
|
|
+ $allSignedFiles += $file
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ($packagePath) {
|
|
if ($packagePath) {
|
|
- Write-Output "### Signing CAB files ###"
|
|
|
|
|
|
+ Write-Host "### Signing CAB files ###"
|
|
$files = @(Get-ChildItem $packagePath -Recurse *.cab | % { $_.FullName })
|
|
$files = @(Get-ChildItem $packagePath -Recurse *.cab | % { $_.FullName })
|
|
foreach ($file in $files) {
|
|
foreach ($file in $files) {
|
|
- Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file
|
|
|
|
|
|
+ $success = Write-Signature -signtool $signtoolPath -filename $file -UseTrustedSigning:$useTrustedSigning -thumbprint $certThumbprint -dlibPath $script:MSDlibPath -metadataPath $script:MetadataFilePath -Verbose:$Verbose
|
|
|
|
+ if ($success) {
|
|
|
|
+ $allSignedFiles += $file
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- Write-Output "### Signing MSI files ###"
|
|
|
|
|
|
+ Write-Host "### Signing MSI files ###"
|
|
$files = @(Get-ChildItem $packagePath -Recurse *.msi | % { $_.FullName })
|
|
$files = @(Get-ChildItem $packagePath -Recurse *.msi | % { $_.FullName })
|
|
foreach ($file in $files) {
|
|
foreach ($file in $files) {
|
|
- & $insigniaPath -im $files
|
|
|
|
- Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file
|
|
|
|
|
|
+ & $insigniaPath -im $file
|
|
|
|
+ $success = Write-Signature -signtool $signtoolPath -filename $file -UseTrustedSigning:$useTrustedSigning -thumbprint $certThumbprint -dlibPath $script:MSDlibPath -metadataPath $script:MetadataFilePath -Verbose:$Verbose
|
|
|
|
+ if ($success) {
|
|
|
|
+ $allSignedFiles += $file
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ($bootstrapPath) {
|
|
if ($bootstrapPath) {
|
|
- Write-Output "### Signing bootstrapper EXE ###"
|
|
|
|
|
|
+ Write-Host "### Signing bootstrapper EXE ###"
|
|
$files = @(Get-ChildItem $bootstrapPath -Recurse *.exe | % { $_.FullName })
|
|
$files = @(Get-ChildItem $bootstrapPath -Recurse *.exe | % { $_.FullName })
|
|
foreach ($file in $files) {
|
|
foreach ($file in $files) {
|
|
& $insigniaPath -ib $file -o $tempPath\engine.exe
|
|
& $insigniaPath -ib $file -o $tempPath\engine.exe
|
|
- Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $tempPath\engine.exe
|
|
|
|
|
|
+ $success = Write-Signature -signtool $signtoolPath -filename $tempPath\engine.exe -UseTrustedSigning:$useTrustedSigning -thumbprint $certThumbprint -dlibPath $script:MSDlibPath -metadataPath $script:MetadataFilePath -Verbose:$Verbose
|
|
|
|
+
|
|
& $insigniaPath -ab $tempPath\engine.exe $file -o $file
|
|
& $insigniaPath -ab $tempPath\engine.exe $file -o $file
|
|
- Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file
|
|
|
|
|
|
+
|
|
|
|
+ $success = Write-Signature -signtool $signtoolPath -filename $file -UseTrustedSigning:$useTrustedSigning -thumbprint $certThumbprint -dlibPath $script:MSDlibPath -metadataPath $script:MetadataFilePath -Verbose:$Verbose
|
|
|
|
+ if ($success) {
|
|
|
|
+ $allSignedFiles += $file
|
|
|
|
+ }
|
|
Remove-Item -Force $tempPath\engine.exe
|
|
Remove-Item -Force $tempPath\engine.exe
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# Verify all signed files at the end
|
|
|
|
+if ($allSignedFiles.Count -gt 0) {
|
|
|
|
+ Write-Host "`n### Verifying signatures ###"
|
|
|
|
+ foreach ($file in $allSignedFiles) {
|
|
|
|
+ Verify-Signature -signtool $signtoolPath -filename $file -Verbose:$Verbose
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Write-Host "`nSummary: Successfully signed $($allSignedFiles.Count) files"
|
|
}
|
|
}
|