//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1996 - 1999
//
//  File:       sigprov.cpp
//
//  Contents:   Microsoft Internet Security Authenticode Policy Provider
//
//  Functions:  SoftpubLoadSignature
//
//              *** local functions ***
//              _ExtractSigner
//              _ExtractCounterSigners
//              _HandleCertChoice
//              _HandleSignerChoice
//              _FindCertificate
//              _FindCounterSignersCert
//              _IsValidTimeStampCert
//
//  History:    05-Jun-1997 pberkman   created
//
//--------------------------------------------------------------------------

#include    "global.hxx"

BOOL _ExtractSigner(HCRYPTMSG hMsg, CRYPT_PROVIDER_DATA *pProvData,
                    int idxSigner);
BOOL _ExtractCounterSigners(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner);
HRESULT _HandleCertChoice(CRYPT_PROVIDER_DATA *pProvData);
HRESULT _HandleSignerChoice(CRYPT_PROVIDER_DATA *pProvData);
PCCERT_CONTEXT _FindCertificate(CRYPT_PROVIDER_DATA *pProvData, CERT_INFO *pCert);
PCCERT_CONTEXT _FindCounterSignersCert(CRYPT_PROVIDER_DATA *pProvData, 
                                            CERT_NAME_BLOB *psIssuer,
                                            CRYPT_INTEGER_BLOB *psSerial);
BOOL WINAPI _IsValidTimeStampCert(
    PCCERT_CONTEXT pCertContext,
    BOOL *pfVerisignTimeStampCert
    );

#ifdef CMS_PKCS7
BOOL _VerifyMessageSignatureWithChainPubKeyParaInheritance(
    IN CRYPT_PROVIDER_DATA *pProvData,
    IN DWORD dwSignerIndex,
    IN PCCERT_CONTEXT pSigner
    );

BOOL _VerifyCountersignatureWithChainPubKeyParaInheritance(
    IN CRYPT_PROVIDER_DATA *pProvData,
    IN PBYTE pbSignerInfo,
    IN DWORD cbSignerInfo,
    IN PBYTE pbSignerInfoCountersignature,
    IN DWORD cbSignerInfoCountersignature,
    IN PCCERT_CONTEXT pSigner
    );
#endif  // CMS_PKCS7

