cryptdlg: Implement CertTrustFinalPolicy.
[wine/testsucceed.git] / dlls / cryptdlg / main.c
blobd87d480f038b33dc21da28cd1c60c761f77fca16
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 #include "config.h"
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winreg.h"
27 #include "wincrypt.h"
28 #include "wintrust.h"
29 #include "winuser.h"
30 #include "cryptdlg.h"
31 #include "cryptuiapi.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg);
36 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
38 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
40 switch (fdwReason)
42 case DLL_WINE_PREATTACH:
43 return FALSE; /* prefer native version */
44 case DLL_PROCESS_ATTACH:
45 DisableThreadLibraryCalls(hinstDLL);
46 break;
47 case DLL_PROCESS_DETACH:
48 break;
49 default:
50 break;
52 return TRUE;
55 /***********************************************************************
56 * GetFriendlyNameOfCertA (CRYPTDLG.@)
58 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
59 DWORD cchBuffer)
61 return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
62 pchBuffer, cchBuffer);
65 /***********************************************************************
66 * GetFriendlyNameOfCertW (CRYPTDLG.@)
68 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
69 DWORD cchBuffer)
71 return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
72 pchBuffer, cchBuffer);
75 /***********************************************************************
76 * CertTrustInit (CRYPTDLG.@)
78 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
80 HRESULT ret = S_FALSE;
82 TRACE("(%p)\n", pProvData);
84 if (pProvData->padwTrustStepErrors &&
85 !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
86 ret = S_OK;
87 TRACE("returning %08x\n", ret);
88 return ret;
91 /***********************************************************************
92 * CertTrustCertPolicy (CRYPTDLG.@)
94 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
96 FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
97 return FALSE;
100 /***********************************************************************
101 * CertTrustCleanup (CRYPTDLG.@)
103 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
105 FIXME("(%p)\n", pProvData);
106 return E_NOTIMPL;
109 static BOOL CRYPTDLG_CheckOnlineCRL(void)
111 static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e',
112 '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g',
113 'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f',
114 '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9',
115 '7','9','3','8','7','e','a','}',0 };
116 static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a',
117 'g','s',0 };
118 HKEY key;
119 BOOL ret = FALSE;
121 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
123 DWORD type, flags, size = sizeof(flags);
125 if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
126 &size) && type == REG_DWORD)
128 /* The flag values aren't defined in any header I'm aware of, but
129 * this value is well documented on the net.
131 if (flags & 0x00010000)
132 ret = TRUE;
134 RegCloseKey(key);
136 return ret;
139 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
140 * is.
142 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
144 BOOL ret;
145 BYTE hash[20];
146 DWORD size = sizeof(hash);
148 if ((ret = CertGetCertificateContextProperty(pCert,
149 CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
151 static const WCHAR disallowedW[] =
152 { 'D','i','s','a','l','l','o','w','e','d',0 };
153 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
154 X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW);
156 if (disallowed)
158 PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
159 X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
161 if (found)
163 ret = FALSE;
164 CertFreeCertificateContext(found);
166 CertCloseStore(disallowed, 0);
169 return ret;
172 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
174 DWORD confidence = 0;
176 confidence = 0;
177 if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
178 confidence |= CERT_CONFIDENCE_SIG;
179 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
180 confidence |= CERT_CONFIDENCE_TIME;
181 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
182 confidence |= CERT_CONFIDENCE_TIMENEST;
183 return confidence;
186 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
187 PCCERT_CHAIN_CONTEXT chain)
189 BOOL ret;
190 CRYPT_PROVIDER_SGNR signer;
191 PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
192 DWORD i;
194 memset(&signer, 0, sizeof(signer));
195 signer.cbStruct = sizeof(signer);
196 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
197 if (ret)
199 CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
200 FALSE, 0);
202 if (sgnr)
204 sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
205 sgnr->pChainContext = CertDuplicateCertificateChain(chain);
207 else
208 ret = FALSE;
209 for (i = 0; ret && i < simpleChain->cElement; i++)
211 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
212 simpleChain->rgpElement[i]->pCertContext);
213 if (ret)
215 CRYPT_PROVIDER_CERT *cert;
217 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
219 CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
221 cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
222 element->TrustStatus.dwErrorStatus);
223 cert->dwError = element->TrustStatus.dwErrorStatus;
224 cert->pChainElement = element;
226 else
227 ret = FALSE;
231 return ret;
234 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
235 CRYPT_PROVIDER_DATA *data)
237 CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
239 /* This should always be true, but just in case the calling function is
240 * called directly:
242 if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
243 data->pWintrustData->pBlob && data->pWintrustData->pBlob->cbMemObject ==
244 sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
245 data->pWintrustData->pBlob->pbMemObject)
246 pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
247 data->pWintrustData->pBlob->pbMemObject;
248 return pCert;
251 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
253 HCERTCHAINENGINE engine = NULL;
254 HCERTSTORE root = NULL, trust = NULL;
255 DWORD i;
257 if (cert->cRootStores)
259 root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
260 CERT_STORE_CREATE_NEW_FLAG, NULL);
261 if (root)
263 for (i = 0; i < cert->cRootStores; i++)
264 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
267 if (cert->cTrustStores)
269 trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
270 CERT_STORE_CREATE_NEW_FLAG, NULL);
271 if (root)
273 for (i = 0; i < cert->cTrustStores; i++)
274 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
277 if (cert->cRootStores || cert->cStores || cert->cTrustStores)
279 CERT_CHAIN_ENGINE_CONFIG config;
281 memset(&config, 0, sizeof(config));
282 config.cbSize = sizeof(config);
283 config.hRestrictedRoot = root;
284 config.hRestrictedTrust = trust;
285 config.cAdditionalStore = cert->cStores;
286 config.rghAdditionalStore = cert->rghstoreCAs;
287 config.hRestrictedRoot = root;
288 CertCreateCertificateChainEngine(&config, &engine);
289 CertCloseStore(root, 0);
290 CertCloseStore(trust, 0);
292 return engine;
295 /***********************************************************************
296 * CertTrustFinalPolicy (CRYPTDLG.@)
298 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
300 BOOL ret;
301 DWORD err = S_OK;
302 CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
304 TRACE("(%p)\n", data);
306 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
307 FIXME("unimplemented for UI choice %d\n",
308 data->pWintrustData->dwUIChoice);
309 if (pCert)
311 DWORD flags = 0;
312 CERT_CHAIN_PARA chainPara;
313 HCERTCHAINENGINE engine;
315 memset(&chainPara, 0, sizeof(chainPara));
316 chainPara.cbSize = sizeof(chainPara);
317 if (CRYPTDLG_CheckOnlineCRL())
318 flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
319 engine = CRYPTDLG_MakeEngine(pCert);
320 GetSystemTimeAsFileTime(&data->sftSystemTime);
321 ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
322 if (ret)
324 PCCERT_CHAIN_CONTEXT chain;
326 ret = CertGetCertificateChain(engine, pCert->pccert,
327 &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
328 if (ret)
330 if (chain->cChain != 1)
332 FIXME("unimplemented for more than 1 simple chain\n");
333 err = TRUST_E_SUBJECT_FORM_UNKNOWN;
334 ret = FALSE;
336 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
338 if (CertVerifyTimeValidity(&data->sftSystemTime,
339 pCert->pccert->pCertInfo))
341 ret = FALSE;
342 err = CERT_E_EXPIRED;
345 else
346 err = TRUST_E_SYSTEM_ERROR;
347 CertFreeCertificateChain(chain);
349 else
350 err = TRUST_E_SUBJECT_NOT_TRUSTED;
352 CertFreeCertificateChainEngine(engine);
354 else
356 ret = FALSE;
357 err = TRUST_E_NOSIGNATURE;
359 /* Oddly, native doesn't set the error in the trust step error location,
360 * probably because this action is more advisory than anything else.
361 * Instead it stores it as the final error, but the function "succeeds" in
362 * any case.
364 if (!ret)
365 data->dwFinalError = err;
366 TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
367 return S_OK;
370 /***********************************************************************
371 * CertViewPropertiesA (CRYPTDLG.@)
373 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
375 CERT_VIEWPROPERTIES_STRUCT_W infoW;
376 LPWSTR title = NULL;
377 BOOL ret;
379 TRACE("(%p)\n", info);
381 memcpy(&infoW, info, sizeof(infoW));
382 if (info->szTitle)
384 int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
386 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
387 if (title)
389 MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
390 infoW.szTitle = title;
392 else
394 ret = FALSE;
395 goto error;
398 ret = CertViewPropertiesW(&infoW);
399 HeapFree(GetProcessHeap(), 0, title);
400 error:
401 return ret;
404 /***********************************************************************
405 * CertViewPropertiesW (CRYPTDLG.@)
407 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
409 static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
410 CERT_VERIFY_CERTIFICATE_TRUST trust;
411 WINTRUST_BLOB_INFO blob;
412 WINTRUST_DATA wtd;
413 LONG err;
414 BOOL ret;
416 TRACE("(%p)\n", info);
418 memset(&trust, 0, sizeof(trust));
419 trust.cbSize = sizeof(trust);
420 trust.pccert = info->pCertContext;
421 trust.cRootStores = info->cRootStores;
422 trust.rghstoreRoots = info->rghstoreRoots;
423 trust.cStores = info->cStores;
424 trust.rghstoreCAs = info->rghstoreCAs;
425 trust.cTrustStores = info->cTrustStores;
426 trust.rghstoreTrust = info->rghstoreTrust;
427 memset(&blob, 0, sizeof(blob));
428 blob.cbStruct = sizeof(blob);
429 blob.cbMemObject = sizeof(trust);
430 blob.pbMemObject = (BYTE *)&trust;
431 memset(&wtd, 0, sizeof(wtd));
432 wtd.cbStruct = sizeof(wtd);
433 wtd.dwUIChoice = WTD_UI_NONE;
434 wtd.dwUnionChoice = WTD_CHOICE_BLOB;
435 wtd.pBlob = &blob;
436 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
437 err = WinVerifyTrust(NULL, &cert_action_verify, &wtd);
438 if (err == ERROR_SUCCESS)
440 CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
441 BOOL propsChanged = FALSE;
443 memset(&uiInfo, 0, sizeof(uiInfo));
444 uiInfo.dwSize = sizeof(uiInfo);
445 uiInfo.hwndParent = info->hwndParent;
446 uiInfo.dwFlags =
447 CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES;
448 uiInfo.szTitle = info->szTitle;
449 uiInfo.pCertContext = info->pCertContext;
450 uiInfo.cPurposes = info->cArrayPurposes;
451 uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes;
452 uiInfo.hWVTStateData = wtd.hWVTStateData;
453 uiInfo.fpCryptProviderDataTrustedUsage = TRUE;
454 uiInfo.cPropSheetPages = info->cArrayPropSheetPages;
455 uiInfo.rgPropSheetPages = info->arrayPropSheetPages;
456 uiInfo.nStartPage = info->nStartPage;
457 ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged);
458 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
459 WinVerifyTrust(NULL, &cert_action_verify, &wtd);
461 else
462 ret = FALSE;
463 return ret;
466 /***********************************************************************
467 * DllRegisterServer (CRYPTDLG.@)
469 HRESULT WINAPI DllRegisterServer(void)
471 static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
472 'd','l','l',0 };
473 static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
474 'd','l','l',0 };
475 static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
476 'I','n','i','t',0 };
477 static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
478 'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
479 static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
480 'C','e','r','t','P','o','l','i','c','y',0 };
481 static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
482 'F','i','n','a','l','P','o','l','i','c','y',0 };
483 static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
484 'C','l','e','a','n','u','p',0 };
485 CRYPT_REGISTER_ACTIONID reg;
486 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
487 HRESULT hr = S_OK;
489 memset(&reg, 0, sizeof(reg));
490 reg.cbStruct = sizeof(reg);
491 reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
492 reg.sInitProvider.pwszDLLName = cryptdlg;
493 reg.sInitProvider.pwszFunctionName = certTrustInit;
494 reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
495 reg.sCertificateProvider.pwszDLLName = wintrust;
496 reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
497 reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
498 reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
499 reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
500 reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
501 reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
502 reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
503 reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
504 reg.sCleanupProvider.pwszDLLName = cryptdlg;
505 reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
506 if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
507 hr = GetLastError();
508 return hr;
511 /***********************************************************************
512 * DllUnregisterServer (CRYPTDLG.@)
514 HRESULT WINAPI DllUnregisterServer(void)
516 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
518 WintrustRemoveActionID(&guid);
519 return S_OK;