winmm: Fix a failing mixer test on 98 and ME.
[wine] / dlls / cryptdlg / main.c
1 /*
2  * Copyright 2008 Maarten Lankhorst
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define NONAMELESSUNION
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
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"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg);
37
38 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
39 {
40     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
41
42     switch (fdwReason)
43     {
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;
53     }
54     return TRUE;
55 }
56
57 /***********************************************************************
58  *              GetFriendlyNameOfCertA (CRYPTDLG.@)
59  */
60 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
61                              DWORD cchBuffer)
62 {
63     return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
64      pchBuffer, cchBuffer);
65 }
66
67 /***********************************************************************
68  *              GetFriendlyNameOfCertW (CRYPTDLG.@)
69  */
70 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
71                              DWORD cchBuffer)
72 {
73     return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
74      pchBuffer, cchBuffer);
75 }
76
77 /***********************************************************************
78  *              CertTrustInit (CRYPTDLG.@)
79  */
80 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
81 {
82     HRESULT ret = S_FALSE;
83
84     TRACE("(%p)\n", pProvData);
85
86     if (pProvData->padwTrustStepErrors &&
87      !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
88         ret = S_OK;
89     TRACE("returning %08x\n", ret);
90     return ret;
91 }
92
93 /***********************************************************************
94  *              CertTrustCertPolicy (CRYPTDLG.@)
95  */
96 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
97 {
98     FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
99     return FALSE;
100 }
101
102 /***********************************************************************
103  *              CertTrustCleanup (CRYPTDLG.@)
104  */
105 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
106 {
107     FIXME("(%p)\n", pProvData);
108     return E_NOTIMPL;
109 }
110
111 static BOOL CRYPTDLG_CheckOnlineCRL(void)
112 {
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;
122
123     if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
124     {
125         DWORD type, flags, size = sizeof(flags);
126
127         if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
128          &size) && type == REG_DWORD)
129         {
130             /* The flag values aren't defined in any header I'm aware of, but
131              * this value is well documented on the net.
132              */
133             if (flags & 0x00010000)
134                 ret = TRUE;
135         }
136         RegCloseKey(key);
137     }
138     return ret;
139 }
140
141 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
142  * is.
143  */
144 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
145 {
146     BOOL ret;
147     BYTE hash[20];
148     DWORD size = sizeof(hash);
149
150     if ((ret = CertGetCertificateContextProperty(pCert,
151      CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
152     {
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);
157
158         if (disallowed)
159         {
160             PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
161              X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
162
163             if (found)
164             {
165                 ret = FALSE;
166                 CertFreeCertificateContext(found);
167             }
168             CertCloseStore(disallowed, 0);
169         }
170     }
171     return ret;
172 }
173
174 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
175 {
176     DWORD confidence = 0;
177
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;
186 }
187
188 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
189  PCCERT_CHAIN_CONTEXT chain)
190 {
191     BOOL ret;
192     CRYPT_PROVIDER_SGNR signer;
193     PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
194     DWORD i;
195
196     memset(&signer, 0, sizeof(signer));
197     signer.cbStruct = sizeof(signer);
198     ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
199     if (ret)
200     {
201         CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
202          FALSE, 0);
203
204         if (sgnr)
205         {
206             sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
207             sgnr->pChainContext = CertDuplicateCertificateChain(chain);
208         }
209         else
210             ret = FALSE;
211         for (i = 0; ret && i < simpleChain->cElement; i++)
212         {
213             ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
214              simpleChain->rgpElement[i]->pCertContext);
215             if (ret)
216             {
217                 CRYPT_PROVIDER_CERT *cert;
218
219                 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
220                 {
221                     CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
222
223                     cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
224                      element->TrustStatus.dwErrorStatus);
225                     cert->dwError = element->TrustStatus.dwErrorStatus;
226                     cert->pChainElement = element;
227                 }
228                 else
229                     ret = FALSE;
230             }
231         }
232     }
233     return ret;
234 }
235
236 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
237  CRYPT_PROVIDER_DATA *data)
238 {
239     CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
240
241     /* This should always be true, but just in case the calling function is
242      * called directly:
243      */
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;
251 }
252
253 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
254 {
255     HCERTCHAINENGINE engine = NULL;
256     HCERTSTORE root = NULL, trust = NULL;
257     DWORD i;
258
259     if (cert->cRootStores)
260     {
261         root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
262          CERT_STORE_CREATE_NEW_FLAG, NULL);
263         if (root)
264         {
265             for (i = 0; i < cert->cRootStores; i++)
266                 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
267         }
268     }
269     if (cert->cTrustStores)
270     {
271         trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
272          CERT_STORE_CREATE_NEW_FLAG, NULL);
273         if (root)
274         {
275             for (i = 0; i < cert->cTrustStores; i++)
276                 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
277         }
278     }
279     if (cert->cRootStores || cert->cStores || cert->cTrustStores)
280     {
281         CERT_CHAIN_ENGINE_CONFIG config;
282
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);
293     }
294     return engine;
295 }
296
297 /***********************************************************************
298  *              CertTrustFinalPolicy (CRYPTDLG.@)
299  */
300 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
301 {
302     BOOL ret;
303     DWORD err = S_OK;
304     CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
305
306     TRACE("(%p)\n", data);
307
308     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
309         FIXME("unimplemented for UI choice %d\n",
310          data->pWintrustData->dwUIChoice);
311     if (pCert)
312     {
313         DWORD flags = 0;
314         CERT_CHAIN_PARA chainPara;
315         HCERTCHAINENGINE engine;
316
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)
325         {
326             PCCERT_CHAIN_CONTEXT chain;
327
328             ret = CertGetCertificateChain(engine, pCert->pccert,
329              &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
330             if (ret)
331             {
332                 if (chain->cChain != 1)
333                 {
334                     FIXME("unimplemented for more than 1 simple chain\n");
335                     err = TRUST_E_SUBJECT_FORM_UNKNOWN;
336                     ret = FALSE;
337                 }
338                 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
339                 {
340                     if (CertVerifyTimeValidity(&data->sftSystemTime,
341                      pCert->pccert->pCertInfo))
342                     {
343                         ret = FALSE;
344                         err = CERT_E_EXPIRED;
345                     }
346                 }
347                 else
348                     err = TRUST_E_SYSTEM_ERROR;
349                 CertFreeCertificateChain(chain);
350             }
351             else
352                 err = TRUST_E_SUBJECT_NOT_TRUSTED;
353         }
354         CertFreeCertificateChainEngine(engine);
355     }
356     else
357     {
358         ret = FALSE;
359         err = TRUST_E_NOSIGNATURE;
360     }
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.
365      */
366     if (!ret)
367         data->dwFinalError = err;
368     TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
369     return S_OK;
370 }
371
372 /***********************************************************************
373  *              CertViewPropertiesA (CRYPTDLG.@)
374  */
375 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
376 {
377     CERT_VIEWPROPERTIES_STRUCT_W infoW;
378     LPWSTR title = NULL;
379     BOOL ret;
380
381     TRACE("(%p)\n", info);
382
383     memcpy(&infoW, info, sizeof(infoW));
384     if (info->szTitle)
385     {
386         int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
387
388         title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
389         if (title)
390         {
391             MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
392             infoW.szTitle = title;
393         }
394         else
395         {
396             ret = FALSE;
397             goto error;
398         }
399     }
400     ret = CertViewPropertiesW(&infoW);
401     HeapFree(GetProcessHeap(), 0, title);
402 error:
403     return ret;
404 }
405
406 /***********************************************************************
407  *              CertViewPropertiesW (CRYPTDLG.@)
408  */
409 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
410 {
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;
417
418     TRACE("(%p)\n", info);
419
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)
441     {
442         CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
443         BOOL propsChanged = FALSE;
444
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);
462     }
463     else
464         ret = FALSE;
465     return ret;
466 }
467
468 /***********************************************************************
469  *              DllRegisterServer (CRYPTDLG.@)
470  */
471 HRESULT WINAPI DllRegisterServer(void)
472 {
473     static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
474      'd','l','l',0 };
475     static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
476      'd','l','l',0 };
477     static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
478      'I','n','i','t',0 };
479     static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
480      'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
481     static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
482      'C','e','r','t','P','o','l','i','c','y',0 };
483     static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
484      'F','i','n','a','l','P','o','l','i','c','y',0 };
485     static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
486      'C','l','e','a','n','u','p',0 };
487     CRYPT_REGISTER_ACTIONID reg;
488     GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
489     HRESULT hr = S_OK;
490
491     memset(&reg, 0, sizeof(reg));
492     reg.cbStruct = sizeof(reg);
493     reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
494     reg.sInitProvider.pwszDLLName = cryptdlg;
495     reg.sInitProvider.pwszFunctionName = certTrustInit;
496     reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
497     reg.sCertificateProvider.pwszDLLName = wintrust;
498     reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
499     reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
500     reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
501     reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
502     reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
503     reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
504     reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
505     reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
506     reg.sCleanupProvider.pwszDLLName = cryptdlg;
507     reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
508     if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
509         hr = GetLastError();
510     return hr;
511 }
512
513 /***********************************************************************
514  *              DllUnregisterServer (CRYPTDLG.@)
515  */
516 HRESULT WINAPI DllUnregisterServer(void)
517 {
518     GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
519
520     WintrustRemoveActionID(&guid);
521     return S_OK;
522 }