/*
 * An example of getting certificates from a signed EXE file using ImageHlp
 *
 * Copyright (c) 2009 Mounir IDRASSI <mounir.idrassi@idrix.fr>. All rights reserved.
 *
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE.
 * 
 */

#ifndef UNICODE
#define UNICODE
#define _UNICODE
#endif

#define _WIN32_WINNT 0x0500
#define WINVER       0x0500

#include <windows.h>
#include <Wincrypt.h>
#include <tchar.h>
#include <stdlib.h>
#include <Imagehlp.h>

#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "Imagehlp.lib")

void printCert(PCCERT_CONTEXT pCert, int dwIndex)
{
   DWORD dwStrType = CERT_X500_NAME_STR;
   DWORD dwCount = CertGetNameString(  pCert,
                                       CERT_NAME_RDN_TYPE,
                                       0,
                                       &dwStrType,
                                       NULL,
                                       0);
   if (dwCount)
   {
      LPTSTR szSubjectRDN = (LPTSTR) LocalAlloc(0, dwCount * sizeof(TCHAR));
      dwCount = CertGetNameString(pCert,
         CERT_NAME_RDN_TYPE,
         0,
         &dwStrType,
         szSubjectRDN,
         dwCount);
      if (dwCount)
      {
         _tprintf(_T("%d - Certificate Subject = %s\n"), dwIndex, szSubjectRDN);
      }

      LocalFree(szSubjectRDN);
   }   
}


int _tmain(int argc, _TCHAR* argv[])
{
   HANDLE hFile = NULL;
   DWORD dwCertsCount = 0;
   DWORD dwIndices[128];
   DWORD i;
   BOOL bStatus = FALSE;
   LPWIN_CERTIFICATE pCert = NULL;
   DWORD dwCertLen = 0;
   HCERTSTORE hStore;
	PCCERT_CONTEXT  pCertContext = NULL;   
	CERT_ENHKEY_USAGE keyUsage;
   char szCodeSigningOID[] = szOID_PKIX_KP_CODE_SIGNING;

   if (argc != 2)
   {
      _tprintf(_T("Usage: GetExeCertificates file_name\n"));
      return -1;
   }

   hFile = CreateFile(argv[1], FILE_READ_DATA , FILE_SHARE_READ, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL , NULL);
   if (INVALID_HANDLE_VALUE == hFile)
   {
      _tprintf(_T("CreateFile failed with error 0x%.8X\n"), GetLastError());
   }
   else
   {
      bStatus = ImageEnumerateCertificates(hFile, CERT_SECTION_TYPE_ANY, &dwCertsCount, dwIndices, 128);
      if (!bStatus)
      {
         _tprintf(_T("ImageEnumerateCertificates failed with error 0x%.8X\n"), GetLastError());
      }
      else if (dwCertsCount == 0)
      {
         _tprintf(_T("No certificates found on the file\n"));
      }
      else
      {
         for (i = 0; i < dwCertsCount; i++)
         {
            dwCertLen = 0;
            pCert = NULL;
            bStatus = ImageGetCertificateData(hFile, dwIndices[i], NULL, &dwCertLen);
            if (!bStatus && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
            {
               pCert = (LPWIN_CERTIFICATE) LocalAlloc(0, dwCertLen);
               bStatus = ImageGetCertificateData(hFile, dwIndices[i], pCert, &dwCertLen);
               if (!bStatus)
               {
                  _tprintf(_T("ImageGetCertificateData failed on index %d with error 0x%.8X\n"), dwIndices[i], GetLastError());
               }
               else
               {
                  CRYPT_DATA_BLOB p7Data;
                  p7Data.cbData = dwCertLen - sizeof(DWORD) - sizeof(WORD) - sizeof(WORD);
                  p7Data.pbData = pCert->bCertificate;
                  hStore = CertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, NULL, 0, &p7Data);
                  if (hStore)
                  {
                     int count = 0;
		               // populate the key usage structure with the Code Signing OID
		               keyUsage.cUsageIdentifier = 1;
		               keyUsage.rgpszUsageIdentifier = (LPSTR*) LocalAlloc(0, sizeof(LPSTR));
		               keyUsage.rgpszUsageIdentifier[0] = &szCodeSigningOID[0];

		               // Find certificates that contain the Code Signing Enhanced Key Usage
                     do
                     {
		                  pCertContext = CertFindCertificateInStore(hStore,
							               X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
							               CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
							               CERT_FIND_ENHKEY_USAGE,
							               &keyUsage,
							               pCertContext);
               		
		                  if (pCertContext)
		                  {        
                           count++;
                           printCert(pCertContext, count);
                        }
                     } while (pCertContext);

                     if (count == 0)
                     {
                        _tprintf(_T("No Code Signing certificates found\n"));
                     }
                     
                     LocalFree(keyUsage.rgpszUsageIdentifier);
                     CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
                  }
                  else
                  {
                     _tprintf(_T("CertOpenStore failed on index %d with error 0x%.8X\n"), dwIndices[i], GetLastError());
                  }
               }
               LocalFree(pCert);
            }
            else
            {
               _tprintf(_T("Unexpected response from ImageGetCertificateData on certificate with index = %d\n"), dwIndices[i]);
            }

         }
      }

      CloseHandle(hFile);
   }


   return 0;
}
