【问题标题】:Determining if a file has a digital signature in c# without actually verifying the signature在不实际验证签名的情况下确定文件是否在 c# 中具有数字签名
【发布时间】:2013-04-11 00:58:13
【问题描述】:

是否有一种简单的方法可以检查文件上是否存在数字签名,而无需尝试验证签名所用的证书?

我想在一个目录中签署一长串 exe 和 dll 文件,但只签署尚未签署的文件。

例如,如果其中一个文件已由 Microsoft 或其他第 3 方签名,我不想使用我公司的证书再次对其进行签名。

通过右键单击文件并查看其属性可以轻松检查文件是否具有数字签名(如果显示数字签名选项卡,则它已被签名)。我正在寻找一种使用 C# 检查此数字签名属性的简单方法。

现在,我正在使用带有 signtool.exe 的 verify 命令 - 它不仅检查数字签名是否存在,还检查用于签署文件的证书是否由受信任的机构颁发。

这是我的简单但笨重的方法:

private static Boolean AlreadySigned(string file)
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardError = true;
    startInfo.FileName = "signTool.exe";
    startInfo.Arguments = "verify /v " + file;
    startInfo.UseShellExecute = false;

    Process process = new Process();
    process.StartInfo = startInfo;
    process.EnableRaisingEvents = true;
    process.Start();
    process.WaitForExit();
    string output = process.StandardOutput.ReadToEnd();

    return output.Contains("Signing Certificate Chain:");
}

请注意,我正在使用详细标志“/v”并检查输出是否包含文本“签名证书链:”——因为我注意到该字符串始终在已签名文件的输出中- 并且在任何未签名的文件中被省略。

无论如何,尽管它很笨拙,但这段代码似乎可以完成工作。我想更改它的一个原因是因为它似乎需要几百毫秒才能对文件执行验证命令。我不需要验证证书,我只是想查看文件上是否存在数字签名。

简而言之,有没有一种简单的方法来检查数字签名是否存在 - 而无需尝试验证它?

【问题讨论】:

  • 附注您可能认为担心几百毫秒是很挑剔的,但如果您要检查数千个文件,这会加起来。
  • 它慢的原因可能不是因为您正在验证签名,它慢的原因是因为您正在为每个文件生成一个新进程。获取 C# 原生的数字签名库,例如 Bouncy Castle。

标签: c# digital-signature signing file-properties


【解决方案1】:

我使用“Get-AuthenticodeSignature”powershell 命令提出了一个相当不错的解决方案。我发现 this site 解释了如何在 c# 中使用 powershell 命令。这样我就不需要生成多个进程,而且速度非常快。

using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;


private static Boolean alreadySigned(string file)
{            
            try
            {
                RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
                runspace.Open();

                Pipeline pipeline = runspace.CreatePipeline();
                pipeline.Commands.AddScript("Get-AuthenticodeSignature \"" + file + "\"");

                Collection<PSObject> results = pipeline.Invoke();
                runspace.Close();
                Signature signature = results[0].BaseObject as Signature;
                return signature == null ? false : (signature.Status != SignatureStatus.NotSigned);
            }
            catch (Exception e)
            {
                throw new Exception("Error when trying to check if file is signed:" + file + " --> " + e.Message);
            }
}

【讨论】:

  • 确保将 System.Management.Automation 引用添加到您的项目中。它应该位于:C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0
  • 工作正常,即使使用来自 NuGet 的 PowerShell 3.0 API
【解决方案2】:

如果您想对 .NET 程序集执行此操作,您可以执行此操作:

        string filePath = "C:/path/to/file.dll";
        Assembly assembly = Assembly.LoadFrom(filePath);
        Module module = assembly.GetModules().First();
        X509Certificate certificate = module.GetSignerCertificate();
        if (certificate == null)
        {
             // file is not signed.
        }

X509Certificate 类有一些静态方法也可能有用(例如CreateFromSignedFile),但我对它们不太熟悉。这是我们用来仔细检查我们的内部工具是否已应用数字签名的方法。

【讨论】:

  • 这看起来是一个很好的解决方案,但我们的产品混合使用了 .NET 程序集和从 C++ 编译的非托管程序集。如果我弄错了,请纠正我,但我相信这个解决方案不适用于从 C++ 编译的非托管程序集。
  • 这是我的应用程序所需的解决方案(所有托管代码 C# DLL)。但是文件也可以“附加”签名,其中可以包含多个证书。以上代码仅在存在 1 个证书时处理。
【解决方案3】:

首先,signtool 仅适用于 PE 文件。对于其他文件类型,可以使用包装签名或嵌入签名或分离签名来完成签名。

包装签名会更改实际文件,使其无法被通常用于读取它的应用程序读取。例如。如果您在 PDF 上创建环绕签名,则在删除签名之前,任何 PDF 工具都无法读取该文件。

某些文件格式支持其格式的嵌入签名(EXE 文件和 Authenticode 格式就是示例)。在那里,您可以将签名嵌入文件中,其他应用程序仍然可以读取它。但这是特定于格式的,支持这一点的格式并不多。

最终分离的签名与文件分开保存。 IE。如果您有一个文件a.txt,则创建一个分离的签名并将其放入例如a.txt.pkcs7detached。

如您所见,分离的签名最适合您的任务。在这种情况下,您有一个 .pkcs7detached 文件列表,因此您可以检查 - 如果该文件没有对应的带有签名的 .pkcs7detached 文件,则创建一个新签名。

我们SecureBlackbox 产品的 PKIBlackbox 包支持上述所有签名类型。

【讨论】:

  • 谢谢尤金。我忽略了在我的问题中提到我实际上只对签署 DLL 和可执行文件感兴趣(不是我在问题中错误陈述的所有文件)。如果我们决定签署不是 dll 或可执行文件的文件,这绝对是一个很好的信息。
  • @ksun 在这种情况下,您可以使用我们的 Authenticode 组件 - 它们让您无需验证签名即可验证文件中是否存在 Authenticode。您还需要注意,PE 文件中的 Authenticode 和托管程序集中的强命名是不同的东西,可以在托管程序集中一起使用。
  • 感谢您的提示。我尝试查找 Authenticode on MSDN 看起来可能 ChkTrust 命令可以工作?我相信这也会检查证书的有效性。但是,我在 StackOverflow 上找到了another post,它有一种使用 powershell 命令检查身份验证签名的简单方法。 Get-AuthenticodeSignature 我们目前没有对文件进行强命名。
猜你喜欢
  • 2018-05-26
  • 1970-01-01
  • 2013-06-02
  • 2015-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
相关资源
最近更新 更多