HRESULT SoftpubLoadSignature(CRYPT_PROVIDER_DATA *pProvData)
{
    if (!(pProvData->padwTrustStepErrors) ||
        (pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT] != ERROR_SUCCESS) ||
        (pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_INITPROV] != ERROR_SUCCESS))
    {
        return(S_FALSE);
    }

    switch (pProvData->pWintrustData->dwUnionChoice)
    {
        case WTD_CHOICE_CERT:
                    return(_HandleCertChoice(pProvData));

        case WTD_CHOICE_SIGNER:
                    return(_HandleSignerChoice(pProvData));

        case WTD_CHOICE_FILE:
        case WTD_CHOICE_CATALOG:
        case WTD_CHOICE_BLOB:
                    break;

        default:
                    pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NOSIGNATURE;
                    return(S_FALSE);
    }

    if (!(pProvData->hMsg))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV]   = TRUST_E_NOSIGNATURE;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_SIGNERCOUNT] = GetLastError();

        return(S_FALSE);
    }

    if ((_ISINSTRUCT(CRYPT_PROVIDER_DATA, pProvData->cbStruct, fRecallWithState)) &&
        (pProvData->fRecallWithState))
    {
        return(S_OK);
    }

    int                 i;
    DWORD               cbSize;
    DWORD               csSigners;
    CRYPT_PROVIDER_SGNR *pSgnr;
    CRYPT_PROVIDER_SGNR sSgnr;
    CRYPT_PROVIDER_CERT *pCert;


    cbSize = sizeof(DWORD);

    // signer count
    if (!(CryptMsgGetParam(pProvData->hMsg,
                           CMSG_SIGNER_COUNT_PARAM,
                           0,
                           &csSigners,
                           &cbSize)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NOSIGNATURE;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_SIGNERCOUNT] = GetLastError();

        return(S_FALSE);
    }

    if (csSigners == 0)
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NOSIGNATURE;

        return(S_FALSE);
    }

    for (i = 0; i < (int)csSigners; i++)
    {
        memset(&sSgnr, 0x00, sizeof(CRYPT_PROVIDER_SGNR));

        sSgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);

        if (!(pProvData->psPfns->pfnAddSgnr2Chain(pProvData, FALSE, i, &sSgnr)))
        {
            pProvData->dwError = GetLastError();
            pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;

            return(S_FALSE);
        }

        pSgnr = WTHelperGetProvSignerFromChain(pProvData, i, FALSE, 0);

        if (_ExtractSigner(pProvData->hMsg, pProvData, i))
        {
            memcpy(&pSgnr->sftVerifyAsOf, &pProvData->sftSystemTime, sizeof(FILETIME));

            _ExtractCounterSigners(pProvData, i);
        }
    }

    //
    //  verify the integrity of the signature(s)
    //
    for (i = 0; i < (int)pProvData->csSigners; i++)
    {
        pSgnr = WTHelperGetProvSignerFromChain(pProvData, i, FALSE, 0);
        pCert = WTHelperGetProvCertFromChain(pSgnr, 0);

        if (pSgnr->csCertChain > 0)
        {
#ifdef CMS_PKCS7
            if(!_VerifyMessageSignatureWithChainPubKeyParaInheritance(
                                pProvData,
                                i,
                                pCert->pCert))
#else
            if (!(CryptMsgControl(pProvData->hMsg, 
                                  0,
                                  CMSG_CTRL_VERIFY_SIGNATURE,
                                  pCert->pCert->pCertInfo)))
#endif  // CMS_PKCS7
            {
                if (pSgnr->dwError == 0)
                {
                    pSgnr->dwError = GetLastError();
                }
                
                pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV]   = TRUST_E_NOSIGNATURE;

                return(S_FALSE);
            }
        }
    }

    return(S_OK);
}


HRESULT _HandleCertChoice(CRYPT_PROVIDER_DATA *pProvData)
{
    if (!(pProvData->pWintrustData->pCert) ||
        !(WVT_IS_CBSTRUCT_GT_MEMBEROFFSET(WINTRUST_CERT_INFO, 
                                          pProvData->pWintrustData->pCert->cbStruct,
                                          pahStores)) ||
        !(pProvData->pWintrustData->pCert->psCertContext))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV]   = ERROR_INVALID_PARAMETER;
        
        return(S_FALSE);
    }

    //
    //  add the stores passed in by the client
    //
    for (int i = 0; i < (int)pProvData->pWintrustData->pCert->chStores; i++)
    {
        if (!(pProvData->psPfns->pfnAddStore2Chain(pProvData, 
                                                pProvData->pWintrustData->pCert->pahStores[i])))
        {
            pProvData->dwError = GetLastError();
            pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;

            return(S_FALSE);
        }
    }

    //
    //  add a dummy signer
    //
    CRYPT_PROVIDER_SGNR sSgnr;

    memset(&sSgnr, 0x00, sizeof(CRYPT_PROVIDER_SGNR));

    sSgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);

    memcpy(&sSgnr.sftVerifyAsOf, &pProvData->sftSystemTime, sizeof(FILETIME));

    if ((_ISINSTRUCT(WINTRUST_CERT_INFO, pProvData->pWintrustData->pCert->cbStruct, psftVerifyAsOf)) &&
        (pProvData->pWintrustData->pCert->psftVerifyAsOf))
    {
        memcpy(&sSgnr.sftVerifyAsOf, pProvData->pWintrustData->pCert->psftVerifyAsOf, sizeof(FILETIME));
    }

    if (!(pProvData->psPfns->pfnAddSgnr2Chain(pProvData, FALSE, 0, &sSgnr)))
    {
        pProvData->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;

        return(S_FALSE);
    }


    //
    //  add the "signer's" cert...
    //
    pProvData->psPfns->pfnAddCert2Chain(pProvData, 0, FALSE, 0, 
                                        pProvData->pWintrustData->pCert->psCertContext);

    return(ERROR_SUCCESS);

}

