2009-02-04 36 views
11

Windows SDK附带一个名为signtool.exe的工具,可让您使用证书签署文件。我需要做同样的事情,但在后台服务中,所以我正在寻找一个库(最好是托管代码,但COM会这样做)来做同样的事情。有任何想法吗?用于替换signtool.exe的API /库

找到了答案。以下是如何使用X.509证书签署文件在.NET:

CmsSigner signer = new CmsSigner(); 
signer.Certificate = new X509Certificate2(certificate); 

SignedCms content = new SignedCms(new ContentInfo(File.ReadAllBytes(fileToSign))); 
content.ComputeSignature(signer, true); 
byte[] signedFile = content.Encode(); 

string signedFileName = fileToSign + ".signed"; 
File.WriteAllBytes(signedFileName, signedFile); 

Console.WriteLine("Signed file: " + signedFileName); 

这里,证书是路径包含证书和fileToSign .pfx文件是签署该文件。

回答

3

SignTool正在使用CAPICOM,它是Crypto API的COM包装器。你可以使用任何一个。如果你打算使用CAPICOM,你可以检查信息here

+0

找到我的答案。有关使用CAPICOM库进行签名的文档: http://msdn.microsoft.com/en-us/library/aa387760(VS.85).aspx 由于CAPICOM API已弃用,因此此页面显示了什么.NET替换为: http://msdn.microsoft.com/en-us/library/cc778518(VS.85).aspx – Arun 2009-02-04 13:00:24

0

你不能只用脚本来描述它吗?写一个简单的批处理文件,给它正确的参数和输入?这至少是我们在UNIX服务器上看到这个问题时所做的。

+0

可能因为他无法假定它部署在目标计算机上并且许可证可能禁止重新分配。 – 2009-02-04 10:42:29

0

我遇到了和塞巴斯蒂安一样的问题。纵观API,看起来这是用于签署封装的消息。 Authenticode - signtool所做的代码签名 - 不同,这就是为什么EXE在签名后不运行的原因。

我仍在寻找替代品。

0

对于到达此地的谷歌 - 旅行者:

This MSDN forum thread说,有Windows中的CryptUIWizDigitalSign API。它还指向Alejandro Campos Magencio的blog article,它显示了VB.NET中的一个示例实现。

由于C#版本似乎缺少,我将Alejandro的代码转换为C#。请注意,以下代码仅适用于文件(还)。

using System; 
using System.Security.Cryptography.X509Certificates; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 

namespace ConsoleApp1 
{ 
    /// <summary> 
    /// Provides code signing functionality via Windows COM Cryptui.dll. 
    /// </summary> 
    class Signer 
    { 

     public const Int32 CRYPTUI_WIZ_NO_UI = 1; 
     public const Int32 CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE = 1; 
     public const Int32 CRYPTUI_WIZ_DIGITAL_SIGN_CERT = 1; 

     public struct CRYPTUI_WIZ_DIGITAL_SIGN_INFO 
     { 
      public Int32 dwSize; 
      public Int32 dwSubjectChoice; 
      [MarshalAs(UnmanagedType.LPWStr)] 
      public string pwszFileName; 
      public Int32 dwSigningCertChoice; 
      public IntPtr pSigningCertContext; 
      public string pwszTimestampURL; 
      public Int32 dwAdditionalCertChoice; 
      public IntPtr pSignExtInfo; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT 
     { 
      public Int32 dwSize; 
      public Int32 cbBlob; 
      public IntPtr pbBlob; 
     } 

     [DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     public static extern bool CryptUIWizDigitalSign(Int32 dwFlags, IntPtr hwndParent, string pwszWizardTitle, ref CRYPTUI_WIZ_DIGITAL_SIGN_INFO pDigitalSignInfo, ref IntPtr ppSignContext); 

     [DllImport("Cryptui.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern bool CryptUIWizFreeDigitalSignContext(IntPtr pSignContext); 

     /// <summary> 
     /// Signs the executable at the given path with the given code signing certificate. 
     /// </summary> 
     /// <example> 
     /// string certPath = @"C:\certs\CodeSigningTestCert.pfx"; 
     /// string exePath = @"C:\temp\ConsoleApp2ToBeSigned.exe"; 
     /// string certPwd = "myGreatSecurePassword"; 
     ///  
     /// try 
     /// { 
     ///  string resultingSignature = Signer.SignExecutable(certPath, exePath, certPwd); 
     /// } 
     /// catch (Win32Exception ex) 
     /// { 
     ///  Console.WriteLine(ex.Message + ", Native error code: " + ex.NativeErrorCode.ToString()); 
     /// } 
     /// catch (Exception ex) 
     /// { 
     ///  // Any unexpected errors? 
     ///  Console.WriteLine(ex.Message); 
     /// } 
     /// 
     /// </example> 
     /// <param name="certPath">The absolute path to the PFX file to be used for signing the exe file.</param> 
     /// <param name="exePath">The absolute path to the executable to be signed.</param> 
     /// <param name="certPwd">The password for the PFX file.</param> 
     public static string SignExecutable(string certPath, string exePath, string certPwd) 
     { 
      X509Certificate2 cert = default(X509Certificate2); 

      CRYPTUI_WIZ_DIGITAL_SIGN_INFO digitalSignInfo = default(CRYPTUI_WIZ_DIGITAL_SIGN_INFO); 
      CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT signContext = default(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT); 

      IntPtr pSignContext = default(IntPtr); 
      IntPtr pSigningCertContext = default(IntPtr); 

      // Get certificate context 
      cert = new X509Certificate2(certPath, certPwd); 
      pSigningCertContext = cert.Handle; 

      // Prepare signing info: exe and cert 
      digitalSignInfo = new CRYPTUI_WIZ_DIGITAL_SIGN_INFO(); 
      digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo); 
      digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE; 
      digitalSignInfo.pwszFileName = exePath; 
      digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT; 
      digitalSignInfo.pSigningCertContext = pSigningCertContext; 
      digitalSignInfo.pwszTimestampURL = null; 
      digitalSignInfo.dwAdditionalCertChoice = 0; 
      digitalSignInfo.pSignExtInfo = IntPtr.Zero; 

      // Sign exe 
      if ((!CryptUIWizDigitalSign(CRYPTUI_WIZ_NO_UI, IntPtr.Zero, null, ref digitalSignInfo, ref pSignContext))) 
       throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizDigitalSign"); 

      // Get the blob with the signature 
      signContext = (CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT)Marshal.PtrToStructure(pSignContext, typeof(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT)); 
      byte[] blob = new byte[signContext.cbBlob + 1]; 
      Marshal.Copy(signContext.pbBlob, blob, 0, signContext.cbBlob); 

      // Free blob memory 
      if ((!CryptUIWizFreeDigitalSignContext(pSignContext))) 
       throw new Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizFreeDigitalSignContext"); 

      return System.Text.Encoding.Default.GetString(blob); 
     } 
    } 
} 

希望它有帮助!