/* * Copyright 2001 Rein Klazes * Copyright 2007 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include <stdarg.h> #define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "winerror.h" #include "winreg.h" #include "guiddef.h" #include "wintrust.h" #include "softpub.h" #include "mscat.h" #include "objbase.h" #include "winuser.h" #include "cryptdlg.h" #include "cryptuiapi.h" #include "wintrust_priv.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(wintrust); /* Utility functions */ void * WINAPI WINTRUST_Alloc(DWORD cb) { return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb); } static void* WINTRUST_ReAlloc(void *ptr, DWORD cb) __WINE_ALLOC_SIZE(2); static void* WINTRUST_ReAlloc(void *ptr, DWORD cb) { return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, cb); } void WINAPI WINTRUST_Free(void *p) { HeapFree(GetProcessHeap(), 0, p); } /*********************************************************************** * DllMain (WINTRUST.@) */ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { switch(reason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( inst ); break; } return TRUE; } /*********************************************************************** * TrustIsCertificateSelfSigned (WINTRUST.@) */ BOOL WINAPI TrustIsCertificateSelfSigned( PCCERT_CONTEXT cert ) { PCERT_EXTENSION ext; DWORD size; BOOL ret; TRACE("%p\n", cert); if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { CERT_AUTHORITY_KEY_ID2_INFO *info; ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info, &size); if (ret) { if (info->AuthorityCertIssuer.cAltEntry && info->AuthorityCertSerialNumber.cbData) { PCERT_ALT_NAME_ENTRY directoryName = NULL; DWORD i; for (i = 0; !directoryName && i < info->AuthorityCertIssuer.cAltEntry; i++) if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) directoryName = &info->AuthorityCertIssuer.rgAltEntry[i]; if (directoryName) { ret = CertCompareCertificateName(cert->dwCertEncodingType, &directoryName->u.DirectoryName, &cert->pCertInfo->Issuer) && CertCompareIntegerBlob(&info->AuthorityCertSerialNumber, &cert->pCertInfo->SerialNumber); } else { FIXME("no supported name type in authority key id2\n"); ret = FALSE; } } else if (info->KeyId.cbData) { ret = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); if (ret && size == info->KeyId.cbData) { LPBYTE buf = CryptMemAlloc(size); if (buf) { CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); ret = !memcmp(buf, info->KeyId.pbData, size); CryptMemFree(buf); } else ret = FALSE; } else ret = FALSE; } LocalFree(info); } } else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { CERT_AUTHORITY_KEY_ID_INFO *info; ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info, &size); if (ret) { if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) { ret = CertCompareCertificateName(cert->dwCertEncodingType, &info->CertIssuer, &cert->pCertInfo->Issuer) && CertCompareIntegerBlob(&info->CertSerialNumber, &cert->pCertInfo->SerialNumber); } else if (info->KeyId.cbData) { ret = CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); if (ret && size == info->KeyId.cbData) { LPBYTE buf = CryptMemAlloc(size); if (buf) { CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); ret = !memcmp(buf, info->KeyId.pbData, size); CryptMemFree(buf); } else ret = FALSE; } else ret = FALSE; } else ret = FALSE; LocalFree(info); } } else ret = CertCompareCertificateName(cert->dwCertEncodingType, &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); return ret; } typedef HRESULT (WINAPI *wintrust_step_func)(CRYPT_PROVIDER_DATA *data); struct wintrust_step { wintrust_step_func func; DWORD error_index; }; static DWORD WINTRUST_ExecuteSteps(const struct wintrust_step *steps, DWORD numSteps, CRYPT_PROVIDER_DATA *provData) { DWORD i, err = ERROR_SUCCESS; for (i = 0; !err && i < numSteps; i++) { err = steps[i].func(provData); if (err) err = provData->padwTrustStepErrors[steps[i].error_index]; } return err; } static CRYPT_PROVIDER_DATA *WINTRUST_AllocateProviderData(void) { CRYPT_PROVIDER_DATA *provData; provData = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_DATA)); if (!provData) goto oom; provData->cbStruct = sizeof(CRYPT_PROVIDER_DATA); provData->padwTrustStepErrors = WINTRUST_Alloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD)); if (!provData->padwTrustStepErrors) goto oom; provData->cdwTrustStepErrors = TRUSTERROR_MAX_STEPS; provData->u.pPDSip = WINTRUST_Alloc(sizeof(PROVDATA_SIP)); if (!provData->u.pPDSip) goto oom; provData->u.pPDSip->cbStruct = sizeof(PROVDATA_SIP); provData->psPfns = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_FUNCTIONS)); if (!provData->psPfns) goto oom; provData->psPfns->cbStruct = sizeof(CRYPT_PROVIDER_FUNCTIONS); return provData; oom: if (provData) { WINTRUST_Free(provData->padwTrustStepErrors); WINTRUST_Free(provData->u.pPDSip); WINTRUST_Free(provData->psPfns); WINTRUST_Free(provData); } return NULL; } /* Adds trust steps for each function in psPfns. Assumes steps has at least * 5 entries. Returns the number of steps added. */ static DWORD WINTRUST_AddTrustStepsFromFunctions(struct wintrust_step *steps, const CRYPT_PROVIDER_FUNCTIONS *psPfns) { DWORD numSteps = 0; if (psPfns->pfnInitialize) { steps[numSteps].func = psPfns->pfnInitialize; steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_WVTINIT; } if (psPfns->pfnObjectTrust) { steps[numSteps].func = psPfns->pfnObjectTrust; steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_OBJPROV; } if (psPfns->pfnSignatureTrust) { steps[numSteps].func = psPfns->pfnSignatureTrust; steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_SIGPROV; } if (psPfns->pfnCertificateTrust) { steps[numSteps].func = psPfns->pfnCertificateTrust; steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_CERTPROV; } if (psPfns->pfnFinalPolicy) { steps[numSteps].func = psPfns->pfnFinalPolicy; steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_POLICYPROV; } return numSteps; } static LONG WINTRUST_DefaultVerify(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { DWORD err = ERROR_SUCCESS, numSteps = 0; CRYPT_PROVIDER_DATA *provData; BOOL ret; struct wintrust_step verifySteps[5]; TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data); provData = WINTRUST_AllocateProviderData(); if (!provData) return ERROR_OUTOFMEMORY; ret = WintrustLoadFunctionPointers(actionID, provData->psPfns); if (!ret) { err = GetLastError(); goto error; } data->hWVTStateData = provData; provData->pWintrustData = data; if (hwnd == INVALID_HANDLE_VALUE) provData->hWndParent = GetDesktopWindow(); else provData->hWndParent = hwnd; provData->pgActionID = actionID; WintrustGetRegPolicyFlags(&provData->dwRegPolicySettings); numSteps = WINTRUST_AddTrustStepsFromFunctions(verifySteps, provData->psPfns); err = WINTRUST_ExecuteSteps(verifySteps, numSteps, provData); goto done; error: if (provData) { WINTRUST_Free(provData->padwTrustStepErrors); WINTRUST_Free(provData->u.pPDSip); WINTRUST_Free(provData->psPfns); WINTRUST_Free(provData); } done: TRACE("returning %08x\n", err); return err; } static LONG WINTRUST_DefaultClose(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { DWORD err = ERROR_SUCCESS; CRYPT_PROVIDER_DATA *provData = data->hWVTStateData; TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data); if (provData) { if (provData->psPfns->pfnCleanupPolicy) err = provData->psPfns->pfnCleanupPolicy(provData); WINTRUST_Free(provData->padwTrustStepErrors); WINTRUST_Free(provData->u.pPDSip); WINTRUST_Free(provData->psPfns); WINTRUST_Free(provData); data->hWVTStateData = NULL; } TRACE("returning %08x\n", err); return err; } static LONG WINTRUST_DefaultVerifyAndClose(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { LONG err; TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data); err = WINTRUST_DefaultVerify(hwnd, actionID, data); WINTRUST_DefaultClose(hwnd, actionID, data); TRACE("returning %08x\n", err); return err; } static LONG WINTRUST_PublishedSoftware(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { WINTRUST_DATA wintrust_data = { sizeof(wintrust_data), 0 }; /* Undocumented: the published software action is passed a path, * and pSIPClientData points to a WIN_TRUST_SUBJECT_FILE. */ LPWIN_TRUST_SUBJECT_FILE subjectFile = data->pSIPClientData; WINTRUST_FILE_INFO fileInfo = { sizeof(fileInfo), 0 }; TRACE("subjectFile->hFile: %p\n", subjectFile->hFile); TRACE("subjectFile->lpPath: %s\n", debugstr_w(subjectFile->lpPath)); fileInfo.pcwszFilePath = subjectFile->lpPath; fileInfo.hFile = subjectFile->hFile; wintrust_data.u.pFile = &fileInfo; wintrust_data.dwUnionChoice = WTD_CHOICE_FILE; wintrust_data.dwUIChoice = WTD_UI_NONE; return WINTRUST_DefaultVerifyAndClose(hwnd, actionID, &wintrust_data); } /* Sadly, the function to load the cert for the CERT_CERTIFICATE_ACTION_VERIFY * action is not stored in the registry and is located in wintrust, not in * cryptdlg along with the rest of the implementation (verified by running the * action with a native wintrust.dll.) */ static HRESULT WINAPI WINTRUST_CertVerifyObjTrust(CRYPT_PROVIDER_DATA *data) { BOOL ret; TRACE("(%p)\n", data); if (!data->padwTrustStepErrors) return S_FALSE; switch (data->pWintrustData->dwUnionChoice) { case WTD_CHOICE_BLOB: if (data->pWintrustData->u.pBlob && WVT_IS_CBSTRUCT_GT_MEMBEROFFSET(WINTRUST_BLOB_INFO, data->pWintrustData->u.pBlob->cbStruct, pbMemObject) && data->pWintrustData->u.pBlob->cbMemObject == sizeof(CERT_VERIFY_CERTIFICATE_TRUST) && data->pWintrustData->u.pBlob->pbMemObject) { CERT_VERIFY_CERTIFICATE_TRUST *pCert = (CERT_VERIFY_CERTIFICATE_TRUST *) data->pWintrustData->u.pBlob->pbMemObject; if (pCert->cbSize == sizeof(CERT_VERIFY_CERTIFICATE_TRUST) && pCert->pccert) { CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } }; DWORD i; SYSTEMTIME sysTime; /* Add a signer with nothing but the time to verify, so we can * add a cert to it */ GetSystemTime(&sysTime); SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf); ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer); if (!ret) goto error; ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0, pCert->pccert); if (!ret) goto error; for (i = 0; ret && i < pCert->cRootStores; i++) ret = data->psPfns->pfnAddStore2Chain(data, pCert->rghstoreRoots[i]); for (i = 0; ret && i < pCert->cStores; i++) ret = data->psPfns->pfnAddStore2Chain(data, pCert->rghstoreCAs[i]); for (i = 0; ret && i < pCert->cTrustStores; i++) ret = data->psPfns->pfnAddStore2Chain(data, pCert->rghstoreTrust[i]); } else { SetLastError(ERROR_INVALID_PARAMETER); ret = FALSE; } } else { SetLastError(ERROR_INVALID_PARAMETER); ret = FALSE; } break; default: FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice); SetLastError(ERROR_INVALID_PARAMETER); ret = FALSE; } error: if (!ret) data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] = GetLastError(); TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE, data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]); return ret ? S_OK : S_FALSE; } static LONG WINTRUST_CertVerify(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { DWORD err = ERROR_SUCCESS, numSteps = 0; CRYPT_PROVIDER_DATA *provData; BOOL ret; struct wintrust_step verifySteps[5]; TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data); provData = WINTRUST_AllocateProviderData(); if (!provData) return ERROR_OUTOFMEMORY; ret = WintrustLoadFunctionPointers(actionID, provData->psPfns); if (!ret) { err = GetLastError(); goto error; } if (!provData->psPfns->pfnObjectTrust) provData->psPfns->pfnObjectTrust = WINTRUST_CertVerifyObjTrust; /* Not sure why, but native skips the policy check */ provData->psPfns->pfnCertCheckPolicy = NULL; data->hWVTStateData = provData; provData->pWintrustData = data; if (hwnd == INVALID_HANDLE_VALUE) provData->hWndParent = GetDesktopWindow(); else provData->hWndParent = hwnd; provData->pgActionID = actionID; WintrustGetRegPolicyFlags(&provData->dwRegPolicySettings); numSteps = WINTRUST_AddTrustStepsFromFunctions(verifySteps, provData->psPfns); err = WINTRUST_ExecuteSteps(verifySteps, numSteps, provData); goto done; error: if (provData) { WINTRUST_Free(provData->padwTrustStepErrors); WINTRUST_Free(provData->u.pPDSip); WINTRUST_Free(provData->psPfns); WINTRUST_Free(provData); } done: TRACE("returning %08x\n", err); return err; } static LONG WINTRUST_CertVerifyAndClose(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { LONG err; TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data); err = WINTRUST_CertVerify(hwnd, actionID, data); WINTRUST_DefaultClose(hwnd, actionID, data); TRACE("returning %08x\n", err); return err; } static LONG WINTRUST_CertActionVerify(HWND hwnd, GUID *actionID, WINTRUST_DATA *data) { DWORD stateAction; LONG err = ERROR_SUCCESS; if (WVT_ISINSTRUCT(WINTRUST_DATA, data->cbStruct, dwStateAction)) stateAction = data->dwStateAction; else { TRACE("no dwStateAction, assuming WTD_STATEACTION_IGNORE\n"); stateAction = WTD_STATEACTION_IGNORE; } switch (stateAction) { case WTD_STATEACTION_IGNORE: err = WINTRUST_CertVerifyAndClose(hwnd, actionID, data); break; case WTD_STATEACTION_VERIFY: err = WINTRUST_CertVerify(hwnd, actionID, data); break; case WTD_STATEACTION_CLOSE: err = WINTRUST_DefaultClose(hwnd, actionID, data); break; default: FIXME("unimplemented for %d\n", data->dwStateAction); } return err; } static void dump_file_info(WINTRUST_FILE_INFO *pFile) { TRACE("%p\n", pFile); if (pFile) { TRACE("cbStruct: %d\n", pFile->cbStruct); TRACE("pcwszFilePath: %s\n", debugstr_w(pFile->pcwszFilePath)); TRACE("hFile: %p\n", pFile->hFile); TRACE("pgKnownSubject: %s\n", debugstr_guid(pFile->pgKnownSubject)); } } static void dump_catalog_info(WINTRUST_CATALOG_INFO *catalog) { TRACE("%p\n", catalog); if (catalog) { TRACE("cbStruct: %d\n", catalog->cbStruct); TRACE("dwCatalogVersion: %d\n", catalog->dwCatalogVersion); TRACE("pcwszCatalogFilePath: %s\n", debugstr_w(catalog->pcwszCatalogFilePath)); TRACE("pcwszMemberTag: %s\n", debugstr_w(catalog->pcwszMemberTag)); TRACE("pcwszMemberFilePath: %s\n", debugstr_w(catalog->pcwszMemberFilePath)); TRACE("hMemberFile: %p\n", catalog->hMemberFile); TRACE("pbCalculatedFileHash: %p\n", catalog->pbCalculatedFileHash); TRACE("cbCalculatedFileHash: %d\n", catalog->cbCalculatedFileHash); TRACE("pcCatalogContext: %p\n", catalog->pcCatalogContext); } } static void dump_blob_info(WINTRUST_BLOB_INFO *blob) { TRACE("%p\n", blob); if (blob) { TRACE("cbStruct: %d\n", blob->cbStruct); TRACE("gSubject: %s\n", debugstr_guid(&blob->gSubject)); TRACE("pcwszDisplayName: %s\n", debugstr_w(blob->pcwszDisplayName)); TRACE("cbMemObject: %d\n", blob->cbMemObject); TRACE("pbMemObject: %p\n", blob->pbMemObject); TRACE("cbMemSignedMsg: %d\n", blob->cbMemSignedMsg); TRACE("pbMemSignedMsg: %p\n", blob->pbMemSignedMsg); } } static void dump_sgnr_info(WINTRUST_SGNR_INFO *sgnr) { TRACE("%p\n", sgnr); if (sgnr) { TRACE("cbStruct: %d\n", sgnr->cbStruct); TRACE("pcwszDisplayName: %s\n", debugstr_w(sgnr->pcwszDisplayName)); TRACE("psSignerInfo: %p\n", sgnr->psSignerInfo); TRACE("chStores: %d\n", sgnr->chStores); } } static void dump_cert_info(WINTRUST_CERT_INFO *cert) { TRACE("%p\n", cert); if (cert) { TRACE("cbStruct: %d\n", cert->cbStruct); TRACE("pcwszDisplayName: %s\n", debugstr_w(cert->pcwszDisplayName)); TRACE("psCertContext: %p\n", cert->psCertContext); TRACE("chStores: %d\n", cert->chStores); TRACE("dwFlags: %08x\n", cert->dwFlags); TRACE("psftVerifyAsOf: %p\n", cert->psftVerifyAsOf); } } static void dump_wintrust_data(WINTRUST_DATA *data) { TRACE("%p\n", data); if (data) { TRACE("cbStruct: %d\n", data->cbStruct); TRACE("pPolicyCallbackData: %p\n", data->pPolicyCallbackData); TRACE("pSIPClientData: %p\n", data->pSIPClientData); TRACE("dwUIChoice: %d\n", data->dwUIChoice); TRACE("fdwRevocationChecks: %08x\n", data->fdwRevocationChecks); TRACE("dwUnionChoice: %d\n", data->dwUnionChoice); switch (data->dwUnionChoice) { case WTD_CHOICE_FILE: dump_file_info(data->u.pFile); break; case WTD_CHOICE_CATALOG: dump_catalog_info(data->u.pCatalog); break; case WTD_CHOICE_BLOB: dump_blob_info(data->u.pBlob); break; case WTD_CHOICE_SIGNER: dump_sgnr_info(data->u.pSgnr); break; case WTD_CHOICE_CERT: dump_cert_info(data->u.pCert); break; } TRACE("dwStateAction: %d\n", data->dwStateAction); TRACE("hWVTStateData: %p\n", data->hWVTStateData); TRACE("pwszURLReference: %s\n", debugstr_w(data->pwszURLReference)); TRACE("dwProvFlags: %08x\n", data->dwProvFlags); TRACE("dwUIContext: %d\n", data->dwUIContext); } } /*********************************************************************** * WinVerifyTrust (WINTRUST.@) * * Verifies an object by calling the specified trust provider. * * PARAMS * hwnd [I] Handle to a caller window. * ActionID [I] Pointer to a GUID that identifies the action to perform. * ActionData [I] Information used by the trust provider to verify the object. * * RETURNS * Success: Zero. * Failure: A TRUST_E_* error code. * * NOTES * Trust providers can be found at: * HKLM\SOFTWARE\Microsoft\Cryptography\Providers\Trust\ */ LONG WINAPI WinVerifyTrust( HWND hwnd, GUID *ActionID, LPVOID ActionData ) { static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47, 0x00,0xC0,0x4F,0xC2,0x95,0xEE } }; static const GUID published_software = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE; static const GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; static const GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY; static const GUID generic_chain_verify = WINTRUST_ACTION_GENERIC_CHAIN_VERIFY; static const GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY; LONG err = ERROR_SUCCESS; WINTRUST_DATA *actionData = ActionData; TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(ActionID), ActionData); dump_wintrust_data(ActionData); /* Support for known old-style callers: */ if (IsEqualGUID(ActionID, &published_software)) err = WINTRUST_PublishedSoftware(hwnd, ActionID, ActionData); else if (IsEqualGUID(ActionID, &cert_action_verify)) err = WINTRUST_CertActionVerify(hwnd, ActionID, ActionData); else { DWORD stateAction; /* Check known actions to warn of possible problems */ if (!IsEqualGUID(ActionID, &unknown) && !IsEqualGUID(ActionID, &generic_verify_v2) && !IsEqualGUID(ActionID, &generic_cert_verify) && !IsEqualGUID(ActionID, &generic_chain_verify)) WARN("unknown action %s, default behavior may not be right\n", debugstr_guid(ActionID)); if (WVT_ISINSTRUCT(WINTRUST_DATA, actionData->cbStruct, dwStateAction)) stateAction = actionData->dwStateAction; else { TRACE("no dwStateAction, assuming WTD_STATEACTION_IGNORE\n"); stateAction = WTD_STATEACTION_IGNORE; } switch (stateAction) { case WTD_STATEACTION_IGNORE: err = WINTRUST_DefaultVerifyAndClose(hwnd, ActionID, ActionData); break; case WTD_STATEACTION_VERIFY: err = WINTRUST_DefaultVerify(hwnd, ActionID, ActionData); break; case WTD_STATEACTION_CLOSE: err = WINTRUST_DefaultClose(hwnd, ActionID, ActionData); break; default: FIXME("unimplemented for %d\n", actionData->dwStateAction); } } TRACE("returning %08x\n", err); return err; } /*********************************************************************** * WinVerifyTrustEx (WINTRUST.@) */ HRESULT WINAPI WinVerifyTrustEx( HWND hwnd, GUID *ActionID, WINTRUST_DATA* ActionData ) { return WinVerifyTrust(hwnd, ActionID, ActionData); } /*********************************************************************** * WTHelperGetProvSignerFromChain (WINTRUST.@) */ CRYPT_PROVIDER_SGNR * WINAPI WTHelperGetProvSignerFromChain( CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSigner, DWORD idxCounterSigner) { CRYPT_PROVIDER_SGNR *sgnr; TRACE("(%p %d %d %d)\n", pProvData, idxSigner, fCounterSigner, idxCounterSigner); if (idxSigner >= pProvData->csSigners || !pProvData->pasSigners) return NULL; sgnr = &pProvData->pasSigners[idxSigner]; if (fCounterSigner) { if (idxCounterSigner >= sgnr->csCounterSigners || !sgnr->pasCounterSigners) return NULL; sgnr = &sgnr->pasCounterSigners[idxCounterSigner]; } TRACE("returning %p\n", sgnr); return sgnr; } /*********************************************************************** * WTHelperGetProvCertFromChain (WINTRUST.@) */ CRYPT_PROVIDER_CERT * WINAPI WTHelperGetProvCertFromChain( CRYPT_PROVIDER_SGNR *pSgnr, DWORD idxCert) { CRYPT_PROVIDER_CERT *cert; TRACE("(%p %d)\n", pSgnr, idxCert); if (idxCert >= pSgnr->csCertChain || !pSgnr->pasCertChain) return NULL; cert = &pSgnr->pasCertChain[idxCert]; TRACE("returning %p\n", cert); return cert; } CRYPT_PROVIDER_PRIVDATA *WINAPI WTHelperGetProvPrivateDataFromChain( CRYPT_PROVIDER_DATA* pProvData, GUID* pgProviderID) { CRYPT_PROVIDER_PRIVDATA *privdata = NULL; DWORD i; TRACE("(%p, %s)\n", pProvData, debugstr_guid(pgProviderID)); for (i = 0; i < pProvData->csProvPrivData; i++) if (IsEqualGUID(pgProviderID, &pProvData->pasProvPrivData[i].gProviderID)) { privdata = &pProvData->pasProvPrivData[i]; break; } return privdata; } /*********************************************************************** * WTHelperProvDataFromStateData (WINTRUST.@) */ CRYPT_PROVIDER_DATA * WINAPI WTHelperProvDataFromStateData(HANDLE hStateData) { TRACE("%p\n", hStateData); return hStateData; } /*********************************************************************** * WTHelperGetFileName(WINTRUST.@) */ LPCWSTR WINAPI WTHelperGetFileName(WINTRUST_DATA *data) { TRACE("%p\n",data); if (data->dwUnionChoice == WTD_CHOICE_FILE) return data->u.pFile->pcwszFilePath; else return NULL; } /*********************************************************************** * WTHelperGetFileHandle(WINTRUST.@) */ HANDLE WINAPI WTHelperGetFileHandle(WINTRUST_DATA *data) { TRACE("%p\n",data); if (data->dwUnionChoice == WTD_CHOICE_FILE) return data->u.pFile->hFile; else return INVALID_HANDLE_VALUE; } static BOOL WINAPI WINTRUST_enumUsages(PCCRYPT_OID_INFO pInfo, void *pvArg) { PCCRYPT_OID_INFO **usages = pvArg; DWORD cUsages; BOOL ret; if (!*usages) { cUsages = 0; *usages = WINTRUST_Alloc(2 * sizeof(PCCRYPT_OID_INFO)); } else { PCCRYPT_OID_INFO *ptr; /* Count the existing usages. * FIXME: make sure the new usage doesn't duplicate any in the list? */ for (cUsages = 0, ptr = *usages; *ptr; ptr++, cUsages++) ; *usages = WINTRUST_ReAlloc(*usages, (cUsages + 2) * sizeof(PCCRYPT_OID_INFO)); } if (*usages) { (*usages)[cUsages] = pInfo; (*usages)[cUsages + 1] = NULL; ret = TRUE; } else { SetLastError(ERROR_OUTOFMEMORY); ret = FALSE; } return ret; } /*********************************************************************** * WTHelperGetKnownUsages(WINTRUST.@) * * Enumerates the known enhanced key usages as an array of PCCRYPT_OID_INFOs. * * PARAMS * action [In] 1 => allocate and return known usages, 2 => free previously * allocated usages. * usages [In/Out] If action == 1, *usages is set to an array of * PCCRYPT_OID_INFO *. The array is terminated with a NULL * pointer. * If action == 2, *usages is freed. * * RETURNS * TRUE on success, FALSE on failure. */ BOOL WINAPI WTHelperGetKnownUsages(DWORD action, PCCRYPT_OID_INFO **usages) { BOOL ret; TRACE("(%d, %p)\n", action, usages); if (!usages) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (action == 1) { *usages = NULL; ret = CryptEnumOIDInfo(CRYPT_ENHKEY_USAGE_OID_GROUP_ID, 0, usages, WINTRUST_enumUsages); } else if (action == 2) { WINTRUST_Free(*usages); *usages = NULL; ret = TRUE; } else { WARN("unknown action %d\n", action); SetLastError(ERROR_INVALID_PARAMETER); ret = FALSE; } return ret; } static const WCHAR Software_Publishing[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\', 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'W','i','n','t','r','u','s','t','\\', 'T','r','u','s','t',' ','P','r','o','v','i','d','e','r','s','\\', 'S','o','f','t','w','a','r','e',' ', 'P','u','b','l','i','s','h','i','n','g',0 }; static const WCHAR State[] = { 'S','t','a','t','e',0 }; /*********************************************************************** * WintrustGetRegPolicyFlags (WINTRUST.@) */ void WINAPI WintrustGetRegPolicyFlags( DWORD* pdwPolicyFlags ) { HKEY key; LONG r; TRACE("%p\n", pdwPolicyFlags); *pdwPolicyFlags = 0; r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0, NULL, 0, KEY_READ, NULL, &key, NULL); if (!r) { DWORD size = sizeof(DWORD); r = RegQueryValueExW(key, State, NULL, NULL, (LPBYTE)pdwPolicyFlags, &size); RegCloseKey(key); if (r) { /* Failed to query, create and return default value */ *pdwPolicyFlags = WTPF_IGNOREREVOCATIONONTS | WTPF_OFFLINEOKNBU_COM | WTPF_OFFLINEOKNBU_IND | WTPF_OFFLINEOK_COM | WTPF_OFFLINEOK_IND; WintrustSetRegPolicyFlags(*pdwPolicyFlags); } } } /*********************************************************************** * WintrustSetRegPolicyFlags (WINTRUST.@) */ BOOL WINAPI WintrustSetRegPolicyFlags( DWORD dwPolicyFlags) { HKEY key; LONG r; TRACE("%x\n", dwPolicyFlags); r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL); if (!r) { r = RegSetValueExW(key, State, 0, REG_DWORD, (LPBYTE)&dwPolicyFlags, sizeof(DWORD)); RegCloseKey(key); } if (r) SetLastError(r); return r == ERROR_SUCCESS; } /* Utility functions */ BOOL WINAPI WINTRUST_AddStore(CRYPT_PROVIDER_DATA *data, HCERTSTORE store) { BOOL ret = FALSE; TRACE("(%p, %p)\n", data, store); if (data->chStores) data->pahStores = WINTRUST_ReAlloc(data->pahStores, (data->chStores + 1) * sizeof(HCERTSTORE)); else { data->pahStores = WINTRUST_Alloc(sizeof(HCERTSTORE)); data->chStores = 0; } if (data->pahStores) { data->pahStores[data->chStores++] = CertDuplicateStore(store); ret = TRUE; } else SetLastError(ERROR_OUTOFMEMORY); return ret; } BOOL WINAPI WINTRUST_AddSgnr(CRYPT_PROVIDER_DATA *data, BOOL fCounterSigner, DWORD idxSigner, CRYPT_PROVIDER_SGNR *sgnr) { BOOL ret = FALSE; TRACE("(%p, %d, %d, %p)\n", data, fCounterSigner, idxSigner, sgnr); if (sgnr->cbStruct > sizeof(CRYPT_PROVIDER_SGNR)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (fCounterSigner) { FIXME("unimplemented for counter signers\n"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (data->csSigners) data->pasSigners = WINTRUST_ReAlloc(data->pasSigners, (data->csSigners + 1) * sizeof(CRYPT_PROVIDER_SGNR)); else { data->pasSigners = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR)); data->csSigners = 0; } if (data->pasSigners) { if (idxSigner < data->csSigners) memmove(&data->pasSigners[idxSigner], &data->pasSigners[idxSigner + 1], (data->csSigners - idxSigner) * sizeof(CRYPT_PROVIDER_SGNR)); ret = TRUE; if (sgnr->cbStruct == sizeof(CRYPT_PROVIDER_SGNR)) { /* The PSDK says psSigner should be allocated using pfnAlloc, but * it doesn't say anything about ownership. Since callers are * internal, assume ownership is passed, and just store the * pointer. */ memcpy(&data->pasSigners[idxSigner], sgnr, sizeof(CRYPT_PROVIDER_SGNR)); } else memset(&data->pasSigners[idxSigner], 0, sizeof(CRYPT_PROVIDER_SGNR)); data->csSigners++; } else SetLastError(ERROR_OUTOFMEMORY); return ret; } BOOL WINAPI WINTRUST_AddCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner, BOOL fCounterSigner, DWORD idxCounterSigner, PCCERT_CONTEXT pCert2Add) { BOOL ret = FALSE; TRACE("(%p, %d, %d, %d, %p)\n", data, idxSigner, fCounterSigner, idxSigner, pCert2Add); if (fCounterSigner) { FIXME("unimplemented for counter signers\n"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (data->pasSigners[idxSigner].csCertChain) data->pasSigners[idxSigner].pasCertChain = WINTRUST_ReAlloc(data->pasSigners[idxSigner].pasCertChain, (data->pasSigners[idxSigner].csCertChain + 1) * sizeof(CRYPT_PROVIDER_CERT)); else { data->pasSigners[idxSigner].pasCertChain = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_CERT)); data->pasSigners[idxSigner].csCertChain = 0; } if (data->pasSigners[idxSigner].pasCertChain) { CRYPT_PROVIDER_CERT *cert = &data->pasSigners[idxSigner].pasCertChain[ data->pasSigners[idxSigner].csCertChain]; cert->cbStruct = sizeof(CRYPT_PROVIDER_CERT); cert->pCert = CertDuplicateCertificateContext(pCert2Add); data->pasSigners[idxSigner].csCertChain++; ret = TRUE; } else SetLastError(ERROR_OUTOFMEMORY); return ret; } BOOL WINAPI WINTRUST_AddPrivData(CRYPT_PROVIDER_DATA *data, CRYPT_PROVIDER_PRIVDATA *pPrivData2Add) { BOOL ret = FALSE; TRACE("(%p, %p)\n", data, pPrivData2Add); if (pPrivData2Add->cbStruct > sizeof(CRYPT_PROVIDER_PRIVDATA)) { SetLastError(ERROR_INVALID_PARAMETER); WARN("invalid struct size\n"); return FALSE; } if (data->csProvPrivData) data->pasProvPrivData = WINTRUST_ReAlloc(data->pasProvPrivData, (data->csProvPrivData + 1) * sizeof(CRYPT_PROVIDER_SGNR)); else { data->pasProvPrivData = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR)); data->csProvPrivData = 0; } if (data->pasProvPrivData) { DWORD i; for (i = 0; i < data->csProvPrivData; i++) if (IsEqualGUID(&pPrivData2Add->gProviderID, &data->pasProvPrivData[i])) break; data->pasProvPrivData[i] = *pPrivData2Add; if (i == data->csProvPrivData) data->csProvPrivData++; } else SetLastError(ERROR_OUTOFMEMORY); return ret; } /*********************************************************************** * OpenPersonalTrustDBDialog (WINTRUST.@) * * Opens the certificate manager dialog, showing only the stores that * contain trusted software publishers. * * PARAMS * hwnd [I] handle of parent window * * RETURNS * TRUE if the dialog could be opened, FALSE if not. */ BOOL WINAPI OpenPersonalTrustDBDialog(HWND hwnd) { CRYPTUI_CERT_MGR_STRUCT uiCertMgr; uiCertMgr.dwSize = sizeof(uiCertMgr); uiCertMgr.hwndParent = hwnd; uiCertMgr.dwFlags = CRYPTUI_CERT_MGR_PUBLISHER_TAB; uiCertMgr.pwszTitle = NULL; uiCertMgr.pszInitUsageOID = NULL; return CryptUIDlgCertMgr(&uiCertMgr); } /*********************************************************************** * WTHelperCertCheckValidSignature */ HRESULT WINAPI WTHelperCertCheckValidSignature(CRYPT_PROVIDER_DATA *pProvData) { FIXME("Stub\n"); return S_OK; } /*********************************************************************** * IsCatalogFile */ BOOL WINAPI IsCatalogFile(HANDLE hFile, WCHAR *pwszFileName) { static const GUID catGUID = { 0xDE351A43, 0x8E59, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; GUID guid; TRACE("(%p, %s)\n", hFile, debugstr_w(pwszFileName)); if (!CryptSIPRetrieveSubjectGuid(pwszFileName, hFile, &guid)) return FALSE; return IsEqualGUID(&guid, &catGUID); } /*********************************************************************** * FindCertsByIssuer */ HRESULT WINAPI FindCertsByIssuer(PCERT_CHAIN pCertChains, DWORD *pcbCertChains, DWORD *pcCertChains, BYTE* pbEncodedIssuerName, DWORD cbEncodedIssuerName, LPCWSTR pwszPurpose, DWORD dwKeySpec) { FIXME("(%p, %p, %p, %p, %d, %s, %d): stub\n", pCertChains, pcbCertChains, pcCertChains, pbEncodedIssuerName, cbEncodedIssuerName, debugstr_w(pwszPurpose), dwKeySpec); return E_FAIL; }