HRESULT _HandleSignerChoice(CRYPT_PROVIDER_DATA *pProvData)
{

    if (!(pProvData->pWintrustData->pSgnr) ||
        !(WVT_IS_CBSTRUCT_GT_MEMBEROFFSET(WINTRUST_SGNR_INFO, 
                                          pProvData->pWintrustData->pSgnr->cbStruct,
                                          pahStores)) ||
        !(pProvData->pWintrustData->pSgnr->psSignerInfo))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV]   = ERROR_INVALID_PARAMETER;
        
        return(S_FALSE);
    }

    int     i;

    if (1 < pProvData->pWintrustData->pCert->chStores &&
            0 == pProvData->chStores) 
        WTHelperOpenKnownStores(pProvData);

    //
    //  add the stores passed in by the client
    //
    for (i = 0; i < (int)pProvData->pWintrustData->pCert->chStores; i++)
    {
        if (!(pProvData->psPfns->pfnAddStore2Chain(pProvData, 
                                                pProvData->pWintrustData->pCert->pahStores[i])))
        {
            pProvData->dwError = GetLastError();
            pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;

            return(S_FALSE);
        }
    }

    CRYPT_PROVIDER_SGNR sSgnr;
    CRYPT_PROVIDER_SGNR *pSgnr;

    memset(&sSgnr, 0x00, sizeof(CRYPT_PROVIDER_SGNR));

    sSgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);

    if (!(sSgnr.psSigner = (CMSG_SIGNER_INFO *)pProvData->psPfns->pfnAlloc(sizeof(CMSG_SIGNER_INFO))))
    {
        pProvData->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;

        return(S_FALSE);
    }

    memcpy(sSgnr.psSigner, pProvData->pWintrustData->pSgnr->psSignerInfo, 
                sizeof(CMSG_SIGNER_INFO));

    memcpy(&sSgnr.sftVerifyAsOf, &pProvData->sftSystemTime, sizeof(FILETIME));

    if (!(pProvData->psPfns->pfnAddSgnr2Chain(pProvData, FALSE, 0, &sSgnr)))
    {
        pProvData->psPfns->pfnFree(sSgnr.psSigner);

        pProvData->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;

        return(S_FALSE);
    }

    if (!(pSgnr = WTHelperGetProvSignerFromChain(pProvData, 0, FALSE, 0)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = GetLastError();
        return(S_FALSE);
    }

    CERT_INFO       sCert;
    PCCERT_CONTEXT  pCertContext;

    memset(&sCert, 0x00, sizeof(CERT_INFO));

    sCert.Issuer.cbData         = pSgnr->psSigner->Issuer.cbData;
    sCert.Issuer.pbData         = pSgnr->psSigner->Issuer.pbData;

    sCert.SerialNumber.cbData   = pSgnr->psSigner->SerialNumber.cbData;
    sCert.SerialNumber.pbData   = pSgnr->psSigner->SerialNumber.pbData;

    if (!(pCertContext = _FindCertificate(pProvData, &sCert)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NO_SIGNER_CERT;
        return(FALSE);
    }

    pProvData->psPfns->pfnAddCert2Chain(pProvData, 0, FALSE, 0, pCertContext);

    _ExtractCounterSigners(pProvData, 0);

    return(ERROR_SUCCESS);
}

BOOL _ExtractSigner(HCRYPTMSG hMsg, CRYPT_PROVIDER_DATA *pProvData, int idxSigner)
{
    DWORD               cb;
    BYTE                *pb;
    CRYPT_PROVIDER_SGNR *pSgnr;
    PCCERT_CONTEXT      pCertContext;

    pSgnr = WTHelperGetProvSignerFromChain(pProvData, idxSigner, FALSE, 0);
    if (pSgnr == NULL)
    {
        return(FALSE);
    }

    //
    //  signer info
    //
    cb = 0;

    CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, idxSigner, NULL, &cb);

    if (cb == 0)
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NOSIGNATURE;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_SIGNERINFO] = GetLastError();
        return(FALSE);
    }

    if (!(pSgnr->psSigner = (CMSG_SIGNER_INFO *)pProvData->psPfns->pfnAlloc(cb)))
    {
        pProvData->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;
        return(FALSE);
    }

    memset(pSgnr->psSigner, 0x00, cb);

    if (!(CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, idxSigner, pSgnr->psSigner, &cb)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NOSIGNATURE;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_SIGNERINFO] = GetLastError();
        return(FALSE);
    }

    //
    //  cert info
    //
    cb = 0;

    CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, idxSigner, NULL, &cb);

    if (cb == 0)
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NO_SIGNER_CERT;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_SIGNERINFO] = GetLastError();
        return(FALSE);
    }

    if (!(pb = (BYTE *)pProvData->psPfns->pfnAlloc(cb)))
    {
        pProvData->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;
        return(FALSE);
    }

    memset(pb, 0x00, cb);

    if (!(CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, idxSigner, pb, &cb)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NO_SIGNER_CERT;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_SIGNERINFO] = GetLastError();

        pProvData->psPfns->pfnFree(pb);

        return(FALSE);
    }

    if (!(pCertContext = _FindCertificate(pProvData, (CERT_INFO *)pb)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_NO_SIGNER_CERT;
        pProvData->psPfns->pfnFree(pb);
        return(FALSE);
    }

    pProvData->psPfns->pfnFree(pb);

    pProvData->psPfns->pfnAddCert2Chain(pProvData, idxSigner, FALSE, 0, pCertContext);

    CertFreeCertificateContext(pCertContext);

    return(TRUE);
}

