2015-12-15 114 views
-1

我知道我可以使用下面的代碼來檢索有關使用X509Certificate類的可執行文件的數字簽名:檢索有關非exe文件數字簽名的信息?

X509Certificate cert = X509Certificate.CreateFromSignedFile("MySignedProgram.exe"); 
string certSubject = cert.Subject; 

我的問題是如何從一個非EXE文件中獲取數字證書的詳細信息,例如,簽署的.js.vbs文件?

PS。 This native codeCryptQueryObject API似乎正確地完成了這項工作。但是我很好奇,如果有.NET的比喻呢?如果我通過「MySignedScript.js」到CreateFromSignedFile方法上面的代碼拋出,錯誤代碼0x80092009和描述Cannot find the requested object異常。

回答

0

我要發佈的更新,因爲我還沒有得到一個答案,我原來的問題(對其他任何人可以用這個來處理。)

我能夠做硬盤的方式來解決這個問題,即通過從非託管進程獲取數字證書詳細信息。

好消息是,有來自微軟good C sample,顯示它是如何做。壞消息是,如果使用PInvoke重寫.NET的C代碼,它似乎不起作用。 (我不知道PInvoke是否足以告訴你爲什麼,所以如果有人知道,我也想知道,所以請在下面的評論中分享它。)

所以唯一的方法是如何設法獲得它的工作原理是通過使用Microsoft code製作一個小型C++控制檯可執行文件並從C#進程調用它。訣竅是傳遞參數。您可以使用命令行參數傳入參數,但要將它們取出,您可以使用STDOUT流。 (Here's的一個例子。)

最後,這是我的推理爲什麼我得到與0x80092009錯誤代碼,這是,順便說一句,在CRYPT_E_NO_MATCH世界WinAPI的一個例外。當然,這個錯誤是由CryptQueryObject API產生的。不幸的是,和微軟一樣,這個錯誤太模糊,不能提供任何關於失敗的更多細節。例如,如果API本身的任何輸入參數配置錯誤,則可能會返回該錯誤。但通過使用微軟的C代碼,我瞭解到,API依靠代碼簽名文件的擴展名來正確解釋附加數字簽名的格式。例如,如果它是一個可執行文件,它將是簽名的數字格式。如果是JScript文件,則簽名將具有其他格式,第三種格式將用於VBScript文件或PowerShell腳本等。所以很有可能,託管的X509Certificate類會重命名導致CryptQueryObject API失敗的目標文件。儘管如此,這並不能解釋爲什麼PInvoke方法似乎會失敗,並出現相同的錯誤代碼。 (雖然在這種情況下,可能是因爲我不知道導致PInvoke調用的知識,因爲對於錯誤的輸入參數返回相同的錯誤代碼。)

最後,如果Microsoft original page進入,那麼這裏是複製和 - 我指的是C代碼的味道:

#include <windows.h> 
#include <wincrypt.h> 
#include <wintrust.h> 
#include <stdio.h> 
#include <tchar.h> 

#pragma comment(lib, "crypt32.lib") 

#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) 

typedef struct { 
    LPWSTR lpszProgramName; 
    LPWSTR lpszPublisherLink; 
    LPWSTR lpszMoreInfoLink; 
} SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO; 

BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, 
          PSPROG_PUBLISHERINFO Info); 
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st); 
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext); 
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, 
          PCMSG_SIGNER_INFO *pCounterSignerInfo); 

int _tmain(int argc, TCHAR *argv[]) 
{ 
    WCHAR szFileName[MAX_PATH]; 
    HCERTSTORE hStore = NULL; 
    HCRYPTMSG hMsg = NULL; 
    PCCERT_CONTEXT pCertContext = NULL; 
    BOOL fResult; 
    DWORD dwEncoding, dwContentType, dwFormatType; 
    PCMSG_SIGNER_INFO pSignerInfo = NULL; 
    PCMSG_SIGNER_INFO pCounterSignerInfo = NULL; 
    DWORD dwSignerInfo; 
    CERT_INFO CertInfo;  
    SPROG_PUBLISHERINFO ProgPubInfo; 
    SYSTEMTIME st; 

    ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo)); 
    __try 
    { 
     if (argc != 2) 
     { 
      _tprintf(_T("Usage: SignedFileInfo <filename>\n")); 
      return 0; 
     } 

#ifdef UNICODE 
     lstrcpynW(szFileName, argv[1], MAX_PATH); 
#else 
     if (mbstowcs(szFileName, argv[1], MAX_PATH) == -1) 
     { 
      printf("Unable to convert to unicode.\n"); 
      __leave; 
     } 
#endif 

     // Get message handle and store handle from the signed file. 
     fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, 
            szFileName, 
            CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, 
            CERT_QUERY_FORMAT_FLAG_BINARY, 
            0, 
            &dwEncoding, 
            &dwContentType, 
            &dwFormatType, 
            &hStore, 
            &hMsg, 
            NULL); 
     if (!fResult) 
     { 
      _tprintf(_T("CryptQueryObject failed with %x\n"), GetLastError()); 
      __leave; 
     } 

     // Get signer information size. 
     fResult = CryptMsgGetParam(hMsg, 
            CMSG_SIGNER_INFO_PARAM, 
            0, 
            NULL, 
            &dwSignerInfo); 
     if (!fResult) 
     { 
      _tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError()); 
      __leave; 
     } 

     // Allocate memory for signer information. 
     pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo); 
     if (!pSignerInfo) 
     { 
      _tprintf(_T("Unable to allocate memory for Signer Info.\n")); 
      __leave; 
     } 

     // Get Signer Information. 
     fResult = CryptMsgGetParam(hMsg, 
            CMSG_SIGNER_INFO_PARAM, 
            0, 
            (PVOID)pSignerInfo, 
            &dwSignerInfo); 
     if (!fResult) 
     { 
      _tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError()); 
      __leave; 
     } 

     // Get program name and publisher information from 
     // signer info structure. 
     if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo)) 
     { 
      if (ProgPubInfo.lpszProgramName != NULL) 
      { 
       wprintf(L"Program Name : %s\n", 
        ProgPubInfo.lpszProgramName); 
      } 

      if (ProgPubInfo.lpszPublisherLink != NULL) 
      { 
       wprintf(L"Publisher Link : %s\n", 
        ProgPubInfo.lpszPublisherLink); 
      } 

      if (ProgPubInfo.lpszMoreInfoLink != NULL) 
      { 
       wprintf(L"MoreInfo Link : %s\n", 
        ProgPubInfo.lpszMoreInfoLink); 
      } 
     } 

     _tprintf(_T("\n")); 

     // Search for the signer certificate in the temporary 
     // certificate store. 
     CertInfo.Issuer = pSignerInfo->Issuer; 
     CertInfo.SerialNumber = pSignerInfo->SerialNumber; 

     pCertContext = CertFindCertificateInStore(hStore, 
                ENCODING, 
                0, 
                CERT_FIND_SUBJECT_CERT, 
                (PVOID)&CertInfo, 
                NULL); 
     if (!pCertContext) 
     { 
      _tprintf(_T("CertFindCertificateInStore failed with %x\n"), 
       GetLastError()); 
      __leave; 
     } 

     // Print Signer certificate information. 
     _tprintf(_T("Signer Certificate:\n\n"));   
     PrintCertificateInfo(pCertContext); 
     _tprintf(_T("\n")); 

     // Get the timestamp certificate signerinfo structure. 
     if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo)) 
     { 
      // Search for Timestamp certificate in the temporary 
      // certificate store. 
      CertInfo.Issuer = pCounterSignerInfo->Issuer; 
      CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber; 

      pCertContext = CertFindCertificateInStore(hStore, 
               ENCODING, 
               0, 
               CERT_FIND_SUBJECT_CERT, 
               (PVOID)&CertInfo, 
               NULL); 
      if (!pCertContext) 
      { 
       _tprintf(_T("CertFindCertificateInStore failed with %x\n"), 
        GetLastError()); 
       __leave; 
      } 

      // Print timestamp certificate information. 
      _tprintf(_T("TimeStamp Certificate:\n\n")); 
      PrintCertificateInfo(pCertContext); 
      _tprintf(_T("\n")); 

      // Find Date of timestamp. 
      if (GetDateOfTimeStamp(pCounterSignerInfo, &st)) 
      { 
       _tprintf(_T("Date of TimeStamp : %02d/%02d/%04d %02d:%02d\n"), 
              st.wMonth, 
              st.wDay, 
              st.wYear, 
              st.wHour, 
              st.wMinute); 
      } 
      _tprintf(_T("\n")); 
     } 
    } 
    __finally 
    {    
     // Clean up. 
     if (ProgPubInfo.lpszProgramName != NULL) 
      LocalFree(ProgPubInfo.lpszProgramName); 
     if (ProgPubInfo.lpszPublisherLink != NULL) 
      LocalFree(ProgPubInfo.lpszPublisherLink); 
     if (ProgPubInfo.lpszMoreInfoLink != NULL) 
      LocalFree(ProgPubInfo.lpszMoreInfoLink); 

     if (pSignerInfo != NULL) LocalFree(pSignerInfo); 
     if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo); 
     if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); 
     if (hStore != NULL) CertCloseStore(hStore, 0); 
     if (hMsg != NULL) CryptMsgClose(hMsg); 
    } 
    return 0; 
} 

BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext) 
{ 
    BOOL fReturn = FALSE; 
    LPTSTR szName = NULL; 
    DWORD dwData; 

    __try 
    { 
     // Print Serial Number. 
     _tprintf(_T("Serial Number: ")); 
     dwData = pCertContext->pCertInfo->SerialNumber.cbData; 
     for (DWORD n = 0; n < dwData; n++) 
     { 
      _tprintf(_T("%02x "), 
       pCertContext->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]); 
     } 
     _tprintf(_T("\n")); 

     // Get Issuer name size. 
     if (!(dwData = CertGetNameString(pCertContext, 
             CERT_NAME_SIMPLE_DISPLAY_TYPE, 
             CERT_NAME_ISSUER_FLAG, 
             NULL, 
             NULL, 
             0))) 
     { 
      _tprintf(_T("CertGetNameString failed.\n")); 
      __leave; 
     } 

     // Allocate memory for Issuer name. 
     szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR)); 
     if (!szName) 
     { 
      _tprintf(_T("Unable to allocate memory for issuer name.\n")); 
      __leave; 
     } 

     // Get Issuer name. 
     if (!(CertGetNameString(pCertContext, 
           CERT_NAME_SIMPLE_DISPLAY_TYPE, 
           CERT_NAME_ISSUER_FLAG, 
           NULL, 
           szName, 
           dwData))) 
     { 
      _tprintf(_T("CertGetNameString failed.\n")); 
      __leave; 
     } 

     // print Issuer name. 
     _tprintf(_T("Issuer Name: %s\n"), szName); 
     LocalFree(szName); 
     szName = NULL; 

     // Get Subject name size. 
     if (!(dwData = CertGetNameString(pCertContext, 
             CERT_NAME_SIMPLE_DISPLAY_TYPE, 
             0, 
             NULL, 
             NULL, 
             0))) 
     { 
      _tprintf(_T("CertGetNameString failed.\n")); 
      __leave; 
     } 

     // Allocate memory for subject name. 
     szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR)); 
     if (!szName) 
     { 
      _tprintf(_T("Unable to allocate memory for subject name.\n")); 
      __leave; 
     } 

     // Get subject name. 
     if (!(CertGetNameString(pCertContext, 
           CERT_NAME_SIMPLE_DISPLAY_TYPE, 
           0, 
           NULL, 
           szName, 
           dwData))) 
     { 
      _tprintf(_T("CertGetNameString failed.\n")); 
      __leave; 
     } 

     // Print Subject Name. 
     _tprintf(_T("Subject Name: %s\n"), szName); 

     fReturn = TRUE; 
    } 
    __finally 
    { 
     if (szName != NULL) LocalFree(szName); 
    } 

    return fReturn; 
} 

LPWSTR AllocateAndCopyWideString(LPCWSTR inputString) 
{ 
    LPWSTR outputString = NULL; 

    outputString = (LPWSTR)LocalAlloc(LPTR, 
     (wcslen(inputString) + 1) * sizeof(WCHAR)); 
    if (outputString != NULL) 
    { 
     lstrcpyW(outputString, inputString); 
    } 
    return outputString; 
} 

BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, 
          PSPROG_PUBLISHERINFO Info) 
{ 
    BOOL fReturn = FALSE; 
    PSPC_SP_OPUS_INFO OpusInfo = NULL; 
    DWORD dwData; 
    BOOL fResult; 

    __try 
    { 
     // Loop through authenticated attributes and find 
     // SPC_SP_OPUS_INFO_OBJID OID. 
     for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) 
     {   
      if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, 
         pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0) 
      { 
       // Get Size of SPC_SP_OPUS_INFO structure. 
       fResult = CryptDecodeObject(ENCODING, 
          SPC_SP_OPUS_INFO_OBJID, 
          pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, 
          pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 
          0, 
          NULL, 
          &dwData); 
       if (!fResult) 
       { 
        _tprintf(_T("CryptDecodeObject failed with %x\n"), 
         GetLastError()); 
        __leave; 
       } 

       // Allocate memory for SPC_SP_OPUS_INFO structure. 
       OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData); 
       if (!OpusInfo) 
       { 
        _tprintf(_T("Unable to allocate memory for Publisher Info.\n")); 
        __leave; 
       } 

       // Decode and get SPC_SP_OPUS_INFO structure. 
       fResult = CryptDecodeObject(ENCODING, 
          SPC_SP_OPUS_INFO_OBJID, 
          pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, 
          pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 
          0, 
          OpusInfo, 
          &dwData); 
       if (!fResult) 
       { 
        _tprintf(_T("CryptDecodeObject failed with %x\n"), 
         GetLastError()); 
        __leave; 
       } 

       // Fill in Program Name if present. 
       if (OpusInfo->pwszProgramName) 
       { 
        Info->lpszProgramName = 
         AllocateAndCopyWideString(OpusInfo->pwszProgramName); 
       } 
       else 
        Info->lpszProgramName = NULL; 

       // Fill in Publisher Information if present. 
       if (OpusInfo->pPublisherInfo) 
       { 

        switch (OpusInfo->pPublisherInfo->dwLinkChoice) 
        { 
         case SPC_URL_LINK_CHOICE: 
          Info->lpszPublisherLink = 
           AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl); 
          break; 

         case SPC_FILE_LINK_CHOICE: 
          Info->lpszPublisherLink = 
           AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile); 
          break; 

         default: 
          Info->lpszPublisherLink = NULL; 
          break; 
        } 
       } 
       else 
       { 
        Info->lpszPublisherLink = NULL; 
       } 

       // Fill in More Info if present. 
       if (OpusInfo->pMoreInfo) 
       { 
        switch (OpusInfo->pMoreInfo->dwLinkChoice) 
        { 
         case SPC_URL_LINK_CHOICE: 
          Info->lpszMoreInfoLink = 
           AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl); 
          break; 

         case SPC_FILE_LINK_CHOICE: 
          Info->lpszMoreInfoLink = 
           AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile); 
          break; 

         default: 
          Info->lpszMoreInfoLink = NULL; 
          break; 
        } 
       }    
       else 
       { 
        Info->lpszMoreInfoLink = NULL; 
       } 

       fReturn = TRUE; 

       break; // Break from for loop. 
      } // lstrcmp SPC_SP_OPUS_INFO_OBJID     
     } // for 
    } 
    __finally 
    { 
     if (OpusInfo != NULL) LocalFree(OpusInfo);  
    } 

    return fReturn; 
} 

BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st) 
{ 
    BOOL fResult; 
    FILETIME lft, ft; 
    DWORD dwData; 
    BOOL fReturn = FALSE; 

    // Loop through authenticated attributes and find 
    // szOID_RSA_signingTime OID. 
    for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) 
    {   
     if (lstrcmpA(szOID_RSA_signingTime, 
        pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0) 
     {    
      // Decode and get FILETIME structure. 
      dwData = sizeof(ft); 
      fResult = CryptDecodeObject(ENCODING, 
         szOID_RSA_signingTime, 
         pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, 
         pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 
         0, 
         (PVOID)&ft, 
         &dwData); 
      if (!fResult) 
      { 
       _tprintf(_T("CryptDecodeObject failed with %x\n"), 
        GetLastError()); 
       break; 
      } 

      // Convert to local time. 
      FileTimeToLocalFileTime(&ft, &lft); 
      FileTimeToSystemTime(&lft, st); 

      fReturn = TRUE; 

      break; // Break from for loop. 

     } //lstrcmp szOID_RSA_signingTime 
    } // for 

    return fReturn; 
} 

BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo) 
{ 
    PCCERT_CONTEXT pCertContext = NULL; 
    BOOL fReturn = FALSE; 
    BOOL fResult;  
    DWORD dwSize; 

    __try 
    { 
     *pCounterSignerInfo = NULL; 

     // Loop through unathenticated attributes for 
     // szOID_RSA_counterSign OID. 
     for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++) 
     { 
      if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, 
         szOID_RSA_counterSign) == 0) 
      { 
       // Get size of CMSG_SIGNER_INFO structure. 
       fResult = CryptDecodeObject(ENCODING, 
          PKCS7_SIGNER_INFO, 
          pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, 
          pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, 
          0, 
          NULL, 
          &dwSize); 
       if (!fResult) 
       { 
        _tprintf(_T("CryptDecodeObject failed with %x\n"), 
         GetLastError()); 
        __leave; 
       } 

       // Allocate memory for CMSG_SIGNER_INFO. 
       *pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize); 
       if (!*pCounterSignerInfo) 
       { 
        _tprintf(_T("Unable to allocate memory for timestamp info.\n")); 
        __leave; 
       } 

       // Decode and get CMSG_SIGNER_INFO structure 
       // for timestamp certificate. 
       fResult = CryptDecodeObject(ENCODING, 
          PKCS7_SIGNER_INFO, 
          pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, 
          pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, 
          0, 
          (PVOID)*pCounterSignerInfo, 
          &dwSize); 
       if (!fResult) 
       { 
        _tprintf(_T("CryptDecodeObject failed with %x\n"), 
         GetLastError()); 
        __leave; 
       } 

       fReturn = TRUE; 

       break; // Break from for loop. 
      }   
     } 
    } 
    __finally 
    { 
     // Clean up. 
     if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); 
    } 

    return fReturn; 
} 
-1

某些文件格式有標準所定義的某種方式應用於數字簽名,而這種方式是不與其他的文件格式兼容。 Authenticode就是這樣的例子之一 - 有一種將簽名嵌入到Authenticode中的EXE文件的標準方法。其他文件格式,如PDF或XML有自己的方式來嵌入簽名。

存在幾種通用方法來進行簽名,但這些方式暗示或者是分離的簽名(在一個存儲在單獨的數據塊),或包裹簽名。在後一種情況下,原始文件內容與簽名相關數據「包裝」在一起,並且這樣的文件不能像原始文件一樣處理 - 它的結構是不同的。這種通用格式是PKCS7/CMS(和CAdES),S/MIME(基於CMS),OpenPGP,XMLDSig(它可以處理二進制內容)。

存在着這將處理所有簽名的世界,儘管這與PKCS7/CMS工作的功能似乎與OpenPGP的最普遍的(一起沒有通用的功能,但後者使用其自己的鑰匙,而不是X.509證書)。

我們SecureBlackbox圖書館的方法來創建和驗證(和提取數據)中最流行的文檔格式的簽名和上述通用簽名格式。

+0

那麼,這一切都非常好。除付費產品之外是否還有其他解決方案?另外它是如何解釋本地API似乎工作? – c00000fd

+0

@ c00000fd似乎在什麼文件上工作?請重新閱讀我的答案,似乎你錯過了大部分內容。該文章適用於Authenticode和MS的一些專有格式,如放置在腳本註釋中的簽名。 –