Determining if a file has a digital signature in c# without actually verifying the signature

ksun picture ksun · Apr 11, 2013 · Viewed 15.3k times · Source

Is there a simple way to check if a digital signature exists on a file without trying to verify the certificate it was signed with?

I want to sign a long list of exe & dll files in a directory, but only files that haven't yet been signed.

For example, if one of the files has been signed by Microsoft or some other 3rd party I don't want to sign them again with my company's certificate.

It is easy to check if a file has a digital signature or not by right-clicking the file and viewing its properties (if the digital signature tab shows up then it has been signed). I'm searching for a simple way to check for this digital signature property using C#.

Right now, I am using the verify command with signtool.exe - which doesn't only check to see if a digital signature exists, but also whether the certificate used to sign the file was issued by a trusted authority.

Here is my simple, yet clunky approach for doing this:

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

Notice that I'm using the verbose flag "/v" and checking if the output contains the text "Signing Certificate chain:" - just because I noticed that that string was always in the output of a file that had been signed - and was omitted from any file that hadn't been signed.

Anyway, despite its clumsiness, this code seems to get the job done. One reason I'd like to change it though is because it appears to take a few hundred milliseconds to execute the verify command on a file. I don't need to verify the certificate I'm just trying to see if a digital signature exists on the file.

So in short, is there a simple way to check if a digital signature exists - without trying to verify it?

Answer

ksun picture ksun · Apr 16, 2013

I came up with a pretty decent solution using the "Get-AuthenticodeSignature" powershell command. I found this site that explains how to use powershell commands in c#. This way I don't need to spawn several processes, and it's pretty quick.

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