1. #include "stdafx.h"
  2.  
  3. #include <windows.h>
  4. #include <wincrypt.h>
  5. #include <wintrust.h>
  6. #include <stdio.h>
  7. #include <tchar.h>
  8.  
  9. #pragma comment(lib, "crypt32.lib")
  10.  
  11. #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
  12.  
  13. typedef struct {
  14.     LPWSTR lpszProgramName;
  15.     LPWSTR lpszPublisherLink;
  16.     LPWSTR lpszMoreInfoLink;
  17. } SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO;
  18.  
  19. BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
  20.                              PSPROG_PUBLISHERINFO Info);
  21. BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st);
  22. BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext);
  23. BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo,
  24.                             PCMSG_SIGNER_INFO *pCounterSignerInfo);
  25.  
  26. int _tmain(int argc, TCHAR *argv[])
  27. {
  28.     WCHAR szFileName[MAX_PATH];
  29.     HCERTSTORE hStore = NULL;
  30.     HCRYPTMSG hMsg = NULL;
  31.     PCCERT_CONTEXT pCertContext = NULL;
  32.     BOOL fResult;  
  33.     DWORD dwEncoding, dwContentType, dwFormatType;
  34.     PCMSG_SIGNER_INFO pSignerInfo = NULL;
  35.     PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
  36.     DWORD dwSignerInfo;
  37.     CERT_INFO CertInfo;    
  38.     SPROG_PUBLISHERINFO ProgPubInfo;
  39.     SYSTEMTIME st;
  40.  
  41.     ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo));
  42.     __try
  43.     {
  44.         if (argc != 2)
  45.         {
  46.             _tprintf(_T("Usage: SignedFileInfo <filename>\n"));
  47.             return 0;
  48.         }
  49.  
  50. #ifdef UNICODE
  51.         lstrcpynW(szFileName, argv[1], MAX_PATH);
  52. #else
  53.         if (mbstowcs(szFileName, argv[1], MAX_PATH) == -1)
  54.         {
  55.             printf("Unable to convert to unicode.\n");
  56.             __leave;
  57.         }
  58. #endif
  59.  
  60.         // Get message handle and store handle from the signed file.
  61.         fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
  62.                                    szFileName,
  63.                                    CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
  64.                                    CERT_QUERY_FORMAT_FLAG_BINARY,
  65.                                    0,
  66.                                    &dwEncoding,
  67.                                    &dwContentType,
  68.                                    &dwFormatType,
  69.                                    &hStore,
  70.                                    &hMsg,
  71.                                    NULL);
  72.         if (!fResult)
  73.         {
  74.             _tprintf(_T("CryptQueryObject failed with %x\n"), GetLastError());
  75.             __leave;
  76.         }
  77.  
  78.         // Get signer information size.
  79.         fResult = CryptMsgGetParam(hMsg,
  80.                                    CMSG_SIGNER_INFO_PARAM,
  81.                                    0,
  82.                                    NULL,
  83.                                    &dwSignerInfo);
  84.         if (!fResult)
  85.         {
  86.             _tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
  87.             __leave;
  88.         }
  89.  
  90.         // Allocate memory for signer information.
  91.         pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
  92.         if (!pSignerInfo)
  93.         {
  94.             _tprintf(_T("Unable to allocate memory for Signer Info.\n"));
  95.             __leave;
  96.         }
  97.  
  98.         // Get Signer Information.
  99.         fResult = CryptMsgGetParam(hMsg,
  100.                                    CMSG_SIGNER_INFO_PARAM,
  101.                                    0,
  102.                                    (PVOID)pSignerInfo,
  103.                                    &dwSignerInfo);
  104.         if (!fResult)
  105.         {
  106.             _tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
  107.             __leave;
  108.         }
  109.        
  110.         // Get program name and publisher information from
  111.         // signer info structure.
  112.         if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo))
  113.         {
  114.             if (ProgPubInfo.lpszProgramName != NULL)
  115.             {
  116.                 wprintf(L"Program Name : %s\n",
  117.                     ProgPubInfo.lpszProgramName);
  118.             }
  119.  
  120.             if (ProgPubInfo.lpszPublisherLink != NULL)
  121.             {
  122.                 wprintf(L"Publisher Link : %s\n",
  123.                     ProgPubInfo.lpszPublisherLink);
  124.             }
  125.  
  126.             if (ProgPubInfo.lpszMoreInfoLink != NULL)
  127.             {
  128.                 wprintf(L"MoreInfo Link : %s\n",
  129.                     ProgPubInfo.lpszMoreInfoLink);
  130.             }
  131.         }
  132.  
  133.         _tprintf(_T("\n"));
  134.  
  135.         // Search for the signer certificate in the temporary
  136.         // certificate store.
  137.         CertInfo.Issuer = pSignerInfo->Issuer;
  138.         CertInfo.SerialNumber = pSignerInfo->SerialNumber;
  139.  
  140.         pCertContext = CertFindCertificateInStore(hStore,
  141.                                                   ENCODING,
  142.                                                   0,
  143.                                                   CERT_FIND_SUBJECT_CERT,
  144.                                                   (PVOID)&CertInfo,
  145.                                                   NULL);
  146.         if (!pCertContext)
  147.         {
  148.             _tprintf(_T("CertFindCertificateInStore failed with %x\n"),
  149.                 GetLastError());
  150.             __leave;
  151.         }
  152.  
  153.         // Print Signer certificate information.
  154.         _tprintf(_T("Signer Certificate:\n\n"));        
  155.         PrintCertificateInfo(pCertContext);
  156.         _tprintf(_T("\n"));
  157.        
  158.         // Get the timestamp certificate signerinfo structure.
  159.         if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo))
  160.         {
  161.             // Search for Timestamp certificate in the temporary
  162.             // certificate store.
  163.             CertInfo.Issuer = pCounterSignerInfo->Issuer;
  164.             CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber;
  165.  
  166.             pCertContext = CertFindCertificateInStore(hStore,
  167.                                                 ENCODING,
  168.                                                 0,
  169.                                                 CERT_FIND_SUBJECT_CERT,
  170.                                                 (PVOID)&CertInfo,
  171.                                                 NULL);
  172.             if (!pCertContext)
  173.             {
  174.                 _tprintf(_T("CertFindCertificateInStore failed with %x\n"),
  175.                     GetLastError());
  176.                 __leave;
  177.             }
  178.  
  179.             // Print timestamp certificate information.
  180.             _tprintf(_T("TimeStamp Certificate:\n\n"));
  181.             PrintCertificateInfo(pCertContext);
  182.             _tprintf(_T("\n"));
  183.  
  184.             // Find Date of timestamp.
  185.             if (GetDateOfTimeStamp(pCounterSignerInfo, &st))
  186.             {
  187.                 _tprintf(_T("Date of TimeStamp : %02d/%02d/%04d %02d:%02d\n"),
  188.                                             st.wMonth,
  189.                                             st.wDay,
  190.                                             st.wYear,
  191.                                             st.wHour,
  192.                                             st.wMinute);
  193.             }
  194.             _tprintf(_T("\n"));
  195.         }
  196.     }
  197.     __finally
  198.     {              
  199.         // Clean up.
  200.         if (ProgPubInfo.lpszProgramName != NULL)
  201.             LocalFree(ProgPubInfo.lpszProgramName);
  202.         if (ProgPubInfo.lpszPublisherLink != NULL)
  203.             LocalFree(ProgPubInfo.lpszPublisherLink);
  204.         if (ProgPubInfo.lpszMoreInfoLink != NULL)
  205.             LocalFree(ProgPubInfo.lpszMoreInfoLink);
  206.  
  207.         if (pSignerInfo != NULL) LocalFree(pSignerInfo);
  208.         if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo);
  209.         if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
  210.         if (hStore != NULL) CertCloseStore(hStore, 0);
  211.         if (hMsg != NULL) CryptMsgClose(hMsg);
  212.     }
  213.     return 0;
  214. }
  215.  
  216. BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext)
  217. {
  218.     BOOL fReturn = FALSE;
  219.     LPTSTR szName = NULL;
  220.     DWORD dwData;
  221.  
  222.     __try
  223.     {
  224.         // Print Serial Number.
  225.         _tprintf(_T("Serial Number: "));
  226.         dwData = pCertContext->pCertInfo->SerialNumber.cbData;
  227.         for (DWORD n = 0; n < dwData; n++)
  228.         {
  229.             _tprintf(_T("%02x "),
  230.               pCertContext->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]);
  231.         }
  232.         _tprintf(_T("\n"));
  233.  
  234.         // Get Issuer name size.
  235.         if (!(dwData = CertGetNameString(pCertContext,
  236.                                          CERT_NAME_SIMPLE_DISPLAY_TYPE,
  237.                                          CERT_NAME_ISSUER_FLAG,
  238.                                          NULL,
  239.                                          NULL,
  240.                                          0)))
  241.         {
  242.             _tprintf(_T("CertGetNameString failed.\n"));
  243.             __leave;
  244.         }
  245.  
  246.         // Allocate memory for Issuer name.
  247.         szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
  248.         if (!szName)
  249.         {
  250.             _tprintf(_T("Unable to allocate memory for issuer name.\n"));
  251.             __leave;
  252.         }
  253.  
  254.         // Get Issuer name.
  255.         if (!(CertGetNameString(pCertContext,
  256.                                 CERT_NAME_SIMPLE_DISPLAY_TYPE,
  257.                                 CERT_NAME_ISSUER_FLAG,
  258.                                 NULL,
  259.                                 szName,
  260.                                 dwData)))
  261.         {
  262.             _tprintf(_T("CertGetNameString failed.\n"));
  263.             __leave;
  264.         }
  265.  
  266.         // print Issuer name.
  267.         _tprintf(_T("Issuer Name: %s\n"), szName);
  268.         LocalFree(szName);
  269.         szName = NULL;
  270.  
  271.         // Get Subject name size.
  272.         if (!(dwData = CertGetNameString(pCertContext,
  273.                                          CERT_NAME_SIMPLE_DISPLAY_TYPE,
  274.                                          0,
  275.                                          NULL,
  276.                                          NULL,
  277.                                          0)))
  278.         {
  279.             _tprintf(_T("CertGetNameString failed.\n"));
  280.             __leave;
  281.         }
  282.  
  283.         // Allocate memory for subject name.
  284.         szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
  285.         if (!szName)
  286.         {
  287.             _tprintf(_T("Unable to allocate memory for subject name.\n"));
  288.             __leave;
  289.         }
  290.  
  291.         // Get subject name.
  292.         if (!(CertGetNameString(pCertContext,
  293.                                 CERT_NAME_SIMPLE_DISPLAY_TYPE,
  294.                                 0,
  295.                                 NULL,
  296.                                 szName,
  297.                                 dwData)))
  298.         {
  299.             _tprintf(_T("CertGetNameString failed.\n"));
  300.             __leave;
  301.         }
  302.  
  303.         // Print Subject Name.
  304.         _tprintf(_T("Subject Name: %s\n"), szName);
  305.  
  306.         fReturn = TRUE;
  307.     }
  308.     __finally
  309.     {
  310.         if (szName != NULL) LocalFree(szName);
  311.     }
  312.  
  313.     return fReturn;
  314. }
  315.  
  316. LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
  317. {
  318.     LPWSTR outputString = NULL;
  319.  
  320.     outputString = (LPWSTR)LocalAlloc(LPTR,
  321.         (wcslen(inputString) + 1) * sizeof(WCHAR));
  322.     if (outputString != NULL)
  323.     {
  324.         lstrcpyW(outputString, inputString);
  325.     }
  326.     return outputString;
  327. }
  328.  
  329. BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
  330.                              PSPROG_PUBLISHERINFO Info)
  331. {
  332.     BOOL fReturn = FALSE;
  333.     PSPC_SP_OPUS_INFO OpusInfo = NULL;  
  334.     DWORD dwData;
  335.     BOOL fResult;
  336.    
  337.     __try
  338.     {
  339.         // Loop through authenticated attributes and find
  340.         // SPC_SP_OPUS_INFO_OBJID OID.
  341.         for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
  342.         {          
  343.             if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID,
  344.                         pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
  345.             {
  346.                 // Get Size of SPC_SP_OPUS_INFO structure.
  347.                 fResult = CryptDecodeObject(ENCODING,
  348.                             SPC_SP_OPUS_INFO_OBJID,
  349.                             pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
  350.                             pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
  351.                             0,
  352.                             NULL,
  353.                             &dwData);
  354.                 if (!fResult)
  355.                 {
  356.                     _tprintf(_T("CryptDecodeObject failed with %x\n"),
  357.                         GetLastError());
  358.                     __leave;
  359.                 }
  360.  
  361.                 // Allocate memory for SPC_SP_OPUS_INFO structure.
  362.                 OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData);
  363.                 if (!OpusInfo)
  364.                 {
  365.                     _tprintf(_T("Unable to allocate memory for Publisher Info.\n"));
  366.                     __leave;
  367.                 }
  368.  
  369.                 // Decode and get SPC_SP_OPUS_INFO structure.
  370.                 fResult = CryptDecodeObject(ENCODING,
  371.                             SPC_SP_OPUS_INFO_OBJID,
  372.                             pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
  373.                             pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
  374.                             0,
  375.                             OpusInfo,
  376.                             &dwData);
  377.                 if (!fResult)
  378.                 {
  379.                     _tprintf(_T("CryptDecodeObject failed with %x\n"),
  380.                         GetLastError());
  381.                     __leave;
  382.                 }
  383.  
  384.                 // Fill in Program Name if present.
  385.                 if (OpusInfo->pwszProgramName)
  386.                 {
  387.                     Info->lpszProgramName =
  388.                         AllocateAndCopyWideString(OpusInfo->pwszProgramName);
  389.                 }
  390.                 else
  391.                     Info->lpszProgramName = NULL;
  392.  
  393.                 // Fill in Publisher Information if present.
  394.                 if (OpusInfo->pPublisherInfo)
  395.                 {
  396.  
  397.                     switch (OpusInfo->pPublisherInfo->dwLinkChoice)
  398.                     {
  399.                         case SPC_URL_LINK_CHOICE:
  400.                             Info->lpszPublisherLink =
  401.                                 AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
  402.                             break;
  403.  
  404.                         case SPC_FILE_LINK_CHOICE:
  405.                             Info->lpszPublisherLink =
  406.                                 AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
  407.                             break;
  408.  
  409.                         default:
  410.                             Info->lpszPublisherLink = NULL;
  411.                             break;
  412.                     }
  413.                 }
  414.                 else
  415.                 {
  416.                     Info->lpszPublisherLink = NULL;
  417.                 }
  418.  
  419.                 // Fill in More Info if present.
  420.                 if (OpusInfo->pMoreInfo)
  421.                 {
  422.                     switch (OpusInfo->pMoreInfo->dwLinkChoice)
  423.                     {
  424.                         case SPC_URL_LINK_CHOICE:
  425.                             Info->lpszMoreInfoLink =
  426.                                 AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
  427.                             break;
  428.  
  429.                         case SPC_FILE_LINK_CHOICE:
  430.                             Info->lpszMoreInfoLink =
  431.                                 AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
  432.                             break;
  433.  
  434.                         default:
  435.                             Info->lpszMoreInfoLink = NULL;
  436.                             break;
  437.                     }
  438.                 }              
  439.                 else
  440.                 {
  441.                     Info->lpszMoreInfoLink = NULL;
  442.                 }
  443.  
  444.                 fReturn = TRUE;
  445.  
  446.                 break; // Break from for loop.
  447.             } // lstrcmp SPC_SP_OPUS_INFO_OBJID                
  448.         } // for
  449.     }
  450.     __finally
  451.     {
  452.         if (OpusInfo != NULL) LocalFree(OpusInfo);      
  453.     }
  454.  
  455.     return fReturn;
  456. }
  457.  
  458. BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st)
  459. {  
  460.     BOOL fResult;
  461.     FILETIME lft, ft;  
  462.     DWORD dwData;
  463.     BOOL fReturn = FALSE;
  464.    
  465.     // Loop through authenticated attributes and find
  466.     // szOID_RSA_signingTime OID.
  467.     for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
  468.     {          
  469.         if (lstrcmpA(szOID_RSA_signingTime,
  470.                     pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
  471.         {              
  472.             // Decode and get FILETIME structure.
  473.             dwData = sizeof(ft);
  474.             fResult = CryptDecodeObject(ENCODING,
  475.                         szOID_RSA_signingTime,
  476.                         pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
  477.                         pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
  478.                         0,
  479.                         (PVOID)&ft,
  480.                         &dwData);
  481.             if (!fResult)
  482.             {
  483.                 _tprintf(_T("CryptDecodeObject failed with %x\n"),
  484.                     GetLastError());
  485.                 break;
  486.             }
  487.  
  488.             // Convert to local time.
  489.             FileTimeToLocalFileTime(&ft, &lft);
  490.             FileTimeToSystemTime(&lft, st);
  491.  
  492.             fReturn = TRUE;
  493.  
  494.             break; // Break from for loop.
  495.                        
  496.         } //lstrcmp szOID_RSA_signingTime
  497.     } // for
  498.  
  499.     return fReturn;
  500. }
  501.  
  502. BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo)
  503. {  
  504.     PCCERT_CONTEXT pCertContext = NULL;
  505.     BOOL fReturn = FALSE;
  506.     BOOL fResult;      
  507.     DWORD dwSize;  
  508.  
  509.     __try
  510.     {
  511.         *pCounterSignerInfo = NULL;
  512.  
  513.         // Loop through unathenticated attributes for
  514.         // szOID_RSA_counterSign OID.
  515.         for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
  516.         {
  517.             if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId,
  518.                          szOID_RSA_counterSign) == 0)
  519.             {
  520.                 // Get size of CMSG_SIGNER_INFO structure.
  521.                 fResult = CryptDecodeObject(ENCODING,
  522.                            PKCS7_SIGNER_INFO,
  523.                            pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
  524.                            pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
  525.                            0,
  526.                            NULL,
  527.                            &dwSize);
  528.                 if (!fResult)
  529.                 {
  530.                     _tprintf(_T("CryptDecodeObject failed with %x\n"),
  531.                         GetLastError());
  532.                     __leave;
  533.                 }
  534.  
  535.                 // Allocate memory for CMSG_SIGNER_INFO.
  536.                 *pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize);
  537.                 if (!*pCounterSignerInfo)
  538.                 {
  539.                     _tprintf(_T("Unable to allocate memory for timestamp info.\n"));
  540.                     __leave;
  541.                 }
  542.  
  543.                 // Decode and get CMSG_SIGNER_INFO structure
  544.                 // for timestamp certificate.
  545.                 fResult = CryptDecodeObject(ENCODING,
  546.                            PKCS7_SIGNER_INFO,
  547.                            pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
  548.                            pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
  549.                            0,
  550.                            (PVOID)*pCounterSignerInfo,
  551.                            &dwSize);
  552.                 if (!fResult)
  553.                 {
  554.                     _tprintf(_T("CryptDecodeObject failed with %x\n"),
  555.                         GetLastError());
  556.                     __leave;
  557.                 }
  558.  
  559.                 fReturn = TRUE;
  560.                
  561.                 break; // Break from for loop.
  562.             }          
  563.         }
  564.     }
  565.     __finally
  566.     {
  567.         // Clean up.
  568.         if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
  569.     }
  570.  
  571.     return fReturn;
  572. }