Изменен ли код для получения информации о двойной подписи из исполняемого файла PE в Windows?

Я боролся некоторое время, чтобы изменить этот пример кода от Microsoft, который показывает (несколько устаревший) способ получения информации о подписи кода из исполняемого файла. Он работает, но не получает информацию, если двоичный файл имеет двойную подпись.

Поэтому я провел некоторое исследование и попытался переписать его, чтобы он распознавал двойные подписи, которые присутствуют во многих современных исполняемых файлах в Windows. К сожалению, существует очень мало (туманных) предложений (1), (2), например, использовать UnauthenticatedAttributes а также szOID_NESTED_SIGNATURE (что бы это ни значило), но только для получения метки времени.

Поэтому я попытался переписать этот код Microsoft, и вот что я получил:

(Чтобы создать его, просто скопируйте его в консольный проект Visual Studio & изменить путь к файлу .exe Код, который имеет дело с двойными подписями, находится в PrintDualSignatureInfo() функция).

#include "stdafx.h"
//SOURCE:
//      https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables
//

#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <stdio.h>
#include <tchar.h>
#include <atlconv.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);
void PrintSignatureAlgorithm(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo);
void PrintDualSignatureInfo(PCMSG_SIGNER_INFO pSignerInfo);
void PrintCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertName);int main()
{
WCHAR szFileName[MAX_PATH];
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
BOOL fResult;
DWORD dwEncoding, dwContentType, dwFormatType;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
DWORD dwSignerInfo;
SPROG_PUBLISHERINFO ProgPubInfo;

ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo));
__try
{
LPCTSTR pExePath = L"C:\\Users\\UserName\\Downloads\\procmon.exe";  //works
//pExePath = L"C:\\Users\\UserName\\Downloads\\putty.exe";      //doesnt work

lstrcpynW(szFileName, pExePath, MAX_PATH);

// 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"));

// Print Signer certificate information.
PrintCertificateInfo(hStore, pSignerInfo, L"Signer Certificate");//Look for dual signature
PrintDualSignatureInfo(pSignerInfo);

}
__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 (hStore != NULL) CertCloseStore(hStore, 0);
if (hMsg != NULL) CryptMsgClose(hMsg);
}
return 0;
}void PrintCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertName)
{

if(hStore &&
pSignerInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
CERT_INFO CertInfo = {0};
PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
SYSTEMTIME st;

__try
{
// 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(L"%s:\n\n", pStrCertName);     //(_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
{
if (pCounterSignerInfo != NULL)
LocalFree(pCounterSignerInfo);

if (pCertContext != NULL)
CertFreeCertificateContext(pCertContext);
}
}

}void PrintDualSignatureInfo(PCMSG_SIGNER_INFO pSignerInfo)
{
if(pSignerInfo)
{

for(DWORD a = 0; a < pSignerInfo->UnauthAttrs.cAttr; a++)
{
if(pSignerInfo->UnauthAttrs.rgAttr[a].pszObjId &&
lstrcmpiA(pSignerInfo->UnauthAttrs.rgAttr[a].pszObjId, szOID_NESTED_SIGNATURE) == 0)
{
HCRYPTMSG hMsg = ::CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
if(hMsg)
{
if(::CryptMsgUpdate(hMsg,
pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->pbData,
pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->cbData,
TRUE))
{
DWORD dwSignerInfo = 0;
::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo);
if(dwSignerInfo != 0)
{
PCMSG_SIGNER_INFO pSignerInfo2 = (PCMSG_SIGNER_INFO)new (std::nothrow) BYTE[dwSignerInfo];
if(pSignerInfo2)
{
if(::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM,
0, (PVOID)pSignerInfo2, &dwSignerInfo))
{
CRYPT_DATA_BLOB p7Data;
p7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->cbData;
p7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->pbData;

HCERTSTORE hStore = ::CertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, &p7Data);
if(hStore)
{
// Print Signer certificate information.
PrintCertificateInfo(hStore, pSignerInfo2, L"Dual Signer Certificate");

//Close
::CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
}
}

//Free mem
delete[] pSignerInfo2;
pSignerInfo2 = NULL;
}
}
}

//Close message
::CryptMsgClose(hMsg);
}

}
}}

}void PrintSignatureAlgorithm(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo)
{
if(pSigAlgo &&
pSigAlgo->pszObjId)
{
PCCRYPT_OID_INFO pCOI = ::CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pSigAlgo->pszObjId, 0);
if(pCOI &&
pCOI->pwszName)
{
_tprintf(L"%s", pCOI->pwszName);
}
else
{
USES_CONVERSION;
_tprintf(L"%s",  A2W(pSigAlgo->pszObjId));
}
}
}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"));//Hashing algoriths
_tprintf(L"Signature Algorithm: ");
PrintSignatureAlgorithm(&pCertContext->pCertInfo->SignatureAlgorithm);
_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;
}

