2009-02-04 52 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); 
     } 
    } 
} 

希望它有幫助!