BOOL _ExtractCounterSigners(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner)
{
    if ((_ISINSTRUCT(CRYPT_PROVIDER_DATA, pProvData->cbStruct, fRecallWithState)) &&
        (pProvData->fRecallWithState))
    {
        return(TRUE);
    }

    CRYPT_ATTRIBUTE     *pAttr;
    PCCERT_CONTEXT      pCertContext;
    CRYPT_PROVIDER_SGNR *pSgnr;
    CRYPT_PROVIDER_SGNR sCS;
    CRYPT_PROVIDER_SGNR *pCS;
    CRYPT_PROVIDER_CERT *pCert;
    DWORD               cbSize;
    BOOL                fVerisignTimeStampCert = FALSE;

    pSgnr = WTHelperGetProvSignerFromChain(pProvData, idxSigner, FALSE, 0);
    if (pSgnr == NULL)
    {
        return(FALSE);
    }

    //
    //  counter signers are stored in the UN-authenticated attributes of the
    //  signer.
    //
    if ((pAttr = CertFindAttribute(szOID_RSA_counterSign,
                                   pSgnr->psSigner->UnauthAttrs.cAttr,
                                   pSgnr->psSigner->UnauthAttrs.rgAttr)) == NULL)
    {
        //
        //  no counter signature
        //
        return(FALSE);
    }


    memset(&sCS, 0x00, sizeof(CRYPT_PROVIDER_SGNR));
    sCS.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);

    memcpy(&sCS.sftVerifyAsOf, &pProvData->sftSystemTime, sizeof(FILETIME));

    if (!(pProvData->psPfns->pfnAddSgnr2Chain(pProvData, TRUE, idxSigner, &sCS)))
    {
        pProvData->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_SYSTEM_ERROR;
        return(FALSE);
    }

    pCS = WTHelperGetProvSignerFromChain(pProvData, idxSigner, TRUE, pSgnr->csCounterSigners - 1);

    // Crack the encoded signer

    if (!(TrustDecode(WVT_MODID_SOFTPUB, (BYTE **)&pCS->psSigner, &cbSize, 1024,
                      pProvData->dwEncoding, PKCS7_SIGNER_INFO, pAttr->rgValue[0].pbData, pAttr->rgValue[0].cbData,
                      CRYPT_DECODE_NOCOPY_FLAG)))
    {
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_COUNTER_SIGNER;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_COUNTERSIGINFO] = GetLastError();
        pCS->dwError = GetLastError();
        return(FALSE);
    }

    //
    //  counter signers cert
    //

    if (!(pCertContext = _FindCounterSignersCert(pProvData, 
                                                 &pCS->psSigner->Issuer,
                                                 &pCS->psSigner->SerialNumber)))
    {
        pCS->dwError = TRUST_E_NO_SIGNER_CERT;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_COUNTER_SIGNER;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_COUNTERSIGCERT] = GetLastError();
        return(FALSE);
    }


    pProvData->psPfns->pfnAddCert2Chain(pProvData, idxSigner, TRUE, 
                                      pProvData->pasSigners[idxSigner].csCounterSigners - 1, 
                                      pCertContext);

    CertFreeCertificateContext(pCertContext);

    pCert           = WTHelperGetProvCertFromChain(pCS, pCS->csCertChain - 1);
    pCertContext    = pCert->pCert;

    {
        //
        // Verify the counter's signature
        //

        BYTE *pbEncodedSigner = NULL;
        DWORD cbEncodedSigner;
        BOOL fResult;

        // First need to re-encode the Signer.
        fResult = CryptEncodeObjectEx(
            PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
            PKCS7_SIGNER_INFO,
            pSgnr->psSigner,
            CRYPT_ENCODE_ALLOC_FLAG,
            NULL,                       // pEncodePara
            (void *) &pbEncodedSigner,
            &cbEncodedSigner
            );

        if (fResult)
#ifdef CMS_PKCS7
            fResult = _VerifyCountersignatureWithChainPubKeyParaInheritance(
                                pProvData,
                                pbEncodedSigner,
                                cbEncodedSigner,
                                pAttr->rgValue[0].pbData,
                                pAttr->rgValue[0].cbData,
                                pCertContext
                                );
#else
            fResult = CryptMsgVerifyCountersignatureEncoded(
                                NULL,   //HCRYPTPROV
                                PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
                                pbEncodedSigner,
                                cbEncodedSigner,
                                pAttr->rgValue[0].pbData,
                                pAttr->rgValue[0].cbData,
                                pCertContext->pCertInfo
                                );
#endif  // CMS_PKCS7
        if (pbEncodedSigner)
            LocalFree((HLOCAL) pbEncodedSigner);

        if (!fResult)
        {
            pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_COUNTER_SIGNER;
            pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_COUNTERSIGINFO] = GetLastError();
            pCS->dwError = GetLastError();
            return(FALSE);
        }
    }

    //
    // see if the counter signer is a TimeStamp.
    //
    if (!(_IsValidTimeStampCert(pCertContext, &fVerisignTimeStampCert)))
    {
        return(TRUE);
    }

    // get the time
    if (!(pAttr = CertFindAttribute(szOID_RSA_signingTime, 
                                   pCS->psSigner->AuthAttrs.cAttr,
                                   pCS->psSigner->AuthAttrs.rgAttr)))
    {
        //
        //  not a time stamp...
        //
        return(TRUE);
    }

    //
    // the time stamp counter signature must have 1 value!
    //
    if (pAttr->cValue <= 0) 
    {
        //
        //  not a time stamp...
        //
        return(TRUE);
    }

    //
    // Crack the time stamp and get the file time.
    //
    FILETIME        ftHold;

    cbSize = sizeof(FILETIME);

    CryptDecodeObject(pProvData->dwEncoding, 
                      PKCS_UTC_TIME,
                      pAttr->rgValue[0].pbData, 
                      pAttr->rgValue[0].cbData,
                      0, 
                      &ftHold, 
                      &cbSize);

    if (cbSize == 0)
    {
        pCS->dwError = GetLastError();
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = TRUST_E_TIME_STAMP;
        pProvData->padwTrustStepErrors[TRUSTERROR_STEP_MSG_COUNTERSIGINFO] = GetLastError();
        return(FALSE);
    }
        

    //
    //  set the signer's verify date to the date in the time stamp!
    //
    memcpy(&pSgnr->sftVerifyAsOf, &ftHold, sizeof(FILETIME));

    // On 12-January-99 Keithv gave me the orders to change the
    // countersigning to use the current time
    //
    // On 25-January-99 backed out the above change
    //
    // On 28-August-99 changed to use the current time for all
    // countersigners excluding the first Verisign Time Stamp
    // certificate
    //
    // On 12-January-00 added a second Verisign Time Stamp cert to exclude
    //
    // On 05-April-01 changed back to W2K semantics. A time stamp chain
    // never expires.
    //
    memcpy(&pCS->sftVerifyAsOf, &ftHold, sizeof(FILETIME));
    

    pCS->dwSignerType |= SGNR_TYPE_TIMESTAMP;

    return(TRUE);
}

