我们最近从 DigiCert 购买了 EV 代码签名证书来签署我们的 MSI 以绕过 Windows SmartScreen 警告消息。问题是证书被传递到不允许导出私钥的 USB 令牌。我们的构建环境位于托管 VM 上,因此我们无法将 USB 令牌插入主机 VM。
有人有在托管 VM 上使用 EV 代码签名证书的解决方案吗?是否所有证书供应商都将此类证书交付给硬件令牌?您如何使用这种类型的证书在虚拟环境中对 MSI 进行代码签名?
我们最近从 DigiCert 购买了 EV 代码签名证书来签署我们的 MSI 以绕过 Windows SmartScreen 警告消息。问题是证书被传递到不允许导出私钥的 USB 令牌。我们的构建环境位于托管 VM 上,因此我们无法将 USB 令牌插入主机 VM。
有人有在托管 VM 上使用 EV 代码签名证书的解决方案吗?是否所有证书供应商都将此类证书交付给硬件令牌?您如何使用这种类型的证书在虚拟环境中对 MSI 进行代码签名?
SafeNet 客户端附带的加密提供程序正在使用 SmardCardAPI (winscard.dll) 访问 USB 令牌。因为智能卡也用于身份验证/登录目的,所以 RDP 堆栈将始终重定向对 RDP 客户端计算机的任何访问。
对于像代码签名这样的场景,这种行为可能非常麻烦。我们使用专用的虚拟机进行签名,每个有权访问该机器的开发人员都应该能够执行签名过程。对于 COVID-19 和所有在家工作的开发人员,使用本地 USB 端口的想法是不可行的。我们的 USB-Token 连接到专用机器上。每次您通过 RDP 连接到这台机器时,加密狗都无法再访问,因为 SmartCardAPI 将重定向访问。
然而,这个问题有一个解决方案:SmartCard 堆栈使用 API-Calls
ProcessIdToSessionId
WinStationGetCurrentSessionCapabilities
确定当前进程是否在 RDP 会话中运行。通过将 DLL 注入 signtool 并使用 Detours 框架,您可以挂钩这些 API 调用并报告本地会话,因此 SmardCardAPI 将访问连接到远程虚拟机的加密狗。
https://github.com/microsoft/Detours
迂回的功能非常简单(代码简化为重要的东西,所以你可以理解)
DWORD WINAPI ProcessIdToSessionIdLocal(DWORD dwProcessId, DWORD *pSessionId)
{
OutputDebugString("Detoured ProcessIdToSessionId\r\n");
if (pSessionId)
pSessionId = 0;
return TRUE;
}
BOOL WINAPI WinStationGetCurrentSessionCapabilitiesLocal(DWORD flags, DWORD *pOutBuffer)
{
BOOL bResult;
OutputDebugString("Detoured WinStationGetCurrentSessionCapabilities\r\n");
bResult = TrueGetCurStationCapabilities(flags,pOutBuffer);
if (bResult)
*pOutBuffer = 0;
return bResult;
}
BOOL WINAPI DllMain (haDLL, dwReason, lpReserved)
HANDLE haDLL;
DWORD dwReason;
LPVOID lpReserved;
{
LONG error;
TCHAR cBuffer[160];
wsprintf(cBuffer,"DllMain Entry %08x\r\n",dwReason);
OutputDebugString(cBuffer);
if (DetourIsHelperProcess()) {
return TRUE;
}
if (dwReason == DLL_PROCESS_ATTACH) {
OutputDebugString("Starting Detour API Calls \r\n");
hStaDLL = LoadLibrary("WINSTA.DLL");
TrueGetCurStationCapabilities = GetProcAddress(hStaDLL,"WinStationGetCurrentSessionCapabilities");
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*)&TrueProcessIdToSessionId, ProcessIdToSessionIdLocal);
DetourAttach((PVOID*)&TrueGetCurStationCapabilities, WinStationGetCurrentSessionCapabilitiesLocal);
error = DetourTransactionCommit();
if (error == NO_ERROR) {
OutputDebugString("Successfully Detoured API Calls \r\n");
}
else {
return FALSE;
}
}
else if (dwReason == DLL_PROCESS_DETACH) {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((PVOID*)&TrueProcessIdToSessionId, ProcessIdToSessionIdLocal);
DetourDetach((PVOID*)&TrueGetCurStationCapabilities, WinStationGetCurrentSessionCapabilitiesLocal);
error = DetourTransactionCommit();
FreeLibrary(hStaDLL);
}
return TRUE;
}
将 DLL 注入到 signtool 中也很容易:只需在 IMPORTs 部分添加一个新条目,该条目将加载带有迂回函数的 DLL。这可以使用名为“Lord PE”的工具(用于 32 位可执行文件)来完成。
我对我们的完全没有问题。我们在不到 15 分钟的时间内从 PFX(文件)支持的标准代码签名证书切换到了 USB 令牌支持的 EV 代码签名证书。
我只需将 USB 令牌设备设置为连接到 VMWare 中的客户端操作系统(请参阅设备客户端操作系统窗口右下方的图标),安装必要的设备驱动程序,将选项设置为每个会话仅需要密码解锁一次,然后很好去。
至于如何签名,您就像使用任何其他证书一样签名。如果操作系统的证书存储中没有其他适用的代码签名证书,那么您甚至不必指定证书的位置。
我担心我们会遇到麻烦,但没有。所以,我认为你不会,也不知道你为什么会遇到麻烦。
对于遇到此问题的其他人,我们使用 VNC 服务器连接到上面有令牌的 VM。它不适用于仅 RDP 的 VNC。
显然,VNC 就像拥有对盒子的控制台访问权限(就 EV 加密狗而言)。
EV 代码签名证书需要使用特殊硬件来存储私钥。这就是使它们比标准证书更昂贵和更安全的部分原因。我的建议是使用 signtool.exe 作为构建后步骤在主机上签署可执行文件。
普通代码签名证书没有硬件要求,但它们不像 EV 证书那样“SmartScreen Filter Friendly”。
包括 VMware 在内的一些虚拟化软件允许重定向 USB 设备。