WinVerifyTrust 检查特定签名?
我正在为 Windows 实现一个进程提升助手。 该程序将以提升模式运行并以管理员权限启动其他程序,而不会显示其他 UAC 提示。 出于安全原因,我想确保只有使用我公司的 Authenticode 密钥进行数字签名的二进制文件才能执行。
WinVerifyTrust 函数让我成功了一半,但它仅确保二进制文件由属于 Microsoft 信任链一部分的某个密钥进行签名。 是否有一种相对简单的方法来执行 Authenticode 验证并确保它是由我们的私钥签名的?
I'm implementing a process elevation helper for Windows. It's a program that will run in elevated mode and launch other programs with administrator privileges without displaying additional UAC prompts. For security reasons, I want to make sure only binaries that are digitally signed with my company's Authenticode key can be executed.
The WinVerifyTrust function gets me halfway there, but it only ensures that a binary is signed by some key that is part of Microsoft's chain of trust. Is there a relatively simple way to perform the Authenticode verification AND ensure that it is signed by our private key?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我相信您正在寻找的是 CryptQueryObject 。
有了它,您应该能够从 PE 中提取相关证书,并执行您想要的任何其他检查。
举例来说,这将使您进入 HCRYPTMSG。 从那里您可以使用 CryptMsgGetParam 提取任何内容你要。 我希望做出一些更“健壮”的东西,但是这些 API 非常复杂,因为它们需要大量分支来处理所有返回情况。
所以,这是 ap/invoke-rific c# 示例(我从 C 开始,但这基本上不可读):
I believe what you're looking for is CryptQueryObject.
With it you should be able to pull the involved certificate out of a PE, and do any additional checks you want.
By way of example, this will get you to a HCRYPTMSG. From there you can use CryptMsgGetParam to pull out whatever you want. I'd hoped to make something more 'robust', but these APIs are pretty hairy insomuch as they require a lot of branching to handle all their return cases.
So, here's a p/invoke-rific c# example (I started in C, but that was basically unreadable):
要从签名代码中获取证书信息,请使用以下命令:
然后您可以获得如下所示的证书详细信息:
To get the certificate information from signed code use this:
Then you can get the cert details like this:
警告:它比你想象的还要糟糕。
至少自从引入 SHA-256 签名以来(情况一直如此吗?),Authenticode 可以拥有多个签名。 它们没有在 PKCS-7 签名消息中编码为多重签名; 相反,它们是 OID_NESTED_SIGNATURE 类型的未经身份验证的消息属性,每个属性都包含另一个完整的 PKCS-7 签名消息。
如果任何签名有效并且来自受信任的证书链,WinVerifyTrust 会告诉您该文件有效。 但是它不会告诉您哪些签名是有效的。 如果您随后使用 CryptQueryObject 读取完整的 PKCS-7 消息,并且仅查看主签名的证书(如此处和 MSDN 上的代码示例所示),则您不一定会查看经过验证的证书。 关联的签名可能与可执行文件不匹配,和/或证书可能没有受信任的 CA 链。
如果您使用主签名的详细信息来验证该证书是否是您的软件信任的证书,则很容易出现 WinVerifyTrust 信任辅助签名的情况,但您的代码正在检查主签名的证书是否符合您的预期,并且您没有注意到主证书的签名是无意义的。 攻击者可以在不拥有私钥的情况下使用您的公共证书,并结合颁发给其他人的其他代码签名证书,以这种方式绕过发布者检查。
从 Win8 开始,WinVerifyTrust 可以选择验证特定签名,因此您应该能够迭代签名以找到有效的签名和满足您要求的签名。
不过,如果您必须兼容 Win7,据我所知,您可以管理的最好方法是 MsiGetFileSignatureInformation。 从实验来看(至于这里的其他所有内容,实际文档是令人沮丧的模糊),当 WinVerifyTrust 信任证书时,它似乎会返回受信任的证书。 但是,如果没有受信任的签名,它无论如何都会返回主签名的证书,因此您仍然必须首先使用 WinVerifyTrust 进行检查。
当然,这里也存在很多可能的检查时间/使用时间问题。
A word of warning: it's worse than you already thought.
At least since introducing SHA-256 signing (has this always been the case?), it's possible for Authenticode to have multiple signatures. They're not encoded as multiple signatures in the PKCS-7 signature message; instead, they're unauthenticated message attributes of type OID_NESTED_SIGNATURE, each containing another complete PKCS-7 signature message.
WinVerifyTrust will tell you the file is valid if any of the signatures are valid and come from a trusted certificate chain. However it won't tell you which of the signatures was valid. If you then use CryptQueryObject to read the full PKCS-7 message, and only look at the certificate for the primary signature (as in the code samples here and on MSDN), you're not necessarily looking at a verified certificate. The associated signature might not match the executable, and/or the certificate might not have a trusted CA chain.
If you're using the details of the primary signature to validate that the certificate is one your software trusts, you're vulnerable to a situation where WinVerifyTrust is trusting a secondary signature, but your code is checking the primary signature's certificate is what you expected, and you haven't noticed that the signature from the primary certificate is nonsense. An attacker could use your public certificate without owning its private key, combined with some other code-signing certificate issued to someone else, to bypass a publisher check this way.
From Win8 onwards, WinVerifyTrust can optionally validate specific signatures, so you should be able to iterate the signatures to find one that is valid and one that satisfies your requirements.
If you have to be Win7-compatible, though, as far as I know the best you can manage is MsiGetFileSignatureInformation. From experimentation (as for everything else here, the actual documentation is frustratingly woolly), it seems to return the trusted certificate when WinVerifyTrust trusts one. But if there isn't a trusted signature, it returns the primary signature's certificate anyway, so you still have to use WinVerifyTrust to check that first.
Of course there also plenty of possible time-of-check/time-of-use problems here.
在这里找到了解决方案:
http://www .ucosoft.com/how-to-program-to-retrieve-the-authenticode-information.html
这里有缩进:
found the solution here:
http://www.ucosoft.com/how-to-program-to-retrieve-the-authenticode-information.html
here it is with indentation: