//+------------------------------------------------------------------------- // // 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