Windows has a built-in anti-virus/anti-malware mechanism called Windows Defender. As part of the protection the operating system provides, it checks any .exe, .dll or installer files that are downloaded from the internet for a valid certificate. If one does not exist, Windows displays a SmartScreen validation error message that requires additional steps from the user in order to bypass and continue installation. Many users rightfully will not proceed with installation when faced with this message, assuming that the installer and/or FreeDV application is infected with a virus.
To improve the FreeDV user experience, it was determined that the project should purchase a code signing certificate and begin signing official releases.
- Pending EV code signing certificate order with SignMyCode.com or another Sectigo reseller.
- NOTE: this costs a fair bit of money, so it's more cost effective to purchase 3 year validity instead of 1.
- There are specific requirements for the private/public key in order for the EV certificate to behave properly, so it is not recommended to bring your own key. Currently (as of 2023) Sectigo issues RSA 4096 bit keys onto their SafeNet tokens.
- EV certificates require a legally registered entity to issue, so (as of 2023) our fiscal sponsor (Software Freedom Conservancy) has been the entity on the certificate.
- Linux machine (Windows packages are currently generated using LLVM MinGW)
- Required packages: pcscd, pcsc-tools, libfuse2*, osslsigncode, opensc, opensc-pkcs11, libengine-pkcs11-openssl, gnutls-bin
Download SafeNet Authentication Client from here and install the Ubuntu package as follows:
$ unzip "SafeNet Authentication Client 10.8 R1 GA Linux.zip"
$ cd "SAC_10_8_R1 GA/Installation/Standard/Ubuntu-2204"
$ sudo dpkg -i safenetauthenticationclient_10.8.1050_amd64.deb
At the terminal, enter p11tool --list-all --provider /usr/lib/libeToken.so
. Look for something
like the following:
Object 0:
URL: pkcs11:model=ID%20Prime%20MD;manufacturer=Gemalto;serial=CB64B873EE27EF1B;token=Software%20Freedom%20Conservancy%2C%20In;id=%87%7F%E9%6E%9E%86%84%43;object=Sectigo_20230908155653;type=cert
Type: X.509 Certificate (RSA-4096)
Expires: Mon Sep 7 16:59:59 2026
Label: Sectigo_20230908155653
ID: 87:7f:e9:6e:9e:86:84:43
Save the URLs to files for later use, e.g.
echo -n "pkcs11:model=ID%20Prime%20MD;manufacturer=Gemalto;serial=CB64B873EE27EF1B;token=Software%20Freedom%20Conservancy%2C%20In;id=%87%7F%E9%6E%9E%86%84%43;type=private" > ~/key.url
echo -n "pkcs11:model=ID%20Prime%20MD;manufacturer=Gemalto;serial=CB64B873EE27EF1B;token=Software%20Freedom%20Conservancy%2C%20In;id=%87%7F%E9%6E%9E%86%84%43;object=Sectigo_20230908155653;type=cert" > ~/cert.url
Use something like the following command:
osslsigncode sign -pkcs11engine /usr/lib/x86_64-linux-gnu/engines-3/pkcs11.so -pkcs11module /usr/lib/libeToken.so -certs [path to exported or provided certicate] -key `cat key.url` -in FreeDV-1.8.12-windows-x86_64.exe -out FreeDV-1.8.12-windows-x86_64-signed.exe
You will be asked for the token's's PIN in order to complete the signature process. To verify that the file is correctly signed, copy it to a Windows machine and view the file's properties (under the "Digital Signatures" tab); the subject should match what was provided either for the CSR submitted to Sectigo/other Certificate Authority or what was entered when generating the self-signed certificate above:
Notes:
- The file specified by
-out
must not already exist. Otherwise, osslsigncode will error out. - libeToken.so must be specified for osslsigncode. Other PKCS11 modules may work but haven't been tested.
To build a signed Windows version of FreeDV, pass in -DSIGN_WINDOWS_BINARIES=1
as well as files containing the intermediare/root certificates, PKCS#11 key and certificate URLs. For example:
$ mkdir build
$ cd build
$ cmake -DSIGN_WINDOWS_BINARIES=1 -DPKCS11_KEY_FILE=~/key.url` -DPKCS11_CERTIFICATE_FILE=~/cert.url -DINTERMEDIATE_CERT_FILE=~/cacerts.crt -DCMAKE_TOOLCHAIN_FILE=/home/mooneer/freedv-gui/cross-compile/freedv-mingw-llvm-x86_64.cmake ..
$ make
$ make package
Other optional variables that can be set are as follows:
PKCS11_ENGINE
/PKCS11_MODULE
: Paths to the PKCS11 engine and module libraries on your system. This is mainly used for those who aren't compiling on amd64 and/or aren't using a SafeNet token.TIMESTAMP_SERVER
: If you prefer an alternate timestamping server than the default.SIGN_HASH
: If you prefer a different hashing algorithm than the default SHA256. (Note: the timestamping server will automatically use this hashing algorithm or stronger.)
You will be prompted for your token's PIN several times during the build process. When done, the installer as well as freedv.exe will be signed with the provided certificate.
NOTE: The PIN prompts can be auto-filled by appending ?pin-value=xxxxxx
to the key's URL (where xxxxxx
is your token's PIN). The best practice is to exclude the ?pin-value=xxxxxx
and manually enter the PIN each time, however.
You can auto-build installers for all supported architectures (x86_64, i686, armv7, aarch64)
by using the build_signed_windows_release.sh
script as follows:
$ ./build_signed_windows_release.sh ~/key.url ~/cert.url ~/intermediate-certs.crt
A build_windows
directory will be created with installers for each architecture
when complete. This may take quite a while (for example, ~1 hour on a 2019 MacBook Pro).
NOTE: Ensure that LLVM MinGW and osslsigncode are in your PATH before executing the above command.
Follow the instructions here to update your VM's .vmx file to allow the VM to take full control. This is a problem at least on macOS hosts, not sure on other platforms.
Ensure that pcscd is running and enabled in systemctl:
$ sudo systemctl start pcscd
$ sudo systemctl enable pcscd
Synchronizing state of pcscd.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable pcscd
Created symlink /etc/systemd/system/sockets.target.wants/pcscd.socket → /lib/systemd/system/pcscd.socket.
$
This is likely due to a problem with the certificate. Open a technical support case with your certificate provider as they may need to reissue.
Some things to check:
- Ensure that
signtool.exe /v /debug /pa file.exe
validates the signed file successfully. (Or use the equivalentosslsigncode verify -CAfile RootCertificateBundle.crt --TSA-CAfile /usr/lib/ssl/certs/ca-certificates.crt -in file.exe
on Linux/macOS.) - The timestamp hash should be the same as the file hash for SmartScreen to properly accept the signed file. If not, the file will need to be re-signed (and CMakeLists.txt possibly updated).
- OV certificates may need a couple of days at minimum to be accepted by Microsoft. It may be possible to accelerate this by sending the signed file to Microsoft for analysis.
- Problems that will definitely require a re-issue:
- ECDSA keys do not work well for code signing. Yes, this is still a problem in 2023 despite the date of the blog post. If you use your certificate vendor's token instead of your own, this isn't likely to be the problem but still worth noting here in case you're tempted to buy a YubiKey FIPS token (which supposedly works but never fully removed SmartScreen popups for the FreeDV project).
- If you're still tempted to bring your own token, note that the CA Forum mandates a minimum RSA key length of 3072 bits. Anything shorter than that will definitely cause problems.