diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake index 5e09743373..377a9fb221 100644 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ b/cmake/Platform/Windows/PackagingPostBuild.cmake @@ -32,6 +32,9 @@ set(_addtional_defines -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging ) +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + if(CPACK_LICENSE_URL) list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) endif() @@ -55,6 +58,30 @@ set(_light_command -o "${_bootstrap_output_file}" ) +set(_signing_command + psexec.exe + -accepteula + -nobanner + -s + powershell.exe + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +message(STATUS "Signing package files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") +endif() + message(STATUS "Creating Bootstrap Installer...") execute_process( COMMAND ${_candle_command} @@ -80,6 +107,19 @@ file(COPY ${_bootstrap_output_file} message(STATUS "Bootstrap installer generated to ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename}") +message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") +execute_process( + COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") +endif() + # use the internal default path if somehow not specified from cpack_configure_downloads if(NOT CPACK_UPLOAD_DIRECTORY) set(CPACK_UPLOAD_DIRECTORY ${CPACK_PACKAGE_DIRECTORY}/CPackUploads) @@ -100,11 +140,9 @@ if(NOT CPACK_UPLOAD_URL) return() endif() -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) - +file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) file(TO_NATIVE_PATH "${_root_path}/python/python.cmd" _python_cmd) file(TO_NATIVE_PATH "${_root_path}/scripts/build/tools/upload_to_s3.py" _upload_script) -file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) function(upload_to_s3 in_url in_local_path in_file_regex) diff --git a/cmake/Platform/Windows/PackagingPreBuild.cmake b/cmake/Platform/Windows/PackagingPreBuild.cmake new file mode 100644 index 0000000000..d3924c7a02 --- /dev/null +++ b/cmake/Platform/Windows/PackagingPreBuild.cmake @@ -0,0 +1,37 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) +set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) +file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + +set(_signing_command + psexec.exe + -accepteula + -nobanner + -s + powershell.exe + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} +) + +message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") +execute_process( + COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE +) + +if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") +endif() + +message(STATUS "Signing exes complete!") diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5bb9928b61..ced7757852 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -108,7 +108,6 @@ set(_raw_text_license [[ ]]) if(LY_INSTALLER_DOWNLOAD_URL) - set(WIX_THEME_WARNING_IMAGE ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/warning.png) if(LY_INSTALLER_LICENSE_URL) @@ -138,6 +137,10 @@ if(LY_INSTALLER_DOWNLOAD_URL) # the bootstrapper will at the very least need a different upgrade guid generate_wix_guid(CPACK_WIX_BOOTSTRAP_UPGRADE_GUID "${_guid_seed_base}_Bootstrap_UpgradeCode") + set(CPACK_PRE_BUILD_SCRIPTS + ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPreBuild.cmake + ) + set(CPACK_POST_BUILD_SCRIPTS ${CPACK_SOURCE_DIR}/Platform/Windows/PackagingPostBuild.cmake ) diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 3848e6f980..e33025a4d9 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -351,17 +351,21 @@ "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, - "windows_installer": { + "installer_vs2019": { "TAGS": [ - "nightly-clean" + "nightly-clean", + "nightly-installer" ], + "PIPELINE_ENV":{ + "NODE_LABEL":"windows-packaging" + }, "COMMAND": "build_installer_windows.cmd", "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DLY_VERSION_ENGINE_NAME=o3de-sdk -DLY_INSTALLER_WIX_ROOT=\"!WIX! \"", - "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=https://www.o3debinaries.org -DLY_INSTALLER_LICENSE_URL=https://www.o3debinaries.org/license", - "CPACK_BUCKET": "spectra-prism-staging-us-west-2", + "EXTRA_CMAKE_OPTIONS": "-DLY_INSTALLER_AUTO_GEN_TAG=ON -DLY_INSTALLER_DOWNLOAD_URL=!INSTALLER_DOWNLOAD_URL! -DLY_INSTALLER_LICENSE_URL=!INSTALLER_DOWNLOAD_URL!/license", + "CPACK_BUCKET": "!INSTALLER_BUCKET!", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/signer/Platform/Windows/signer.ps1 b/scripts/signer/Platform/Windows/signer.ps1 new file mode 100644 index 0000000000..5366564140 --- /dev/null +++ b/scripts/signer/Platform/Windows/signer.ps1 @@ -0,0 +1,99 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +param ( + [String[]] $exePath, + [String[]] $packagePath, + [String[]] $bootstrapPath, + [String[]] $certificate +) + +# 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 +$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" + } +} + +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 Write-Signature { + param ( + $signtool, + $thumbprint, + $filename + ) + + $attempts = 2 + $sleepSec = 5 + + Do { + $attempts-- + Try { + & $signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 $thumbprint /sm $filename + & $signtool verify /pa /v $filename + return + } + Catch { + Write-Error $_.Exception.InnerException.Message -ErrorAction Continue + Start-Sleep -Seconds $sleepSec + } + } while ($attempts -lt 0) + + throw "Failed to sign $filename" # Bypassed in try block if the command is successful +} + +# Looping through each path insteaad of globbing to prevent hitting maximum command string length limit +if ($exePath) { + Write-Output "### Signing EXE files ###" + $files = @(Get-ChildItem $exePath -Recurse *.exe | % { $_.FullName }) + foreach ($file in $files) { + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } +} + +if ($packagePath) { + Write-Output "### Signing CAB files ###" + $files = @(Get-ChildItem $packagePath -Recurse *.cab | % { $_.FullName }) + foreach ($file in $files) { + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } + + Write-Output "### Signing MSI files ###" + $files = @(Get-ChildItem $packagePath -Recurse *.msi | % { $_.FullName }) + foreach ($file in $files) { + & $insigniaPath -im $files + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + } +} + +if ($bootstrapPath) { + Write-Output "### Signing bootstrapper EXE ###" + $files = @(Get-ChildItem $bootstrapPath -Recurse *.exe | % { $_.FullName }) + foreach ($file in $files) { + & $insigniaPath -ib $file -o $tempPath\engine.exe + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $tempPath\engine.exe + & $insigniaPath -ab $tempPath\engine.exe $file -o $file + Write-Signature -signtool $signtoolPath -thumbprint $certThumbprint -filename $file + Remove-Item -Force $tempPath\engine.exe + } +} \ No newline at end of file