Amended code to retrieve dual signature information from PE executable in Windows?

删除回忆录丶 提交于 2019-12-04 11:11:37

The reason the digest algorithm in your output does not match the digest algorithm shown in file properties is because what you are showing in your output is the digest algorithm of the first certificate in the certificate chain for the signature, not the digest algorithm of the Authenticode signature itself. It's like this:

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

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

The way Authenticode works is that first the file digest is computed using what is sometimes referred to (by Microsoft) as the "digest algorithm." That digest is then signed with a signing key whose certificate is provided. But that certificate itself is signed by computing its digest with what's referred to as "signature digest" and signing it with a key from a certificate higher up in the certificate chain and so on.

The first certificate in the certificate chain can be obtained with the CertFindCertificateInStore function. You are then supposed to keep invoking CertFindCertificateInStore in a while loop to get the other certificates. What you do in your code is obtain the first certificate in the certificate chain (with CertFindCertificateInStore) and print its signature digest algorithm. What you want to do instead is obtain and print the digest algorithm for the file signature. You can do that with CryptMsgGetParam with the CMSG_SIGNER_INFO_PARAM flag, and you do obtain it, you just don't print it.


Another way to think about this is in terms of the relationship between MSG_SIGNER_INFO and CERT_INFO. It's not a 1-1 relationship where the information needs to match. It's more like:

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

I think I got it to work:

Here's the updated code. Please make sure to check before you use it and post a comment if there are any issues:

#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());
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!