CMake/Utilities/Release/win/sign-package.ps1
Brad King 1f46bc299b ci: Extend packaging pipeline to sign Windows binaries automatically
Split packaging on Windows into dedicated jobs that run with access to
an EV signing certificate.

Prior to commit 0929221ca3 (gitlab-ci: Simplify Windows packaging
pipeline, 2023-02-28, v3.26.0-rc5~3^2~3) we had separate packaging jobs,
but they did not run in release packaging pipelines.  Restore them, and
run them in both nightly and release packaging pipelines.
2025-03-19 11:22:30 -04:00

95 lines
3.4 KiB
PowerShell

# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file LICENSE.rst or https://cmake.org/licensing for details.
# Run this script on a Windows host in a CMake single-config build tree.
param (
[string]$signtool = 'signtool',
[string]$cpack = 'bin\cpack',
[string]$pass = $null
)
$ErrorActionPreference = 'Stop'
# Cleanup temporary file(s) on exit.
$null = Register-EngineEvent PowerShell.Exiting -Action {
if ($certFile) {
Remove-Item $certFile -Force
}
}
# If the passphrase was not provided on the command-line,
# check for a GitLab CI variable in the environment.
if (-not $pass) {
$pass = $env:SIGNTOOL_PASS
# If the environment variable looks like a GitLab CI file-type variable,
# replace it with the content of the file.
if ($pass -and
$pass.EndsWith("SIGNTOOL_PASS") -and
(Test-Path -Path "$pass" -IsValid) -and
(Test-Path -Path "$pass" -PathType Leaf)) {
$pass = Get-Content -Path "$pass"
}
}
# Collect signtool arguments to specify a certificate.
$cert = @()
# Select a signing certificate to pass to signtool.
if ($certX509 = Get-ChildItem -Recurse -Path "Cert:" -CodeSigningCert |
Where-Object { $_.PublicKey.Oid.FriendlyName -eq "RSA" } |
Select-Object -First 1) {
# Identify the private key provider name and container name.
if ($certRSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($certX509)) {
# $certRSA -is [System.Security.Cryptography.RSACng]
# Cryptography Next Generation (CNG) implementation
$csp = $certRSA.Key.Provider
$kc = $certRSA.Key.KeyName
} elseif ($certRSA = $certX509.PrivateKey) {
# $certRSA -is [System.Security.Cryptography.RSACryptoServiceProvider]
$csp = $certRSA.CspKeyContainerInfo.ProviderName
$kc = $certRSA.CspKeyContainerInfo.KeyContainerName
}
# Pass the selected certificate to signtool.
$certFile = New-TemporaryFile
$certBase64 = [System.Convert]::ToBase64String($certX509.RawData, [System.Base64FormattingOptions]::InsertLineBreaks)
$certPEM = "-----BEGIN CERTIFICATE-----", $certBase64, "-----END CERTIFICATE-----" -join "`n"
$certPEM | Out-File -FilePath "$certFile" -Encoding Ascii
$cert += "-f","$certFile"
# Tell signtool how to find the certificate's private key.
if ($csp) {
$cert += "-csp","$csp"
}
if ($kc) {
if ($pass) {
# The provider offers a syntax to encode the token passphrase in the key container name.
# https://web.archive.org/web/20250315200813/https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing-with-safenet-etoken
$cert += "-kc","[{{$pass}}]=$kc"
$pass = $null
} else {
$cert += "-kc","$kc"
}
}
} else {
$cert += @("-a")
}
# Sign binaries with SHA-1 for Windows 7 and below.
& $signtool sign -v $cert -t http://timestamp.digicert.com -fd sha1 bin\*.exe
if (-not $?) { Exit $LastExitCode }
# Sign binaries with SHA-256 for Windows 8 and above.
& $signtool sign -v $cert -tr http://timestamp.digicert.com -fd sha256 -td sha256 -as bin\*.exe
if (-not $?) { Exit $LastExitCode }
# Create packages.
& $cpack -G "ZIP;WIX"
if (-not $?) { Exit $LastExitCode }
# Sign installer with SHA-256.
& $signtool sign -v $cert -tr http://timestamp.digicert.com -fd sha256 -td sha256 -d "CMake Windows Installer" cmake-*-win*.msi
if (-not $?) { Exit $LastExitCode }