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

34
我们最近从DigiCert购买了一张EV代码签名证书,以签署我们的MSI文件,以避免Windows SmartScreen警告消息的影响。问题是,该证书被交付到一个不允许导出私钥的USB令牌上。由于我们的构建环境位于托管的VM上,因此我们无法将USB令牌插入主机VM中。
请问,有没有解决方案可以在托管的VM上使用EV代码签名证书?所有证书供应商是否都会向硬件令牌交付此类证书?如何在虚拟环境中使用此类型的证书对MSI进行代码签名?

我有同样的问题。有任何发现吗? - Kavinda Gayashan
5个回答

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

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

对于像代码签名这样的场景,这种行为可能会很麻烦。我们正在使用专用虚拟机进行签名,每个有权访问此机器的开发人员都应该能够执行签名过程。由于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位可执行文件)。


1
非常感谢您的解释和代码。它在我的应用程序中运行得很好。我认为这一行“pSessionId = 0;”应该改为“*pSessionId = 0;”。 - dsmtoday
这对我来说也完美地起作用了!我使用了Stud_PE来修改导入表,因为有些帖子说Lord PE可能已经被感染了。我没有检查过,只是为了安全起见。现在所有的场景(单个和批量签名)在本地和远程都可以工作了。 - undefined

4

对于其他遇到此问题的人,我们使用了VNC服务器连接了拥有令牌的虚拟机。在RDP上无法工作,只能使用VNC。

显然,对于EV Dongle来说,VNC就像访问控制台一样。


2

我们使用PFX(文件)支持的标准代码签名证书切换到基于USB令牌支持的EV代码签名证书,整个过程不到15分钟,没有任何问题。

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

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

我曾担心我们会遇到麻烦,但实际上并没有。所以,我认为您也不会遇到问题,也不知道为什么您会遇到问题。


1
在虚拟机上安装了证书后,我可以使用 cmd 成功签名程序集,但每次构建代理(在我们的情况下是 Team City)尝试执行命令行或调用带有命令行的批处理文件时,都会返回“SignTool 错误: 未找到符合所有给定条件的证书”。构建代理在该计算机上是管理员。您是否遇到过此问题?如果没有,也许您可以详细说明您的设置? - nlv
@NeilVarnas 在你的 signtool 命令中添加“/debug”,并找出 signtool 在 TeamCity 情况下是根据什么标准消除了你所有的证书。你可以调整 signtool 调用来提示 signtool 选择哪个证书。 - azhrei
@NeilVarnas 不,我从未遇到过这样的情况。听起来像是与您的构建代理有关的特定问题。我的所有签名都通过signtool.exe完成。 - dyasta
1
更新:我后来改用远程桌面会话进行开发,规则如下 - USB令牌必须插入客户端计算机(您所在的计算机,而不是您远程登录到的虚拟机)。如果将USB令牌插入主机而不是客户端,则无法使用它,因为它会立即断开USB令牌连接(我认为这是设计上的问题)。但是,您可以使用TeamViewer或VNC并将令牌保留在主机上。我喜欢将其放在客户端上,因为我可以远程连接到不同的虚拟机,并且随着我的操作,它会连接到每个虚拟机。 - dyasta
您需要在虚拟机中安装USB令牌软件/驱动程序。我只在插入令牌的计算机上拥有它们,但这并没有起作用。将它们安装在虚拟机中可以解决此问题。 - Thomas Woelfer
是哪一个VMware产品呢?“在VMware”这个说法相当不具体,因为他们销售的产品既有裸机虚拟化软件,也有像Fusion、Workstation或Player这样的托管产品。 - 0xC0000022L

0

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

普通代码签名证书没有硬件要求,但它们不像EV证书那样“智能屏幕过滤器友好”。


-1

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


1
请确保使用VNC连接到您的虚拟机,而不是远程桌面。 - azhrei
@azhrei 你知道为什么在使用远程桌面时加密狗似乎断开连接吗?一旦我在VMware中使用控制台窗口,它就正常了(证书软件可以看到加密狗)。 - nlv
@NeilVarnas我不知道为什么-我猜测可能是因为安全目的,硬件锁驱动程序明确要求(并检查)您必须在控制台上进行操作。 - azhrei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接