2013-04-11 28 views
10

Czy istnieje prosty sposób sprawdzenia, czy podpis cyfrowy istnieje w pliku bez próby zweryfikowania certyfikatu, z którym został podpisany?Określanie, czy plik ma podpis cyfrowy w języku C# bez faktycznego weryfikowania podpisu

Chcę podpisać długą listę exe & plików dll w katalogu, ale tylko pliki, które nie zostały jeszcze podpisane.

Na przykład, jeśli jeden z plików został podpisany przez Microsoft lub inną firmę zewnętrzną, nie chcę podpisywać ich ponownie za pomocą certyfikatu mojej firmy.

Łatwo jest sprawdzić, czy plik ma podpis cyfrowy, czy też nie, klikając plik prawym przyciskiem myszy i wyświetlając jego właściwości (jeśli pojawi się karta podpisu cyfrowego, oznacza to, że została podpisana). Poszukuję prostego sposobu sprawdzenia tej właściwości podpisu cyfrowego przy użyciu C#.

W tej chwili używam polecenia verify z signtool.exe - które nie tylko sprawdza, czy podpis cyfrowy istnieje, ale także czy certyfikat użyty do podpisania pliku został wydany przez zaufany organ.

Oto mój prosty, ale przylegający podejście do w ten sposób:

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:"); 
     } 

Zauważ, że używam opisowy flagę „/ v” i sprawdzenie, czy wyjście zawiera tekst „łańcuch certyfikatu podpisu:” - tylko dlatego, że zauważyłem, że ten ciąg był zawsze na wyjściu pliku, który został podpisany - i został pominięty w każdym pliku, który nie został podpisany.

W każdym razie, pomimo niezgrabności, kod ten wydaje się wykonywać swoją pracę. Jednym z powodów, dla których chciałbym to zmienić, jest to, że wykonanie polecenia verify na pliku trwa kilkaset milisekund. Nie muszę weryfikować certyfikatu, który próbuję sprawdzić, czy w pliku istnieje podpis cyfrowy.

Krótko mówiąc, czy istnieje prosty sposób sprawdzenia, czy podpis cyfrowy istnieje - bez próby jego weryfikacji?

+0

p.s. Możesz pomyśleć, że to jest wybredne, aby martwić się o kilkaset milisekund, ale to się sumuje, jeśli sprawdzasz tysiące plików. – ksun

+0

Powód jest powolny, prawdopodobnie nie dlatego, że weryfikujesz podpis, powód jest powolny, ponieważ tworzysz nowy proces dla każdego pliku. Uzyskaj bibliotekę podpisów cyfrowych, która jest natywna dla języka C#, na przykład Bouncy Castle. –

Odpowiedz

9

Wpadłem na całkiem przyzwoite rozwiązanie za pomocą polecenia "powershare". Znalazłem this site, który wyjaśnia, jak używać poleceń powershell w języku C#. W ten sposób nie potrzebuję spawnować kilku procesów i jest to dość szybkie.

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

Pamiętaj, aby dodać odniesienie do System.Management.Automation dla swojego projektu. Powinien być zlokalizowany tutaj: C: \ Program Files \ Referencje Zespoły \ Microsoft \ WindowsPowerShell \ v1.0 – ksun

+1

Działa dobrze, nawet z PowerShell 3.0 API od NuGet –

1

Przede wszystkim signtool działa tylko z plikami PE. W przypadku innych typów plików podpisywanie może odbywać się za pomocą zawijania podpisu lub osadzonego podpisu lub oddzielnego podpisu.

Zawijanie podpisu zmienia rzeczywisty plik, czyniąc go nieczytelnym przez aplikacje zwykle używane do jego odczytu. Na przykład. jeśli utworzysz podpis zawijający w formacie PDF, żadne narzędzie PDF nie będzie mogło odczytać pliku, dopóki podpis nie zostanie usunięty.

Niektóre formaty plików obsługują podpisy osadzone bezpośrednio w ich formacie (na przykład pliki EXE i Authenticode). Tam możesz umieścić sygnaturę w pliku, a inne aplikacje mogą ją odczytać. Jest to zależne od formatu i nie obsługuje wielu formatów.

Ostatecznie oddzielne podpisy są przechowywane oddzielnie od pliku. To znaczy. jeśli masz plik a.txt, tworzysz odłączoną sygnaturę i umieszczasz ją na przykład w a.txt.pkcs7detached.

Jak widać, odłączone sygnatury są optymalne do Twojego zadania. W tym przypadku masz listę plików .pkcs7detached, dzięki czemu możesz sprawdzić - jeśli plik nie ma odpowiedniego pliku .pkcs7detached z podpisem, utworzysz nowy podpis.

Wszystkie powyższe typy sygnatur są obsługiwane przez pakiet PKIBlackbox naszego produktu SecureBlackbox.

+0

Dziękuję Eugene. Zignorowałem, aby wspomnieć w moim pytaniu, że faktycznie interesuję się tylko podpisywaniem plików DLL i plików wykonywalnych (nie wszystkie pliki, które błędnie podałem w pytaniu). Jest to zdecydowanie dobra informacja, ale jeśli zdecydujemy się podpisać pliki, które nie są bibliotekami dll lub plikami wykonywalnymi. – ksun

+0

@ksun W tym przypadku możesz użyć naszych komponentów Authenticode - umożliwiają one sprawdzenie, czy w pliku znajduje się Authenticode bez sprawdzania poprawności podpisu. Należy również zauważyć, że Authenticode w plikach PE i silne nazwy w zarządzanych złożeniach to różne rzeczy, które mogą być używane razem w zarządzanych złożeniach. –

+0

Dzięki za cynk. Próbowałem wyszukać [Authenticode na MSDN] (http://msdn.microsoft.com/en-us/library/ms537364 (v = vs.85) .aspx) Wygląda na to, że może działać polecenie ChkTrust? Uważam, że sprawdza to również ważność certyfikatu. Jednak znalazłem [inny post] (http://stackoverflow.com/questions/5555214/what-is-the-best-way-to-check-programatically-if-dll-exe-file-is-signed- with-aut) w StackOverflow, który miał łatwy sposób sprawdzenia podpisu Autodesk za pomocą polecenia powershell. Get-AuthenticodeSignature Obecnie nie nazywamy plików mocnymi nazwami. – ksun

4

Jeśli chcesz to zrobić dla zespołów .NET, można to zrobić:

 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. 
     } 

Klasa X509Certificate ma kilka statycznych metod, które mogą być również użyteczne (np CreateFromSignedFile), ale nie jestem tak zna je. Jest to metoda, której używamy do podwójnego sprawdzenia, czy podpis cyfrowy został zastosowany przez nasze wewnętrzne narzędzia.

+0

To wygląda na świetne rozwiązanie, ale nasze produkty korzystają z kombinacji zarówno zespołów .NET, jak i niezarządzanych zestawów skompilowanych z C++. Proszę mnie poprawić, jeśli się mylę, ale wierzę, że to rozwiązanie nie zadziała w przypadku niezarządzanych złożeń, które zostały skompilowane z C++. – ksun

+0

To jest rozwiązanie potrzebne dla mojej aplikacji (wszystkie zarządzane biblioteki DLL C#). Ale pliki mogą być również "dołączane" podpisane, gdzie może zawierać więcej niż jeden certyfikat. Powyższy kod obsługuje tylko wtedy, gdy obecny jest 1 certyfikat. –