PCCERT_CONTEXT _FindCertificate(CRYPT_PROVIDER_DATA *pProvData, CERT_INFO *pCert)
{
    PCCERT_CONTEXT pCertContext;
    DWORD i;

    if (!(pCert))
    {
        return(NULL);
    }

    for (i = 0; i < pProvData->chStores; i++)
    {
        if (pCertContext = CertGetSubjectCertificateFromStore(pProvData->pahStores[i],
                                                                            pProvData->dwEncoding,
                                                                            pCert))
        {
            return(pCertContext);
        }
    }

    if (1 >= pProvData->chStores) {
        DWORD cOrig = pProvData->chStores;

        WTHelperOpenKnownStores(pProvData);
        for (i = cOrig; i < pProvData->chStores; i++) {
            if (pCertContext = CertGetSubjectCertificateFromStore(
                    pProvData->pahStores[i],
                    pProvData->dwEncoding,
                    pCert))
                return (pCertContext);
        }
    }

    return(NULL);
}

PCCERT_CONTEXT _FindCounterSignersCert(CRYPT_PROVIDER_DATA *pProvData, 
                                            CERT_NAME_BLOB *psIssuer,
                                            CRYPT_INTEGER_BLOB *psSerial)
{
    CERT_INFO       sCert;
    PCCERT_CONTEXT  pCertContext;
    DWORD           i;

    memset(&sCert, 0x00, sizeof(CERT_INFO));

    sCert.Issuer        = *psIssuer;
    sCert.SerialNumber  = *psSerial;

    for (i = 0; i < pProvData->chStores; i++)
    {
        if (pCertContext = CertGetSubjectCertificateFromStore(pProvData->pahStores[i],
                                                                            pProvData->dwEncoding,
                                                                            &sCert))
        {
            return(pCertContext);
        }
    }

    if (1 >= pProvData->chStores) {
        DWORD cOrig = pProvData->chStores;

        WTHelperOpenKnownStores(pProvData);
        for (i = cOrig; i < pProvData->chStores; i++) {
            if (pCertContext = CertGetSubjectCertificateFromStore(
                    pProvData->pahStores[i],
                    pProvData->dwEncoding,
                    &sCert))
                return (pCertContext);
        }
    }

    return(NULL);
}

