| /* |
| * Copyright 2008 Maarten Lankhorst |
| * |
| * 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 |
| */ |
| |
| #define NONAMELESSUNION |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "winreg.h" |
| #include "wincrypt.h" |
| #include "wintrust.h" |
| #include "winuser.h" |
| #include "objbase.h" |
| #include "cryptdlg.h" |
| #include "cryptuiapi.h" |
| #include "cryptres.h" |
| #include "wine/unicode.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg); |
| |
| static HINSTANCE hInstance; |
| |
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) |
| { |
| TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); |
| |
| switch (fdwReason) |
| { |
| case DLL_WINE_PREATTACH: |
| return FALSE; /* prefer native version */ |
| case DLL_PROCESS_ATTACH: |
| DisableThreadLibraryCalls(hinstDLL); |
| hInstance = hinstDLL; |
| break; |
| } |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * GetFriendlyNameOfCertA (CRYPTDLG.@) |
| */ |
| DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer, |
| DWORD cchBuffer) |
| { |
| return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, |
| pchBuffer, cchBuffer); |
| } |
| |
| /*********************************************************************** |
| * GetFriendlyNameOfCertW (CRYPTDLG.@) |
| */ |
| DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer, |
| DWORD cchBuffer) |
| { |
| return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, |
| pchBuffer, cchBuffer); |
| } |
| |
| /*********************************************************************** |
| * CertTrustInit (CRYPTDLG.@) |
| */ |
| HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData) |
| { |
| HRESULT ret = S_FALSE; |
| |
| TRACE("(%p)\n", pProvData); |
| |
| if (pProvData->padwTrustStepErrors && |
| !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT]) |
| ret = S_OK; |
| TRACE("returning %08x\n", ret); |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * CertTrustCertPolicy (CRYPTDLG.@) |
| */ |
| BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner) |
| { |
| FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner); |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * CertTrustCleanup (CRYPTDLG.@) |
| */ |
| HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData) |
| { |
| FIXME("(%p)\n", pProvData); |
| return E_NOTIMPL; |
| } |
| |
| static BOOL CRYPTDLG_CheckOnlineCRL(void) |
| { |
| static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e', |
| '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g', |
| 'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f', |
| '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9', |
| '7','9','3','8','7','e','a','}',0 }; |
| static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a', |
| 'g','s',0 }; |
| HKEY key; |
| BOOL ret = FALSE; |
| |
| if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key)) |
| { |
| DWORD type, flags, size = sizeof(flags); |
| |
| if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags, |
| &size) && type == REG_DWORD) |
| { |
| /* The flag values aren't defined in any header I'm aware of, but |
| * this value is well documented on the net. |
| */ |
| if (flags & 0x00010000) |
| ret = TRUE; |
| } |
| RegCloseKey(key); |
| } |
| return ret; |
| } |
| |
| /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it |
| * is. |
| */ |
| static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert) |
| { |
| BOOL ret; |
| BYTE hash[20]; |
| DWORD size = sizeof(hash); |
| |
| if ((ret = CertGetCertificateContextProperty(pCert, |
| CERT_SIGNATURE_HASH_PROP_ID, hash, &size))) |
| { |
| static const WCHAR disallowedW[] = |
| { 'D','i','s','a','l','l','o','w','e','d',0 }; |
| HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, |
| X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW); |
| |
| if (disallowed) |
| { |
| PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed, |
| X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL); |
| |
| if (found) |
| { |
| ret = FALSE; |
| CertFreeCertificateContext(found); |
| } |
| CertCloseStore(disallowed, 0); |
| } |
| } |
| return ret; |
| } |
| |
| static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus) |
| { |
| DWORD confidence = 0; |
| |
| confidence = 0; |
| if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)) |
| confidence |= CERT_CONFIDENCE_SIG; |
| if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID)) |
| confidence |= CERT_CONFIDENCE_TIME; |
| if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED)) |
| confidence |= CERT_CONFIDENCE_TIMENEST; |
| return confidence; |
| } |
| |
| static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data, |
| PCCERT_CHAIN_CONTEXT chain) |
| { |
| BOOL ret; |
| CRYPT_PROVIDER_SGNR signer; |
| PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0]; |
| DWORD i; |
| |
| memset(&signer, 0, sizeof(signer)); |
| signer.cbStruct = sizeof(signer); |
| ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer); |
| if (ret) |
| { |
| CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0, |
| FALSE, 0); |
| |
| if (sgnr) |
| { |
| sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus; |
| sgnr->pChainContext = CertDuplicateCertificateChain(chain); |
| } |
| else |
| ret = FALSE; |
| for (i = 0; ret && i < simpleChain->cElement; i++) |
| { |
| ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0, |
| simpleChain->rgpElement[i]->pCertContext); |
| if (ret) |
| { |
| CRYPT_PROVIDER_CERT *cert; |
| |
| if ((cert = WTHelperGetProvCertFromChain(sgnr, i))) |
| { |
| CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i]; |
| |
| cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence( |
| element->TrustStatus.dwErrorStatus); |
| cert->dwError = element->TrustStatus.dwErrorStatus; |
| cert->pChainElement = element; |
| } |
| else |
| ret = FALSE; |
| } |
| } |
| } |
| return ret; |
| } |
| |
| static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData( |
| CRYPT_PROVIDER_DATA *data) |
| { |
| CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL; |
| |
| /* This should always be true, but just in case the calling function is |
| * called directly: |
| */ |
| if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB && |
| data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject == |
| sizeof(CERT_VERIFY_CERTIFICATE_TRUST) && |
| data->pWintrustData->u.pBlob->pbMemObject) |
| pCert = (CERT_VERIFY_CERTIFICATE_TRUST *) |
| data->pWintrustData->u.pBlob->pbMemObject; |
| return pCert; |
| } |
| |
| static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert) |
| { |
| HCERTCHAINENGINE engine = NULL; |
| HCERTSTORE root = NULL, trust = NULL; |
| DWORD i; |
| |
| if (cert->cRootStores) |
| { |
| root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| if (root) |
| { |
| for (i = 0; i < cert->cRootStores; i++) |
| CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0); |
| } |
| } |
| if (cert->cTrustStores) |
| { |
| trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| if (trust) |
| { |
| for (i = 0; i < cert->cTrustStores; i++) |
| CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0); |
| } |
| } |
| if (cert->cRootStores || cert->cStores || cert->cTrustStores) |
| { |
| CERT_CHAIN_ENGINE_CONFIG config; |
| |
| memset(&config, 0, sizeof(config)); |
| config.cbSize = sizeof(config); |
| config.hRestrictedRoot = root; |
| config.hRestrictedTrust = trust; |
| config.cAdditionalStore = cert->cStores; |
| config.rghAdditionalStore = cert->rghstoreCAs; |
| config.hRestrictedRoot = root; |
| CertCreateCertificateChainEngine(&config, &engine); |
| CertCloseStore(root, 0); |
| CertCloseStore(trust, 0); |
| } |
| return engine; |
| } |
| |
| /*********************************************************************** |
| * CertTrustFinalPolicy (CRYPTDLG.@) |
| */ |
| HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data) |
| { |
| BOOL ret; |
| DWORD err = S_OK; |
| CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data); |
| |
| TRACE("(%p)\n", data); |
| |
| if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) |
| FIXME("unimplemented for UI choice %d\n", |
| data->pWintrustData->dwUIChoice); |
| if (pCert) |
| { |
| DWORD flags = 0; |
| CERT_CHAIN_PARA chainPara; |
| HCERTCHAINENGINE engine; |
| |
| memset(&chainPara, 0, sizeof(chainPara)); |
| chainPara.cbSize = sizeof(chainPara); |
| if (CRYPTDLG_CheckOnlineCRL()) |
| flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT; |
| engine = CRYPTDLG_MakeEngine(pCert); |
| GetSystemTimeAsFileTime(&data->sftSystemTime); |
| ret = CRYPTDLG_IsCertAllowed(pCert->pccert); |
| if (ret) |
| { |
| PCCERT_CHAIN_CONTEXT chain; |
| |
| ret = CertGetCertificateChain(engine, pCert->pccert, |
| &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain); |
| if (ret) |
| { |
| if (chain->cChain != 1) |
| { |
| FIXME("unimplemented for more than 1 simple chain\n"); |
| err = TRUST_E_SUBJECT_FORM_UNKNOWN; |
| ret = FALSE; |
| } |
| else if ((ret = CRYPTDLG_CopyChain(data, chain))) |
| { |
| if (CertVerifyTimeValidity(&data->sftSystemTime, |
| pCert->pccert->pCertInfo)) |
| { |
| ret = FALSE; |
| err = CERT_E_EXPIRED; |
| } |
| } |
| else |
| err = TRUST_E_SYSTEM_ERROR; |
| CertFreeCertificateChain(chain); |
| } |
| else |
| err = TRUST_E_SUBJECT_NOT_TRUSTED; |
| } |
| CertFreeCertificateChainEngine(engine); |
| } |
| else |
| { |
| ret = FALSE; |
| err = TRUST_E_NOSIGNATURE; |
| } |
| /* Oddly, native doesn't set the error in the trust step error location, |
| * probably because this action is more advisory than anything else. |
| * Instead it stores it as the final error, but the function "succeeds" in |
| * any case. |
| */ |
| if (!ret) |
| data->dwFinalError = err; |
| TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError); |
| return S_OK; |
| } |
| |
| /*********************************************************************** |
| * CertViewPropertiesA (CRYPTDLG.@) |
| */ |
| BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info) |
| { |
| CERT_VIEWPROPERTIES_STRUCT_W infoW; |
| LPWSTR title = NULL; |
| BOOL ret; |
| |
| TRACE("(%p)\n", info); |
| |
| memcpy(&infoW, info, sizeof(infoW)); |
| if (info->szTitle) |
| { |
| int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0); |
| |
| title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); |
| if (title) |
| { |
| MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len); |
| infoW.szTitle = title; |
| } |
| else |
| { |
| ret = FALSE; |
| goto error; |
| } |
| } |
| ret = CertViewPropertiesW(&infoW); |
| HeapFree(GetProcessHeap(), 0, title); |
| error: |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * CertViewPropertiesW (CRYPTDLG.@) |
| */ |
| BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info) |
| { |
| static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY; |
| CERT_VERIFY_CERTIFICATE_TRUST trust; |
| WINTRUST_BLOB_INFO blob; |
| WINTRUST_DATA wtd; |
| LONG err; |
| BOOL ret; |
| |
| TRACE("(%p)\n", info); |
| |
| memset(&trust, 0, sizeof(trust)); |
| trust.cbSize = sizeof(trust); |
| trust.pccert = info->pCertContext; |
| trust.cRootStores = info->cRootStores; |
| trust.rghstoreRoots = info->rghstoreRoots; |
| trust.cStores = info->cStores; |
| trust.rghstoreCAs = info->rghstoreCAs; |
| trust.cTrustStores = info->cTrustStores; |
| trust.rghstoreTrust = info->rghstoreTrust; |
| memset(&blob, 0, sizeof(blob)); |
| blob.cbStruct = sizeof(blob); |
| blob.cbMemObject = sizeof(trust); |
| blob.pbMemObject = (BYTE *)&trust; |
| memset(&wtd, 0, sizeof(wtd)); |
| wtd.cbStruct = sizeof(wtd); |
| wtd.dwUIChoice = WTD_UI_NONE; |
| wtd.dwUnionChoice = WTD_CHOICE_BLOB; |
| wtd.u.pBlob = &blob; |
| wtd.dwStateAction = WTD_STATEACTION_VERIFY; |
| err = WinVerifyTrust(NULL, &cert_action_verify, &wtd); |
| if (err == ERROR_SUCCESS) |
| { |
| CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo; |
| BOOL propsChanged = FALSE; |
| |
| memset(&uiInfo, 0, sizeof(uiInfo)); |
| uiInfo.dwSize = sizeof(uiInfo); |
| uiInfo.hwndParent = info->hwndParent; |
| uiInfo.dwFlags = |
| CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES; |
| uiInfo.szTitle = info->szTitle; |
| uiInfo.pCertContext = info->pCertContext; |
| uiInfo.cPurposes = info->cArrayPurposes; |
| uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes; |
| uiInfo.u.hWVTStateData = wtd.hWVTStateData; |
| uiInfo.fpCryptProviderDataTrustedUsage = TRUE; |
| uiInfo.cPropSheetPages = info->cArrayPropSheetPages; |
| uiInfo.rgPropSheetPages = info->arrayPropSheetPages; |
| uiInfo.nStartPage = info->nStartPage; |
| ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged); |
| wtd.dwStateAction = WTD_STATEACTION_CLOSE; |
| WinVerifyTrust(NULL, &cert_action_verify, &wtd); |
| } |
| else |
| ret = FALSE; |
| return ret; |
| } |
| |
| static BOOL CRYPT_FormatHexString(const BYTE *pbEncoded, DWORD cbEncoded, |
| WCHAR *str, DWORD *pcchStr) |
| { |
| BOOL ret; |
| DWORD charsNeeded; |
| |
| if (cbEncoded) |
| charsNeeded = (cbEncoded * 3); |
| else |
| charsNeeded = 1; |
| if (!str) |
| { |
| *pcchStr = charsNeeded; |
| ret = TRUE; |
| } |
| else if (*pcchStr < charsNeeded) |
| { |
| *pcchStr = charsNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| { |
| static const WCHAR fmt[] = { '%','0','2','x',' ',0 }; |
| static const WCHAR endFmt[] = { '%','0','2','x',0 }; |
| DWORD i; |
| LPWSTR ptr = str; |
| |
| *pcchStr = charsNeeded; |
| if (cbEncoded) |
| { |
| for (i = 0; i < cbEncoded; i++) |
| { |
| if (i < cbEncoded - 1) |
| ptr += sprintfW(ptr, fmt, pbEncoded[i]); |
| else |
| ptr += sprintfW(ptr, endFmt, pbEncoded[i]); |
| } |
| } |
| else |
| *ptr = 0; |
| ret = TRUE; |
| } |
| return ret; |
| } |
| |
| static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 }; |
| static const WCHAR colonCrlf[] = { ':','\r','\n',0 }; |
| static const WCHAR colonSpace[] = { ':',' ',0 }; |
| static const WCHAR crlf[] = { '\r','\n',0 }; |
| static const WCHAR commaSep[] = { ',',' ',0 }; |
| |
| static BOOL CRYPT_FormatCPS(DWORD dwCertEncodingType, |
| DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded, |
| WCHAR *str, DWORD *pcchStr) |
| { |
| BOOL ret; |
| DWORD size, charsNeeded = 1; |
| CERT_NAME_VALUE *cpsValue; |
| |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &cpsValue, &size))) |
| { |
| LPCWSTR sep; |
| DWORD sepLen; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| sep = crlf; |
| else |
| sep = commaSep; |
| |
| sepLen = strlenW(sep); |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 3 * strlenW(indent); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += cpsValue->Value.cbData / sizeof(WCHAR); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, (LPWSTR)cpsValue->Value.pbData); |
| str += cpsValue->Value.cbData / sizeof(WCHAR); |
| } |
| charsNeeded += sepLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, sep); |
| str += sepLen; |
| } |
| LocalFree(cpsValue); |
| if (!str) |
| *pcchStr = charsNeeded; |
| else if (*pcchStr < charsNeeded) |
| { |
| *pcchStr = charsNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| *pcchStr = charsNeeded; |
| } |
| return ret; |
| } |
| |
| static BOOL CRYPT_FormatUserNotice(DWORD dwCertEncodingType, |
| DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded, |
| WCHAR *str, DWORD *pcchStr) |
| { |
| BOOL ret; |
| DWORD size, charsNeeded = 1; |
| CERT_POLICY_QUALIFIER_USER_NOTICE *notice; |
| |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, |
| X509_PKIX_POLICY_QUALIFIER_USERNOTICE, pbEncoded, cbEncoded, |
| CRYPT_DECODE_ALLOC_FLAG, NULL, ¬ice, &size))) |
| { |
| static const WCHAR numFmt[] = { '%','d',0 }; |
| CERT_POLICY_QUALIFIER_NOTICE_REFERENCE *pNoticeRef = |
| notice->pNoticeReference; |
| LPCWSTR headingSep, sep; |
| DWORD headingSepLen, sepLen; |
| LPWSTR noticeRef, organization, noticeNum, noticeText; |
| DWORD noticeRefLen, organizationLen, noticeNumLen, noticeTextLen; |
| WCHAR noticeNumStr[11]; |
| |
| noticeRefLen = LoadStringW(hInstance, IDS_NOTICE_REF, |
| (LPWSTR)¬iceRef, 0); |
| organizationLen = LoadStringW(hInstance, IDS_ORGANIZATION, |
| (LPWSTR)&organization, 0); |
| noticeNumLen = LoadStringW(hInstance, IDS_NOTICE_NUM, |
| (LPWSTR)¬iceNum, 0); |
| noticeTextLen = LoadStringW(hInstance, IDS_NOTICE_TEXT, |
| (LPWSTR)¬iceText, 0); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| headingSep = colonCrlf; |
| sep = crlf; |
| } |
| else |
| { |
| headingSep = colonSpace; |
| sep = commaSep; |
| } |
| sepLen = strlenW(sep); |
| headingSepLen = strlenW(headingSep); |
| |
| if (pNoticeRef) |
| { |
| DWORD k; |
| LPCSTR src; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 3 * strlenW(indent); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += noticeRefLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| memcpy(str, noticeRef, noticeRefLen * sizeof(WCHAR)); |
| str += noticeRefLen; |
| } |
| charsNeeded += headingSepLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, headingSep); |
| str += headingSepLen; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 4 * strlenW(indent); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += organizationLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| memcpy(str, organization, organizationLen * sizeof(WCHAR)); |
| str += organizationLen; |
| } |
| charsNeeded += strlen(pNoticeRef->pszOrganization); |
| if (str && *pcchStr >= charsNeeded) |
| for (src = pNoticeRef->pszOrganization; src && *src; |
| src++, str++) |
| *str = *src; |
| charsNeeded += sepLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, sep); |
| str += sepLen; |
| } |
| for (k = 0; k < pNoticeRef->cNoticeNumbers; k++) |
| { |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 4 * strlenW(indent); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += noticeNumLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| memcpy(str, noticeNum, noticeNumLen * sizeof(WCHAR)); |
| str += noticeNumLen; |
| } |
| sprintfW(noticeNumStr, numFmt, k + 1); |
| charsNeeded += strlenW(noticeNumStr); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, noticeNumStr); |
| str += strlenW(noticeNumStr); |
| } |
| charsNeeded += sepLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, sep); |
| str += sepLen; |
| } |
| } |
| } |
| if (notice->pszDisplayText) |
| { |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 3 * strlenW(indent); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += noticeTextLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| memcpy(str, noticeText, noticeTextLen * sizeof(WCHAR)); |
| str += noticeTextLen; |
| } |
| charsNeeded += strlenW(notice->pszDisplayText); |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, notice->pszDisplayText); |
| str += strlenW(notice->pszDisplayText); |
| } |
| charsNeeded += sepLen; |
| if (str && *pcchStr >= charsNeeded) |
| { |
| strcpyW(str, sep); |
| str += sepLen; |
| } |
| } |
| LocalFree(notice); |
| if (!str) |
| *pcchStr = charsNeeded; |
| else if (*pcchStr < charsNeeded) |
| { |
| *pcchStr = charsNeeded; |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| *pcchStr = charsNeeded; |
| } |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * FormatVerisignExtension (CRYPTDLG.@) |
| */ |
| BOOL WINAPI FormatVerisignExtension(DWORD dwCertEncodingType, |
| DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, |
| LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, |
| DWORD *pcbFormat) |
| { |
| CERT_POLICIES_INFO *policies; |
| DWORD size; |
| BOOL ret = FALSE; |
| |
| if (!cbEncoded) |
| { |
| SetLastError(E_INVALIDARG); |
| return FALSE; |
| } |
| if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_POLICIES, |
| pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))) |
| { |
| static const WCHAR numFmt[] = { '%','d',0 }; |
| DWORD charsNeeded = 1; /* space for NULL terminator */ |
| LPCWSTR headingSep, sep; |
| DWORD headingSepLen, sepLen; |
| WCHAR policyNum[11], policyQualifierNum[11]; |
| LPWSTR certPolicy, policyId, policyQualifierInfo, policyQualifierId; |
| LPWSTR cps, userNotice, qualifier; |
| DWORD certPolicyLen, policyIdLen, policyQualifierInfoLen; |
| DWORD policyQualifierIdLen, cpsLen, userNoticeLen, qualifierLen; |
| DWORD i; |
| LPWSTR str = pbFormat; |
| |
| certPolicyLen = LoadStringW(hInstance, IDS_CERT_POLICY, |
| (LPWSTR)&certPolicy, 0); |
| policyIdLen = LoadStringW(hInstance, IDS_POLICY_ID, (LPWSTR)&policyId, |
| 0); |
| policyQualifierInfoLen = LoadStringW(hInstance, |
| IDS_POLICY_QUALIFIER_INFO, (LPWSTR)&policyQualifierInfo, 0); |
| policyQualifierIdLen = LoadStringW(hInstance, IDS_POLICY_QUALIFIER_ID, |
| (LPWSTR)&policyQualifierId, 0); |
| cpsLen = LoadStringW(hInstance, IDS_CPS, (LPWSTR)&cps, 0); |
| userNoticeLen = LoadStringW(hInstance, IDS_USER_NOTICE, |
| (LPWSTR)&userNotice, 0); |
| qualifierLen = LoadStringW(hInstance, IDS_QUALIFIER, |
| (LPWSTR)&qualifier, 0); |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| headingSep = colonCrlf; |
| sep = crlf; |
| } |
| else |
| { |
| headingSep = colonSpace; |
| sep = commaSep; |
| } |
| sepLen = strlenW(sep); |
| headingSepLen = strlenW(headingSep); |
| |
| for (i = 0; ret && i < policies->cPolicyInfo; i++) |
| { |
| CERT_POLICY_INFO *policy = &policies->rgPolicyInfo[i]; |
| DWORD j; |
| LPCSTR src; |
| |
| charsNeeded += 1; /* '['*/ |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| *str++ = '['; |
| sprintfW(policyNum, numFmt, i + 1); |
| charsNeeded += strlenW(policyNum); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, policyNum); |
| str += strlenW(policyNum); |
| } |
| charsNeeded += 1; /* ']'*/ |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| *str++ = ']'; |
| charsNeeded += certPolicyLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, certPolicy, certPolicyLen * sizeof(WCHAR)); |
| str += certPolicyLen; |
| } |
| charsNeeded += headingSepLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, headingSep); |
| str += headingSepLen; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += strlenW(indent); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += policyIdLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, policyId, policyIdLen * sizeof(WCHAR)); |
| str += policyIdLen; |
| } |
| charsNeeded += strlen(policy->pszPolicyIdentifier); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| for (src = policy->pszPolicyIdentifier; src && *src; |
| src++, str++) |
| *str = *src; |
| } |
| charsNeeded += sepLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, sep); |
| str += sepLen; |
| } |
| for (j = 0; j < policy->cPolicyQualifier; j++) |
| { |
| CERT_POLICY_QUALIFIER_INFO *qualifierInfo = |
| &policy->rgPolicyQualifier[j]; |
| DWORD sizeRemaining; |
| |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += strlenW(indent); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += 1; /* '['*/ |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| *str++ = '['; |
| charsNeeded += strlenW(policyNum); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, policyNum); |
| str += strlenW(policyNum); |
| } |
| charsNeeded += 1; /* ','*/ |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| *str++ = ','; |
| sprintfW(policyQualifierNum, numFmt, j + 1); |
| charsNeeded += strlenW(policyQualifierNum); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, policyQualifierNum); |
| str += strlenW(policyQualifierNum); |
| } |
| charsNeeded += 1; /* ']'*/ |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| *str++ = ']'; |
| charsNeeded += policyQualifierInfoLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, policyQualifierInfo, |
| policyQualifierInfoLen * sizeof(WCHAR)); |
| str += policyQualifierInfoLen; |
| } |
| charsNeeded += headingSepLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, headingSep); |
| str += headingSepLen; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 2 * strlenW(indent); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += policyQualifierIdLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, policyQualifierId, |
| policyQualifierIdLen * sizeof(WCHAR)); |
| str += policyQualifierIdLen; |
| } |
| if (!strcmp(qualifierInfo->pszPolicyQualifierId, |
| szOID_PKIX_POLICY_QUALIFIER_CPS)) |
| { |
| charsNeeded += cpsLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, cps, cpsLen * sizeof(WCHAR)); |
| str += cpsLen; |
| } |
| } |
| else if (!strcmp(qualifierInfo->pszPolicyQualifierId, |
| szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)) |
| { |
| charsNeeded += userNoticeLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, userNotice, userNoticeLen * sizeof(WCHAR)); |
| str += userNoticeLen; |
| } |
| } |
| else |
| { |
| charsNeeded += strlen(qualifierInfo->pszPolicyQualifierId); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| for (src = qualifierInfo->pszPolicyQualifierId; |
| src && *src; src++, str++) |
| *str = *src; |
| } |
| } |
| charsNeeded += sepLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, sep); |
| str += sepLen; |
| } |
| if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) |
| { |
| charsNeeded += 2 * strlenW(indent); |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| strcpyW(str, indent); |
| str += strlenW(indent); |
| } |
| } |
| charsNeeded += qualifierLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| memcpy(str, qualifier, qualifierLen * sizeof(WCHAR)); |
| str += qualifierLen; |
| } |
| charsNeeded += headingSepLen; |
| if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) |
| { |
| strcpyW(str, headingSep); |
| str += headingSepLen; |
| } |
| /* This if block is deliberately redundant with the same if |
| * block above, in order to keep the code more readable (the |
| * code flow follows the order in which the strings are output.) |
| */ |
| if (!strcmp(qualifierInfo->pszPolicyQualifierId, |
| szOID_PKIX_POLICY_QUALIFIER_CPS)) |
| { |
| if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR)) |
| { |
| /* Insufficient space, determine how much is needed. */ |
| ret = CRYPT_FormatCPS(dwCertEncodingType, |
| dwFormatStrType, qualifierInfo->Qualifier.pbData, |
| qualifierInfo->Qualifier.cbData, NULL, &size); |
| if (ret) |
| charsNeeded += size - 1; |
| } |
| else |
| { |
| sizeRemaining = *pcbFormat / sizeof(WCHAR); |
| sizeRemaining -= str - (LPWSTR)pbFormat; |
| ret = CRYPT_FormatCPS(dwCertEncodingType, |
| dwFormatStrType, qualifierInfo->Qualifier.pbData, |
| qualifierInfo->Qualifier.cbData, str, &sizeRemaining); |
| if (ret || GetLastError() == ERROR_MORE_DATA) |
| { |
| charsNeeded += sizeRemaining - 1; |
| str += sizeRemaining - 1; |
| } |
| } |
| } |
| else if (!strcmp(qualifierInfo->pszPolicyQualifierId, |
| szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)) |
| { |
| if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR)) |
| { |
| /* Insufficient space, determine how much is needed. */ |
| ret = CRYPT_FormatUserNotice(dwCertEncodingType, |
| dwFormatStrType, qualifierInfo->Qualifier.pbData, |
| qualifierInfo->Qualifier.cbData, NULL, &size); |
| if (ret) |
| charsNeeded += size - 1; |
| } |
| else |
| { |
| sizeRemaining = *pcbFormat / sizeof(WCHAR); |
| sizeRemaining -= str - (LPWSTR)pbFormat; |
| ret = CRYPT_FormatUserNotice(dwCertEncodingType, |
| dwFormatStrType, qualifierInfo->Qualifier.pbData, |
| qualifierInfo->Qualifier.cbData, str, &sizeRemaining); |
| if (ret || GetLastError() == ERROR_MORE_DATA) |
| { |
| charsNeeded += sizeRemaining - 1; |
| str += sizeRemaining - 1; |
| } |
| } |
| } |
| else |
| { |
| if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR)) |
| { |
| /* Insufficient space, determine how much is needed. */ |
| ret = CRYPT_FormatHexString( |
| qualifierInfo->Qualifier.pbData, |
| qualifierInfo->Qualifier.cbData, NULL, &size); |
| if (ret) |
| charsNeeded += size - 1; |
| } |
| else |
| { |
| sizeRemaining = *pcbFormat / sizeof(WCHAR); |
| sizeRemaining -= str - (LPWSTR)pbFormat; |
| ret = CRYPT_FormatHexString( |
| qualifierInfo->Qualifier.pbData, |
| qualifierInfo->Qualifier.cbData, str, &sizeRemaining); |
| if (ret || GetLastError() == ERROR_MORE_DATA) |
| { |
| charsNeeded += sizeRemaining - 1; |
| str += sizeRemaining - 1; |
| } |
| } |
| } |
| } |
| } |
| LocalFree(policies); |
| if (ret) |
| { |
| if (!pbFormat) |
| *pcbFormat = charsNeeded * sizeof(WCHAR); |
| else if (*pcbFormat < charsNeeded * sizeof(WCHAR)) |
| { |
| *pcbFormat = charsNeeded * sizeof(WCHAR); |
| SetLastError(ERROR_MORE_DATA); |
| ret = FALSE; |
| } |
| else |
| *pcbFormat = charsNeeded * sizeof(WCHAR); |
| } |
| } |
| return ret; |
| } |
| |
| #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4" |
| |
| /*********************************************************************** |
| * DllRegisterServer (CRYPTDLG.@) |
| */ |
| HRESULT WINAPI DllRegisterServer(void) |
| { |
| static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.', |
| 'd','l','l',0 }; |
| static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.', |
| 'd','l','l',0 }; |
| static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t', |
| 'I','n','i','t',0 }; |
| static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t', |
| 'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 }; |
| static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t', |
| 'C','e','r','t','P','o','l','i','c','y',0 }; |
| static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t', |
| 'F','i','n','a','l','P','o','l','i','c','y',0 }; |
| static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t', |
| 'C','l','e','a','n','u','p',0 }; |
| static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.', |
| 'd','l','l',0 }; |
| CRYPT_REGISTER_ACTIONID reg; |
| GUID guid = CERT_CERTIFICATE_ACTION_VERIFY; |
| HRESULT hr = S_OK; |
| |
| memset(®, 0, sizeof(reg)); |
| reg.cbStruct = sizeof(reg); |
| reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); |
| reg.sInitProvider.pwszDLLName = cryptdlg; |
| reg.sInitProvider.pwszFunctionName = certTrustInit; |
| reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); |
| reg.sCertificateProvider.pwszDLLName = wintrust; |
| reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust; |
| reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); |
| reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg; |
| reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy; |
| reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); |
| reg.sFinalPolicyProvider.pwszDLLName = cryptdlg; |
| reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy; |
| reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); |
| reg.sCleanupProvider.pwszDLLName = cryptdlg; |
| reg.sCleanupProvider.pwszFunctionName = certTrustCleanup; |
| if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, ®)) |
| hr = GetLastError(); |
| CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, |
| "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence"); |
| CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, |
| szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID"); |
| CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, |
| "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence"); |
| CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, |
| szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID"); |
| CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, |
| szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection"); |
| CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, |
| szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension"); |
| return hr; |
| } |
| |
| /*********************************************************************** |
| * DllUnregisterServer (CRYPTDLG.@) |
| */ |
| HRESULT WINAPI DllUnregisterServer(void) |
| { |
| GUID guid = CERT_CERTIFICATE_ACTION_VERIFY; |
| |
| WintrustRemoveActionID(&guid); |
| CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, |
| "1.3.6.1.4.1.311.16.1.1"); |
| CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, |
| szOID_MICROSOFT_Encryption_Key_Preference); |
| CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, |
| "1.3.6.1.4.1.311.16.1.1"); |
| CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, |
| szOID_MICROSOFT_Encryption_Key_Preference); |
| CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, |
| szOID_PKIX_KP_EMAIL_PROTECTION); |
| CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, |
| szOID_CERT_POLICIES); |
| return S_OK; |
| } |