C# 如何以编程方式验证程序集是否使用特定证书签名?

C# 如何以编程方式验证程序集是否使用特定证书签名?,c#,.net,digital-certificate,assembly-signing,C#,.net,Digital Certificate,Assembly Signing,我的设想是,如果在特定文件夹中找到一个程序(exe),它将启动其他程序。我想确保它只启动使用我们的公司证书(Verisign approved等)签名的程序。从本质上讲,它将只使用与自身相同的证书启动程序。我不想把证书寄出去 我一直在搜索web和系统名称空间,但没有找到一个清晰的示例,可以从文件中读取证书数据并对其进行验证,还可以对照另一个文件进行检查。我发现最接近的是Signtool,在一个单独的exe中进行验证是没有意义的。我知道强命名的东西不会有帮助,因为数字签名的文件是不同的,这里有帮助

我的设想是,如果在特定文件夹中找到一个程序(exe),它将启动其他程序。我想确保它只启动使用我们的公司证书(Verisign approved等)签名的程序。从本质上讲,它将只使用与自身相同的证书启动程序。我不想把证书寄出去

我一直在搜索web和系统名称空间,但没有找到一个清晰的示例,可以从文件中读取证书数据并对其进行验证,还可以对照另一个文件进行检查。我发现最接近的是Signtool,在一个单独的exe中进行验证是没有意义的。我知道强命名的东西不会有帮助,因为数字签名的文件是不同的,这里有帮助地解释了这一点(http://blog.codingoutloud.com/2010/03/13/three-ways-to-tell-whether-an-assembly-dl-is-strong-named/)还有一些其他示例显示了原始数据的加密和验证,但不是以某种方式打包在一起的程序集


有什么想法或建议吗?

有两种用于.NET程序集的签名技术:strong命名和Authenticode(Authenticode用于对PE和其他一些文件进行签名,而不仅仅是.NET程序集)。它们用于不同的目的。在Authenticode中,证书仅用于对作者进行身份验证。strong命名根本不对作者进行身份验证

除了检查签名外,还必须验证证书,以确保它是为给定的作者颁发的。正确的验证是一个复杂的过程,涉及CRL(证书吊销列表)和OCSP(在线证书状态)检查

要执行Authenticode签名验证,您需要Authenticode验证组件。其中一个选项是使用我们的SecureBackbox产品包。该软件包包括Authenticode验证以及完整的证书验证机制


请注意,如果您不打算验证证书,那么验证签名就毫无意义,因为您可以创建具有相同主题、序列号等的自签名证书,并使用它对伪造的程序集进行签名

您可以在这里尝试三个选项

1) 第一个是使用程序集加载,如下所示:

Assembly myDll =
    Assembly.Load("myDll, Version=1.0.0.1, Culture=neutral, PublicKeyToken=9b35aa32c18d4fb1");
可以使用以下强名称(Sn.exe)命令打印特定程序集的公钥和公钥令牌的十六进制格式:

sn-Tp。并使用p/Invoke处理此类问题

3) 还有第三种更灵活、更复杂的方法。这是一个具有约束力的策略。当您需要为已部署的应用程序提供升级时,您可以考虑这一点。当您的应用程序可以从共享组件的新版本中受益时,应用程序策略文件将允许您提供这些好处,而无需重新编译或更换现有安装

您可以在此处找到有关此功能的更多信息:


下面是一篇关于如何验证程序集签名的代码示例的博文:

最后的代码示例演示了如何验证程序集是否由Microsoft签名-您可以通过获取公司证书的证书令牌来执行相同的操作

更新:user@Saber使用以下更新编辑了此更新,但该更新被其他人拒绝。但是,这是一个非常有效的建议,因此我将重新发布他/她的编辑,因为so不允许我批准:


编辑(谢谢,OP):如果您想更安全地执行此操作(即使您的程序更防篡改),请引用程序中使用相关密钥强命名的程序集,然后使用引用程序集的标记与调用程序集的标记进行比较。如果您使用字节数组(根据链接),它可以简单地进行十六进制编辑和更改。

我相信有一种方法可以使用强名称来达到“信任”的目的。我知道Microsoft只建议使用强名称以确保程序集内容未被修改,并建议使用“Authenticode”以获得信任

但是如果加载器应用程序(加载这些程序集/程序的应用程序)维护一个可以加载的“程序集”的加密列表;这难道不能解决“信任”问题吗

例如,包加载器可以使用公钥维护程序集名称,并通过完整的程序集名称加载程序集/程序

<PackageHandlers>
  <PackageHandler>
    <Package type="Package1" assembyName="SomeAssembly" publickey="d45755dbb8b44e59" />
  </PackageHandler>
</PackageHandlers>


为什么要投否决票?阅读我链接到的博客文章,您将看到它确实显示了强命名如何链接到程序集签名,并且您可以使用它来验证程序集是否已使用特定证书进行签名。我正在通过API调用验证客户端计算机上的证书是否可信。如何在不将程序集加载到当前应用程序域的情况下检查公钥令牌?在.Net框架中似乎没有办法做到这一点。链接的博客文章当然很有帮助,但凭良心说,我不能投票给一个纯链接的答案。没有必要完全复制博客文章的内容,但至少这个答案应该包含对所用技术的提及(称为strongNameSignatureReferenceEx),如果未来的访问者因任何原因无法访问该链接,则允许他们独立研究该解决方案。@jmbpiano自2020年起高度相关,因为它似乎已经消失。这是Wayback机器为其编制索引的最后有效时间:
sn -tp <assembly>
<PackageHandlers>
  <PackageHandler>
    <Package type="Package1" assembyName="SomeAssembly" publickey="d45755dbb8b44e59" />
  </PackageHandler>
</PackageHandlers>