2 * Copyright 2008 Maarten Lankhorst
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
34 #include "cryptuiapi.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg);
39 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
41 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
45 case DLL_WINE_PREATTACH:
46 return FALSE; /* prefer native version */
47 case DLL_PROCESS_ATTACH:
48 DisableThreadLibraryCalls(hinstDLL);
50 case DLL_PROCESS_DETACH:
58 /***********************************************************************
59 * GetFriendlyNameOfCertA (CRYPTDLG.@)
61 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
64 return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
65 pchBuffer, cchBuffer);
68 /***********************************************************************
69 * GetFriendlyNameOfCertW (CRYPTDLG.@)
71 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
74 return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
75 pchBuffer, cchBuffer);
78 /***********************************************************************
79 * CertTrustInit (CRYPTDLG.@)
81 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
83 HRESULT ret = S_FALSE;
85 TRACE("(%p)\n", pProvData);
87 if (pProvData->padwTrustStepErrors &&
88 !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
90 TRACE("returning %08x\n", ret);
94 /***********************************************************************
95 * CertTrustCertPolicy (CRYPTDLG.@)
97 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
99 FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
103 /***********************************************************************
104 * CertTrustCleanup (CRYPTDLG.@)
106 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
108 FIXME("(%p)\n", pProvData);
112 static BOOL CRYPTDLG_CheckOnlineCRL(void)
114 static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e',
115 '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g',
116 'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f',
117 '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9',
118 '7','9','3','8','7','e','a','}',0 };
119 static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a',
124 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
126 DWORD type, flags, size = sizeof(flags);
128 if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
129 &size) && type == REG_DWORD)
131 /* The flag values aren't defined in any header I'm aware of, but
132 * this value is well documented on the net.
134 if (flags & 0x00010000)
142 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
145 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
149 DWORD size = sizeof(hash);
151 if ((ret = CertGetCertificateContextProperty(pCert,
152 CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
154 static const WCHAR disallowedW[] =
155 { 'D','i','s','a','l','l','o','w','e','d',0 };
156 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
157 X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW);
161 PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
162 X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
167 CertFreeCertificateContext(found);
169 CertCloseStore(disallowed, 0);
175 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
177 DWORD confidence = 0;
180 if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
181 confidence |= CERT_CONFIDENCE_SIG;
182 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
183 confidence |= CERT_CONFIDENCE_TIME;
184 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
185 confidence |= CERT_CONFIDENCE_TIMENEST;
189 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
190 PCCERT_CHAIN_CONTEXT chain)
193 CRYPT_PROVIDER_SGNR signer;
194 PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
197 memset(&signer, 0, sizeof(signer));
198 signer.cbStruct = sizeof(signer);
199 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
202 CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
207 sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
208 sgnr->pChainContext = CertDuplicateCertificateChain(chain);
212 for (i = 0; ret && i < simpleChain->cElement; i++)
214 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
215 simpleChain->rgpElement[i]->pCertContext);
218 CRYPT_PROVIDER_CERT *cert;
220 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
222 CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
224 cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
225 element->TrustStatus.dwErrorStatus);
226 cert->dwError = element->TrustStatus.dwErrorStatus;
227 cert->pChainElement = element;
237 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
238 CRYPT_PROVIDER_DATA *data)
240 CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
242 /* This should always be true, but just in case the calling function is
245 if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
246 data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject ==
247 sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
248 data->pWintrustData->u.pBlob->pbMemObject)
249 pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
250 data->pWintrustData->u.pBlob->pbMemObject;
254 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
256 HCERTCHAINENGINE engine = NULL;
257 HCERTSTORE root = NULL, trust = NULL;
260 if (cert->cRootStores)
262 root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
263 CERT_STORE_CREATE_NEW_FLAG, NULL);
266 for (i = 0; i < cert->cRootStores; i++)
267 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
270 if (cert->cTrustStores)
272 trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
273 CERT_STORE_CREATE_NEW_FLAG, NULL);
276 for (i = 0; i < cert->cTrustStores; i++)
277 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
280 if (cert->cRootStores || cert->cStores || cert->cTrustStores)
282 CERT_CHAIN_ENGINE_CONFIG config;
284 memset(&config, 0, sizeof(config));
285 config.cbSize = sizeof(config);
286 config.hRestrictedRoot = root;
287 config.hRestrictedTrust = trust;
288 config.cAdditionalStore = cert->cStores;
289 config.rghAdditionalStore = cert->rghstoreCAs;
290 config.hRestrictedRoot = root;
291 CertCreateCertificateChainEngine(&config, &engine);
292 CertCloseStore(root, 0);
293 CertCloseStore(trust, 0);
298 /***********************************************************************
299 * CertTrustFinalPolicy (CRYPTDLG.@)
301 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
305 CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
307 TRACE("(%p)\n", data);
309 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
310 FIXME("unimplemented for UI choice %d\n",
311 data->pWintrustData->dwUIChoice);
315 CERT_CHAIN_PARA chainPara;
316 HCERTCHAINENGINE engine;
318 memset(&chainPara, 0, sizeof(chainPara));
319 chainPara.cbSize = sizeof(chainPara);
320 if (CRYPTDLG_CheckOnlineCRL())
321 flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
322 engine = CRYPTDLG_MakeEngine(pCert);
323 GetSystemTimeAsFileTime(&data->sftSystemTime);
324 ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
327 PCCERT_CHAIN_CONTEXT chain;
329 ret = CertGetCertificateChain(engine, pCert->pccert,
330 &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
333 if (chain->cChain != 1)
335 FIXME("unimplemented for more than 1 simple chain\n");
336 err = TRUST_E_SUBJECT_FORM_UNKNOWN;
339 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
341 if (CertVerifyTimeValidity(&data->sftSystemTime,
342 pCert->pccert->pCertInfo))
345 err = CERT_E_EXPIRED;
349 err = TRUST_E_SYSTEM_ERROR;
350 CertFreeCertificateChain(chain);
353 err = TRUST_E_SUBJECT_NOT_TRUSTED;
355 CertFreeCertificateChainEngine(engine);
360 err = TRUST_E_NOSIGNATURE;
362 /* Oddly, native doesn't set the error in the trust step error location,
363 * probably because this action is more advisory than anything else.
364 * Instead it stores it as the final error, but the function "succeeds" in
368 data->dwFinalError = err;
369 TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
373 /***********************************************************************
374 * CertViewPropertiesA (CRYPTDLG.@)
376 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
378 CERT_VIEWPROPERTIES_STRUCT_W infoW;
382 TRACE("(%p)\n", info);
384 memcpy(&infoW, info, sizeof(infoW));
387 int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
389 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
392 MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
393 infoW.szTitle = title;
401 ret = CertViewPropertiesW(&infoW);
402 HeapFree(GetProcessHeap(), 0, title);
407 /***********************************************************************
408 * CertViewPropertiesW (CRYPTDLG.@)
410 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
412 static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
413 CERT_VERIFY_CERTIFICATE_TRUST trust;
414 WINTRUST_BLOB_INFO blob;
419 TRACE("(%p)\n", info);
421 memset(&trust, 0, sizeof(trust));
422 trust.cbSize = sizeof(trust);
423 trust.pccert = info->pCertContext;
424 trust.cRootStores = info->cRootStores;
425 trust.rghstoreRoots = info->rghstoreRoots;
426 trust.cStores = info->cStores;
427 trust.rghstoreCAs = info->rghstoreCAs;
428 trust.cTrustStores = info->cTrustStores;
429 trust.rghstoreTrust = info->rghstoreTrust;
430 memset(&blob, 0, sizeof(blob));
431 blob.cbStruct = sizeof(blob);
432 blob.cbMemObject = sizeof(trust);
433 blob.pbMemObject = (BYTE *)&trust;
434 memset(&wtd, 0, sizeof(wtd));
435 wtd.cbStruct = sizeof(wtd);
436 wtd.dwUIChoice = WTD_UI_NONE;
437 wtd.dwUnionChoice = WTD_CHOICE_BLOB;
439 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
440 err = WinVerifyTrust(NULL, &cert_action_verify, &wtd);
441 if (err == ERROR_SUCCESS)
443 CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
444 BOOL propsChanged = FALSE;
446 memset(&uiInfo, 0, sizeof(uiInfo));
447 uiInfo.dwSize = sizeof(uiInfo);
448 uiInfo.hwndParent = info->hwndParent;
450 CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES;
451 uiInfo.szTitle = info->szTitle;
452 uiInfo.pCertContext = info->pCertContext;
453 uiInfo.cPurposes = info->cArrayPurposes;
454 uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes;
455 uiInfo.u.hWVTStateData = wtd.hWVTStateData;
456 uiInfo.fpCryptProviderDataTrustedUsage = TRUE;
457 uiInfo.cPropSheetPages = info->cArrayPropSheetPages;
458 uiInfo.rgPropSheetPages = info->arrayPropSheetPages;
459 uiInfo.nStartPage = info->nStartPage;
460 ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged);
461 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
462 WinVerifyTrust(NULL, &cert_action_verify, &wtd);
469 #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4"
471 /***********************************************************************
472 * DllRegisterServer (CRYPTDLG.@)
474 HRESULT WINAPI DllRegisterServer(void)
476 static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
478 static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
480 static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
482 static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
483 'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
484 static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
485 'C','e','r','t','P','o','l','i','c','y',0 };
486 static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
487 'F','i','n','a','l','P','o','l','i','c','y',0 };
488 static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
489 'C','l','e','a','n','u','p',0 };
490 static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.',
492 CRYPT_REGISTER_ACTIONID reg;
493 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
496 memset(®, 0, sizeof(reg));
497 reg.cbStruct = sizeof(reg);
498 reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
499 reg.sInitProvider.pwszDLLName = cryptdlg;
500 reg.sInitProvider.pwszFunctionName = certTrustInit;
501 reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
502 reg.sCertificateProvider.pwszDLLName = wintrust;
503 reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
504 reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
505 reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
506 reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
507 reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
508 reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
509 reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
510 reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
511 reg.sCleanupProvider.pwszDLLName = cryptdlg;
512 reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
513 if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, ®))
515 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
516 "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence");
517 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
518 szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID");
519 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
520 "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence");
521 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
522 szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID");
523 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
524 szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection");
525 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
526 szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension");
530 /***********************************************************************
531 * DllUnregisterServer (CRYPTDLG.@)
533 HRESULT WINAPI DllUnregisterServer(void)
535 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
537 WintrustRemoveActionID(&guid);
538 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
539 "1.3.6.1.4.1.311.16.1.1");
540 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
541 szOID_MICROSOFT_Encryption_Key_Preference);
542 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
543 "1.3.6.1.4.1.311.16.1.1");
544 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
545 szOID_MICROSOFT_Encryption_Key_Preference);
546 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
547 szOID_PKIX_KP_EMAIL_PROTECTION);
548 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
549 szOID_CERT_POLICIES);