在 macOS/Linux 上签名 Windows 应用程序
信息
仅当您拥有 EV 代码签名证书时,才需要描述的设置和配置。常规证书开箱即用。
支持在 Unix 上签名 Windows 应用程序。 有多种方法可以实现此目的。 基本上,您需要一个能够使用 PKCS 11 签名代码的应用程序。 有一种使用 Java 的方法可以在 Linux 和 Mac 上运行。 您也可以在这两个系统上使用 osslsigncode
,文档中包含 Linux 和 Mac 的操作指南。 本文档最后总结了一些备注以及如何将签名过程与 Electron Builder 集成。
在 Mac/Linux 上使用 JSign 签名 Windows 应用程序¶
此方法需要 Java。 在尝试此解决方案之前,请确保您已安装 Java。
- 通过运行
java -v
确保已安装 Java - 下载 JSign
- 创建一个名为
hardwareToken.cfg
的文件。 用以下内容填充它。 - 检查库链接以确保您拥有正确的 PKCS 模块。 此链接可能因令牌而异。 在 Linux 上,您可以在
/lib
中找到它,而在 Mac 上,您可以在/Library/Frameworks
或/usr/local/lib
中找到它。 - 安装 Mac 的令牌驱动程序,导出证书(如果是 .cer,则将其转换为 pem)
- 使用正确的参数运行
java -jar jsign-2.1.jar
。
hardwareToken.cfg
name = HardwareToken
library = /Library/Frameworks/eToken.framework/Versions/A/libeToken.dylib
slotListIndex = 0
链接:- 来自 Github 的 JSign
完整的签名命令
java -jar jsign-2.1.jar --keystore hardwareToken.cfg --storepass "your password here" --storetype PKCS11 --tsaurl http://timestamp.digicert.com --alias /link/to/cert.pem /link/to/app.exe
在 Mac 上使用 osslsigncode 签名 Windows 应用程序¶
主要问题是 brew 中缺少支持 OpenSSL 1.1 的引擎 PKCS 11。 当前版本仅支持 OpenSSL 1.0。 因此,您需要自己编译大多数应用程序。
- 使用 brew 安装一些应用程序,例如
autoconf
、automake
、libtool
、pkg-config
和gnu-tar
。 - 创建类似
/usr/local/mac-dev
的文件夹,授予当前用户权限,在编译期间使用该文件夹作为前缀。 - 下载 OpenSSL 1.1.1 tar.gz,请参阅下面的链接,解压并编译:
./config --prefix=/usr/local/mac-dev && make && make install
- 导出 OpenSSL 1.1 变量以编译以下应用程序
export LDFLAGS="-L/usr/local/mac-dev/lib"
export CPPFLAGS="-I/usr/local/mac-dev/include"
export PATH="/usr/local/mac-dev/bin:$PATH"
export PKG_CONFIG_PATH="/usr/local/mac-dev/lib/pkgconfig"
- 安装 opensc (.dmg 文件)
- 下载 libp11 .tar.gz,解压并编译:
./configure --prefix=/usr/local/mac-dev && make && make install
- 安装 Mac 的令牌驱动程序,导出证书(如果是 .cer,则将其转换为 pem)
- 下载 osslsigncode .tar.gz,解压并编译:
./autogen.sh && ./configure --prefix=/usr/local/mac-dev && make && make install
(之后将二进制文件符号链接到/usr/local/bin
) - 通过运行
pkcs11-tool --module /usr/local/lib/libeTPkcs11.dylib -l -O
找出密钥 ID - 使用正确的模块、引擎和密钥 ID 运行
osslsigncode
链接:- 来自其网站的 OpenSSL 1.1 - 来自 Github 的 OpenSC - 来自 Github 的 Libp11 - 来自 Github 的 osslsigncode
完整的签名命令,pkcs11module 参数可能因令牌而异。
osslsigncode sign -verbose -pkcs11engine /usr/local/mac-dev/lib/engines-1.1/libpkcs11.dylib -pkcs11module /usr/local/lib/libeTPkcs11.dylib -h sha256 -n app-name -t https://timestamp.verisign.com/scripts/timestamp.dll -certs /link/to/cert.pem -key 'key-id-here' -pass 'password' -in /link/to/app.exe -out /link/to/app.signed.exe
在 Ubuntu 18.04 上使用 osslsigncode 签名 Windows 应用程序¶
这些步骤也适用于其他 Linux 操作系统,但软件包的名称可能不同。
- 使用 APT 更新软件包。
sudo apt-get update
。 - 使用 APT 安装软件包
sudo apt-get install -y openssl libcurl4-openssl-dev libssl-dev libengine-pkcs11-openssl curl libcurl4 git automake libtool pkg-config wget libccid libpcsclite1 pcscd usbutils opensc
。 - 下载 osslsigncode .tar.gz,解压并编译:
./autogen.sh && ./configure && make && make install
- 安装 Linux 的令牌驱动程序,导出证书(如果是 .cer,则将其转换为 pem)
- 通过运行
pkcs11-tool --module /lib/libeToken.so -l -O
找出密钥 ID。 检查路径以确保您拥有正确的 PKCS 模块。 此路径可能因令牌而异。 - 使用正确的模块、引擎和密钥 ID 运行
osslsigncode
完整的签名命令
osslsigncode sign -verbose -pkcs11engine /usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so -pkcs11module /lib/libeToken.so -h sha256 -n app-name -t https://timestamp.verisign.com/scripts/timestamp.dll -certs /link/to/cert.pem -key 'key-id-here' -pass 'password' -in /link/to/app.exe -out /link/to/app.signed.exe
备注¶
当事情不顺利时,请考虑以下事项。
- 确保您使用正确的 PKCS 11 引擎和模块。 如果您收到
no slot with a token was found
或一些错误,例如sc connect card error
和Card is invalid or cannot be handled
,则说明您没有使用正确的模块,请确保使用正确的模块。 - 如果您自己编译了 OpenSSL,请确保您使用的引擎也是为 OpenSSL 编译的。 否则,您将遇到*兼容性*问题。
- 使用 URL 列表中提到的
osslsigncode
。 还有更多 forks/版本可供找到。 这里包含的是实际维护的库,需要 OpenSSL 1.1。
将签名与 Electron Builder 集成¶
根据您选择的方法,您可以通过创建 sign.js
文件来自动化签名过程。 然后在您的 package.json
中指向此文件。
package.json
...
"win": {
"target": "nsis",
"signtoolOptions": {
"sign": "./sign.js"
}
},
...
sign.js
exports.default = async function(configuration) {
// do not include passwords or other sensitive data in the file
// rather create environment variables with sensitive data
const CERTIFICATE_NAME = process.env.WINDOWS_SIGN_CERTIFICATE_NAME;
const TOKEN_PASSWORD = process.env.WINDOWS_SIGN_TOKEN_PASSWORD;
require("child_process").execSync(
// your commande here ! For exemple and with JSign :
`java -jar jsign-2.1.jar --keystore hardwareToken.cfg --storepass "${TOKEN_PASSWORD}" --storetype PKCS11 --tsaurl http://timestamp.digicert.com --alias "${CERTIFICATE_NAME}" "${configuration.path}"`,
{
stdio: "inherit"
}
);
};