986 lines
31 KiB
C++
986 lines
31 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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
|