push 07a2b33f792746135ccf34a3b3e1dfb2a3c1e823
[wine/hacks.git] / dlls / cryptdlg / main.c
blobe8f2514adb40cd88bc857bade0c97d00eeda7917
1 /*
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
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "wincrypt.h"
30 #include "wintrust.h"
31 #include "winuser.h"
32 #include "cryptdlg.h"
33 #include "cryptuiapi.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg);
38 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
40 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
42 switch (fdwReason)
44 case DLL_WINE_PREATTACH:
45 return FALSE; /* prefer native version */
46 case DLL_PROCESS_ATTACH:
47 DisableThreadLibraryCalls(hinstDLL);
48 break;
49 case DLL_PROCESS_DETACH:
50 break;
51 default:
52 break;
54 return TRUE;
57 /***********************************************************************
58 * GetFriendlyNameOfCertA (CRYPTDLG.@)
60 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
61 DWORD cchBuffer)
63 return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
64 pchBuffer, cchBuffer);
67 /***********************************************************************
68 * GetFriendlyNameOfCertW (CRYPTDLG.@)
70 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
71 DWORD cchBuffer)
73 return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
74 pchBuffer, cchBuffer);
77 /***********************************************************************
78 * CertTrustInit (CRYPTDLG.@)
80 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
82 HRESULT ret = S_FALSE;
84 TRACE("(%p)\n", pProvData);
86 if (pProvData->padwTrustStepErrors &&
87 !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
88 ret = S_OK;
89 TRACE("returning %08x\n", ret);
90 return ret;
93 /***********************************************************************
94 * CertTrustCertPolicy (CRYPTDLG.@)
96 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
98 FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
99 return FALSE;
102 /***********************************************************************
103 * CertTrustCleanup (CRYPTDLG.@)
105 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
107 FIXME("(%p)\n", pProvData);
108 return E_NOTIMPL;
111 static BOOL CRYPTDLG_CheckOnlineCRL(void)
113 static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e',
114 '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g',
115 'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f',
116 '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9',
117 '7','9','3','8','7','e','a','}',0 };
118 static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a',
119 'g','s',0 };
120 HKEY key;
121 BOOL ret = FALSE;
123 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
125 DWORD type, flags, size = sizeof(flags);
127 if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
128 &size) && type == REG_DWORD)
130 /* The flag values aren't defined in any header I'm aware of, but
131 * this value is well documented on the net.
133 if (flags & 0x00010000)
134 ret = TRUE;
136 RegCloseKey(key);
138 return ret;
141 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
142 * is.
144 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
146 BOOL ret;
147 BYTE hash[20];
148 DWORD size = sizeof(hash);
150 if ((ret = CertGetCertificateContextProperty(pCert,
151 CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
153 static const WCHAR disallowedW[] =
154 { 'D','i','s','a','l','l','o','w','e','d',0 };
155 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
156 X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW);
158 if (disallowed)
160 PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
161 X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
163 if (found)
165 ret = FALSE;
166 CertFreeCertificateContext(found);
168 CertCloseStore(disallowed, 0);
171 return ret;
174 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
176 DWORD confidence = 0;
178 confidence = 0;
179 if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
180 confidence |= CERT_CONFIDENCE_SIG;
181 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
182 confidence |= CERT_CONFIDENCE_TIME;
183 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
184 confidence |= CERT_CONFIDENCE_TIMENEST;
185 return confidence;
188 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
189 PCCERT_CHAIN_CONTEXT chain)
191 BOOL ret;
192 CRYPT_PROVIDER_SGNR signer;
193 PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
194 DWORD i;
196 memset(&signer, 0, sizeof(signer));
197 signer.cbStruct = sizeof(signer);
198 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
199 if (ret)
201 CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
202 FALSE, 0);
204 if (sgnr)
206 sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
207 sgnr->pChainContext = CertDuplicateCertificateChain(chain);
209 else
210 ret = FALSE;
211 for (i = 0; ret && i < simpleChain->cElement; i++)
213 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
214 simpleChain->rgpElement[i]->pCertContext);
215 if (ret)
217 CRYPT_PROVIDER_CERT *cert;
219 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
221 CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
223 cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
224 element->TrustStatus.dwErrorStatus);
225 cert->dwError = element->TrustStatus.dwErrorStatus;
226 cert->pChainElement = element;
228 else
229 ret = FALSE;
233 return ret;
236 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
237 CRYPT_PROVIDER_DATA *data)
239 CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
241 /* This should always be true, but just in case the calling function is
242 * called directly:
244 if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
245 data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject ==
246 sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
247 data->pWintrustData->u.pBlob->pbMemObject)
248 pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
249 data->pWintrustData->u.pBlob->pbMemObject;
250 return pCert;
253 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
255 HCERTCHAINENGINE engine = NULL;
256 HCERTSTORE root = NULL, trust = NULL;
257 DWORD i;
259 if (cert->cRootStores)
261 root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
262 CERT_STORE_CREATE_NEW_FLAG, NULL);
263 if (root)
265 for (i = 0; i < cert->cRootStores; i++)
266 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
269 if (cert->cTrustStores)
271 trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
272 CERT_STORE_CREATE_NEW_FLAG, NULL);
273 if (root)
275 for (i = 0; i < cert->cTrustStores; i++)
276 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
279 if (cert->cRootStores || cert->cStores || cert->cTrustStores)
281 CERT_CHAIN_ENGINE_CONFIG config;
283 memset(&config, 0, sizeof(config));
284 config.cbSize = sizeof(config);
285 config.hRestrictedRoot = root;
286 config.hRestrictedTrust = trust;
287 config.cAdditionalStore = cert->cStores;
288 config.rghAdditionalStore = cert->rghstoreCAs;
289 config.hRestrictedRoot = root;
290 CertCreateCertificateChainEngine(&config, &engine);
291 CertCloseStore(root, 0);
292 CertCloseStore(trust, 0);
294 return engine;
297 /***********************************************************************
298 * CertTrustFinalPolicy (CRYPTDLG.@)
300 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
302 BOOL ret;
303 DWORD err = S_OK;
304 CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
306 TRACE("(%p)\n", data);
308 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
309 FIXME("unimplemented for UI choice %d\n",
310 data->pWintrustData->dwUIChoice);
311 if (pCert)
313 DWORD flags = 0;
314 CERT_CHAIN_PARA chainPara;
315 HCERTCHAINENGINE engine;
317 memset(&chainPara, 0, sizeof(chainPara));
318 chainPara.cbSize = sizeof(chainPara);
319 if (CRYPTDLG_CheckOnlineCRL())
320 flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
321 engine = CRYPTDLG_MakeEngine(pCert);
322 GetSystemTimeAsFileTime(&data->sftSystemTime);
323 ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
324 if (ret)
326 PCCERT_CHAIN_CONTEXT chain;
328 ret = CertGetCertificateChain(engine, pCert->pccert,
329 &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
330 if (ret)
332 if (chain->cChain != 1)
334 FIXME("unimplemented for more than 1 simple chain\n");
335 err = TRUST_E_SUBJECT_FORM_UNKNOWN;
336 ret = FALSE;
338 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
340 if (CertVerifyTimeValidity(&data->sftSystemTime,
341 pCert->pccert->pCertInfo))
343 ret = FALSE;
344 err = CERT_E_EXPIRED;
347 else
348 err = TRUST_E_SYSTEM_ERROR;
349 CertFreeCertificateChain(chain);
351 else
352 err = TRUST_E_SUBJECT_NOT_TRUSTED;
354 CertFreeCertificateChainEngine(engine);
356 else
358 ret = FALSE;
359 err = TRUST_E_NOSIGNATURE;
361 /* Oddly, native doesn't set the error in the trust step error location,
362 * probably because this action is more advisory than anything else.
363 * Instead it stores it as the final error, but the function "succeeds" in
364 * any case.
366 if (!ret)
367 data->dwFinalError = err;
368 TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
369 return S_OK;
372 /***********************************************************************
373 * CertViewPropertiesA (CRYPTDLG.@)
375 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
377 CERT_VIEWPROPERTIES_STRUCT_W infoW;
378 LPWSTR title = NULL;
379 BOOL ret;
381 TRACE("(%p)\n", info);
383 memcpy(&infoW, info, sizeof(infoW));
384 if (info->szTitle)
386 int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
388 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
389 if (title)
391 MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
392 infoW.szTitle = title;
394 else
396 ret = FALSE;
397 goto error;
400 ret = CertViewPropertiesW(&infoW);
401 HeapFree(GetProcessHeap(), 0, title);
402 error:
403 return ret;
406 /***********************************************************************
407 * CertViewPropertiesW (CRYPTDLG.@)
409 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
411 static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
412 CERT_VERIFY_CERTIFICATE_TRUST trust;
413 WINTRUST_BLOB_INFO blob;
414 WINTRUST_DATA wtd;
415 LONG err;
416 BOOL ret;
418 TRACE("(%p)\n", info);
420 memset(&trust, 0, sizeof(trust));
421 trust.cbSize = sizeof(trust);
422 trust.pccert = info->pCertContext;
423 trust.cRootStores = info->cRootStores;
424 trust.rghstoreRoots = info->rghstoreRoots;
425 trust.cStores = info->cStores;
426 trust.rghstoreCAs = info->rghstoreCAs;
427 trust.cTrustStores = info->cTrustStores;
428 trust.rghstoreTrust = info->rghstoreTrust;
429 memset(&blob, 0, sizeof(blob));
430 blob.cbStruct = sizeof(blob);
431 blob.cbMemObject = sizeof(trust);
432 blob.pbMemObject = (BYTE *)&trust;
433 memset(&wtd, 0, sizeof(wtd));
434 wtd.cbStruct = sizeof(wtd);
435 wtd.dwUIChoice = WTD_UI_NONE;
436 wtd.dwUnionChoice = WTD_CHOICE_BLOB;
437 wtd.u.pBlob = &blob;
438 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
439 err = WinVerifyTrust(NULL, &cert_action_verify, &wtd);
440 if (err == ERROR_SUCCESS)
442 CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
443 BOOL propsChanged = FALSE;
445 memset(&uiInfo, 0, sizeof(uiInfo));
446 uiInfo.dwSize = sizeof(uiInfo);
447 uiInfo.hwndParent = info->hwndParent;
448 uiInfo.dwFlags =
449 CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES;
450 uiInfo.szTitle = info->szTitle;
451 uiInfo.pCertContext = info->pCertContext;
452 uiInfo.cPurposes = info->cArrayPurposes;
453 uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes;
454 uiInfo.u.hWVTStateData = wtd.hWVTStateData;
455 uiInfo.fpCryptProviderDataTrustedUsage = TRUE;
456 uiInfo.cPropSheetPages = info->cArrayPropSheetPages;
457 uiInfo.rgPropSheetPages = info->arrayPropSheetPages;
458 uiInfo.nStartPage = info->nStartPage;
459 ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged);
460 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
461 WinVerifyTrust(NULL, &cert_action_verify, &wtd);
463 else
464 ret = FALSE;
465 return ret;
468 #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4"
470 /***********************************************************************
471 * DllRegisterServer (CRYPTDLG.@)
473 HRESULT WINAPI DllRegisterServer(void)
475 static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
476 'd','l','l',0 };
477 static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
478 'd','l','l',0 };
479 static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
480 'I','n','i','t',0 };
481 static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
482 'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
483 static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
484 'C','e','r','t','P','o','l','i','c','y',0 };
485 static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
486 'F','i','n','a','l','P','o','l','i','c','y',0 };
487 static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
488 'C','l','e','a','n','u','p',0 };
489 static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.',
490 'd','l','l',0 };
491 CRYPT_REGISTER_ACTIONID reg;
492 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
493 HRESULT hr = S_OK;
495 memset(&reg, 0, sizeof(reg));
496 reg.cbStruct = sizeof(reg);
497 reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
498 reg.sInitProvider.pwszDLLName = cryptdlg;
499 reg.sInitProvider.pwszFunctionName = certTrustInit;
500 reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
501 reg.sCertificateProvider.pwszDLLName = wintrust;
502 reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
503 reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
504 reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
505 reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
506 reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
507 reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
508 reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
509 reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
510 reg.sCleanupProvider.pwszDLLName = cryptdlg;
511 reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
512 if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
513 hr = GetLastError();
514 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
515 "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence");
516 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
517 szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID");
518 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
519 "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence");
520 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
521 szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID");
522 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
523 szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection");
524 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
525 szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension");
526 return hr;
529 /***********************************************************************
530 * DllUnregisterServer (CRYPTDLG.@)
532 HRESULT WINAPI DllUnregisterServer(void)
534 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
536 WintrustRemoveActionID(&guid);
537 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
538 "1.3.6.1.4.1.311.16.1.1");
539 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
540 szOID_MICROSOFT_Encryption_Key_Preference);
541 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
542 "1.3.6.1.4.1.311.16.1.1");
543 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
544 szOID_MICROSOFT_Encryption_Key_Preference);
545 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
546 szOID_PKIX_KP_EMAIL_PROTECTION);
547 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
548 szOID_CERT_POLICIES);
549 return S_OK;