#define SH1_HASH_LENGTH     20

BOOL WINAPI _IsValidTimeStampCert(
    PCCERT_CONTEXT pCertContext,
    BOOL *pfVerisignTimeStampCert
    )
{
    DWORD               cbSize;
    PCERT_ENHKEY_USAGE  pCertEKU;
    BYTE                baSignersThumbPrint[SH1_HASH_LENGTH];
    static BYTE         baVerisignTimeStampThumbPrint[SH1_HASH_LENGTH] =
                            { 0x38, 0x73, 0xB6, 0x99, 0xF3, 0x5B, 0x9C, 0xCC, 0x36, 0x62,
                              0xB6, 0x48, 0x3A, 0x96, 0xBD, 0x6E, 0xEC, 0x97, 0xCF, 0xB7 };

    static BYTE         baVerisignTimeStampThumbPrint2[SH1_HASH_LENGTH] = {
        0x9A, 0x3F, 0xF0, 0x5B, 0x42, 0x88, 0x52, 0x64,
        0x84, 0xA9, 0xFC, 0xB8, 0xBC, 0x14, 0x7D, 0x53,
        0xE1, 0x5A, 0x43, 0xBB
    };

    cbSize = SH1_HASH_LENGTH;

    if (!(CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, 
                                          &baSignersThumbPrint[0], &cbSize)))
    {
        return(FALSE);
    }

    //
    //  1st, check to see if it's Verisign's first timestamp certificate.  This one did NOT
    //  have the enhanced key usage in it.
    //
    //  12-January-00
    //  Also, check for the second Verisign timestamp certificate. Its only
    //  valid for 5 years. Will grandfather in to be valid forever.
    //
    if (memcmp(&baSignersThumbPrint[0], &baVerisignTimeStampThumbPrint[0],
            SH1_HASH_LENGTH) == 0
                    ||
        memcmp(&baSignersThumbPrint[0], &baVerisignTimeStampThumbPrint2[0],
            SH1_HASH_LENGTH) == 0)
    {
        *pfVerisignTimeStampCert = TRUE;
        return(TRUE);
    }
    else
    {
        *pfVerisignTimeStampCert = FALSE;
    }

    //
    //  see if the certificate has the proper enhanced key usage OID
    //
    cbSize = 0;

    CertGetEnhancedKeyUsage(pCertContext, 
                            CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
                            NULL,
                            &cbSize);

    if (cbSize == 0)
    {
        return(FALSE);
    }
                      
    if (!(pCertEKU = (PCERT_ENHKEY_USAGE)new BYTE[cbSize]))
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return(FALSE);
    }

    if (!(CertGetEnhancedKeyUsage(pCertContext,
                                  CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
                                  pCertEKU,
                                  &cbSize)))
    {
        delete pCertEKU;
        return(FALSE);
    }

    for (int i = 0; i < (int)pCertEKU->cUsageIdentifier; i++)
    {
        if (strcmp(pCertEKU->rgpszUsageIdentifier[i], szOID_KP_TIME_STAMP_SIGNING) == 0)
        {
            delete pCertEKU;
            return(TRUE);
        }

        if (strcmp(pCertEKU->rgpszUsageIdentifier[i], szOID_PKIX_KP_TIMESTAMP_SIGNING) == 0)
        {
            delete pCertEKU;
            return(TRUE);
        }
    }

    delete pCertEKU;

    return(FALSE);
}

