2010-07-19 16 views
17

Tenemos que verificar que los archivos binarios están firmados correctamente con firma digital (Authenticode). Esto se puede lograr con signtool.exe con bastante facilidad. Sin embargo, necesitamos una forma automática que también verifique el nombre del firmante y la marca de tiempo. Esto es factible en C++ nativo con CryptQueryObject() API como se muestra en esta maravillosa muestra: How To Get Information from Authenticode Signed ExecutablesObtener marca de tiempo de Authenticode Firmó archivos en .NET

Sin embargo, vivimos en un mundo administrado :) por lo tanto, buscamos la solución C para el mismo problema. El enfoque directo sería invocar Crypt32.dll y todo está hecho. Pero hay una API administrada similar en el espacio de nombres System.Security.Cryptography.X509Certificates. X509Certificate2 La clase parece proporcionar cierta información, pero no marca de tiempo. Ahora llegamos a la pregunta original ¿cómo podemos obtener esa marca de tiempo de una firma digital en C Sharp?

+3

Las clases authenticode administradas dejan un * lote * fuera! Probablemente sea más fácil simplemente p/invocar. –

+1

La primera razón es que el código administrado se ve mejor. En segundo lugar, en varios artículos de MSDN hay notas aterradoras como esta Nota La función WinVerifyTrust está disponible para su uso en los sistemas operativos enumerados en la sección Requisitos. Puede estar alterado o no disponible en versiones posteriores. Donde Windows Vista es el último sistema compatible. Por supuesto, WinVerifyTrust y CryptQueryObject funcionan en Windows 7, pero con todas estas advertencias parecía lógico usar alguna otra API. Parece que el espacio de nombres de Certificados está medio cocido de hecho. Gracioso, pero esta advertencia no está presente en MSDN en línea ahora ... – SlavaGu

Respuesta

1

Como veo que no tienes respuestas de todos modos, déjame ofrecerte una.

Si no le molesta usar componentes de terceros, eche un vistazo al componente TElAuthenticodeVerifier de nuestro producto SecureBlackbox. Con este componente puede verificar la firma y verificar las marcas de tiempo.

+0

La clase se ve bien, gracias. ¿VerifySignature verifica la validez del certificado contra CRL en línea? Por cierto, ya he implementado el control de marca de tiempo pinvoking CryptQueryObject, así que estoy preguntando solo por mi curiosidad. – SlavaGu

+0

Hola SlavaGu, ¿podría compartir su solución conmigo? o puede dar una idea de cómo puedo hacer. También tengo un problema similar. Gracias. – Akie

11

Volviendo a la pregunta original, no pude encontrar logrado manera así que terminamos usando PInvoke de la siguiente manera:

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; 
} 

y la WinCrypt.cs contiene los siguientes:

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

Gracias a la OP para tu trabajo. Agregué la implementación para obtener el TimeStamp real del certificado.

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

Gracias chicos,

usted me ayuda mucho :)

cierto: me encontré manera más sencilla la forma de obtener la marca de tiempo.

aquí está:

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

me gusta la idea de evitar alguna desagradable p/invocar código utilizando la clase SignedCms, pero ten en cuenta que en algunas circunstancias la red el constructor SignedCms puede bloquear durante mucho tiempo --- Estoy viendo unos 15 segundos en una prueba que estoy ejecutando actualmente. Alejandro Campos Magencio tiene información sobre esto en su blog de MSDN en una publicación titulada Big delay while calling EnvelopedCms constructor.

3

yo queríamos el tema fuera el certificado digital, su un tipo de cadena OU como

  • CN = Microsoft Corporation, OU = MOPR, O = Microsoft Corporation, L = Redmond, S = Washington, C = US

Encontré que el X509Certificate es realmente lento y carga todo el archivo en la memoria. Traté de leer un archivo de parche de 800Mb y mi memoria aumentó en 800Mb mientras lo leía, ¡¡¡¡¡¡¡¡¡¡¡y tomó más de 30 segundos !!

He estado parado en los sholders de los carteles de arriba y logré modificar el código anterior para obtener un objeto X509Certificate2 cientos de veces más rápido que usando el objeto X509.

Lea la publicación de mi blog para obtener más detalles con imágenes de las diferencias de rendimiento. X509Certificate object c# performance and memory issues alternative – fixed

Prueba esto:

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; 
    } 

Parece que si se utiliza el "WinCrypt.CERT_QUERY_CONTENT_FLAG_ALL" en la CryptQueryObject llaman sufre el mismo rendimiento de la memoria golpear el objeto X509Certificate, pero si recorta hacia abajo solo para los tipos de contenido de PKCS7 funciona como un sueño y parece darme la información que necesito.

Cuestiones relacionadas