From e0852d2f731ffdc7b6a83109c3f0fb8329cf970c Mon Sep 17 00:00:00 2001 From: "Michael Bradley, Jr" Date: Tue, 21 Jul 2020 11:28:42 -0500 Subject: [PATCH] build: implement code signing step for the Windows build Add a code signing step to the `pkg-windows` target. If the environment variable `WINDOWS_CODESIGN_PFX_PATH` is not set then code signing is skipped. If the environment variable `WINDOWS_CODESIGN_TIMESTAMP_URL` is not set then a verified timestamp will not be included in the signature. Both variables should be set in production/CI builds. Signing is performed with Window's [SignTool][signtool]. There is a helpful [Stack Overflow answer][soa] which explains how to easily setup a self-signed CA and code signing certificate and then use them with `signtool`, which is how I tested these changes on my local Windows machine. Absolute paths are used for `egrep`, `xargs`, and `bash` to avoid accidentally running other installations of those executables than the ones that ship with Git Bash. I was experiencing mysterious failures in the sequence of commands and then noticed that e.g. `which xargs` was resolving to an executable in `${HOME}/scoop/shims`. I tested locally that the signed DLLs and EXEs run correctly on Windows 7 and Windows 10. For CI builds Status will need to acquire a signing certificate from e.g. DigiCert. There will be a yearly renewal cost. In researching what files should be signed, I concluded that it only makes sense to sign `.dll` and `.exe` files. It's possible to generate signatures for other file types but the signatures would have to be stored apart from those files, unlike `.dll` and `.exe` where the signature is embedded in the executable. Also, it doesn't seem to be possible to embed a signature in a `.zip` file, though it would be possible to sign the compressed package if we chose to build and distribute a self-extracting `Status.exe` instead of `Status.zip`. If a DLL or EXE file is already validly signed, e.g. the Qt DLLs, `signtool.exe sign` is not invoked on that file. Closes #288. [signtool]: https://docs.microsoft.com/en-us/windows/win32/seccrypto/signtool [soa]: https://stackoverflow.com/a/201277 --- Makefile | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 559feb0fa4..1f6d54cc1a 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ else ifeq ($(detected_OS),Windows) PKG_TARGET := pkg-windows QRCODEGEN_MAKE_PARAMS := CC=gcc RUN_TARGET := run-windows + SIGNTOOL ?= C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.17763.0\\x64\\signtool.exe VCINSTALLDIR ?= C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\ export VCINSTALLDIR else @@ -320,6 +321,10 @@ $(NIM_WINDOWS_PREBUILT_DLLS): nim_windows_launcher: | deps $(ENV_SCRIPT) nim c -d:debug --outdir:./bin --passL:"-static-libgcc -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive" src/nim_windows_launcher.nim +ifneq ($(WINDOWS_CODESIGN_TIMESTAMP_URL),) + WINDOWS_CODESIGN_TIMESTAMP_PARAM := -t $(WINDOWS_CODESIGN_TIMESTAMP_URL) +endif + STATUS_CLIENT_ZIP ?= pkg/Status.zip $(STATUS_CLIENT_ZIP): nim_status_client nim_windows_launcher $(NIM_WINDOWS_PREBUILT_DLLS) @@ -336,7 +341,7 @@ $(STATUS_CLIENT_ZIP): nim_status_client nim_windows_launcher $(NIM_WINDOWS_PREBU cp status.svg tmp/windows/dist/Status/resources/ cp resources.rcc tmp/windows/dist/Status/resources/ cp bin/nim_status_client.exe tmp/windows/dist/Status/bin/Status.exe - mv bin/nim_windows_launcher.exe tmp/windows/dist/Status/Status.exe + cp bin/nim_windows_launcher.exe tmp/windows/dist/Status/Status.exe rcedit \ tmp/windows/dist/Status/bin/Status.exe \ --set-icon tmp/windows/dist/Status/resources/status.ico @@ -355,13 +360,25 @@ $(STATUS_CLIENT_ZIP): nim_status_client nim_windows_launcher $(NIM_WINDOWS_PREBU --release \ tmp/windows/dist/Status/bin/DOtherSide.dll mv tmp/windows/dist/Status/bin/vc_redist.x64.exe tmp/windows/dist/Status/vendor/ - # implement code signing of applicable files in deployable folder + + # if WINDOWS_CODESIGN_PFX_PATH is not set then DLLs, EXEs are not signed +ifdef WINDOWS_CODESIGN_PFX_PATH + find ./tmp/windows/dist/Status -type f \ + | /usr/bin/egrep -i "\.(dll|exe)$$" \ + | /usr/bin/xargs -I{} /usr/bin/bash -c \ + "if ! '$(SIGNTOOL)' verify -pa {} &>/dev/null; then echo {}; fi" \ + | /usr/bin/xargs -I{} "$(SIGNTOOL)" \ + sign \ + -v \ + -f $(WINDOWS_CODESIGN_PFX_PATH) \ + $(WINDOWS_CODESIGN_TIMESTAMP_PARAM) \ + {} +endif echo -e $(BUILD_MSG) "zip" mkdir -p pkg cd tmp/windows/dist/Status && \ 7z a ../../../../pkg/Status.zip * - # can the final .zip file be code signed as well? pkg: $(PKG_TARGET)