是否有一种简单的方法可以检查文件中是否存在数字签名,而无需验证其签名的证书?
我想签署一长串的exe& amp;目录中的dll文件,但只有尚未签名的文件。
例如,如果其中一个文件已经由Microsoft或其他第三方签名,我不想再使用我公司的证书签名。
通过右键单击文件并查看其属性(如果数字签名选项卡显示已签名),可以轻松检查文件是否具有数字签名。我正在寻找一种使用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"并检查输出是否包含文本"签署证书链:" - 只是因为我注意到该字符串总是在已经签名的文件的输出中 - 并且从没有签名的任何文件中省略。
无论如何,尽管它的笨拙,这段代码似乎完成了工作。我想改变它的一个原因是因为它似乎需要几百毫秒才能对文件执行verify命令。我不需要验证证书,我只是想查看文件中是否存在数字签名。
简而言之,是否有一种简单的方法来检查数字签名是否存在 - 而不是试图验证它?
答案 0 :(得分:9)
我使用“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);
}
}
答案 1 :(得分:6)
如果要对.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
),但我对它们并不熟悉。这是我们用来仔细检查我们的内部工具是否已应用数字签名的方法。
答案 2 :(得分:2)
首先,signtool仅适用于PE文件。对于其他文件类型,可以使用包装签名或嵌入式签名或分离签名来完成签名。
包装签名会更改实际文件,使那些通常用于读取它的应用程序无法读取。例如。如果您在PDF上创建包装签名,则在删除签名之前,任何PDF工具都无法读取该文件。
某些文件格式支持其格式的嵌入式签名(EXE文件和Authenticode格式就是示例)。在那里,您可以将签名嵌入到文件中,其他应用程序仍然可以读取它。但这是特定于格式的,并没有很多格式支持这一点。
最后,分离的签名与文件分开存放。即如果您有文件a.txt
,则创建一个分离的签名并将其放入,例如a.txt.pkcs7detached
。
如您所见,分离的签名最适合您的任务。在这种情况下,您有一个.pkcs7detached文件列表,以便您可以检查 - 如果文件没有带签名的相应.pkcs7detached文件,则创建一个新签名。
我们的SecureBlackbox产品的PKIBlackbox包支持以上所有签名类型。