2014-10-13 5 views
10

Я пытаюсь определить лучший метод для подписи кода исполняемого файла с использованием Bouncy Castle, управляемого кода или не управляемого кода из C#. Поскольку CAPICOM теперь устарел, я полагаю, что один из методов SignerSign из mssign32.dll - лучший способ пойти, если это нужно сделать неуправляемым.Как с программным кодом Подписать исполняемый файл с помощью PFX (Bouncy Castle или в противном случае)

Этот ответ (https://stackoverflow.com/a/3952235/722078) кажется близким, но он создает файл .p7m, который, будучи правильным размером, не будет работать корректно (очевидно, переименован в .exe перед запуском).

Решение, данное вопросчиком (API/Library to replace signtool.exe), казалось перспективным и управляемым, но, как отмечает Том Кэнэм в комментариях ниже, «похоже, что это для подписания огибаемых сообщений. Authenticode - подписание кода, signtool does - отличается, поэтому EXE не запускается после подписания. " Я получаю ту же ошибку, что и Том, когда я подписываюсь, используя либо решение вопросчика, либо ранее упоминавшееся решение Bouncy Castle.

Единственный вариант, который я еще не предпринял, приведен здесь (https://stackoverflow.com/a/6429860/722078), и, хотя он выглядит многообещающим, я не уверен, что он использует подписание под псевдонимом «подписи под кодовым названием», в отличие от «огибаемого сообщения». Этот ответ также имеет преимущество не использовать методы взаимодействия CAPICOM, которые теперь устарели, поэтому я предполагаю, что сегодня сообщаю о результатах, используя этот метод. Если это лучший вариант, может ли кто-нибудь там говорить о различиях между SignerSign, SignerSignEx и SignerSignEx2 функциями, которые экспортируются из mssign32.dll? Я прочитал, что SignerSignEx2 следует использовать с Windows 8 и выше ...

Короче говоря, я хотел бы реплицировать способность signtool.exe подписывать исполняемый файл с заданным файлом .exe, .pfx-файлом и пароль так:

signtool sign /f cert.pfx /p password application.exe 

Я ищу лучший вариант для программного кода подписать исполняемый файл (PE, если это имеет значение), используя подписывание Authenticode, и я предпочел бы использовать Надувной замок или управляемый код, если это возможно, хотя Я буду использовать что-то неуправляемое, если оно работает и в настоящее время не рекомендуется.

Спасибо!

+0

Просто люркер, но это похоже на http://stackoverflow.com/a/6429860/722078 - применимый пример. FYI, в этих функциях слово «SIP» означает [пакет интерфейса пользователя] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms721625 (v = vs.85) .aspx # _security_subject_interface_package_gly) –

+0

Вот и я тоже склоняюсь, хотя я надеюсь, что кто-то может прояснить различия между исторической доступностью методов SignerSign. Я посмотрю, смогу ли я выкопать ссылку, в которой указано, что SignerSignEx2 следует использовать с Windows 8, хотя он не предоставил никаких дополнительных сведений. –

+0

Этот комментарий к Windows 8 - это комментарий к этому ответу: (http://stackoverflow.com/a/9925866/722078). Похоже, что SignerSignEx2 был введен для подписания приложений Windows App Store, что не имеет для меня отношения. –

ответ

11

Насколько я могу судить, SignSigner и SignSignerEx доступны с Windows XP, которая является самой старой операционной системой, которую я поддерживаю. Поскольку мне не нужно беспокоиться о публикации Windows App Store, этот ответ ограничивается SignSigner и SignSignerEx, хотя импорт для SignSignerEx2 очень похож на SignSignerEx, и я не ожидал, что он вызовет какие-либо проблемы.

Следующий класс позволяет подписать исполняемый файл с .pfx по телефону:

SignWithCert(string appPath, string certPath, string certPassword, string timestampUrl); 

Это также позволяет подписать исполняемый файл с сертификатом из хранилища ключей по телефону:

SignWithThumbPrint(string appPath, string thumbprint, string timestampUrl); 

Если вы хотите подписаться с помощью сертификата, установленного в хранилище ключей, вам может потребоваться обновить FindCertByThumbPrint (string thumbPrint), чтобы проверить больше хранилищ ключей, чем я хочу проверить. 99,5% времени, наши клиенты подписываются с .pfx, а не с отпечатком пальца.

Для иллюстрации SignWithCert() использует SignerSignEx и SignerTimeStampEx, а SignWithThumbPrint() использует SignerSign и SignerTimeStamp.

Их легко заменить.SignerSignEx и SignerTimeStampEx возвращают указатель SIGNER_CONTEXT и позволяют изменять поведение функций с помощью аргумента dwFlags (если вы подписываете переносимый исполняемый файл). Параметры действительного флага указаны в here. В принципе, если вы передадите 0x0 в качестве dwFlags в SignerSignEx, вывод будет идентичным только с использованием SignerSign. В моем случае, я полагаю, я буду использовать SignerSign, потому что я не верю, что мне нужен указатель на контекст подписывающего лица по любой мыслимой причине.

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

Код работает, как ожидалось, и исполняемый файл работает нормально и подписан, НО двоичный вывод блока подписи немного отличается от двоичного вывода файла signtool.exe (в этом тесте временная метка не использовалась ни одним инструментом). Я объясняю это тем фактом, что signtool.exe, по-видимому, использует CAPICOM для подписи, и это использует Mssign32.dll, но в целом я очень доволен этим в начальном наборе тестов.

Очевидно, что обработка ошибок требует улучшения.

Благодаря GregS и всем, кто ранее разместил образцы кода.

Вот что вам нужно. Я обновлю этот блок комментариями и улучшениями, когда у меня появится такая возможность.

Обновление 1: Добавлена ​​несколько улучшенная обработка ошибок и комментарии, а также некоторые переформатирования отпечатка пальца в FindCertByThumbprint (строчный отпечаток), чтобы можно было найти сертификат в Windows 8 и Windows 10 (общедоступный просмотр). Эти ОС не вернут совпадение, когда в отпечатке остались пробелы, поэтому теперь я исправляю их перед поиском.

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

namespace Utilities 
{ 
    internal static class SignTool 
    { 
     #region Structures 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_SUBJECT_INFO 
     { 
      public uint cbSize; 
      public IntPtr pdwIndex; 
      public uint dwSubjectChoice; 
      public SubjectChoiceUnion Union1; 
      [StructLayoutAttribute(LayoutKind.Explicit)] 
      internal struct SubjectChoiceUnion 
      { 
       [FieldOffsetAttribute(0)] 
       public System.IntPtr pSignerFileInfo; 
       [FieldOffsetAttribute(0)] 
       public System.IntPtr pSignerBlobInfo; 
      }; 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_CERT 
     { 
      public uint cbSize; 
      public uint dwCertChoice; 
      public SignerCertUnion Union1; 
      [StructLayoutAttribute(LayoutKind.Explicit)] 
      internal struct SignerCertUnion 
      { 
       [FieldOffsetAttribute(0)] 
       public IntPtr pwszSpcFile; 
       [FieldOffsetAttribute(0)] 
       public IntPtr pCertStoreInfo; 
       [FieldOffsetAttribute(0)] 
       public IntPtr pSpcChainInfo; 
      }; 
      public IntPtr hwnd; 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_SIGNATURE_INFO 
     { 
      public uint cbSize; 
      public uint algidHash; // ALG_ID 
      public uint dwAttrChoice; 
      public IntPtr pAttrAuthCode; 
      public IntPtr psAuthenticated; // PCRYPT_ATTRIBUTES 
      public IntPtr psUnauthenticated; // PCRYPT_ATTRIBUTES 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_FILE_INFO 
     { 
      public uint cbSize; 
      public IntPtr pwszFileName; 
      public IntPtr hFile; 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_CERT_STORE_INFO 
     { 
      public uint cbSize; 
      public IntPtr pSigningCert; // CERT_CONTEXT 
      public uint dwCertPolicy; 
      public IntPtr hCertStore; 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_CONTEXT 
     { 
      public uint cbSize; 
      public uint cbBlob; 
      public IntPtr pbBlob; 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SIGNER_PROVIDER_INFO 
     { 
      public uint cbSize; 
      public IntPtr pwszProviderName; 
      public uint dwProviderType; 
      public uint dwKeySpec; 
      public uint dwPvkChoice; 
      public SignerProviderUnion Union1; 
      [StructLayoutAttribute(LayoutKind.Explicit)] 
      internal struct SignerProviderUnion 
      { 
       [FieldOffsetAttribute(0)] 
       public IntPtr pwszPvkFileName; 
       [FieldOffsetAttribute(0)] 
       public IntPtr pwszKeyContainer; 
      }; 
     } 

     #endregion 

     #region Imports 

     [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     private static extern int SignerSign(
      IntPtr pSubjectInfo,  // SIGNER_SUBJECT_INFO 
      IntPtr pSignerCert,   // SIGNER_CERT 
      IntPtr pSignatureInfo,  // SIGNER_SIGNATURE_INFO 
      IntPtr pProviderInfo,  // SIGNER_PROVIDER_INFO 
      string pwszHttpTimeStamp, // LPCWSTR 
      IntPtr psRequest,   // PCRYPT_ATTRIBUTES 
      IntPtr pSipData    // LPVOID 
      ); 

     [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     private static extern int SignerSignEx(
      uint dwFlags,    // DWORD 
      IntPtr pSubjectInfo,  // SIGNER_SUBJECT_INFO 
      IntPtr pSignerCert,   // SIGNER_CERT 
      IntPtr pSignatureInfo,  // SIGNER_SIGNATURE_INFO 
      IntPtr pProviderInfo,  // SIGNER_PROVIDER_INFO 
      string pwszHttpTimeStamp, // LPCWSTR 
      IntPtr psRequest,   // PCRYPT_ATTRIBUTES 
      IntPtr pSipData,   // LPVOID 
      out SIGNER_CONTEXT ppSignerContext // SIGNER_CONTEXT 
      ); 

     [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     private static extern int SignerTimeStamp(
      IntPtr pSubjectInfo,  // SIGNER_SUBJECT_INFO 
      string pwszHttpTimeStamp, // LPCWSTR 
      IntPtr psRequest,   // PCRYPT_ATTRIBUTES 
      IntPtr pSipData    // LPVOID 
      ); 

     [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     private static extern int SignerTimeStampEx(
      uint dwFlags,    // DWORD 
      IntPtr pSubjectInfo,  // SIGNER_SUBJECT_INFO 
      string pwszHttpTimeStamp, // LPCWSTR 
      IntPtr psRequest,   // PCRYPT_ATTRIBUTES 
      IntPtr pSipData,   // LPVOID 
      out SIGNER_CONTEXT ppSignerContext // SIGNER_CONTEXT 
      ); 

     [DllImport("Crypt32.dll", EntryPoint = "CertCreateCertificateContext", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] 
     private static extern IntPtr CertCreateCertificateContext(
      int dwCertEncodingType, 
      byte[] pbCertEncoded, 
      int cbCertEncoded); 

     #endregion 

     #region public methods 

     // Call SignerSignEx and SignerTimeStampEx for a given .pfx 
     public static void SignWithCert(string appPath, string certPath, string certPassword, string timestampUrl) 
     { 
      IntPtr pSignerCert = IntPtr.Zero; 
      IntPtr pSubjectInfo = IntPtr.Zero; 
      IntPtr pSignatureInfo = IntPtr.Zero; 
      IntPtr pProviderInfo = IntPtr.Zero; 

      try 
      { 
       // Grab the X509Certificate from the .pfx file. 
       X509Certificate2 cert = new X509Certificate2(certPath, certPassword); 

       pSignerCert = CreateSignerCert(cert); 
       pSubjectInfo = CreateSignerSubjectInfo(appPath); 
       pSignatureInfo = CreateSignerSignatureInfo(); 
       pProviderInfo = GetProviderInfo(cert); 

       SIGNER_CONTEXT signerContext; 

       SignCode(0x0, pSubjectInfo, pSignerCert, pSignatureInfo, pProviderInfo, out signerContext); 

       // Only attempt to timestamp if we've got a timestampUrl. 
       if (!string.IsNullOrEmpty(timestampUrl)) 
       { 
        TimeStampSignedCode(0x0, pSubjectInfo, timestampUrl, out signerContext); 
       } 
      } 
      catch (CryptographicException ce) 
      { 
       string exception; 

       // do anything with this useful information? 
       switch (Marshal.GetHRForException(ce)) 
       { 
        case -2146885623: 
         exception = string.Format(@"An error occurred while attempting to load the signing certificate. ""{0}"" does not appear to contain a valid certificate.", certPath); 
         break; 
        case -2147024810: 
         exception = string.Format(@"An error occurred while attempting to load the signing certificate. The specified password was incorrect."); 
         break; 
        default: 
         exception = string.Format(@"An error occurred while attempting to load the signing certificate. {0}", ce.Message); 
         break; 
       } 
      } 
      catch (Exception e) 
      { 
       // do anything with this useful information? 
       string exception = e.Message; 
      } 
      finally 
      { 
       if (pSignerCert != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSignerCert, typeof(SIGNER_CERT)); 
       } 
       if (pSubjectInfo != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO)); 
       } 
       if (pSignatureInfo != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSignatureInfo, typeof(SIGNER_SIGNATURE_INFO)); 
       } 
       if (pProviderInfo != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSignatureInfo, typeof(SIGNER_PROVIDER_INFO)); 
       } 
      } 
     } 

     // Call SignerSign and SignerTimeStamp for a given thumbprint. 
     public static void SignWithThumbprint(string appPath, string thumbprint, string timestampUrl) 
     { 
      IntPtr pSignerCert = IntPtr.Zero; 
      IntPtr pSubjectInfo = IntPtr.Zero; 
      IntPtr pSignatureInfo = IntPtr.Zero; 
      IntPtr pProviderInfo = IntPtr.Zero; 

      try 
      { 
       pSignerCert = CreateSignerCert(thumbprint); 
       pSubjectInfo = CreateSignerSubjectInfo(appPath); 
       pSignatureInfo = CreateSignerSignatureInfo(); 

       SignCode(pSubjectInfo, pSignerCert, pSignatureInfo, pProviderInfo); 

       // Only attempt to timestamp if we've got a timestampUrl. 
       if (!string.IsNullOrEmpty(timestampUrl)) 
       { 
        TimeStampSignedCode(pSubjectInfo, timestampUrl); 
       } 
      } 
      catch (CryptographicException ce) 
      { 
       // do anything with this useful information? 
       string exception = string.Format(@"An error occurred while attempting to load the signing certificate. {0}", ce.Message); 
      } 
      catch (Exception e) 
      { 
       // do anything with this useful information? 
       string exception = e.Message; 
      } 
      finally 
      { 
       if (pSignerCert != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSignerCert, typeof(SIGNER_CERT)); 
       } 
       if (pSubjectInfo != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO)); 
       } 
       if (pSignatureInfo != IntPtr.Zero) 
       { 
        Marshal.DestroyStructure(pSignatureInfo, typeof(SIGNER_SIGNATURE_INFO)); 
       } 
      } 
     } 

     #endregion 

     #region private methods 

     private static IntPtr CreateSignerSubjectInfo(string pathToAssembly) 
     { 
      SIGNER_SUBJECT_INFO info = new SIGNER_SUBJECT_INFO 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)), 
       pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint))) 
      }; 
      var index = 0; 
      Marshal.StructureToPtr(index, info.pdwIndex, false); 

      info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE 
      IntPtr assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly); 

      SIGNER_FILE_INFO fileInfo = new SIGNER_FILE_INFO 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)), 
       pwszFileName = assemblyFilePtr, 
       hFile = IntPtr.Zero 
      }; 

      info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion 
      { 
       pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO))) 
      }; 

      Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false); 

      IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info)); 
      Marshal.StructureToPtr(info, pSubjectInfo, false); 

      return pSubjectInfo; 
     } 

     private static X509Certificate2 FindCertByThumbprint(string thumbprint) 
     { 
      try 
      { 
       // Remove spaces convert to upper. Windows 10 (preview) and Windows 8 will not return a cert 
       // unless it is a perfect match with no spaces and all uppercase characters. 
       string thumbprintFixed = thumbprint.Replace(" ", string.Empty).ToUpperInvariant(); 

       // Check common store locations for the corresponding code-signing cert. 
       X509Store[] stores = new X509Store[4] { new X509Store(StoreName.My, StoreLocation.CurrentUser), 
                 new X509Store(StoreName.My, StoreLocation.LocalMachine), 
                 new X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser), 
                 new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine) }; 

       foreach (X509Store store in stores) 
       { 
        store.Open(OpenFlags.ReadOnly); 

        // Find the cert! 
        X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprintFixed, false); 

        store.Close(); 

        // If we didn't find the cert, try the next store. 
        if (certs.Count < 1) 
        { 
         continue; 
        } 

        // Return the cert (first one if there is more than one identical cert in the collection). 
        return certs[0]; 
       } 

       // No cert was found. Return null. 
       throw new Exception(string.Format(@"A certificate matching the thumbprint: ""{0}"" could not be found. Make sure that a valid certificate matching the provided thumbprint is installed.", thumbprint)); 
      } 
      catch (Exception e) 
      { 
       throw new Exception(string.Format("{0}", e.Message)); 
      } 
     } 

     private static IntPtr CreateSignerCert(X509Certificate2 cert) 
     { 
      SIGNER_CERT signerCert = new SIGNER_CERT 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_CERT)), 
       dwCertChoice = 0x2, 
       Union1 = new SIGNER_CERT.SignerCertUnion 
       { 
        pCertStoreInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_CERT_STORE_INFO))) 
       }, 
       hwnd = IntPtr.Zero 
      }; 

      const int X509_ASN_ENCODING = 0x00000001; 
      const int PKCS_7_ASN_ENCODING = 0x00010000; 

      IntPtr pCertContext = CertCreateCertificateContext(
       X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
       cert.GetRawCertData(), 
       cert.GetRawCertData().Length); 

      SIGNER_CERT_STORE_INFO certStoreInfo = new SIGNER_CERT_STORE_INFO 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_CERT_STORE_INFO)), 
       pSigningCert = pCertContext, 
       dwCertPolicy = 0x2, // SIGNER_CERT_POLICY_CHAIN 
       hCertStore = IntPtr.Zero 
      }; 

      Marshal.StructureToPtr(certStoreInfo, signerCert.Union1.pCertStoreInfo, false); 

      IntPtr pSignerCert = Marshal.AllocHGlobal(Marshal.SizeOf(signerCert)); 
      Marshal.StructureToPtr(signerCert, pSignerCert, false); 

      return pSignerCert; 
     } 

     private static IntPtr CreateSignerCert(string thumbprint) 
     { 
      SIGNER_CERT signerCert = new SIGNER_CERT 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_CERT)), 
       dwCertChoice = 0x2, 
       Union1 = new SIGNER_CERT.SignerCertUnion 
       { 
        pCertStoreInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_CERT_STORE_INFO))) 
       }, 
       hwnd = IntPtr.Zero 
      }; 

      const int X509_ASN_ENCODING = 0x00000001; 
      const int PKCS_7_ASN_ENCODING = 0x00010000; 

      X509Certificate2 cert = FindCertByThumbprint(thumbprint); 

      IntPtr pCertContext = CertCreateCertificateContext(
       X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
       cert.GetRawCertData(), 
       cert.GetRawCertData().Length); 

      SIGNER_CERT_STORE_INFO certStoreInfo = new SIGNER_CERT_STORE_INFO 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_CERT_STORE_INFO)), 
       pSigningCert = pCertContext, 
       dwCertPolicy = 0x2, // SIGNER_CERT_POLICY_CHAIN 
       hCertStore = IntPtr.Zero 
      }; 

      Marshal.StructureToPtr(certStoreInfo, signerCert.Union1.pCertStoreInfo, false); 

      IntPtr pSignerCert = Marshal.AllocHGlobal(Marshal.SizeOf(signerCert)); 
      Marshal.StructureToPtr(signerCert, pSignerCert, false); 

      return pSignerCert; 
     } 

     private static IntPtr CreateSignerSignatureInfo() 
     { 
      SIGNER_SIGNATURE_INFO signatureInfo = new SIGNER_SIGNATURE_INFO 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SIGNATURE_INFO)), 
       algidHash = 0x00008004, // CALG_SHA1 
       dwAttrChoice = 0x0, // SIGNER_NO_ATTR 
       pAttrAuthCode = IntPtr.Zero, 
       psAuthenticated = IntPtr.Zero, 
       psUnauthenticated = IntPtr.Zero 
      }; 

      IntPtr pSignatureInfo = Marshal.AllocHGlobal(Marshal.SizeOf(signatureInfo)); 
      Marshal.StructureToPtr(signatureInfo, pSignatureInfo, false); 

      return pSignatureInfo; 
     } 

     private static IntPtr GetProviderInfo(X509Certificate2 cert) 
     { 
      if (cert == null || !cert.HasPrivateKey) 
      { 
       return IntPtr.Zero; 
      } 

      ICspAsymmetricAlgorithm key = (ICspAsymmetricAlgorithm)cert.PrivateKey; 
      const int PVK_TYPE_KEYCONTAINER = 2; 

      if (key == null) 
      { 
       return IntPtr.Zero; 
      } 

      SIGNER_PROVIDER_INFO providerInfo = new SIGNER_PROVIDER_INFO 
      { 
       cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_PROVIDER_INFO)), 
       pwszProviderName = Marshal.StringToHGlobalUni(key.CspKeyContainerInfo.ProviderName), 
       dwProviderType = (uint)key.CspKeyContainerInfo.ProviderType, 
       dwPvkChoice = PVK_TYPE_KEYCONTAINER, 
       Union1 = new SIGNER_PROVIDER_INFO.SignerProviderUnion 
       { 
        pwszKeyContainer = Marshal.StringToHGlobalUni(key.CspKeyContainerInfo.KeyContainerName) 
       }, 
      }; 

      IntPtr pProviderInfo = Marshal.AllocHGlobal(Marshal.SizeOf(providerInfo)); 
      Marshal.StructureToPtr(providerInfo, pProviderInfo, false); 

      return pProviderInfo; 
     } 

     // Use SignerSign 
     private static void SignCode(IntPtr pSubjectInfo, IntPtr pSignerCert, IntPtr pSignatureInfo, IntPtr pProviderInfo) 
     { 
      int hResult = SignerSign(
       pSubjectInfo, 
       pSignerCert, 
       pSignatureInfo, 
       pProviderInfo, 
       null, 
       IntPtr.Zero, 
       IntPtr.Zero 
       ); 

      if (hResult != 0) 
      { 
       // See if we can get anything useful. Jury's still out on this one. 
       Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
      } 
     } 

     // Use SignerSignEx 
     private static void SignCode(uint dwFlags, IntPtr pSubjectInfo, IntPtr pSignerCert, IntPtr pSignatureInfo, IntPtr pProviderInfo, out SIGNER_CONTEXT signerContext) 
     { 

      int hResult = SignerSignEx(
       dwFlags, 
       pSubjectInfo, 
       pSignerCert, 
       pSignatureInfo, 
       pProviderInfo, 
       null, 
       IntPtr.Zero, 
       IntPtr.Zero, 
       out signerContext 
       ); 

      if (hResult != 0) 
      { 
       // See if we can get anything useful. Jury's still out on this one. 
       Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
      } 
     } 

     // Use SignerTimeStamp 
     private static void TimeStampSignedCode(IntPtr pSubjectInfo, string timestampUrl) 
     { 
      int hResult = SignerTimeStamp(
       pSubjectInfo, 
       timestampUrl, 
       IntPtr.Zero, 
       IntPtr.Zero 
       ); 

      if (hResult != 0) 
      { 
       // We can't get anything useful from GetHRForLastWin32Error, so let's throw our own. 
       //Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
       throw new Exception(string.Format(@"""{0}"" could not be used at this time. If necessary, check the timestampUrl, internet connection, and try again.", timestampUrl)); 
      } 
     } 

     // Use SignerTimeStampEx 
     private static void TimeStampSignedCode(uint dwFlags, IntPtr pSubjectInfo, string timestampUrl, out SIGNER_CONTEXT signerContext) 
     { 
      int hResult = SignerTimeStampEx(
       dwFlags, 
       pSubjectInfo, 
       timestampUrl, 
       IntPtr.Zero, 
       IntPtr.Zero, 
       out signerContext 
       ); 

      if (hResult != 0) 
      { 
       // We can't get anything useful from GetHRForLastWin32Error, so let's throw our own. 
       //Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
       throw new Exception(string.Format(@"""{0}"" could not be used at this time. If necessary, check the timestampUrl, internet connection, and try again.", timestampUrl)); 
      } 
     } 

     #endregion 

    } 
} 
+0

Впечатляет. Красиво сделано! –

+0

Что делать, если мне нужно подписать исполняемый файл, который уже находится в памяти. Скажем, я загрузил его с помощью 'byte [] executable = File.ReadAllBytes (filename)'. Я должен использовать структуру SIGNER_BLOB_INFO, верно? Если так, мне нужен GUID для SIP, который я не знаю? Означает ли это, что мне нужен GUID, который скажет, что «этот blob, который у меня есть, является исполняемым»? – clzola

+0

Я не могу подписать файл, отличный от исполняемого файла с этим кодом. Не могли бы вы сообщить мне, есть ли другой способ подписать другие исполняемые файлы, кроме исполняемых файлов? –