К сожалению, то, что я придумал, не всегда работает правильно при работе с двойными подписями.

Например, рабочий пример. Если я запускаю его на Sysiternal’s ProcMon, это имеет двойную подпись, как мы видим из проводника Windows:

введите описание изображения здесь

Мой код правильно получает оба SHA1 а также SHA256 подписи:

введите описание изображения здесь

Но вот нерабочий пример. Если я запускаю его на другом файле с двойной подписью, скажем, шпатлевка исполняемый файл, который также имеет двойную подпись:

введите описание изображения здесь

Код выше извлекает то же самое SHA256 подтверждаю дважды:

введите описание изображения здесь

Есть идеи почему?

PS. Это происходит не только с подписью Putty. Существуют другие исполняемые файлы с двойной подписью, которые демонстрируют такое же поведение.

2

Решение

Причина, по которой алгоритм дайджеста в ваших выходных данных не совпадает с алгоритмом дайджеста, показанным в свойствах файла, заключается в том, что в ваших выходных данных отображается алгоритм дайджеста первого сертификата в цепочке сертификатов для подписи, а не алгоритм дайджеста Authenticode. Сама подпись. Это вот так:

+-----------+          +-------------------+          +---------+
| Root Cert |  signs   | Intermediate Cert |  signs   | PE Data |
|-----------|=========>|-------------------|=========>|---------|
|  SHA256   |          |      SHA256       |          |  SHA1   |
+-----------+          +-------------------+          +---------+

^                          ^
|                          |
You are showing                But you
this                    want to show
this

Authenticode работает так, что сначала дайджест файла вычисляется с использованием того, что иногда называют (Microsoft) «алгоритмом дайджеста». Затем этот дайджест подписывается ключом подписи, сертификат которого предоставляется. Но сам этот сертификат подписывается путем вычисления его дайджеста с помощью так называемого «дайджеста подписи» и подписывания его ключом из сертификата, расположенного выше в цепочке сертификатов, и так далее.

Первый сертификат в цепочке сертификатов можно получить с помощью CertFindCertificateInStore функция. Затем вы должны продолжать призывать CertFindCertificateInStore в цикле while, чтобы получить другие сертификаты. В коде вы получаете первый сертификат в цепочке сертификатов (с CertFindCertificateInStore) и распечатать его алгоритм дайджеста подписи. Вместо этого вы хотите получить и распечатать алгоритм дайджеста для подписи файла. Вы можете сделать это с CryptMsgGetParam с CMSG_SIGNER_INFO_PARAM флаг, и вы получите его, вы просто не печатаете его.


Еще один способ думать об этом с точки зрения отношений между MSG_SIGNER_INFO а также CERT_INFO, Это не отношения 1-1, где информация должна соответствовать. Это больше похоже на:

+---------------+                  +---------------+
| SIGNER_INFO 1 |                  | SIGNER_INFO 2 |
|---------------|                  |---------------|
|     SHA1      |                  |    SHA256     |
+---------------+                  +---------------+
|                                  |
|   +-------------+                |   +-------------+
+---| CERT_INFO 1 |                +---| CERT_INFO 3 |
|-------------|                    |-------------|
|   SHA256    |                    |   SHA256    |
+-------------+                    +-------------+
|                                  |
+-------------+                    +-------------+
| CERT_INFO 2 |                    | CERT_INFO 4 |
|-------------|                    |-------------|
|    SHA1     |                    |    SHA1     |
+-------------+                    +-------------+
1

Другие решения

Я думаю, что я получил это на работу:

введите описание изображения здесь

Вот обновленный код. Пожалуйста, не забудьте проверить, прежде чем использовать его и оставить комментарий, если есть какие-либо проблемы:

#include <new>

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

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

#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)enum RESULT_FIND_CONTEXT{
RFC_FOUND_CONTEXT,
RFC_NO_CONTEXT,
};

