Определение, имеет ли файл цифровую подпись в С# без фактической проверки подписи

Есть ли простой способ проверить, существует ли цифровая подпись в файле, не пытаясь проверить сертификат, с которым он был подписан?

Я хочу подписать длинный список файлов exe и dll в каталоге, но только файлы, которые еще не были подписаны.

Например, если один из файлов был подписан Microsoft или какой-либо другой сторонней стороной, я не хочу подписывать их снова с сертификатом компании.

Легко проверить, есть ли у файла цифровая подпись или нет, щелкнув правой кнопкой мыши файл и просмотрев его свойства (если на закладке цифровой подписи появится подпись). Я ищу простой способ проверить это свойство цифровой подписи с помощью С#.

В настоящее время я использую команду verify с signtool.exe - которая не только проверяет, существует ли цифровая подпись, но также и сертификат, используемый для подписи файла, был выдан доверенным органом.

Вот мой простой, но неуклюжий подход для этого:

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" и проверяю, содержит ли вывод текст "Цепочка сертификата подписки:" - только потому, что я заметил, что эта строка всегда находилась на выходе файла, который был подписан - и был исключен из любого файла, который не был подписан.

В любом случае, несмотря на свою неуклюжесть, этот код, похоже, выполняет свою работу. Одна из причин, по которой я хочу ее изменить, состоит в том, что для выполнения команды проверки файла требуется несколько сотен миллисекунд. Мне не нужно проверять сертификат, который я просто пытаюсь проверить, существует ли цифровая подпись в файле.

Короче говоря, есть ли простой способ проверить, существует ли цифровая подпись - не пытаясь ее проверить?

Ответ 1

Я придумал довольно приличное решение, используя команду powershell "Get-AuthenticodeSignature". Я нашел этот сайт, в котором объясняется, как использовать команды 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);
            }
}

Ответ 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), но я не так хорошо знаком с ними. Это метод, который мы используем, чтобы дважды проверить, что цифровая подпись была применена нашими внутренними инструментами.

Ответ 3

Прежде всего, signtool работает только с PE файлами. Для других типов файлов подпись может быть выполнена с использованием либо сигнатуры упаковки, либо встроенной подписи или отдельной подписи.

Подпись подписи изменяет фактический файл, что делает его нечитаемым для тех приложений, которые обычно используются для его чтения. Например. если вы создаете подпись для упаковки в PDF, ни один инструмент PDF не сможет прочитать файл до тех пор, пока подпись не будет удалена.

Некоторые форматы файлов поддерживают встроенные подписи прямо в их формате (например, EXE файлы и формат Authenticode). Там вы можете вставить подпись в файл, и другие приложения все еще могут ее прочитать. Но это зависит от формата, и не все форматы поддерживают это.

Наконец, отдельные записи хранятся отдельно от файла. То есть если у вас есть файл a.txt, вы создаете отдельную подпись и помещаете ее, например, в a.txt.pkcs7detached.

Как вы видите, отдельные записи являются оптимальными для вашей задачи. И в этом случае у вас есть список файлов .pkcs7detached, чтобы вы могли проверить - если файл не имеет соответствующего файла .pkcs7detached с подписью, вы создаете новую подпись.

Все указанные типы подписей поддерживаются пакетом PKIBlackbox нашего продукта SecureBlackbox.