如何在虚拟机上使用 EV 代码签名证书来签署 MSI

问题描述 投票:0回答:5

我们最近从 DigiCert 购买了 EV 代码签名证书来签署我们的 MSI,以绕过 Windows SmartScreen 警告消息。问题在于证书被传送到不允许导出私钥的 USB 令牌。我们的构建环境位于托管虚拟机上,因此我们无法将 USB 令牌插入主机虚拟机。

有人有在托管虚拟机上使用 EV 代码签名证书的解决方案吗?是否所有证书供应商都将此类证书提供给硬件令牌?如何使用此类证书在虚拟环境中对 MSI 进行代码签名?

code-signing code-signing-certificate
5个回答
7
投票

SafeNet 客户端附带的加密提供程序正在使用 SmardCardAPI (winscard.dll) 访问 USB 令牌。由于智能卡还用于身份验证/登录目的,因此 RDP 堆栈将始终重定向对 RDP 客户端计算机的任何访问。

https://learn.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-and-remote-desktop-services

对于代码签名这样的场景,这种行为可能非常麻烦。我们使用专用虚拟机进行签名,每个有权访问该计算机的开发人员都应该能够执行签名过程。由于 COVID-19 和所有开发人员都在家工作,使用本地 USB 端口的想法是不可行的。我们的 USB 令牌附在专用机器上。每次您通过 RDP 连接到该计算机时,加密狗将不再可访问,因为 SmartCardAPI 将重定向访问。

但是这个问题有一个解决方案: 智能卡堆栈使用 API 调用

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 位可执行文件)来完成。


3
投票

对于遇到此问题的其他人,我们使用 VNC 服务器连接到具有令牌的虚拟机。仅在 VNC 上无法通过 RDP 运行。

显然,VNC 就像通过控制台访问盒子(就电动汽车适配器而言)。


2
投票

我对我们的完全没有问题。我们在不到 15 分钟的时间内从 PFX(文件)支持的标准代码签名证书切换到 USB 令牌支持的 EV 代码签名证书。

我只需将 USB 令牌设备设置为连接到 VMWare 中的客户端操作系统(请参阅设备客户端操作系统窗口右下角的图标),安装必要的设备驱动程序,将选项设置为需要密码才能解锁一次会议,然后就可以开始了。

至于如何签名,您可以像使用任何其他证书一样进行签名。如果操作系统的证书存储中没有其他适用的代码签名证书,那么您甚至不必指定证书的位置

我担心我们会遇到麻烦,但没有。所以,我认为你不会,也不知道为什么你会遇到麻烦。


0
投票

EV代码签名证书需要使用特殊硬件来存储私钥。这就是它们比标准证书更昂贵、更安全的部分原因。我的建议是使用signtool.exe 在主机上签署可执行文件作为构建后步骤。

普通代码签名证书没有硬件要求,但它们不像 EV 证书那样“SmartScreen Filter 友好”。


-1
投票

包括 VMware 在内的一些虚拟化软件允许 USB 设备重定向。

© www.soinside.com 2019 - 2024. All rights reserved.