enum RESULT_FIND_CERT_STORE{
RFCS_ERROR = -1,
RFCS_NONE = 0,
RFCS_FOUND_ONE = 1,
};void RetrieveDigitalSignatureInfo(const WCHAR* pFilePath);
void PrintProgramAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo);
RESULT_FIND_CONTEXT PrintCertificateInformation(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc = NULL);
void PrintCertContextDetails(PCCERT_CONTEXT pCertContext, DWORD dwNameOutputType, CRYPT_ALGORITHM_IDENTIFIER* pHashAlgo);
void PrintDigestAlgorithmName(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo);
BOOL PrintSignerDateTime(FILETIME* pftUtc);
int PrintSignerTimeStampDateTime(PCMSG_SIGNER_INFO pSignerInfo);
RESULT_FIND_CERT_STORE FindCertStoreByIndex(int iIndex, HCERTSTORE& hOutStore, CRYPT_DATA_BLOB* p7Data = NULL);
void PrintDualSignatureInformation(PCMSG_SIGNER_INFO pSignerInfo);
void FindAppropriateStoreAndPrintCertificateInformation(PCMSG_SIGNER_INFO pSignerInfo, CRYPT_DATA_BLOB* p7Data, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc = NULL);int _tmain(int argc, WCHAR* argv[])
{
LPCTSTR pExePath;

if(argc <= 1)
{
pExePath = L"C:\\Users\\UserName\\Downloads\\procmon.exe";
//pExePath = L"C:\\Users\\UserName\\Downloads\\putty.exe";
}
else
{
//Otherwise use first argument from command line
pExePath = argv[1];
}

_tprintf(L"File: %s\n", pExePath);

RetrieveDigitalSignatureInfo(pExePath);

return 0;
}
//The following functions were re-written from the following source to be able to
//retrieve dual-signatures from PE binaries:
//
//  https://support.microsoft.com/en-us/help/323809/how-to-get-information-from-authenticode-signed-executables

void RetrieveDigitalSignatureInfo(const WCHAR* pFilePath)
{
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;

if(CryptQueryObject(CERT_QUERY_OBJECT_FILE,
pFilePath,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
NULL,
NULL,
NULL,
&hStore,
&hMsg,
NULL))
{
//We must have at least one signer
DWORD dwCountSigners = 0;
DWORD dwcbSz = sizeof(dwCountSigners);
if(CryptMsgGetParam(hMsg, CMSG_SIGNER_COUNT_PARAM, 0, &dwCountSigners, &dwcbSz))
{
if(dwCountSigners != 0)
{
//Get Signer Information
dwcbSz = 0;
CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwcbSz);
if(dwcbSz)
{
PCMSG_SIGNER_INFO pSignerInfo = (PCMSG_SIGNER_INFO)new (std::nothrow) BYTE[dwcbSz];
if(pSignerInfo)
{
DWORD dwcbSz2 = dwcbSz;
if(CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, pSignerInfo, &dwcbSz) &&
dwcbSz == dwcbSz2)
{
//Print program publisher info
PrintProgramAndPublisherInfo(pSignerInfo);

_tprintf(L"\n");

//Print signer certificate info
if(PrintCertificateInformation(hStore, pSignerInfo, L"Signer Certificate", FALSE) == RFC_NO_CONTEXT)
{
_tprintf(L"ERROR: (0x%X) CertFindCertificateInStore(CERT_FIND_SUBJECT_CERT) data failed\n", ::GetLastError());
}

//Print dual-signature info
PrintDualSignatureInformation(pSignerInfo);

}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) data failed\n", ::GetLastError());

//Free mem
delete[] pSignerInfo;
pSignerInfo = NULL;
}
else
_tprintf(L"ERROR: (0x%X) new(PCMSG_SIGNER_INFO) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: Must have to least one signer\n");
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_COUNT_PARAM) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptQueryObject(CERT_QUERY_OBJECT_FILE) failed\n", ::GetLastError());//Clear up
if (hStore != NULL)
{
CertCloseStore(hStore, 0);
hStore = NULL;
}

if (hMsg != NULL)
{
CryptMsgClose(hMsg);
hMsg = NULL;
}

}

void PrintProgramAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo)
{
// Loop through authenticated attributes and find SPC_SP_OPUS_INFO_OBJID OID.
for(DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId)
{
if(lstrcmpA(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId, SPC_SP_OPUS_INFO_OBJID) == 0)
{
// Get Size of SPC_SP_OPUS_INFO structure.
PSPC_SP_OPUS_INFO pInfo = NULL;
DWORD dwcbSz = 0;

if(CryptDecodeObjectEx(ENCODING, SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&pInfo, &dwcbSz) &&
pInfo &&
dwcbSz)
{

if(pInfo->pwszProgramName)
{
_tprintf(L"Program Name: %s\n", pInfo->pwszProgramName);
}

if (pInfo->pPublisherInfo)
{
switch (pInfo->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
_tprintf(L"Publisher Link: %s\n", pInfo->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
_tprintf(L"Publisher Link: %s\n", pInfo->pPublisherInfo->pwszFile);
break;
}
}

if (pInfo->pMoreInfo)
{
switch (pInfo->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
_tprintf(L"MoreInfo Link: %s\n", pInfo->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
_tprintf(L"MoreInfo Link: %s\n", pInfo->pMoreInfo->pwszFile);
break;
}
}
}
else
_tprintf(L"ERROR: (0x%X) CryptDecodeObjectEx(SPC_SP_OPUS_INFO_OBJID) data failed\n", ::GetLastError());

if(pInfo)
{
::LocalFree(pInfo);
pInfo = NULL;
}
}
}
}

}RESULT_FIND_CONTEXT PrintCertificateInformation(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc)
{
CERT_INFO ci = {0};
ci.Issuer = pSignerInfo->Issuer;
ci.SerialNumber = pSignerInfo->SerialNumber;

PCCERT_CONTEXT pCertContext = NULL;

DWORD dwcbSz;

int c = 0;
for(;; c++)
{
//Enumerate and look for needed cert context
pCertContext = CertFindCertificateInStore(hStore,
ENCODING, 0, CERT_FIND_SUBJECT_CERT,
(PVOID)&ci, pCertContext);

if(!pCertContext)
{
break;
}

if(!c)
{
//Print Signer certificate information.
_tprintf(L"%s:\n", pStrCertDescription);
if(!bIsTimeStamp)
{
_tprintf(L"----------------\n");
}

_tprintf(L"\n");
}

//In case of a timestamp
if(bIsTimeStamp)
{
//Print time stamp
if(!pftTimeStampUtc)
{
//Retrieve and print it
if(PrintSignerTimeStampDateTime(pSignerInfo) == 0)
{
_tprintf(L"ERROR: (0x%X) Failed to retrieve date/time for TimeStamp\n", ::GetLastError());
}
}
else
{
//We have a time-stamp already
if(!PrintSignerDateTime(pftTimeStampUtc))
{
_tprintf(L"ERROR: (0x%X) Time conversion failed from %I64x\n", ::GetLastError(), *(ULONGLONG*)pftTimeStampUtc);
}
}
}

//Print subject name, issuer name, serial, signature algorithm
PrintCertContextDetails(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,      //Or use CERT_NAME_RDN_TYPE for a more detailed output
&pSignerInfo->HashAlgorithm);
volatile static char pmsgDoNotCopyAsIs[] =
"Please read & verify this code before you ""copy-and-paste it into your production project! ""https://stackoverflow.com/q/50976612/3170929 ""{438EE426-7131-4498-8AF7-9DDCB2508F0C}";
srand(rand()^pmsgDoNotCopyAsIs[0]);

_tprintf(L"\n");#ifndef szOID_RFC3161_counterSign
#define szOID_RFC3161_counterSign           "1.3.6.1.4.1.311.3.3.1"#endif

if(!bIsTimeStamp)
{
//Get time stamp certificate(s)
//Loop through unathenticated attributes and look for specific OIDs
for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
{
if(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId)
{
if(lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign) == 0)
{
//This is a legacy signature standard
PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
dwcbSz = 0;

if(CryptDecodeObjectEx(ENCODING, PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&pCounterSignerInfo, &dwcbSz) &&
pCounterSignerInfo &&
dwcbSz)
{
//Got one signature
if(PrintCertificateInformation(hStore, pCounterSignerInfo, L"TimeStamp Certificate", TRUE) == RFC_NO_CONTEXT)
{
_tprintf(L"ERROR: (0x%X) CertFindCertificateInStore(CERT_FIND_SUBJECT_CERT) data failed\n", ::GetLastError());
}

}
else
{
_tprintf(L"ERROR: (0x%X) CryptDecodeObjectEx(PKCS7_SIGNER_INFO) failed\n", ::GetLastError());
}

//Free mem
if(pCounterSignerInfo)
{
::LocalFree(pCounterSignerInfo);
pCounterSignerInfo = NULL;
}
}
else if(lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RFC3161_counterSign) == 0)
{
//Using an RFC3161 time stamp
if(pSignerInfo->UnauthAttrs.rgAttr[n].cValue != 0)
{
HCRYPTMSG hMsg = ::CryptMsgOpenToDecode(ENCODING, 0, 0, NULL, NULL, NULL);
if(hMsg)
{
if(::CryptMsgUpdate(hMsg,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->cbData,
TRUE))
{
dwcbSz = 0;
::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &dwcbSz);
if(dwcbSz != 0)
{
BYTE* pCntData = new (std::nothrow) BYTE[dwcbSz];
if(pCntData)
{
if(::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pCntData, &dwcbSz))
{

//Retrieve time stamp
FILETIME ftUtc = {0};

void* pTmData = NULL;
DWORD dwcbTmDataSz = 0;

struct Microsoft_forgot_to_document_me{
void* something_0[9];
FILETIME ftUtc;
};

#ifndef TIMESTAMP_INFO
#define TIMESTAMP_INFO                     ((LPCSTR) 80)
#endif

if(CryptDecodeObjectEx(ENCODING,    //X509_ASN_ENCODING,
TIMESTAMP_INFO,
pCntData,
dwcbSz,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&pTmData, &dwcbTmDataSz) &&
pTmData &&
dwcbTmDataSz >= sizeof(Microsoft_forgot_to_document_me))
{
ftUtc = ((Microsoft_forgot_to_document_me*)pTmData)->ftUtc;
}
else
_tprintf(L"ERROR: (0x%X) CryptDecodeObjectEx(RFC3161/TIMESTAMP_INFO) data failed\n", ::GetLastError());

if(pTmData)
{
::LocalFree(pTmData);
pTmData = NULL;
}//Try to get signer info
dwcbSz = 0;
::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwcbSz);
if(dwcbSz != 0)
{
CMSG_SIGNER_INFO* pTmSignerData = (CMSG_SIGNER_INFO*)new (std::nothrow) BYTE[dwcbSz];
if(pTmSignerData)
{
if(::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, pTmSignerData, &dwcbSz))
{
CRYPT_DATA_BLOB c7Data;
c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->pbData;
c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[n].rgValue->cbData;

//Try to locate the appropriate store
FindAppropriateStoreAndPrintCertificateInformation(pTmSignerData, &c7Data, L"TimeStamp Certificate", TRUE, &ftUtc);
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_SIGNER_INFO_PARAM) data failed\n", ::GetLastError());

//Free mem
delete[] pTmSignerData;
pTmSignerData = NULL;
}
else
_tprintf(L"ERROR: (0x%X) new(RFC3161) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_SIGNER_INFO_PARAM) failed\n", ::GetLastError());}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_CONTENT_PARAM) data failed\n", ::GetLastError());

//Free mem
delete[] pCntData;
pCntData = NULL;
}
else
_tprintf(L"ERROR: (0x%X) new(RFC3161) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(RFC3161/CMSG_CONTENT_PARAM) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgUpdate(RFC3161) failed\n", ::GetLastError());

//Free handle
::CryptMsgClose(hMsg);
hMsg = NULL;
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgOpenToDecode(ENCODING) failed\n", ::GetLastError());
}

}
}
}
}}

