【问题标题】:How to check if a file has a digital signature如何检查文件是否有数字签名
【发布时间】:2010-10-14 14:23:15
【问题描述】:

我想以编程方式检查文件是否经过数字签名。

目前,我发现了一个相当晦涩的Microsoft code,它无法编译...

关于这个主题有什么想法吗?

顺便说一句,带有命令行的外部工具也很棒。

【问题讨论】:

    标签: certificate code-signing


    【解决方案1】:

    提到signtool的答案中缺少的重要部分是:

    是的,通过众所周知的signtool.exe,您还可以查明文件是否已签名。无需下载其他工具!

    例如用简单的一行:

    signtool verify /pa myfile.exe
    if %ERRORLEVEL% GEQ 1 echo This file is not signed.
    

    (对于详细输出,在/pa 之后添加/v。)

    有人可能会问:为什么这很重要?我只是(再次)签署了应该签署的文件并且它可以工作。

    我的目标是保持构建干净,并且不要第二次签署文件,因为不仅日期改变了,而且之后的二进制文件也不同。

    业务示例: 我的客户有一个简化的自动化“开发操作”类构建和后期构建过程。不同的文件集有多个来源,最后所有文件都经过构建、测试和捆绑分发 - 为此必须对一些文件进行签名。为保证某些文件不会在没有签名的情况下离开设备,我们曾经对在媒体上找到的所有重要文件进行签名,即使它们已经签名。

    但这还不够干净!一般:

    1. 如果我们再次对已签名的文件进行签名,则文件日期和二进制指纹会发生变化,并且如果只是复制文件,则该文件将失去与其来源的可比性。 (至少如果您使用时间戳签名,我们总是这样做,我认为这是强烈推荐的。)

    这是一个严重的质量损失,因为尽管文件本身并没有改变,但该文件不再与之前的文件相同。

    1. 如果我们再次签署文件,当它是不应由我们公司签署的第三方文件时,这也可能是一个错误。

    您可以通过根据前面提到的signtool verify 调用的返回码使签名本身成为条件来避免这两种情况。

    【讨论】:

    • 系统exe也不行signtool verify /pa c:\Windows\regedit.exe
    【解决方案2】:

    下载Sigcheck并使用以下命令。

    sigcheck.exe -a -u -e 
    

    签名 dll 示例

    File version:   0.0.0.0
    Strong Name:    Signed
    

    未签名 dll 的示例

    File version:   0.0.0.0
    Strong Name:    Unsigned
    

    Sigcheck 是一个显示文件版本号的命令行实用程序。祝你好运

    【讨论】:

      【解决方案3】:

      我在网上找到了另一个选项(纯 .NET 代码)here

      代码非常简单且有效。

      using System;
      using System.Collections.Generic;
      using System.IO;
      using System.Linq;
      using System.Security.Cryptography.X509Certificates;
      using System.Text;
      using System.Threading.Tasks;
      
      internal class Program
      {
          private static void Main(string[] args)
          {
              string filePath = args[0];
      
              if (!File.Exists(filePath))
              {
                  Console.WriteLine("File not found");
                  return;
              }
      
              X509Certificate2 theCertificate;
      
              try
              {
                  X509Certificate theSigner = X509Certificate.CreateFromSignedFile(filePath);
                  theCertificate = new X509Certificate2(theSigner);
              }
              catch (Exception ex)
              {
                  Console.WriteLine("No digital signature found: " + ex.Message);
      
                  return;
              }
      
              bool chainIsValid = false;
      
              /*
               *
               * This section will check that the certificate is from a trusted authority IE
               * not self-signed.
               *
               */
      
              var theCertificateChain = new X509Chain();
      
              theCertificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
      
              /*
               *
               * Using .Online here means that the validation WILL CALL OUT TO THE INTERNET
               * to check the revocation status of the certificate. Change to .Offline if you
               * don't want that to happen.
               */
      
              theCertificateChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
      
              theCertificateChain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
      
              theCertificateChain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
      
              chainIsValid = theCertificateChain.Build(theCertificate);
      
              if (chainIsValid)
              {
                  Console.WriteLine("Publisher Information : " + theCertificate.SubjectName.Name);
                  Console.WriteLine("Valid From: " + theCertificate.GetEffectiveDateString());
                  Console.WriteLine("Valid To: " + theCertificate.GetExpirationDateString());
                  Console.WriteLine("Issued By: " + theCertificate.Issuer);
              }
              else
              {
                  Console.WriteLine("Chain Not Valid (certificate is self-signed)");
              }
          }
      }
      

      【讨论】:

      • 请注意,这会检索用于签署文件的证书,但它不会验证文件的签名是否有效(即,如果您篡改文件,此方法仍将返回原始签名者,它不会提醒您文件已被篡改)
      • X509Certificates 和 X509Chain 对象需要正确处理。建议将它们包装在 using 语句中。
      • 您在顶部添加的链接不再有效。
      【解决方案4】:

      如果需要外部工具,可以使用signtool.exe。它是 Windows SDK 的一部分,它接受命令行参数,您可以在此处了解更多信息,http://msdn.microsoft.com/en-us/library/aa387764.aspx

      【讨论】:

        【解决方案5】:

        从 PowerShell 5.1 开始,您可以使用 Get-AuthenticodeSignature 来验证二进制文件或 PowerShell 脚本的签名。

        > Get-AuthenticodeSignature -FilePath .\MyFile.exe
        
        SignerCertificate                 Status        Path                                                                                   
        -----------------                 ------        ----                                                                                   
        A59E92E31475F813DDAF41C3CCBC8B78  Valid         MyFile.exe   
        

        或者

        > (Get-AuthenticodeSignature -FilePath .\MyFile.exe).Status
        Valid
        

        【讨论】:

        • Get-AuthenticodeSignature 是否对数字签名有效期有依赖关系? “Valid To”通过后Status会变成“Not Valid”吗?
        【解决方案6】:

        你也可以尝试使用 npm package sign-check 来达到这个目的。

        这个包实现了WinVerifyTrust API,使用简单:

        npm install -g sign-check
        
        sign-check 'path/to/file'
        

        【讨论】:

          【解决方案7】:

          选择<*>.exe右键>属性。如果文件已签名,那么您将在该文件的属性窗口中看到此选项卡。

          【讨论】:

          • 我看不出这如何有助于“以编程方式”验证文件是否被数字签名:)
          • 这个答案对我很有帮助
          • 哇,这个答案太糟糕了。 @JerryGoyal:数字签名的存在没有任何意义确保转到数字签名,选择签名,然后选择详细信息并检查“数字签名正常”是否显示在顶部。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-04
          • 2021-10-31
          • 2011-09-29
          • 2018-01-05
          相关资源
          最近更新 更多