Определение наличия у файла цифровой подписи в C# без фактической проверки подписи

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

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

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

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

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

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

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

3 ответа

Решение

Я придумал довольно приличное решение, используя команду powershell "Get-AuthenticodeSignature". Я нашел этот сайт, который объясняет, как использовать команды powershell в C#. Таким образом, мне не нужно создавать несколько процессов, и это довольно быстро.

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,

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

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

Другие вопросы по тегам