2010-07-19 90 views
17

我们需要验证二进制文件是否使用数字签名(Authenticode)正确签名。这可以很容易地用signtool.exe来实现。但是,我们需要一种自动方式来验证签名者名称和时间戳。这是可行的本地C++与CryptQueryObject() API,如以下精彩示例所示:How To Get Information from Authenticode Signed Executables从Authenticode中获取时间戳.NET中的签名文件

但是,我们生活在托管世界:)因此寻找C#解决方案来解决同样的问题。直接的方法是pInvoke Crypt32.dll,一切都完成了。但System.Security.Cryptography.X509Certificates命名空间中有类似的托管API。 X509Certificate2类似乎提供了一些信息,但没有时间戳。现在我们回到原来的问题,我们如何才能在C夏普获得数字签名的时间戳?

+3

托管的authenticode类会使* lot *出来!只是p/Invoke可能更容易。 – 2010-07-19 12:51:37

+1

第一个原因是托管代码看起来更好。其次,在几个MSDN文章中有像这样的令人恐惧的注释注意WinVerifyTrust函数可用于需求部分列出的操作系统。它可能会在后续版本中被更改或不可用。 Windows Vista是最新支持的系统。当然,WinVerifyTrust和CryptQueryObject在Windows 7上工作,但所有这些警告似乎使用一些其他的API。看来证书名称空间确实是不完整的。有趣,但这个警告是不是现在在线MSDN现在... – SlavaGu 2010-07-19 13:26:57

回答

1

因为我看到你没有答复,所以让我提供一个。

如果您不介意使用第三方组件,请查看我们的SecureBlackbox产品的TElAuthenticodeVerifier组件。使用此组件,您可以验证签名并检查时间戳。

+0

该班看起来不错,谢谢。 VerifySignature是否检查CRL在线的证书有效性?顺便说一句,我已经通过pinvoking CryptQueryObject来实现时间戳检查,所以我只是在问我的好奇心。 – SlavaGu 2010-08-28 07:06:12

+0

嗨SlavaGu,你可以与我分享你的解决方案吗?或者可能会提供一些想法,我该怎么做。我也有类似的问题。谢谢。 – Akie 2010-09-24 10:02:37

11

回到原来的问题,我找不到的方式进行管理,从而结束了使用的PInvoke如下:

