在c#中确定文件是否具有数字签名,而不实际验证签名



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

我想签一长串的exe &DLL文件,但仅限于尚未签名的文件。

例如,如果其中一个文件已经被微软或其他第三方签名,我不想用我公司的证书再次签名。

很容易检查文件是否有数字签名,右键单击文件并查看其属性(如果数字签名选项卡显示,那么它已被签名)。我正在寻找一个简单的方法来检查这个数字签名属性使用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",并检查输出是否包含文本"Signing Certificate chain:" -只是因为我注意到该字符串总是在已签名的文件的输出中-并且在未签名的文件中被省略。

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

所以简而言之,有没有一种简单的方法来检查数字签名是否存在——而不需要验证它?

我想出了一个相当不错的解决方案,使用"Get-AuthenticodeSignature" powershell命令。我发现这个网站解释了如何在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);
            }
}

如果你想为。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),但我对它们不太熟悉。这是我们用来反复检查数字签名是否被我们的内部工具应用的方法。

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

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

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

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

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

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

相关内容

最新更新