//Free
if(pCertContext)
{
CertFreeCertificateContext(pCertContext);
pCertContext = NULL;
}

return c != 0 ? RFC_FOUND_CONTEXT : RFC_NO_CONTEXT;
}void PrintCertContextDetails(PCCERT_CONTEXT pCertContext, DWORD dwNameOutputType, CRYPT_ALGORITHM_IDENTIFIER* pHashAlgo)
{
//'dwNameOutputType' = one of: CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_RDN_TYPE, etc. see CertGetNameString()
DWORD dwcbSz;
WCHAR* pBuff;

//Get subject name.
dwcbSz = CertGetNameString(pCertContext, dwNameOutputType, 0, NULL, NULL, 0);
if(dwcbSz != 0)
{
pBuff = new (std::nothrow) WCHAR[dwcbSz];
if(pBuff)
{
if(CertGetNameString(pCertContext, dwNameOutputType, 0, NULL, pBuff, dwcbSz) == dwcbSz)
{
_tprintf(L"Subject: %s\n", pBuff);
}
else
_tprintf(L"ERROR: (0x%X) CertGetNameString(subject) data failed\n", ::GetLastError());

//Free mem
delete[] pBuff;
pBuff = NULL;
}
else
_tprintf(L"ERROR: (0x%X) new CertGetNameString(subject) data failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CertGetNameString(subject) failed\n", ::GetLastError());//Issuer
dwcbSz = CertGetNameString(pCertContext, dwNameOutputType, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
if(dwcbSz != 0)
{
pBuff = new (std::nothrow) WCHAR[dwcbSz];
if(pBuff)
{
if(CertGetNameString(pCertContext, dwNameOutputType, CERT_NAME_ISSUER_FLAG, NULL, pBuff, dwcbSz) == dwcbSz)
{
_tprintf(L"Issuer: %s\n", pBuff);
}
else
_tprintf(L"ERROR: (0x%X) CertGetNameString(issuer) data failed\n", ::GetLastError());

//Free mem
delete[] pBuff;
pBuff = NULL;
}
else
_tprintf(L"ERROR: (0x%X) new CertGetNameString(issuer) data failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CertGetNameString(issuer) failed\n", ::GetLastError());//Print Serial Number.
_tprintf(_T("Serial Number: "));
dwcbSz = pCertContext->pCertInfo->SerialNumber.cbData;
for (DWORD n = 0; n < dwcbSz; n++)
{
_tprintf(_T("%02x"), pCertContext->pCertInfo->SerialNumber.pbData[dwcbSz - (n + 1)]);
}
_tprintf(_T("\n"));//Digest algorithm
_tprintf(L"Digest Algorithm: ");
PrintDigestAlgorithmName(pHashAlgo);
_tprintf(_T("\n"));

}void PrintDigestAlgorithmName(CRYPT_ALGORITHM_IDENTIFIER* pSigAlgo)
{
if(pSigAlgo &&
pSigAlgo->pszObjId)
{
PCCRYPT_OID_INFO pCOI = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pSigAlgo->pszObjId, 0);
if(pCOI &&
pCOI->pwszName)
{
_tprintf(L"%s", pCOI->pwszName);
}
else
{
USES_CONVERSION;
_tprintf(L"%s",  A2W(pSigAlgo->pszObjId));
}
}
}BOOL PrintSignerDateTime(FILETIME* pftUtc)
{
BOOL bRes = FALSE;

if(pftUtc)
{
//Convert to local time
FILETIME ftLoc = {0};
SYSTEMTIME stLoc = {0};

if(FileTimeToLocalFileTime(pftUtc, &ftLoc) &&
FileTimeToSystemTime(&ftLoc, &stLoc))
{
_tprintf(L"Date of TimeStamp : %02d/%02d/%04d %02d:%02d:%02d\n",
stLoc.wMonth,
stLoc.wDay,
stLoc.wYear,
stLoc.wHour,
stLoc.wMinute,
stLoc.wSecond);

bRes = TRUE;
}
}
else
::SetLastError(ERROR_INVALID_PARAMETER);

return bRes;
}

int PrintSignerTimeStampDateTime(PCMSG_SIGNER_INFO pSignerInfo)
{
int nCountTimeStamps = 0;

//Loop through authenticated attributes
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (pSignerInfo->AuthAttrs.rgAttr[n].pszObjId &&
lstrcmpA(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId, szOID_RSA_signingTime) == 0)
{
// Decode and get FILETIME structure.
FILETIME ftUtc = {0};
DWORD dwData = sizeof(ftUtc);

if(CryptDecodeObject(ENCODING, PKCS_UTC_TIME,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)&ftUtc, &dwData))
{
//Got time stamp
nCountTimeStamps++;

//And print it
if(!PrintSignerDateTime(&ftUtc))
{
_tprintf(L"ERROR: (0x%X) Time conversion failed from %I64x\n", ::GetLastError(), *(ULONGLONG*)&ftUtc);
}
}
else
{
_tprintf(L"ERROR: (0x%X) CryptDecodeObject(PKCS_UTC_TIME) failed\n", ::GetLastError());
}
}
}

return nCountTimeStamps;
}RESULT_FIND_CERT_STORE FindCertStoreByIndex(int iIndex, HCERTSTORE& hOutStore, CRYPT_DATA_BLOB* p7Data)
{
//'hOutStore' = receives cert store handle. If not NULL, make sure to release it by calling CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
//'p7Data' = used with index 0 only
hOutStore = NULL;

switch (iIndex)
{
case 0:
hOutStore = CertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, p7Data);
break;

case 1:
hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
"ROOT");
break;
case 2:
hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
"TRUST");
break;
case 3:
hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
"CA");
break;
case 4:
hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x10000,      // flags = 0x18001
"MY");
break;
case 5:
hOutStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0,
CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_READONLY_FLAG | 0x20000,      // flags = 0x28001
"SPC");
break;

