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
This commit is contained in:
Michael Bradley, Jr 2020-07-21 11:28:42 -05:00 committed by Iuri Matias
parent 3140d76a5c
commit e0852d2f73
1 changed files with 20 additions and 3 deletions

View File

@ -76,6 +76,7 @@ else ifeq ($(detected_OS),Windows)
PKG_TARGET := pkg-windows PKG_TARGET := pkg-windows
QRCODEGEN_MAKE_PARAMS := CC=gcc QRCODEGEN_MAKE_PARAMS := CC=gcc
RUN_TARGET := run-windows 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\\ VCINSTALLDIR ?= C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\
export VCINSTALLDIR export VCINSTALLDIR
else else
@ -320,6 +321,10 @@ $(NIM_WINDOWS_PREBUILT_DLLS):
nim_windows_launcher: | deps 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 $(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 ?= pkg/Status.zip
$(STATUS_CLIENT_ZIP): nim_status_client nim_windows_launcher $(NIM_WINDOWS_PREBUILT_DLLS) $(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 status.svg tmp/windows/dist/Status/resources/
cp resources.rcc 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 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 \ rcedit \
tmp/windows/dist/Status/bin/Status.exe \ tmp/windows/dist/Status/bin/Status.exe \
--set-icon tmp/windows/dist/Status/resources/status.ico --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 \ --release \
tmp/windows/dist/Status/bin/DOtherSide.dll tmp/windows/dist/Status/bin/DOtherSide.dll
mv tmp/windows/dist/Status/bin/vc_redist.x64.exe tmp/windows/dist/Status/vendor/ 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" echo -e $(BUILD_MSG) "zip"
mkdir -p pkg mkdir -p pkg
cd tmp/windows/dist/Status && \ cd tmp/windows/dist/Status && \
7z a ../../../../pkg/Status.zip * 7z a ../../../../pkg/Status.zip *
# can the final .zip file be code signed as well?
pkg: $(PKG_TARGET) pkg: $(PKG_TARGET)