#ifdef CMS_PKCS7

void _BuildChainForPubKeyParaInheritance(
    IN CRYPT_PROVIDER_DATA *pProvData,
    IN PCCERT_CONTEXT pSigner
    )
{
    PCCERT_CHAIN_CONTEXT pChainContext;
    CERT_CHAIN_PARA ChainPara;
    HCERTSTORE hAdditionalStore;

    if (0 == pProvData->chStores)
        hAdditionalStore = NULL;
    else if (1 < pProvData->chStores) {
        if (hAdditionalStore = CertOpenStore(
                CERT_STORE_PROV_COLLECTION,
                0,                      // dwEncodingType
                0,                      // hCryptProv
                0,                      // dwFlags
                NULL                    // pvPara
                )) {
            DWORD i;
            for (i = 0; i < pProvData->chStores; i++)
                CertAddStoreToCollection(
                    hAdditionalStore,
                    pProvData->pahStores[i],
                    CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
                    0                       // dwPriority
                    );
        }
    } else
        hAdditionalStore = CertDuplicateStore(pProvData->pahStores[0]);

    // Build a chain. Hopefully, the signer inherit's its public key
    // parameters from up the chain

    memset(&ChainPara, 0, sizeof(ChainPara));
    ChainPara.cbSize = sizeof(ChainPara);
    if (CertGetCertificateChain(
            NULL,                   // hChainEngine
            pSigner,
            NULL,                   // pTime
            hAdditionalStore,
            &ChainPara,
            CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
            NULL,                   // pvReserved
            &pChainContext
            ))
        CertFreeCertificateChain(pChainContext);
    if (hAdditionalStore)
        CertCloseStore(hAdditionalStore, 0);
}