default:
return RFCS_NONE;
}

return hOutStore ? RFCS_FOUND_ONE : RFCS_ERROR;
}void FindAppropriateStoreAndPrintCertificateInformation(PCMSG_SIGNER_INFO pSignerInfo, CRYPT_DATA_BLOB* p7Data, LPCTSTR pStrCertDescription, BOOL bIsTimeStamp, FILETIME* pftTimeStampUtc)
{
HCERTSTORE hStore = NULL;

//Try to locate the appropriate store
for(int i = 0;; i++)
{
if(hStore)
{
CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
hStore = NULL;
}

RESULT_FIND_CERT_STORE resFnd = FindCertStoreByIndex(i, hStore, p7Data);
if(resFnd == RFCS_FOUND_ONE)
{
//Try to retrieve info
if(PrintCertificateInformation(hStore, pSignerInfo, pStrCertDescription, bIsTimeStamp, pftTimeStampUtc) == RFC_FOUND_CONTEXT)
{
//All done
break;
}
}
else
{
//Stop the seatch
if(resFnd == RFCS_NONE)
{
//No context
_tprintf(L"ERROR: (0x%X) CertOpenStore(no_context) failed\n", ::GetLastError());
}
else
{
//Error
_tprintf(L"ERROR: (0x%X) CertOpenStore(%i) data failed\n", ::GetLastError(), i);
}

break;
}
}if(hStore)
{
::CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
hStore = NULL;
}

}void PrintDualSignatureInformation(PCMSG_SIGNER_INFO pSignerInfo)
{
//Loop through unauthenticated attributes
for(DWORD a = 0; a < pSignerInfo->UnauthAttrs.cAttr; a++)
{
#ifndef szOID_NESTED_SIGNATURE
#define szOID_NESTED_SIGNATURE              "1.3.6.1.4.1.311.2.4.1"#endif

//We need szOID_NESTED_SIGNATURE att
if(pSignerInfo->UnauthAttrs.rgAttr[a].pszObjId &&
lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[a].pszObjId, szOID_NESTED_SIGNATURE) == 0)
{
HCRYPTMSG hMsg = ::CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
if(hMsg)
{
if(::CryptMsgUpdate(hMsg,
pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->pbData,
pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->cbData,
TRUE))
{
DWORD dwSignerInfo = 0;
::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo);
if(dwSignerInfo != 0)
{
PCMSG_SIGNER_INFO pSignerInfo2 = (PCMSG_SIGNER_INFO)new (std::nothrow) BYTE[dwSignerInfo];
if(pSignerInfo2)
{
if(::CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM,
0, (PVOID)pSignerInfo2, &dwSignerInfo))
{
CRYPT_DATA_BLOB c7Data;
c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->cbData;
c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[a].rgValue->pbData;

//Try to locate the appropriate store & print from it
FindAppropriateStoreAndPrintCertificateInformation(pSignerInfo2, &c7Data, L"Dual Signer Certificate", FALSE);
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) data failed\n", ::GetLastError());

//Free mem
delete[] pSignerInfo2;
pSignerInfo2 = NULL;
}
else
_tprintf(L"ERROR: (0x%X) new(PCMSG_SIGNER_INFO) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed\n", ::GetLastError());
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgUpdate(dual-sig) failed\n", ::GetLastError());

//Close message
::CryptMsgClose(hMsg);
}
else
_tprintf(L"ERROR: (0x%X) CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) failed\n", ::GetLastError());
}
}
}
0

По вопросам рекламы [email protected]