2013-04-11 39 views
10

是否有一種簡單的方法檢查文件上是否存在數字簽名而不嘗試驗證其簽名的證書?確定文件是否具有c#中的數字簽名而未真正驗證簽名

我想在一個目錄中籤名很長的exe文件列表& 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

p.s.您可能認爲擔心幾百毫秒會很挑剔,但是如果您正在檢查數千個文件,則會加起來。 – ksun 2013-04-11 01:00:06

+0

速度慢的原因可能並不是因爲您正在驗證簽名,而是速度緩慢的原因是因爲您正在爲每個文件產生一個新的進程。獲取C#原生的數字簽名庫,例如Bouncy Castle。 – 2013-04-11 01:16:15

回答

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

確保將System.Management.Automation引用添加到您的項目中。它應該位於:C:\ Program Files \ Reference Assemblies \ Microsoft \ WindowsPowerShell \ v1.0 – ksun 2013-04-16 01:03:21

+1

工作正常,即使使用NuGet的PowerShell 3.0 API – 2015-03-09 18:07:35

1

首先,signtool只適用於PE文件。對於其他文件類型,可以使用包裝簽名或嵌入簽名或分離簽名來完成簽名。

包裝簽名會更改實際文件,使其通常用於讀取的應用程序無法讀取。例如。如果您在PDF上創建包裝簽名,則在簽名被移除之前,任何PDF工具都無法讀取該文件。

某些文件格式支持格式正確的嵌入式簽名(以EXE文件和Authenticode格式爲例)。您可以在其中嵌入簽名,其他應用程序仍然可以讀取它。但這是特定於格式的,並不是很多格式都支持這種格式。

最後分離的簽名與文件分開保存。即如果您有文件a.txt,則創建一個分離簽名並將其放入,例如a.txt.pkcs7detached

如您所見,分離的簽名對於您的任務是最佳的。在這種情況下,您有一個.pkcs7detached文件的列表,以便您可以檢查 - 如果該文件沒有對應的帶有簽名的.pkcs7detached文件,則會創建一個新簽名。

以上所有簽名類型均由我們的SecureBlackbox產品的PKIBlackbox包支持。

+0

謝謝尤金。我忽略了在我的問題中提到我實際上只對簽名DLL和可執行文件感興趣(並不是像我在我的問題中錯誤地指出的那樣的所有文件)。 如果我們決定簽署不是dll或可執行文件的文件,這絕對是很好的信息。 – ksun 2013-04-11 16:43:47

+0

@ksun在這種情況下,您可以使用我們的Authenticode組件 - 它們讓您驗證Authenticode是否存在於文件中而不驗證簽名。還需要注意PE文件中的Authenticode和託管程序集中的強名稱是可以在託管程序集中一起使用的不同事物。 – 2013-04-11 17:12:03

+0

感謝您的提示。我嘗試查找[MSDN上的Authenticode](http://msdn.microsoft.com/en-us/library/ms537364(v = vs.85).aspx) 看起來也許ChkTrust命令會工作?我相信這也會檢查證書的有效性。 但是,我發現[另一篇文章](http://stackoverflow.com/questions/5555214/what-is-the-best-way-to-check-programatically-if-dll-exe-file-is-signed-與-Aut)在StackOverflow,有一個簡單的方法來檢查與powershell命令的authenticode簽名。 Get-AuthenticodeSignature 我們目前沒有強大的命名文件。 – ksun 2013-04-12 00:07:02

4

如果你想爲.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),但我不爲熟悉它們。這是我們用來仔細檢查數字簽名是否已被我們的內部工具應用的方法。

+0

這看起來像一個很好的解決方案,但是我們的產品使用了.NET程序集和從C++編譯的非託管程序集的混合體。請糾正我,如果我錯了,但我相信這個解決方案不適用於從C++編譯的非託管程序集。 – ksun 2013-04-11 17:22:36

+0

這是我的應用程序(所有託管代碼C#DLL)所需的解決方案。但是,如果文件可以包含多個證書,它們也可以「附加」簽名。以上代碼僅在存在1個證書時處理。 – 2016-10-25 13:13:12