【问题标题】:Show digital signature / certificate dialogs显示数字签名/证书对话框
【发布时间】:2014-01-14 19:38:17
【问题描述】:

我有来自 Authenticode 签名的 PE 文件的 PKCS #7 SignedData。我想在这样的对话框中显示它:

这是一个标准的 Windows 对话框,如果您在 PE 文件的 数字签名 选项卡上单击 详细信息,就会看到该对话框。

知道怎么做吗?

我更喜欢 C# 解决方案,但标准 C API 也可以工作(我可以制作 C++/CLI 接口。)

【问题讨论】:

    标签: c# c winapi


    【解决方案1】:

    CryptUIDlgViewSignerInfo 调用之前的大部分工作似乎已经由 .NET 类 System.Security.Cryptography.Pkcs.SignedCms 在内部完成。

    填充CRYPTUI_VIEWSIGNERINFO_STRUCT 所需的两个部分已经存在,作为SignedCms 的私有字段:

    • hMsgSignedCms.m_safeCryptMsgHandle
    • pSignerInfoSignerInfo.m_pbCmsgSignerInfo

    如果我们可以调用一个假设的 SignedCms.ShowSignerInfoDialog() 函数,或者以某种方式无需反射就可以访问这些成员,那将是不可思议的。

    以下 hack 确实有效!

    class Program
    {
        static void Main(string[] args) {
            var data = ...;
    
            var cms = new SignedCms();
            cms.Decode(data);
    
            var pbCmsgSignerInfo = typeof(SignerInfo).GetField("m_pbCmsgSignerInfo", BindingFlags.NonPublic | BindingFlags.Instance);
            var si = (SafeHandle)pbCmsgSignerInfo.GetValue(cms.SignerInfos[0]);
    
            var safeCryptMessageHandle = typeof(SignedCms).GetField("m_safeCryptMsgHandle", BindingFlags.NonPublic | BindingFlags.Instance);
            var hMsg = (SafeHandle)safeCryptMessageHandle.GetValue(cms);
    
            var vsi = new CRYPTUI_VIEWSIGNERINFO_STRUCT {
                dwSize = (uint)Marshal.SizeOf(typeof(CRYPTUI_VIEWSIGNERINFO_STRUCT)),
                pSignerInfo = si,
                hMsg = hMsg,
            };
    
            CryptUIDlgViewSignerInfo(ref vsi);
        }
    
        [DllImport("Cryptui.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern bool CryptUIDlgViewSignerInfo(ref CRYPTUI_VIEWSIGNERINFO_STRUCT pcvsi);
    }
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct CRYPTUI_VIEWSIGNERINFO_STRUCT
    {
        public UInt32 dwSize;
        public IntPtr hwndParent;
        public UInt32 dwFlags;
        public string szTitle;
        public SafeHandle pSignerInfo;
        public SafeHandle hMsg;
    
        [MarshalAs(UnmanagedType.LPStr)]
        public string pszOID;
        public IntPtr dwReserved;
        public UInt32 cStores;
        public IntPtr rghStores;
        public UInt32 cPropSheetPages;
        public IntPtr rgPropSheetPages;
    }
    

    【讨论】:

      【解决方案2】:

      这需要大量的研究和一些逆向工程,但我最终让它发挥了作用。

      魔法函数是CryptUIDlgViewSignerInfo()

      CryptUIDlgViewSignerInfo 函数显示一个对话框,其中包含已签名消息的签名者信息。

      不幸的是,连同其唯一参数的定义,CRYPTUI_VIEWSIGNERINFO_STRUCT 不在任何头文件中。所以首先你需要声明:

      CryptUI.h

      #ifdef __cplusplus
      extern "C" {
      #endif
      
      typedef struct tagCRYPTUI_VIEWSIGNERINFO_STRUCT {
        DWORD            dwSize;
        HWND             hwndParent;
        DWORD            dwFlags;
        LPCTSTR          szTitle;
        CMSG_SIGNER_INFO *pSignerInfo;
        HCRYPTMSG        hMsg;
        LPCSTR           pszOID;
        DWORD_PTR        dwReserved;
        DWORD            cStores;
        HCERTSTORE       *rghStores;
        DWORD            cPropSheetPages;
        LPCPROPSHEETPAGE rgPropSheetPages;
      } CRYPTUI_VIEWSIGNERINFO_STRUCT, *PCRYPTUI_VIEWSIGNERINFO_STRUCT;
      
      
      
      #ifdef UNICODE
      #define CryptUIDlgViewSignerInfo CryptUIDlgViewSignerInfoW
      #else
      #define CryptUIDlgViewSignerInfo CryptUIDlgViewSignerInfoA
      #endif
      
      BOOL WINAPI CryptUIDlgViewSignerInfo(
        _In_  CRYPTUI_VIEWSIGNERINFO_STRUCT *pcvsi
      );
      
      
      #ifdef __cplusplus
      }  // extern "C"
      #endif
      

      现在,这是一个 C++ CLI 函数,但如果您调整开头,它应该很容易在纯 C 中工作。当然,您还需要做一些更好的错误检查,但这只是一个概念验证:

      // Link against these libraries
      #pragma comment (lib, "Crypt32")
      #pragma comment (lib, "Cryptui")
      
      void CertHelper::DoStuff(array<Byte>^ data) {
      
          // http://stackoverflow.com/questions/17689154
          pin_ptr<Byte> pData = &data[0];
      
          CERT_BLOB blob;
          blob.cbData = data->Length;
          blob.pbData = pData;
      
          BOOL res;
      
          DWORD MsgAndCertEncodingType;
          DWORD ContentType;
          DWORD FormatType;
          HCERTSTORE hCertStore;
          HCRYPTMSG hMsg;
      
          res = CryptQueryObject(
              CERT_QUERY_OBJECT_BLOB,         // dwObjectType [in]
              &blob,                          // pvObject [in]
              CERT_QUERY_CONTENT_FLAG_ALL,    // dwExpectedContentTypeFlags [in]
              CERT_QUERY_FORMAT_FLAG_BINARY,  // dwExpectedFormatTypeFlags [in]
              0,                              // dwFlags [in]
      
              &MsgAndCertEncodingType,        // pdwMsgAndCertEncodingType [out]
              &ContentType,                   // pdwContentType [out]
              &FormatType,                    // pdwFormatType [out]
              &hCertStore,                    // phCertStore [out]
              &hMsg,                          // phMsg [out]
              NULL                            // ppvContext [out]
              );
      
      
          // Get the SignerInfo - call once to get size
          DWORD cb;
      
          res = CryptMsgGetParam(
              hMsg,                           // hCryptMsg [in]
              CMSG_SIGNER_INFO_PARAM,         // dwParamType [in]
              0,                              // dwIndex [in]
              NULL,                           // pvData [out]
              &cb                             // pcbData [in, out]
              );
      
          CMSG_SIGNER_INFO* signerinfo = (CMSG_SIGNER_INFO*)LocalAlloc(LPTR, cb);
      
          res = CryptMsgGetParam(
              hMsg,                           // hCryptMsg [in]
              CMSG_SIGNER_INFO_PARAM,         // dwParamType [in]
              0,                              // dwIndex [in]
              signerinfo,                     // pvData [out]
              &cb                             // pcbData [in, out]
              );
      
      
          // Initialize the View Signer Info structure
          CRYPTUI_VIEWSIGNERINFO_STRUCT vsi;
          memset(&vsi, 0, sizeof(vsi));
          vsi.dwSize = sizeof(vsi);
          vsi.hwndParent = NULL;  // TODO
          vsi.dwFlags = 0;    // SHDocvw.dll passes 0x14
          vsi.szTitle = NULL;
          vsi.pSignerInfo = signerinfo;
          vsi.hMsg = hMsg;
          vsi.pszOID = "1.3.6.1.5.5.7.3.3";   // XCN_OID_PKIX_KP_CODE_SIGNING
      
      
          // Show the dialog already!
          res = CryptUIDlgViewSignerInfo(&vsi);
      
          // Free resources
          LocalFree(signerinfo);
          if (hCertStore)   CertCloseStore(hCertStore, 0);
          if (hMsg)         CryptMsgClose(hMsg);
      }
      

      为了参考起见,这是从ViewCertProperties()shdocvw.dll 中回复的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-02
        • 2013-05-26
        • 1970-01-01
        • 2011-11-21
        • 2011-08-17
        • 1970-01-01
        • 2011-09-22
        • 1970-01-01
        相关资源
        最近更新 更多