【问题标题】:Amended code to retrieve dual signature information from PE executable in Windows?修改代码以从 Windows 中的 PE 可执行文件中检索双重签名信息?
【发布时间】:2018-12-01 06:18:49
【问题描述】:

我一直在努力修改来自 Microsoft 的 this code sample,它显示了(有些过时的)如何从可执行文件中检索代码签名信息。它可以工作,但如果二进制文件是双重签名的,它不会检索信息。

所以我做了一些研究并尝试重写它以使其识别 Windows 中许多现代可执行文件中存在的双重签名。不幸的是,很少有(模糊的)建议可用(1)、(2),例如那些使用UnauthenticatedAttributesszOID_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 的 ProcMon 上运行它,我们可以从 Windows 资源管理器中看到它具有双重签名:

我的代码正确检索SHA1SHA256 签名:

但是,这是一个不起作用的例子。如果我在其他一些双重签名文件上运行它,比如Putty 可执行文件,它也有双重签名:

上面的代码两次检索相同的SHA256 证书:

知道为什么吗?

PS。这不仅仅发生在 Putty 的签名上。还有其他双重签名的可执行文件表现出相同的行为。

【问题讨论】:

    标签: c++ winapi digital-signature code-signing authenticode


    【解决方案1】:

    输出中的摘要算法与文件属性中显示的摘要算法不匹配的原因是,您在输出中显示的是签名证书链中第一个证书的摘要算法,而不是摘要算法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函数获得。然后,您应该在 while 循环中继续调用 CertFindCertificateInStore 以获取其他证书。您在代码中所做的是获取证书链中的第一个证书(使用CertFindCertificateInStore)并打印其签名摘要算法。您想要做的是获取并打印文件签名的摘要算法。您可以使用带有CMSG_SIGNER_INFO_PARAM 标志的CryptMsgGetParam 来做到这一点,并且您确实获得了它,只是不打印它。


    另一种思考方式是考虑MSG_SIGNER_INFOCERT_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     |
                +-------------+                    +-------------+
    

    【讨论】:

    • 嗯,我认为这就是我在 PrintDualSignatureInfo 函数中所做的。我不是吗?你能用代码说明你的意思吗?
    • 没有什么可显示的,这个答案只是为了解释你自己的代码中发生了什么。 main 和 PrintDualSignatureInfo 最终都调用了 3 参数 PrintCertificateInfo。您已经将 pSignerInfo 传递给该函数。所以只需将PrintCertificateInfo 重命名为PrintSignatureInfo(希望您从答案中理解原因)并打印pSignerInfo 中包含的摘要算法,例如:PrintSignatureAlgorithm(pSignerInfo-&gt;HashAlgorithm);,而不是打印证书的摘要算法。
    • 哦,哇,就这么简单。谢啦!我能再问你一个问题吗?出于好奇,用于procmon 的证书(在我上面的屏幕截图中)有两个不同的序列号,分别用于 sha1 和 sha256。但是 putty 的证书对于 sha1 和 sha256 具有相同的序列号。有什么诀窍?
    • 不是证书有两个不同的序列号,而是两个摘要用不同的证书签名。谁知道为什么?也许微软有一个政策,每个摘要必须用不同的证书签名;从技术上讲,没有什么可以阻止他们使用相同的证书进行签名,例如 putty。
    • 您知道,我正要发布更新的代码时,我意识到还有一件事需要介绍。 GetTimeStampSignerInfo 函数似乎无法检索所有类型的时间戳。例如,它适用于szOID_RSA_counterSign,但也可能有szOID_RFC3161_counterSign,在这种情况下,我可以使用CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_CONTENT_INFO, ...) 从中获取PCRYPT_CONTENT_INFO,但我不确定如何从那里获取PCMSG_SIGNER_INFO
    【解决方案2】:

    我想我已经成功了:

    这是更新后的代码。使用前请务必检查,如有任何问题请发表评论:

    #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());
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-24
      • 2012-03-12
      • 2013-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-16
      • 1970-01-01
      • 2011-08-02
      相关资源
      最近更新 更多