//+-------------------------------------------------------------------------
//  If the verify signature fails with CRYPT_E_MISSING_PUBKEY_PARA,
//  build a certificate chain. Retry. Hopefully, the signer's
//  CERT_PUBKEY_ALG_PARA_PROP_ID property gets set while building the chain.
//--------------------------------------------------------------------------
BOOL _VerifyMessageSignatureWithChainPubKeyParaInheritance(
    IN CRYPT_PROVIDER_DATA *pProvData,
    IN DWORD dwSignerIndex,
    IN PCCERT_CONTEXT pSigner
    )
{
    CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA CtrlPara;

    memset(&CtrlPara, 0, sizeof(CtrlPara));
    CtrlPara.cbSize = sizeof(CtrlPara);
    // CtrlPara.hCryptProv =
    CtrlPara.dwSignerIndex = dwSignerIndex;
    CtrlPara.dwSignerType = CMSG_VERIFY_SIGNER_CERT;
    CtrlPara.pvSigner = (void *) pSigner;

    if (CryptMsgControl(
            pProvData->hMsg, 
            0,                              // dwFlags
            CMSG_CTRL_VERIFY_SIGNATURE_EX,
            &CtrlPara
            ))
        return TRUE;
    else if (CRYPT_E_MISSING_PUBKEY_PARA != GetLastError())
        return FALSE;
    else {
        _BuildChainForPubKeyParaInheritance(pProvData, pSigner);

        // Try again. Hopefully the above chain building updated the signer's
        // context property with the missing public key parameters
        return CryptMsgControl(
            pProvData->hMsg, 
            0,                              // dwFlags
            CMSG_CTRL_VERIFY_SIGNATURE_EX,
            &CtrlPara
            );
    }
}

//+-------------------------------------------------------------------------
//  If the verify counter signature fails with CRYPT_E_MISSING_PUBKEY_PARA,
//  build a certificate chain. Retry. Hopefully, the signer's
//  CERT_PUBKEY_ALG_PARA_PROP_ID property gets set while building the chain.
//--------------------------------------------------------------------------
BOOL _VerifyCountersignatureWithChainPubKeyParaInheritance(
    IN CRYPT_PROVIDER_DATA *pProvData,
    IN PBYTE pbSignerInfo,
    IN DWORD cbSignerInfo,
    IN PBYTE pbSignerInfoCountersignature,
    IN DWORD cbSignerInfoCountersignature,
    IN PCCERT_CONTEXT pSigner
    )
{
    if (CryptMsgVerifyCountersignatureEncodedEx(
            0,                                      // hCryptProv
            PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
            pbSignerInfo,
            cbSignerInfo,
            pbSignerInfoCountersignature,
            cbSignerInfoCountersignature,
            CMSG_VERIFY_SIGNER_CERT,
            (void *) pSigner,
            0,                                      // dwFlags
            NULL                                    // pvReserved
            ))
        return TRUE;
    else if (CRYPT_E_MISSING_PUBKEY_PARA != GetLastError())
        return FALSE;
    else {
        _BuildChainForPubKeyParaInheritance(pProvData, pSigner);

        // Try again. Hopefully the above chain building updated the signer's
        // context property with the missing public key parameters
        return CryptMsgVerifyCountersignatureEncodedEx(
                0,                                      // hCryptProv
                PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING,
                pbSignerInfo,
                cbSignerInfo,
                pbSignerInfoCountersignature,
                cbSignerInfoCountersignature,
                CMSG_VERIFY_SIGNER_CERT,
                (void *) pSigner,
                0,                                      // dwFlags
                NULL                                    // pvReserved
                );
    }
}

#endif  // CMS_PKCS7