public static bool IsTimestamped(string filename) 
{ 
    try 
    { 
     int encodingType; 
     int contentType; 
     int formatType; 
     IntPtr certStore = IntPtr.Zero; 
     IntPtr cryptMsg = IntPtr.Zero; 
     IntPtr context = IntPtr.Zero; 

     if (!WinCrypt.CryptQueryObject(
      WinCrypt.CERT_QUERY_OBJECT_FILE, 
      Marshal.StringToHGlobalUni(filename), 
      WinCrypt.CERT_QUERY_CONTENT_FLAG_ALL, 
      WinCrypt.CERT_QUERY_FORMAT_FLAG_ALL, 
      0, 
      out encodingType, 
      out contentType, 
      out formatType, 
      ref certStore, 
      ref cryptMsg, 
      ref context)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     //expecting contentType=10; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED 
     //Logger.LogInfo(string.Format("Querying file '{0}':", filename)); 
     //Logger.LogInfo(string.Format(" Encoding Type: {0}", encodingType)); 
     //Logger.LogInfo(string.Format(" Content Type: {0}", contentType)); 
     //Logger.LogInfo(string.Format(" Format Type: {0}", formatType)); 
     //Logger.LogInfo(string.Format(" Cert Store: {0}", certStore.ToInt32())); 
     //Logger.LogInfo(string.Format(" Crypt Msg: {0}", cryptMsg.ToInt32())); 
     //Logger.LogInfo(string.Format(" Context: {0}", context.ToInt32())); 


     // Get size of the encoded message. 
     int cbData = 0; 
     if (!WinCrypt.CryptMsgGetParam(
      cryptMsg, 
      WinCrypt.CMSG_ENCODED_MESSAGE,//Crypt32.CMSG_SIGNER_INFO_PARAM, 
      0, 
      IntPtr.Zero, 
      ref cbData)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     var vData = new byte[cbData]; 

     // Get the encoded message. 
     if (!WinCrypt.CryptMsgGetParam(
      cryptMsg, 
      WinCrypt.CMSG_ENCODED_MESSAGE,//Crypt32.CMSG_SIGNER_INFO_PARAM, 
      0, 
      vData, 
      ref cbData)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     var signedCms = new SignedCms(); 
     signedCms.Decode(vData); 

     foreach (var signerInfo in signedCms.SignerInfos) 
     { 
      foreach (var unsignedAttribute in signerInfo.UnsignedAttributes) 
      { 
       if (unsignedAttribute.Oid.Value == WinCrypt.szOID_RSA_counterSign) 
       { 
        //Note at this point we assume this counter signature is the timestamp 
        //refer to http://support.microsoft.com/kb/323809 for the origins 

        //TODO: extract timestamp value, if required 
        return true; 
       } 

      } 
     } 
    } 
    catch (Exception) 
    { 
     // no logging 
    } 

    return false; 
} 

和WinCrypt.cs包含以下内容:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace MyNamespace.Win32 
{ 
    static class WinCrypt 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     public struct BLOB 
     { 
      public int cbData; 
      public IntPtr pbData; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CRYPT_ALGORITHM_IDENTIFIER 
     { 
      public String pszObjId; 
      BLOB Parameters; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CERT_ID 
     { 
      public int dwIdChoice; 
      public BLOB IssuerSerialNumberOrKeyIdOrHashId; 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     public struct SIGNER_SUBJECT_INFO 
     { 
      /// DWORD->unsigned int 
      public uint cbSize; 

      /// DWORD* 
      public System.IntPtr pdwIndex; 

      /// DWORD->unsigned int 
      public uint dwSubjectChoice; 

      /// SubjectChoiceUnion 
      public SubjectChoiceUnion Union1; 
     } 

     [StructLayoutAttribute(LayoutKind.Explicit)] 
     public struct SubjectChoiceUnion 
     { 

      /// SIGNER_FILE_INFO* 
      [FieldOffsetAttribute(0)] 
      public System.IntPtr pSignerFileInfo; 

      /// SIGNER_BLOB_INFO* 
      [FieldOffsetAttribute(0)] 
      public System.IntPtr pSignerBlobInfo; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CERT_NAME_BLOB 
     { 
      public uint cbData; 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] 
      public byte[] pbData; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CRYPT_INTEGER_BLOB 
     { 
      public UInt32 cbData; 
      public IntPtr pbData; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CRYPT_ATTR_BLOB 
     { 
      public uint cbData; 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] 
      public byte[] pbData; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CRYPT_ATTRIBUTE 
     { 
      [MarshalAs(UnmanagedType.LPStr)] 
      public string pszObjId; 
      public uint cValue; 
      [MarshalAs(UnmanagedType.LPStruct)] 
      public CRYPT_ATTR_BLOB rgValue; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct CMSG_SIGNER_INFO 
     { 
      public int dwVersion; 
      private CERT_NAME_BLOB Issuer; 
      CRYPT_INTEGER_BLOB SerialNumber; 
      CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; 
      CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; 
      BLOB EncryptedHash; 
      CRYPT_ATTRIBUTE[] AuthAttrs; 
      CRYPT_ATTRIBUTE[] UnauthAttrs; 
     } 

     [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern Boolean CryptQueryObject(
      int dwObjectType, 
      IntPtr pvObject, 
      int dwExpectedContentTypeFlags, 
      int dwExpectedFormatTypeFlags, 
      int dwFlags, 
      out int pdwMsgAndCertEncodingType, 
      out int pdwContentType, 
      out int pdwFormatType, 
      ref IntPtr phCertStore, 
      ref IntPtr phMsg, 
      ref IntPtr ppvContext); 


     [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern Boolean CryptMsgGetParam(
      IntPtr hCryptMsg, 
      int dwParamType, 
      int dwIndex, 
      IntPtr pvData, 
      ref int pcbData 
     ); 

     [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern Boolean CryptMsgGetParam(
      IntPtr hCryptMsg, 
      int dwParamType, 
      int dwIndex, 
      [In, Out] byte[] vData, 
      ref int pcbData 
     ); 

     [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool CryptDecodeObject(
      uint CertEncodingType, 
      UIntPtr lpszStructType, 
      byte[] pbEncoded, 
      uint cbEncoded, 
      uint flags, 
      [In, Out] byte[] pvStructInfo, 
      ref uint cbStructInfo); 


     public const int CRYPT_ASN_ENCODING = 0x00000001; 
     public const int CRYPT_NDR_ENCODING = 0x00000002; 
     public const int X509_ASN_ENCODING = 0x00000001; 
     public const int X509_NDR_ENCODING = 0x00000002; 
     public const int PKCS_7_ASN_ENCODING = 0x00010000; 
     public const int PKCS_7_NDR_ENCODING = 0x00020000; 

     public static UIntPtr PKCS7_SIGNER_INFO = new UIntPtr(500); 
     public static UIntPtr CMS_SIGNER_INFO = new UIntPtr(501); 

     public static string szOID_RSA_signingTime = "1.2.840.113549.1.9.5"; 
     public static string szOID_RSA_counterSign = "1.2.840.113549.1.9.6"; 

     //+------------------------------------------------------------------------- 
     // Get parameter types and their corresponding data structure definitions. 
     //-------------------------------------------------------------------------- 
     public const int CMSG_TYPE_PARAM = 1; 
     public const int CMSG_CONTENT_PARAM = 2; 
     public const int CMSG_BARE_CONTENT_PARAM = 3; 
     public const int CMSG_INNER_CONTENT_TYPE_PARAM = 4; 
     public const int CMSG_SIGNER_COUNT_PARAM = 5; 
     public const int CMSG_SIGNER_INFO_PARAM = 6; 
     public const int CMSG_SIGNER_CERT_INFO_PARAM = 7; 
     public const int CMSG_SIGNER_HASH_ALGORITHM_PARAM = 8; 
     public const int CMSG_SIGNER_AUTH_ATTR_PARAM = 9; 
     public const int CMSG_SIGNER_UNAUTH_ATTR_PARAM = 10; 
     public const int CMSG_CERT_COUNT_PARAM = 11; 
     public const int CMSG_CERT_PARAM = 12; 
     public const int CMSG_CRL_COUNT_PARAM = 13; 
     public const int CMSG_CRL_PARAM = 14; 
     public const int CMSG_ENVELOPE_ALGORITHM_PARAM = 15; 
     public const int CMSG_RECIPIENT_COUNT_PARAM = 17; 
     public const int CMSG_RECIPIENT_INDEX_PARAM = 18; 
     public const int CMSG_RECIPIENT_INFO_PARAM = 19; 
     public const int CMSG_HASH_ALGORITHM_PARAM = 20; 
     public const int CMSG_HASH_DATA_PARAM = 21; 
     public const int CMSG_COMPUTED_HASH_PARAM = 22; 
     public const int CMSG_ENCRYPT_PARAM = 26; 
     public const int CMSG_ENCRYPTED_DIGEST = 27; 
     public const int CMSG_ENCODED_SIGNER = 28; 
     public const int CMSG_ENCODED_MESSAGE = 29; 
     public const int CMSG_VERSION_PARAM = 30; 
     public const int CMSG_ATTR_CERT_COUNT_PARAM = 31; 
     public const int CMSG_ATTR_CERT_PARAM = 32; 
     public const int CMSG_CMS_RECIPIENT_COUNT_PARAM = 33; 
     public const int CMSG_CMS_RECIPIENT_INDEX_PARAM = 34; 
     public const int CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM = 35; 
     public const int CMSG_CMS_RECIPIENT_INFO_PARAM = 36; 
     public const int CMSG_UNPROTECTED_ATTR_PARAM = 37; 
     public const int CMSG_SIGNER_CERT_ID_PARAM = 38; 
     public const int CMSG_CMS_SIGNER_INFO_PARAM = 39; 


     //------------------------------------------------------------------------- 
     //dwObjectType for CryptQueryObject 
     //------------------------------------------------------------------------- 
     public const int CERT_QUERY_OBJECT_FILE = 0x00000001; 
     public const int CERT_QUERY_OBJECT_BLOB = 0x00000002; 

     //------------------------------------------------------------------------- 
     //dwContentType for CryptQueryObject 
     //------------------------------------------------------------------------- 
     //encoded single certificate 
     public const int CERT_QUERY_CONTENT_CERT = 1; 
     //encoded single CTL 
     public const int CERT_QUERY_CONTENT_CTL = 2; 
     //encoded single CRL 
     public const int CERT_QUERY_CONTENT_CRL = 3; 
     //serialized store 
     public const int CERT_QUERY_CONTENT_SERIALIZED_STORE = 4; 
     //serialized single certificate 
     public const int CERT_QUERY_CONTENT_SERIALIZED_CERT = 5; 
     //serialized single CTL 
     public const int CERT_QUERY_CONTENT_SERIALIZED_CTL = 6; 
     //serialized single CRL 
     public const int CERT_QUERY_CONTENT_SERIALIZED_CRL = 7; 
     //a PKCS#7 signed message 
     public const int CERT_QUERY_CONTENT_PKCS7_SIGNED = 8; 
     //a PKCS#7 message, such as enveloped message. But it is not a signed message, 
     public const int CERT_QUERY_CONTENT_PKCS7_UNSIGNED = 9; 
     //a PKCS7 signed message embedded in a file 
     public const int CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10; 
     //an encoded PKCS#10 
     public const int CERT_QUERY_CONTENT_PKCS10 = 11; 
     //an encoded PKX BLOB 
     public const int CERT_QUERY_CONTENT_PFX = 12; 
     //an encoded CertificatePair (contains forward and/or reverse cross certs) 
     public const int CERT_QUERY_CONTENT_CERT_PAIR = 13; 

     //------------------------------------------------------------------------- 
     //dwExpectedConentTypeFlags for CryptQueryObject 
     //------------------------------------------------------------------------- 
     //encoded single certificate 
     public const int CERT_QUERY_CONTENT_FLAG_CERT = (1 << CERT_QUERY_CONTENT_CERT); 

     //encoded single CTL 
     public const int CERT_QUERY_CONTENT_FLAG_CTL = (1 << CERT_QUERY_CONTENT_CTL); 

     //encoded single CRL 
     public const int CERT_QUERY_CONTENT_FLAG_CRL = (1 << CERT_QUERY_CONTENT_CRL); 

     //serialized store 
     public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE = (1 << CERT_QUERY_CONTENT_SERIALIZED_STORE); 

     //serialized single certificate 
     public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT = (1 << CERT_QUERY_CONTENT_SERIALIZED_CERT); 

     //serialized single CTL 
     public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL = (1 << CERT_QUERY_CONTENT_SERIALIZED_CTL); 

     //serialized single CRL 
     public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL = (1 << CERT_QUERY_CONTENT_SERIALIZED_CRL); 

     //an encoded PKCS#7 signed message 
     public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED = (1 << CERT_QUERY_CONTENT_PKCS7_SIGNED); 

     //an encoded PKCS#7 message. But it is not a signed message 
     public const int CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED = (1 << CERT_QUERY_CONTENT_PKCS7_UNSIGNED); 

     //the content includes an embedded PKCS7 signed message 
     public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = (1 << CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED); 

     //an encoded PKCS#10 
     public const int CERT_QUERY_CONTENT_FLAG_PKCS10 = (1 << CERT_QUERY_CONTENT_PKCS10); 

     //an encoded PFX BLOB 
     public const int CERT_QUERY_CONTENT_FLAG_PFX = (1 << CERT_QUERY_CONTENT_PFX); 

     //an encoded CertificatePair (contains forward and/or reverse cross certs) 
     public const int CERT_QUERY_CONTENT_FLAG_CERT_PAIR = (1 << CERT_QUERY_CONTENT_CERT_PAIR); 

     //content can be any type 
     public const int CERT_QUERY_CONTENT_FLAG_ALL = 
      CERT_QUERY_CONTENT_FLAG_CERT | 
      CERT_QUERY_CONTENT_FLAG_CTL | 
      CERT_QUERY_CONTENT_FLAG_CRL | 
      CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | 
      CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT | 
      CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL | 
      CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL | 
      CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | 
      CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED | 
      CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | 
      CERT_QUERY_CONTENT_FLAG_PKCS10 | 
      CERT_QUERY_CONTENT_FLAG_PFX | 
      CERT_QUERY_CONTENT_FLAG_CERT_PAIR; 

     //------------------------------------------------------------------------- 
     //dwFormatType for CryptQueryObject 
     //------------------------------------------------------------------------- 
     //the content is in binary format 
     public const int CERT_QUERY_FORMAT_BINARY = 1; 

     //the content is base64 encoded 
     public const int CERT_QUERY_FORMAT_BASE64_ENCODED = 2; 

     //the content is ascii hex encoded with "{ASN}" prefix 
     public const int CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3; 

     //------------------------------------------------------------------------- 
     //dwExpectedFormatTypeFlags for CryptQueryObject 
     //------------------------------------------------------------------------- 
     //the content is in binary format 
     public const int CERT_QUERY_FORMAT_FLAG_BINARY = (1 << CERT_QUERY_FORMAT_BINARY); 

     //the content is base64 encoded 
     public const int CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = (1 << CERT_QUERY_FORMAT_BASE64_ENCODED); 

     //the content is ascii hex encoded with "{ASN}" prefix 
     public const int CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = (1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED); 

     //the content can be of any format 
     public const int CERT_QUERY_FORMAT_FLAG_ALL = 
      CERT_QUERY_FORMAT_FLAG_BINARY | 
      CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | 
      CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED; 

    } 
} 
3

得益于OP为您的工作。我添加了实现来获取证书的实际时间戳。

foreach (var signerInfo in signedCms.SignerInfos) 
      { 
       foreach (var unsignedAttribute in signerInfo.UnsignedAttributes) 
       { 
        if (unsignedAttribute.Oid.Value == WinCrypt.szOID_RSA_counterSign) 
        { 
         foreach (var counterSignInfo in signerInfo.CounterSignerInfos) 
         { 
          foreach (var signedAttribute in counterSignInfo.SignedAttributes) 
          { 
           if (signedAttribute.Oid.Value == WinCrypt.szOID_RSA_signingTime) 
           {           
            System.Runtime.InteropServices.ComTypes.FILETIME fileTime = new System.Runtime.InteropServices.ComTypes.FILETIME(); 
            int fileTimeSize = Marshal.SizeOf(fileTime); 
            IntPtr fileTimePtr = Marshal.AllocCoTaskMem(fileTimeSize); 
            Marshal.StructureToPtr(fileTime, fileTimePtr, true); 

            byte[] buffdata = new byte[fileTimeSize]; 
            Marshal.Copy(fileTimePtr, buffdata, 0, fileTimeSize); 

            uint buffSize = (uint)buffdata.Length; 

            uint encoding = WinCrypt.X509_ASN_ENCODING | WinCrypt.PKCS_7_ASN_ENCODING; 

            UIntPtr rsaSigningTime = (UIntPtr)(uint)Marshal.StringToHGlobalAnsi(WinCrypt.szOID_RSA_signingTime); 

            byte[] pbData = signedAttribute.Values[0].RawData;           
            uint ucbData = (uint)pbData.Length; 

            bool workie = WinCrypt.CryptDecodeObject(encoding, rsaSigningTime.ToUInt32(), pbData, ucbData, 0, buffdata, ref buffSize); 

            if (workie) 
            { 
             IntPtr fileTimePtr2 = Marshal.AllocCoTaskMem(buffdata.Length); 
             Marshal.Copy(buffdata, 0, fileTimePtr2, buffdata.Length); 
             System.Runtime.InteropServices.ComTypes.FILETIME fileTime2 = (System.Runtime.InteropServices.ComTypes.FILETIME)Marshal.PtrToStructure(fileTimePtr2, typeof(System.Runtime.InteropServices.ComTypes.FILETIME)); 

             long hFT2 = (((long)fileTime2.dwHighDateTime) << 32) + ((uint)fileTime2.dwLowDateTime); 

             DateTime dte = DateTime.FromFileTime(hFT2); 
             Console.WriteLine(dte.ToString()); 
            } 
            else 
            { 
             throw new Win32Exception(Marshal.GetLastWin32Error());            
            } 

           }  
          } 

         }        

         return true; 
        } 

       } 
      } 
5

谢谢你们,

你帮了我很多:)

BTW:我发现了更简单的方法如何获取时间戳。

那就是:

foreach (var signerInfo in signedCms.SignerInfos) 
{ 
    foreach (var unsignedAttribute in signerInfo.UnsignedAttributes) 
    { 
    if (unsignedAttribute.Oid.Value == WinCrypt.szOID_RSA_counterSign) 
    { 
     foreach (var counterSignInfo in signerInfo.CounterSignerInfos) 
     { 
     foreach (var signedAttribute in counterSignInfo.SignedAttributes) 
     { 
      if (signedAttribute.Oid.Value == WinCrypt.szOID_RSA_signingTime) 
      { 
      Pkcs9SigningTime signingTime = (Pkcs9SigningTime)signedAttribute.Values[0]; 
      Console.Out.WriteLine("Signing Time UTC: " + signingTime.SigningTime); 
      } 
     } 
     } 
     return true; 
    } 
    } 
} 
0

我想避免一些讨厌的P /使用SignedCms类调用代码的想法,但要知道,在某些网络情况下SignedCms构造可以阻止长时间---我正在运行的测试中看到大约15秒。 Alejandro Campos Magencio在他的MSDN博客上发表了一篇名为Big delay while calling EnvelopedCms constructor的文章。

3

我希望得到的主题关闭数字证书,它的OU型串像

  • CN =微软公司,OU = MOPR,O = Microsoft公司,L =雷德蒙S =华盛顿,C =美国

我发现X509Certificate真的很慢,并将整个文件加载到内存中。我试图读取一个800Mb的补丁文件,当它读取它时,我的内存增加了800Mb,并花了30秒!

我已经站在上面海报的sholders上面,设法调整上述代码以获得比使用X509对象快数百倍的X509Certificate2对象。

请阅读我的博客文章,了解有关性能差异图片的更多详细信息。 X509Certificate object c# performance and memory issues alternative – fixed

试试这个:

public static X509Certificate2 GetDigitalCertificate(string filename) 
    { 
     X509Certificate2 cert = null; 

     int encodingType; 
     int contentType; 
     int formatType; 
     IntPtr certStore = IntPtr.Zero; 
     IntPtr cryptMsg = IntPtr.Zero; 
     IntPtr context = IntPtr.Zero; 

     if (!WinCrypt.CryptQueryObject(
      WinCrypt.CERT_QUERY_OBJECT_FILE, 
      Marshal.StringToHGlobalUni(filename), 
      (WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED 
      | WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED 
      | WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED), // <-- These are the attributes that makes it fast!! 
      WinCrypt.CERT_QUERY_FORMAT_FLAG_ALL, 
      0, 
      out encodingType, 
      out contentType, 
      out formatType, 
      ref certStore, 
      ref cryptMsg, 
      ref context)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     // Get size of the encoded message. 
     int cbData = 0; 
     if (!WinCrypt.CryptMsgGetParam(
      cryptMsg, 
      WinCrypt.CMSG_ENCODED_MESSAGE, 
      0, 
      IntPtr.Zero, 
      ref cbData)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     var vData = new byte[cbData]; 

     // Get the encoded message. 
     if (!WinCrypt.CryptMsgGetParam(
      cryptMsg, 
      WinCrypt.CMSG_ENCODED_MESSAGE, 
      0, 
      vData, 
      ref cbData)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     var signedCms = new SignedCms(); 
     signedCms.Decode(vData); 

     if (signedCms.SignerInfos.Count > 0) 
     { 
      var signerInfo = signedCms.SignerInfos[0]; 

      if (signerInfo.Certificate != null) 
      { 
       cert = signerInfo.Certificate; 
      } 
     } 

     return cert; 
    } 

看来,如果你在CryptQueryObject使用“WinCrypt.CERT_QUERY_CONTENT_FLAG_ALL”把它从相同的内存性能击中作为X509Certificate对象受到影响,但如果你修剪下来到只是PKCS7内容类型,它像梦一样表现,似乎给了我需要的信息。