2023-09-11 06:15:22 +03:00
|
|
|
#
|
|
|
|
# CodeSign.cmake
|
|
|
|
#
|
|
|
|
# Copyright (c) 2023 Oleg Shparber and contributors. All rights reserved.
|
|
|
|
# Licensed under the MIT License.
|
|
|
|
#
|
|
|
|
|
|
|
|
include_guard()
|
|
|
|
|
|
|
|
# codesign(FILES <files>...
|
|
|
|
# [DESCRIPTION] <description-string>
|
|
|
|
# [URL] <url-string>
|
|
|
|
# [CERTIFICATE_FILE] <filename>
|
2023-09-11 08:50:17 +03:00
|
|
|
# [PASSWORD] <password-string>
|
2023-09-11 06:15:22 +03:00
|
|
|
# [TIMESTAMP_URL] <url-string>
|
|
|
|
# [QUIET]
|
|
|
|
# [VERBOSE]
|
|
|
|
# [DEBUG])
|
|
|
|
function(codesign)
|
|
|
|
if(NOT WIN32)
|
|
|
|
message(FATAL_ERROR "Code signing is only supported on Windows.")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
cmake_parse_arguments(_ARG
|
2023-09-11 08:50:17 +03:00
|
|
|
"QUIET;VERBOSE;DEBUG" # Options.
|
|
|
|
"DESCRIPTION;URL;CERTIFICATE_FILE;PASSWORD;TIMESTAMP_URL" # Single-value keywords.
|
|
|
|
"FILES" # Multi-value keywords.
|
2023-09-11 06:15:22 +03:00
|
|
|
${ARGN}
|
|
|
|
)
|
|
|
|
|
|
|
|
if(NOT _ARG_FILES)
|
|
|
|
message(FATAL_ERROR "FILES argument is required.")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Find signtool executable.
|
|
|
|
# TODO: Add option for path to signtool.exe.
|
|
|
|
|
|
|
|
# Add Windows 10 SDK paths.
|
|
|
|
get_filename_component(_w10sdk_root_path
|
|
|
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]"
|
|
|
|
ABSOLUTE CACHE
|
|
|
|
)
|
|
|
|
if(_w10sdk_root_path)
|
|
|
|
file(GLOB _w10sdk_paths "${_w10sdk_root_path}/bin/10.*")
|
|
|
|
list(REVERSE _w10sdk_paths) # Newest version first.
|
|
|
|
|
|
|
|
# Detect target architecture.
|
|
|
|
# https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details#environment-variables
|
|
|
|
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
|
|
|
set(_w10sdk_arch "x64")
|
|
|
|
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "IA64")
|
|
|
|
set(_w10sdk_arch "x64")
|
|
|
|
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "X86")
|
|
|
|
set(_w10sdk_arch "x86")
|
|
|
|
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
|
|
|
set(_w10sdk_arch "arm64")
|
|
|
|
else()
|
|
|
|
message(DEBUG "Unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}.")
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# TODO: Add microsoft.windows.sdk.buildtools path.
|
|
|
|
|
|
|
|
find_program(_cmd
|
|
|
|
NAMES signtool
|
|
|
|
PATHS ${_w10sdk_paths}
|
|
|
|
PATH_SUFFIXES ${_w10sdk_arch}
|
|
|
|
)
|
|
|
|
|
|
|
|
if(NOT _cmd)
|
|
|
|
message(NOTICE "signtool.exe was not found, no binaries will be signed.")
|
|
|
|
return()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
message(DEBUG "Found signtool.exe: ${_cmd}")
|
|
|
|
|
|
|
|
# Start constructing command.
|
|
|
|
set(_cmd_args "sign")
|
|
|
|
list(APPEND _cmd_args "/fd" "sha256")
|
|
|
|
|
|
|
|
# Set certificate file.
|
|
|
|
if(NOT _ARG_CERTIFICATE_FILE)
|
|
|
|
if(CODESIGN_CERTIFICATE_FILE)
|
|
|
|
set(_ARG_CERTIFICATE_FILE ${CODESIGN_CERTIFICATE_FILE})
|
|
|
|
elseif(DEFINED ENV{CODESIGN_CERTIFICATE_FILE})
|
|
|
|
set(_ARG_CERTIFICATE_FILE $ENV{CODESIGN_CERTIFICATE_FILE})
|
|
|
|
elseif(DEFINED ENV{CODESIGN_CERTIFICATE})
|
|
|
|
# Read the whole certificate from environment variable and store it
|
|
|
|
# in a temporary file for signtool to use.
|
|
|
|
|
|
|
|
# Determine temporary file location. Try to keep it local to the build.
|
|
|
|
if(CMAKE_BINARY_DIR)
|
|
|
|
set(_temp_path ${CMAKE_BINARY_DIR})
|
|
|
|
elseif(CPACK_TEMPORARY_DIRECTORY)
|
|
|
|
set(_temp_path ${CPACK_TEMPORARY_DIRECTORY})
|
|
|
|
else()
|
|
|
|
set(_temp_path $ENV{TEMP})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
set(_certificate_file "${_temp_path}/codesign.pem")
|
|
|
|
file(WRITE ${_certificate_file} $ENV{CODESIGN_CERTIFICATE})
|
|
|
|
set(_ARG_CERTIFICATE_FILE ${_certificate_file})
|
|
|
|
else()
|
|
|
|
message(NOTICE "Certificate is not provided, no binaries will be signed.")
|
|
|
|
return()
|
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
|
|
|
|
list(APPEND _cmd_args "/f" ${_ARG_CERTIFICATE_FILE})
|
|
|
|
|
|
|
|
# Set password.
|
2023-09-11 08:50:17 +03:00
|
|
|
if(NOT _ARG_PASSWORD)
|
|
|
|
if(CODESIGN_PASSWORD)
|
|
|
|
set(_ARG_PASSWORD ${CODESIGN_PASSWORD})
|
|
|
|
elseif(DEFINED ENV{CODESIGN_PASSWORD})
|
|
|
|
set(_ARG_PASSWORD $ENV{CODESIGN_PASSWORD})
|
2023-09-11 06:15:22 +03:00
|
|
|
endif()
|
|
|
|
endif()
|
|
|
|
|
2023-09-11 08:50:17 +03:00
|
|
|
if(_ARG_PASSWORD)
|
|
|
|
list(APPEND _cmd_args "/p" ${_ARG_PASSWORD})
|
2023-09-11 06:15:22 +03:00
|
|
|
endif()
|
|
|
|
|
|
|
|
# Set description.
|
|
|
|
if(NOT _ARG_DESCRIPTION AND PROJECT_DESCRIPTION)
|
|
|
|
set(_ARG_DESCRIPTION ${PROJECT_DESCRIPTION})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_ARG_DESCRIPTION)
|
|
|
|
list(APPEND _cmd_args "/d" ${_ARG_DESCRIPTION})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Set project URL.
|
|
|
|
if(NOT _ARG_URL AND PROJECT_HOMEPAGE_URL)
|
|
|
|
set(_ARG_URL ${PROJECT_HOMEPAGE_URL})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_ARG_URL)
|
|
|
|
list(APPEND _cmd_args "/du" ${_ARG_URL})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Set timestamp server.
|
|
|
|
if(NOT _ARG_TIMESTAMP_URL)
|
|
|
|
set(_ARG_TIMESTAMP_URL "http://timestamp.digicert.com")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_ARG_TIMESTAMP_URL)
|
|
|
|
list(APPEND _cmd_args "/t" ${_ARG_TIMESTAMP_URL})
|
|
|
|
endif()
|
|
|
|
|
|
|
|
# Set quiet, verbose, or debug options.
|
|
|
|
if(_ARG_QUIET)
|
|
|
|
list(APPEND _cmd_args "/q")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_ARG_VERBOSE)
|
|
|
|
list(APPEND _cmd_args "/v")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(_ARG_DEBUG)
|
|
|
|
list(APPEND _cmd_args "/debug")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
foreach(_file ${_ARG_FILES})
|
|
|
|
message(STATUS "Signing ${_file}...")
|
|
|
|
execute_process(COMMAND ${_cmd} ${_cmd_args} ${_file}
|
|
|
|
RESULT_VARIABLE _rc
|
|
|
|
OUTPUT_VARIABLE _stdout
|
|
|
|
ERROR_VARIABLE _stderr
|
|
|
|
)
|
|
|
|
|
|
|
|
if(NOT _rc EQUAL 0)
|
|
|
|
message(NOTICE "Signing failed: ${_stderr}")
|
|
|
|
endif()
|
|
|
|
|
|
|
|
if(NOT _ARG_QUIET)
|
|
|
|
message(NOTICE ${_stdout})
|
|
|
|
endif()
|
|
|
|
endforeach()
|
|
|
|
|
|
|
|
# Cleanup
|
|
|
|
if(_certificate_file)
|
|
|
|
file(REMOVE ${_certificate_file})
|
|
|
|
endif()
|
|
|
|
endfunction()
|