wintrust: Implement WTHelperGetKnownUsages.
[wine] / dlls / wintrust / wintrust_main.c
1 /*
2  * Copyright 2001 Rein Klazes
3  * Copyright 2007 Juan Lang
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "config.h"
21
22 #include <stdarg.h>
23
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "winreg.h"
30 #include "guiddef.h"
31 #include "wintrust.h"
32 #include "softpub.h"
33 #include "mscat.h"
34 #include "objbase.h"
35 #include "winuser.h"
36 #include "cryptdlg.h"
37 #include "wintrust_priv.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
41
42
43 /***********************************************************************
44  *              DllMain  (WINTRUST.@)
45  */
46 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
47 {
48     switch(reason)
49     {
50     case DLL_PROCESS_ATTACH:
51         DisableThreadLibraryCalls( inst );
52         break;
53     }
54     return TRUE;
55 }
56
57 /***********************************************************************
58  *              TrustIsCertificateSelfSigned (WINTRUST.@)
59  */
60 BOOL WINAPI TrustIsCertificateSelfSigned( PCCERT_CONTEXT cert )
61 {
62     BOOL ret;
63
64     TRACE("%p\n", cert);
65     ret = CertCompareCertificateName(cert->dwCertEncodingType,
66      &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
67     return ret;
68 }
69
70 typedef HRESULT (WINAPI *wintrust_step_func)(CRYPT_PROVIDER_DATA *data);
71
72 struct wintrust_step
73 {
74     wintrust_step_func func;
75     DWORD              error_index;
76 };
77
78 static DWORD WINTRUST_ExecuteSteps(const struct wintrust_step *steps,
79  DWORD numSteps, CRYPT_PROVIDER_DATA *provData)
80 {
81     DWORD i, err = ERROR_SUCCESS;
82
83     for (i = 0; !err && i < numSteps; i++)
84     {
85         err = steps[i].func(provData);
86         if (err)
87             err = provData->padwTrustStepErrors[steps[i].error_index];
88     }
89     return err;
90 }
91
92 static CRYPT_PROVIDER_DATA *WINTRUST_AllocateProviderData(void)
93 {
94     CRYPT_PROVIDER_DATA *provData;
95
96     provData = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_DATA));
97     if (!provData)
98         goto oom;
99     provData->cbStruct = sizeof(CRYPT_PROVIDER_DATA);
100
101     provData->padwTrustStepErrors =
102      WINTRUST_Alloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
103     if (!provData->padwTrustStepErrors)
104         goto oom;
105     provData->cdwTrustStepErrors = TRUSTERROR_MAX_STEPS;
106
107     provData->u.pPDSip = WINTRUST_Alloc(sizeof(PROVDATA_SIP));
108     if (!provData->u.pPDSip)
109         goto oom;
110     provData->u.pPDSip->cbStruct = sizeof(PROVDATA_SIP);
111
112     provData->psPfns = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_FUNCTIONS));
113     if (!provData->psPfns)
114         goto oom;
115     provData->psPfns->cbStruct = sizeof(CRYPT_PROVIDER_FUNCTIONS);
116     return provData;
117
118 oom:
119     if (provData)
120     {
121         WINTRUST_Free(provData->padwTrustStepErrors);
122         WINTRUST_Free(provData->u.pPDSip);
123         WINTRUST_Free(provData->psPfns);
124         WINTRUST_Free(provData);
125     }
126     return NULL;
127 }
128
129 /* Adds trust steps for each function in psPfns.  Assumes steps has at least
130  * 5 entries.  Returns the number of steps added.
131  */
132 static DWORD WINTRUST_AddTrustStepsFromFunctions(struct wintrust_step *steps,
133  const CRYPT_PROVIDER_FUNCTIONS *psPfns)
134 {
135     DWORD numSteps = 0;
136
137     if (psPfns->pfnInitialize)
138     {
139         steps[numSteps].func = psPfns->pfnInitialize;
140         steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_WVTINIT;
141     }
142     if (psPfns->pfnObjectTrust)
143     {
144         steps[numSteps].func = psPfns->pfnObjectTrust;
145         steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_OBJPROV;
146     }
147     if (psPfns->pfnSignatureTrust)
148     {
149         steps[numSteps].func = psPfns->pfnSignatureTrust;
150         steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_SIGPROV;
151     }
152     if (psPfns->pfnCertificateTrust)
153     {
154         steps[numSteps].func = psPfns->pfnCertificateTrust;
155         steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_CERTPROV;
156     }
157     if (psPfns->pfnFinalPolicy)
158     {
159         steps[numSteps].func = psPfns->pfnFinalPolicy;
160         steps[numSteps++].error_index = TRUSTERROR_STEP_FINAL_POLICYPROV;
161     }
162     return numSteps;
163 }
164
165 static LONG WINTRUST_DefaultVerify(HWND hwnd, GUID *actionID,
166  WINTRUST_DATA *data)
167 {
168     DWORD err = ERROR_SUCCESS, numSteps = 0;
169     CRYPT_PROVIDER_DATA *provData;
170     BOOL ret;
171     struct wintrust_step verifySteps[5];
172
173     TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
174
175     provData = WINTRUST_AllocateProviderData();
176     if (!provData)
177         return ERROR_OUTOFMEMORY;
178
179     ret = WintrustLoadFunctionPointers(actionID, provData->psPfns);
180     if (!ret)
181     {
182         err = GetLastError();
183         goto error;
184     }
185
186     data->hWVTStateData = (HANDLE)provData;
187     provData->pWintrustData = data;
188     if (hwnd == INVALID_HANDLE_VALUE)
189         provData->hWndParent = GetDesktopWindow();
190     else
191         provData->hWndParent = hwnd;
192     provData->pgActionID = actionID;
193     WintrustGetRegPolicyFlags(&provData->dwRegPolicySettings);
194
195     numSteps = WINTRUST_AddTrustStepsFromFunctions(verifySteps,
196      provData->psPfns);
197     err = WINTRUST_ExecuteSteps(verifySteps, numSteps, provData);
198     goto done;
199
200 error:
201     if (provData)
202     {
203         WINTRUST_Free(provData->padwTrustStepErrors);
204         WINTRUST_Free(provData->u.pPDSip);
205         WINTRUST_Free(provData->psPfns);
206         WINTRUST_Free(provData);
207     }
208 done:
209     TRACE("returning %08x\n", err);
210     return err;
211 }
212
213 static LONG WINTRUST_DefaultClose(HWND hwnd, GUID *actionID,
214  WINTRUST_DATA *data)
215 {
216     DWORD err = ERROR_SUCCESS;
217     CRYPT_PROVIDER_DATA *provData = (CRYPT_PROVIDER_DATA *)data->hWVTStateData;
218
219     TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
220
221     if (provData)
222     {
223         if (provData->psPfns->pfnCleanupPolicy)
224             err = provData->psPfns->pfnCleanupPolicy(provData);
225
226         WINTRUST_Free(provData->padwTrustStepErrors);
227         WINTRUST_Free(provData->u.pPDSip);
228         WINTRUST_Free(provData->psPfns);
229         WINTRUST_Free(provData);
230         data->hWVTStateData = NULL;
231     }
232     TRACE("returning %08x\n", err);
233     return err;
234 }
235
236 static LONG WINTRUST_DefaultVerifyAndClose(HWND hwnd, GUID *actionID,
237  WINTRUST_DATA *data)
238 {
239     LONG err;
240
241     TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
242
243     err = WINTRUST_DefaultVerify(hwnd, actionID, data);
244     WINTRUST_DefaultClose(hwnd, actionID, data);
245     TRACE("returning %08x\n", err);
246     return err;
247 }
248
249 static LONG WINTRUST_PublishedSoftware(HWND hwnd, GUID *actionID,
250  WINTRUST_DATA *data)
251 {
252     WINTRUST_DATA wintrust_data = { sizeof(wintrust_data), 0 };
253     /* Undocumented: the published software action is passed a path,
254      * and pSIPClientData points to a WIN_TRUST_SUBJECT_FILE.
255      */
256     LPWIN_TRUST_SUBJECT_FILE subjectFile =
257      (LPWIN_TRUST_SUBJECT_FILE)data->pSIPClientData;
258     WINTRUST_FILE_INFO fileInfo = { sizeof(fileInfo), 0 };
259
260     TRACE("subjectFile->hFile: %p\n", subjectFile->hFile);
261     TRACE("subjectFile->lpPath: %s\n", debugstr_w(subjectFile->lpPath));
262     fileInfo.pcwszFilePath = subjectFile->lpPath;
263     fileInfo.hFile = subjectFile->hFile;
264     wintrust_data.u.pFile = &fileInfo;
265     wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
266     wintrust_data.dwUIChoice = WTD_UI_NONE;
267
268     return WINTRUST_DefaultVerifyAndClose(hwnd, actionID, &wintrust_data);
269 }
270
271 /* Sadly, the function to load the cert for the CERT_CERTIFICATE_ACTION_VERIFY
272  * action is not stored in the registry and is located in wintrust, not in
273  * cryptdlg along with the rest of the implementation (verified by running the
274  * action with a native wintrust.dll.)
275  */
276 static HRESULT WINAPI WINTRUST_CertVerifyObjTrust(CRYPT_PROVIDER_DATA *data)
277 {
278     BOOL ret;
279
280     TRACE("(%p)\n", data);
281
282     if (!data->padwTrustStepErrors)
283         return S_FALSE;
284
285     switch (data->pWintrustData->dwUnionChoice)
286     {
287     case WTD_CHOICE_BLOB:
288         if (data->pWintrustData->u.pBlob &&
289          data->pWintrustData->u.pBlob->cbStruct == sizeof(WINTRUST_BLOB_INFO) &&
290          data->pWintrustData->u.pBlob->cbMemObject ==
291          sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
292          data->pWintrustData->u.pBlob->pbMemObject)
293         {
294             CERT_VERIFY_CERTIFICATE_TRUST *pCert =
295              (CERT_VERIFY_CERTIFICATE_TRUST *)
296              data->pWintrustData->u.pBlob->pbMemObject;
297
298             if (pCert->cbSize == sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
299              pCert->pccert)
300             {
301                 CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } };
302                 DWORD i;
303                 SYSTEMTIME sysTime;
304
305                 /* Add a signer with nothing but the time to verify, so we can
306                  * add a cert to it
307                  */
308                 GetSystemTime(&sysTime);
309                 SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf);
310                 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
311                 if (!ret)
312                     goto error;
313                 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
314                  pCert->pccert);
315                 if (!ret)
316                     goto error;
317                 for (i = 0; ret && i < pCert->cRootStores; i++)
318                     ret = data->psPfns->pfnAddStore2Chain(data,
319                      pCert->rghstoreRoots[i]);
320                 for (i = 0; ret && i < pCert->cStores; i++)
321                     ret = data->psPfns->pfnAddStore2Chain(data,
322                      pCert->rghstoreCAs[i]);
323                 for (i = 0; ret && i < pCert->cTrustStores; i++)
324                     ret = data->psPfns->pfnAddStore2Chain(data,
325                      pCert->rghstoreTrust[i]);
326             }
327             else
328             {
329                 SetLastError(ERROR_INVALID_PARAMETER);
330                 ret = FALSE;
331             }
332         }
333         else
334         {
335             SetLastError(ERROR_INVALID_PARAMETER);
336             ret = FALSE;
337         }
338         break;
339     default:
340         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
341         SetLastError(ERROR_INVALID_PARAMETER);
342         ret = FALSE;
343     }
344
345 error:
346     if (!ret)
347         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
348          GetLastError();
349     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
350      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
351     return ret ? S_OK : S_FALSE;
352 }
353
354 static LONG WINTRUST_CertVerify(HWND hwnd, GUID *actionID,
355  WINTRUST_DATA *data)
356 {
357     DWORD err = ERROR_SUCCESS, numSteps = 0;
358     CRYPT_PROVIDER_DATA *provData;
359     BOOL ret;
360     struct wintrust_step verifySteps[5];
361
362     TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
363
364     provData = WINTRUST_AllocateProviderData();
365     if (!provData)
366         return ERROR_OUTOFMEMORY;
367
368     ret = WintrustLoadFunctionPointers(actionID, provData->psPfns);
369     if (!ret)
370     {
371         err = GetLastError();
372         goto error;
373     }
374     if (!provData->psPfns->pfnObjectTrust)
375         provData->psPfns->pfnObjectTrust = WINTRUST_CertVerifyObjTrust;
376     /* Not sure why, but native skips the policy check */
377     provData->psPfns->pfnCertCheckPolicy = NULL;
378
379     data->hWVTStateData = (HANDLE)provData;
380     provData->pWintrustData = data;
381     if (hwnd == INVALID_HANDLE_VALUE)
382         provData->hWndParent = GetDesktopWindow();
383     else
384         provData->hWndParent = hwnd;
385     provData->pgActionID = actionID;
386     WintrustGetRegPolicyFlags(&provData->dwRegPolicySettings);
387
388     numSteps = WINTRUST_AddTrustStepsFromFunctions(verifySteps,
389      provData->psPfns);
390     err = WINTRUST_ExecuteSteps(verifySteps, numSteps, provData);
391     goto done;
392
393 error:
394     if (provData)
395     {
396         WINTRUST_Free(provData->padwTrustStepErrors);
397         WINTRUST_Free(provData->u.pPDSip);
398         WINTRUST_Free(provData->psPfns);
399         WINTRUST_Free(provData);
400     }
401 done:
402     TRACE("returning %08x\n", err);
403     return err;
404 }
405
406 static LONG WINTRUST_CertVerifyAndClose(HWND hwnd, GUID *actionID,
407  WINTRUST_DATA *data)
408 {
409     LONG err;
410
411     TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(actionID), data);
412
413     err = WINTRUST_CertVerify(hwnd, actionID, data);
414     WINTRUST_DefaultClose(hwnd, actionID, data);
415     TRACE("returning %08x\n", err);
416     return err;
417 }
418
419 static LONG WINTRUST_CertActionVerify(HWND hwnd, GUID *actionID,
420  WINTRUST_DATA *data)
421 {
422     DWORD stateAction;
423     LONG err = ERROR_SUCCESS;
424
425     if (WVT_ISINSTRUCT(WINTRUST_DATA, data->cbStruct, dwStateAction))
426         stateAction = data->dwStateAction;
427     else
428     {
429         TRACE("no dwStateAction, assuming WTD_STATEACTION_IGNORE\n");
430         stateAction = WTD_STATEACTION_IGNORE;
431     }
432     switch (stateAction)
433     {
434     case WTD_STATEACTION_IGNORE:
435         err = WINTRUST_CertVerifyAndClose(hwnd, actionID, data);
436         break;
437     case WTD_STATEACTION_VERIFY:
438         err = WINTRUST_CertVerify(hwnd, actionID, data);
439         break;
440     case WTD_STATEACTION_CLOSE:
441         err = WINTRUST_DefaultClose(hwnd, actionID, data);
442         break;
443     default:
444         FIXME("unimplemented for %d\n", data->dwStateAction);
445     }
446     return err;
447 }
448
449 static void dump_file_info(WINTRUST_FILE_INFO *pFile)
450 {
451     TRACE("%p\n", pFile);
452     if (pFile)
453     {
454         TRACE("cbStruct: %d\n", pFile->cbStruct);
455         TRACE("pcwszFilePath: %s\n", debugstr_w(pFile->pcwszFilePath));
456         TRACE("hFile: %p\n", pFile->hFile);
457         TRACE("pgKnownSubject: %s\n", debugstr_guid(pFile->pgKnownSubject));
458     }
459 }
460
461 static void dump_catalog_info(WINTRUST_CATALOG_INFO *catalog)
462 {
463     TRACE("%p\n", catalog);
464     if (catalog)
465     {
466         TRACE("cbStruct: %d\n", catalog->cbStruct);
467         TRACE("dwCatalogVersion: %d\n", catalog->dwCatalogVersion);
468         TRACE("pcwszCatalogFilePath: %s\n",
469          debugstr_w(catalog->pcwszCatalogFilePath));
470         TRACE("pcwszMemberTag: %s\n", debugstr_w(catalog->pcwszMemberTag));
471         TRACE("pcwszMemberFilePath: %s\n",
472          debugstr_w(catalog->pcwszMemberFilePath));
473         TRACE("hMemberFile: %p\n", catalog->hMemberFile);
474         TRACE("pbCalculatedFileHash: %p\n", catalog->pbCalculatedFileHash);
475         TRACE("cbCalculatedFileHash: %d\n", catalog->cbCalculatedFileHash);
476         TRACE("pcCatalogContext: %p\n", catalog->pcCatalogContext);
477     }
478 }
479
480 static void dump_blob_info(WINTRUST_BLOB_INFO *blob)
481 {
482     TRACE("%p\n", blob);
483     if (blob)
484     {
485         TRACE("cbStruct: %d\n", blob->cbStruct);
486         TRACE("gSubject: %s\n", debugstr_guid(&blob->gSubject));
487         TRACE("pcwszDisplayName: %s\n", debugstr_w(blob->pcwszDisplayName));
488         TRACE("cbMemObject: %d\n", blob->cbMemObject);
489         TRACE("pbMemObject: %p\n", blob->pbMemObject);
490         TRACE("cbMemSignedMsg: %d\n", blob->cbMemSignedMsg);
491         TRACE("pbMemSignedMsg: %p\n", blob->pbMemSignedMsg);
492     }
493 }
494
495 static void dump_sgnr_info(WINTRUST_SGNR_INFO *sgnr)
496 {
497     TRACE("%p\n", sgnr);
498     if (sgnr)
499     {
500         TRACE("cbStruct: %d\n", sgnr->cbStruct);
501         TRACE("pcwszDisplayName: %s\n", debugstr_w(sgnr->pcwszDisplayName));
502         TRACE("psSignerInfo: %p\n", sgnr->psSignerInfo);
503         TRACE("chStores: %d\n", sgnr->chStores);
504     }
505 }
506
507 static void dump_cert_info(WINTRUST_CERT_INFO *cert)
508 {
509     TRACE("%p\n", cert);
510     if (cert)
511     {
512         TRACE("cbStruct: %d\n", cert->cbStruct);
513         TRACE("pcwszDisplayName: %s\n", debugstr_w(cert->pcwszDisplayName));
514         TRACE("psCertContext: %p\n", cert->psCertContext);
515         TRACE("chStores: %d\n", cert->chStores);
516         TRACE("dwFlags: %08x\n", cert->dwFlags);
517         TRACE("psftVerifyAsOf: %p\n", cert->psftVerifyAsOf);
518     }
519 }
520
521 static void dump_wintrust_data(WINTRUST_DATA *data)
522 {
523     TRACE("%p\n", data);
524     if (data)
525     {
526         TRACE("cbStruct: %d\n", data->cbStruct);
527         TRACE("pPolicyCallbackData: %p\n", data->pPolicyCallbackData);
528         TRACE("pSIPClientData: %p\n", data->pSIPClientData);
529         TRACE("dwUIChoice: %d\n", data->dwUIChoice);
530         TRACE("fdwRevocationChecks: %08x\n", data->fdwRevocationChecks);
531         TRACE("dwUnionChoice: %d\n", data->dwUnionChoice);
532         switch (data->dwUnionChoice)
533         {
534         case WTD_CHOICE_FILE:
535             dump_file_info(data->u.pFile);
536             break;
537         case WTD_CHOICE_CATALOG:
538             dump_catalog_info(data->u.pCatalog);
539             break;
540         case WTD_CHOICE_BLOB:
541             dump_blob_info(data->u.pBlob);
542             break;
543         case WTD_CHOICE_SIGNER:
544             dump_sgnr_info(data->u.pSgnr);
545             break;
546         case WTD_CHOICE_CERT:
547             dump_cert_info(data->u.pCert);
548             break;
549         }
550         TRACE("dwStateAction: %d\n", data->dwStateAction);
551         TRACE("hWVTStateData: %p\n", data->hWVTStateData);
552         TRACE("pwszURLReference: %s\n", debugstr_w(data->pwszURLReference));
553         TRACE("dwProvFlags: %08x\n", data->dwProvFlags);
554         TRACE("dwUIContext: %d\n", data->dwUIContext);
555     }
556 }
557
558 /***********************************************************************
559  *              WinVerifyTrust (WINTRUST.@)
560  *
561  * Verifies an object by calling the specified trust provider.
562  *
563  * PARAMS
564  *   hwnd       [I] Handle to a caller window.
565  *   ActionID   [I] Pointer to a GUID that identifies the action to perform.
566  *   ActionData [I] Information used by the trust provider to verify the object.
567  *
568  * RETURNS
569  *   Success: Zero.
570  *   Failure: A TRUST_E_* error code.
571  *
572  * NOTES
573  *   Trust providers can be found at:
574  *   HKLM\SOFTWARE\Microsoft\Cryptography\Providers\Trust\
575  */
576 LONG WINAPI WinVerifyTrust( HWND hwnd, GUID *ActionID, LPVOID ActionData )
577 {
578     static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
579      0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
580     static const GUID published_software = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
581     static const GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
582     static const GUID generic_cert_verify = WINTRUST_ACTION_GENERIC_CERT_VERIFY;
583     static const GUID generic_chain_verify = WINTRUST_ACTION_GENERIC_CHAIN_VERIFY;
584     static const GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
585     LONG err = ERROR_SUCCESS;
586     WINTRUST_DATA *actionData = (WINTRUST_DATA *)ActionData;
587
588     TRACE("(%p, %s, %p)\n", hwnd, debugstr_guid(ActionID), ActionData);
589     dump_wintrust_data(ActionData);
590
591     /* Support for known old-style callers: */
592     if (IsEqualGUID(ActionID, &published_software))
593         err = WINTRUST_PublishedSoftware(hwnd, ActionID, ActionData);
594     else if (IsEqualGUID(ActionID, &cert_action_verify))
595         err = WINTRUST_CertActionVerify(hwnd, ActionID, ActionData);
596     else
597     {
598         DWORD stateAction;
599
600         /* Check known actions to warn of possible problems */
601         if (!IsEqualGUID(ActionID, &unknown) &&
602          !IsEqualGUID(ActionID, &generic_verify_v2) &&
603          !IsEqualGUID(ActionID, &generic_cert_verify) &&
604          !IsEqualGUID(ActionID, &generic_chain_verify))
605             WARN("unknown action %s, default behavior may not be right\n",
606              debugstr_guid(ActionID));
607         if (WVT_ISINSTRUCT(WINTRUST_DATA, actionData->cbStruct, dwStateAction))
608             stateAction = actionData->dwStateAction;
609         else
610         {
611             TRACE("no dwStateAction, assuming WTD_STATEACTION_IGNORE\n");
612             stateAction = WTD_STATEACTION_IGNORE;
613         }
614         switch (stateAction)
615         {
616         case WTD_STATEACTION_IGNORE:
617             err = WINTRUST_DefaultVerifyAndClose(hwnd, ActionID, ActionData);
618             break;
619         case WTD_STATEACTION_VERIFY:
620             err = WINTRUST_DefaultVerify(hwnd, ActionID, ActionData);
621             break;
622         case WTD_STATEACTION_CLOSE:
623             err = WINTRUST_DefaultClose(hwnd, ActionID, ActionData);
624             break;
625         default:
626             FIXME("unimplemented for %d\n", actionData->dwStateAction);
627         }
628     }
629
630     TRACE("returning %08x\n", err);
631     return err;
632 }
633
634 /***********************************************************************
635  *              WinVerifyTrustEx (WINTRUST.@)
636  */
637 HRESULT WINAPI WinVerifyTrustEx( HWND hwnd, GUID *ActionID,
638  WINTRUST_DATA* ActionData )
639 {
640     return WinVerifyTrust(hwnd, ActionID, ActionData);
641 }
642
643 /***********************************************************************
644  *              WTHelperGetProvSignerFromChain (WINTRUST.@)
645  */
646 CRYPT_PROVIDER_SGNR * WINAPI WTHelperGetProvSignerFromChain(
647  CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSigner,
648  DWORD idxCounterSigner)
649 {
650     CRYPT_PROVIDER_SGNR *sgnr;
651
652     TRACE("(%p %d %d %d)\n", pProvData, idxSigner, fCounterSigner,
653      idxCounterSigner);
654
655     if (idxSigner >= pProvData->csSigners || !pProvData->pasSigners)
656         return NULL;
657     sgnr = &pProvData->pasSigners[idxSigner];
658     if (fCounterSigner)
659     {
660         if (idxCounterSigner >= sgnr->csCounterSigners ||
661          !sgnr->pasCounterSigners)
662             return NULL;
663         sgnr = &sgnr->pasCounterSigners[idxCounterSigner];
664     }
665     TRACE("returning %p\n", sgnr);
666     return sgnr;
667 }
668
669 /***********************************************************************
670  *              WTHelperGetProvCertFromChain (WINTRUST.@)
671  */
672 CRYPT_PROVIDER_CERT * WINAPI WTHelperGetProvCertFromChain(
673  CRYPT_PROVIDER_SGNR *pSgnr, DWORD idxCert)
674 {
675     CRYPT_PROVIDER_CERT *cert;
676
677     TRACE("(%p %d)\n", pSgnr, idxCert);
678
679     if (idxCert >= pSgnr->csCertChain || !pSgnr->pasCertChain)
680         return NULL;
681     cert = &pSgnr->pasCertChain[idxCert];
682     TRACE("returning %p\n", cert);
683     return cert;
684 }
685
686 CRYPT_PROVIDER_PRIVDATA *WINAPI WTHelperGetProvPrivateDataFromChain(
687  CRYPT_PROVIDER_DATA* pProvData,
688  GUID* pgProviderID)
689 {
690     CRYPT_PROVIDER_PRIVDATA *privdata = NULL;
691     DWORD i;
692
693     TRACE("(%p, %s)\n", pProvData, debugstr_guid(pgProviderID));
694
695     for (i = 0; i < pProvData->csProvPrivData; i++)
696         if (IsEqualGUID(pgProviderID, &pProvData->pasProvPrivData[i].gProviderID))
697         {
698             privdata = &pProvData->pasProvPrivData[i];
699             break;
700         }
701
702     return privdata;
703 }
704
705 /***********************************************************************
706  *              WTHelperProvDataFromStateData (WINTRUST.@)
707  */
708 CRYPT_PROVIDER_DATA * WINAPI WTHelperProvDataFromStateData(HANDLE hStateData)
709 {
710     TRACE("%p\n", hStateData);
711     return (CRYPT_PROVIDER_DATA *)hStateData;
712 }
713
714 /***********************************************************************
715  *              WTHelperGetFileName(WINTRUST.@)
716  */
717 LPCWSTR WINAPI WTHelperGetFileName(WINTRUST_DATA *data)
718 {
719     TRACE("%p\n",data);
720     if (data->dwUnionChoice == WTD_CHOICE_FILE)
721         return data->u.pFile->pcwszFilePath;
722     else
723         return NULL;
724 }
725
726 /***********************************************************************
727  *              WTHelperGetFileHandle(WINTRUST.@)
728  */
729 HANDLE WINAPI WTHelperGetFileHandle(WINTRUST_DATA *data)
730 {
731     TRACE("%p\n",data);
732     if (data->dwUnionChoice == WTD_CHOICE_FILE)
733         return data->u.pFile->hFile;
734     else
735         return INVALID_HANDLE_VALUE;
736 }
737
738 static BOOL WINAPI WINTRUST_enumUsages(PCCRYPT_OID_INFO pInfo, void *pvArg)
739 {
740     PCCRYPT_OID_INFO **usages = (PCCRYPT_OID_INFO **)pvArg;
741     DWORD cUsages;
742     BOOL ret;
743
744     if (!*usages)
745     {
746         cUsages = 0;
747         *usages = WINTRUST_Alloc(2 * sizeof(PCCRYPT_OID_INFO));
748     }
749     else
750     {
751         PCCRYPT_OID_INFO *ptr;
752
753         /* Count the existing usages.
754          * FIXME: make sure the new usage doesn't duplicate any in the list?
755          */
756         for (cUsages = 0, ptr = *usages; *ptr; ptr++, cUsages++)
757             ;
758         *usages = WINTRUST_ReAlloc((CRYPT_OID_INFO *)*usages,
759          (cUsages + 1) * sizeof(PCCRYPT_OID_INFO));
760     }
761     if (*usages)
762     {
763         (*usages)[cUsages] = pInfo;
764         (*usages)[cUsages + 1] = NULL;
765         ret = TRUE;
766     }
767     else
768     {
769         SetLastError(ERROR_OUTOFMEMORY);
770         ret = FALSE;
771     }
772     return ret;
773 }
774
775 /***********************************************************************
776  *              WTHelperGetKnownUsages(WINTRUST.@)
777  *
778  * Enumerates the known enhanced key usages as an array of PCCRYPT_OID_INFOs.
779  *
780  * PARAMS
781  *  action      [In]     1 => allocate and return known usages, 2 => free previously
782  *                       allocated usages.
783  *  usages      [In/Out] If action == 1, *usages is set to an array of
784  *                       PCCRYPT_OID_INFO *.  The array is terminated with a NULL
785  *                       pointer.
786  *                       If action == 2, *usages is freed.
787  *
788  * RETURNS
789  *  TRUE on success, FALSE on failure.
790  */
791 BOOL WINAPI WTHelperGetKnownUsages(DWORD action, PCCRYPT_OID_INFO **usages)
792 {
793     BOOL ret;
794
795     TRACE("(%d, %p)\n", action, usages);
796
797     if (!usages)
798     {
799         SetLastError(ERROR_INVALID_PARAMETER);
800         return FALSE;
801     }
802
803     if (action == 1)
804     {
805         *usages = NULL;
806         ret = CryptEnumOIDInfo(CRYPT_ENHKEY_USAGE_OID_GROUP_ID, 0, usages,
807          WINTRUST_enumUsages);
808     }
809     else if (action == 2)
810     {
811         WINTRUST_Free((CRYPT_OID_INFO *)*usages);
812         *usages = NULL;
813         ret = TRUE;
814     }
815     else
816     {
817         WARN("unknown action %d\n", action);
818         SetLastError(ERROR_INVALID_PARAMETER);
819         ret = FALSE;
820     }
821     return ret;
822 }
823
824 static const WCHAR Software_Publishing[] = {
825  'S','o','f','t','w','a','r','e','\\',
826  'M','i','c','r','o','s','o','f','t','\\',
827  'W','i','n','d','o','w','s','\\',
828  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
829  'W','i','n','t','r','u','s','t','\\',
830  'T','r','u','s','t',' ','P','r','o','v','i','d','e','r','s','\\',
831  'S','o','f','t','w','a','r','e',' ',
832  'P','u','b','l','i','s','h','i','n','g',0 };
833 static const WCHAR State[] = { 'S','t','a','t','e',0 };
834
835 /***********************************************************************
836  *              WintrustGetRegPolicyFlags (WINTRUST.@)
837  */
838 void WINAPI WintrustGetRegPolicyFlags( DWORD* pdwPolicyFlags )
839 {
840     HKEY key;
841     LONG r;
842
843     TRACE("%p\n", pdwPolicyFlags);
844
845     *pdwPolicyFlags = 0;
846     r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0, NULL, 0,
847      KEY_READ, NULL, &key, NULL);
848     if (!r)
849     {
850         DWORD size = sizeof(DWORD);
851
852         r = RegQueryValueExW(key, State, NULL, NULL, (LPBYTE)pdwPolicyFlags,
853          &size);
854         RegCloseKey(key);
855         if (r)
856         {
857             /* Failed to query, create and return default value */
858             *pdwPolicyFlags = WTPF_IGNOREREVOCATIONONTS |
859              WTPF_OFFLINEOKNBU_COM |
860              WTPF_OFFLINEOKNBU_IND |
861              WTPF_OFFLINEOK_COM |
862              WTPF_OFFLINEOK_IND;
863             WintrustSetRegPolicyFlags(*pdwPolicyFlags);
864         }
865     }
866 }
867
868 /***********************************************************************
869  *              WintrustSetRegPolicyFlags (WINTRUST.@)
870  */
871 BOOL WINAPI WintrustSetRegPolicyFlags( DWORD dwPolicyFlags)
872 {
873     HKEY key;
874     LONG r;
875
876     TRACE("%x\n", dwPolicyFlags);
877
878     r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0,
879      NULL, 0, KEY_WRITE, NULL, &key, NULL);
880     if (!r)
881     {
882         r = RegSetValueExW(key, State, 0, REG_DWORD, (LPBYTE)&dwPolicyFlags,
883          sizeof(DWORD));
884         RegCloseKey(key);
885     }
886     if (r) SetLastError(r);
887     return r == ERROR_SUCCESS;
888 }
889
890 /* Utility functions */
891 void * WINAPI WINTRUST_Alloc(DWORD cb)
892 {
893     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
894 }
895
896 void * WINAPI WINTRUST_ReAlloc(void *ptr, DWORD cb)
897 {
898     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, cb);
899 }
900
901 void WINAPI WINTRUST_Free(void *p)
902 {
903     HeapFree(GetProcessHeap(), 0, p);
904 }
905
906 BOOL WINAPI WINTRUST_AddStore(CRYPT_PROVIDER_DATA *data, HCERTSTORE store)
907 {
908     BOOL ret = FALSE;
909
910     TRACE("(%p, %p)\n", data, store);
911
912     if (data->chStores)
913         data->pahStores = WINTRUST_ReAlloc(data->pahStores,
914          (data->chStores + 1) * sizeof(HCERTSTORE));
915     else
916     {
917         data->pahStores = WINTRUST_Alloc(sizeof(HCERTSTORE));
918         data->chStores = 0;
919     }
920     if (data->pahStores)
921     {
922         data->pahStores[data->chStores++] = CertDuplicateStore(store);
923         ret = TRUE;
924     }
925     else
926         SetLastError(ERROR_OUTOFMEMORY);
927     return ret;
928 }
929
930 BOOL WINAPI WINTRUST_AddSgnr(CRYPT_PROVIDER_DATA *data,
931  BOOL fCounterSigner, DWORD idxSigner, CRYPT_PROVIDER_SGNR *sgnr)
932 {
933     BOOL ret = FALSE;
934
935     TRACE("(%p, %d, %d, %p)\n", data, fCounterSigner, idxSigner, sgnr);
936
937     if (sgnr->cbStruct > sizeof(CRYPT_PROVIDER_SGNR))
938     {
939         SetLastError(ERROR_INVALID_PARAMETER);
940         return FALSE;
941     }
942     if (fCounterSigner)
943     {
944         FIXME("unimplemented for counter signers\n");
945         SetLastError(ERROR_INVALID_PARAMETER);
946         return FALSE;
947     }
948     if (data->csSigners)
949         data->pasSigners = WINTRUST_ReAlloc(data->pasSigners,
950          (data->csSigners + 1) * sizeof(CRYPT_PROVIDER_SGNR));
951     else
952     {
953         data->pasSigners = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR));
954         data->csSigners = 0;
955     }
956     if (data->pasSigners)
957     {
958         if (idxSigner < data->csSigners)
959             memmove(&data->pasSigners[idxSigner],
960              &data->pasSigners[idxSigner + 1],
961              (data->csSigners - idxSigner) * sizeof(CRYPT_PROVIDER_SGNR));
962         ret = TRUE;
963         if (sgnr->cbStruct == sizeof(CRYPT_PROVIDER_SGNR))
964         {
965             /* The PSDK says psSigner should be allocated using pfnAlloc, but
966              * it doesn't say anything about ownership.  Since callers are
967              * internal, assume ownership is passed, and just store the
968              * pointer.
969              */
970             memcpy(&data->pasSigners[idxSigner], sgnr,
971              sizeof(CRYPT_PROVIDER_SGNR));
972         }
973         else
974             memset(&data->pasSigners[idxSigner], 0,
975              sizeof(CRYPT_PROVIDER_SGNR));
976         data->csSigners++;
977     }
978     else
979         SetLastError(ERROR_OUTOFMEMORY);
980     return ret;
981 }
982
983 BOOL WINAPI WINTRUST_AddCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
984  BOOL fCounterSigner, DWORD idxCounterSigner, PCCERT_CONTEXT pCert2Add)
985 {
986     BOOL ret = FALSE;
987
988     TRACE("(%p, %d, %d, %d, %p)\n", data, idxSigner, fCounterSigner,
989      idxSigner, pCert2Add);
990
991     if (fCounterSigner)
992     {
993         FIXME("unimplemented for counter signers\n");
994         SetLastError(ERROR_INVALID_PARAMETER);
995         return FALSE;
996     }
997     if (data->pasSigners[idxSigner].csCertChain)
998         data->pasSigners[idxSigner].pasCertChain =
999          WINTRUST_ReAlloc(data->pasSigners[idxSigner].pasCertChain,
1000          (data->pasSigners[idxSigner].csCertChain + 1) *
1001          sizeof(CRYPT_PROVIDER_CERT));
1002     else
1003     {
1004         data->pasSigners[idxSigner].pasCertChain =
1005          WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_CERT));
1006         data->pasSigners[idxSigner].csCertChain = 0;
1007     }
1008     if (data->pasSigners[idxSigner].pasCertChain)
1009     {
1010         CRYPT_PROVIDER_CERT *cert = &data->pasSigners[idxSigner].pasCertChain[
1011          data->pasSigners[idxSigner].csCertChain];
1012
1013         cert->cbStruct = sizeof(CRYPT_PROVIDER_CERT);
1014         cert->pCert = CertDuplicateCertificateContext(pCert2Add);
1015         data->pasSigners[idxSigner].csCertChain++;
1016         ret = TRUE;
1017     }
1018     else
1019         SetLastError(ERROR_OUTOFMEMORY);
1020     return ret;
1021 }
1022
1023 BOOL WINAPI WINTRUST_AddPrivData(CRYPT_PROVIDER_DATA *data,
1024  CRYPT_PROVIDER_PRIVDATA *pPrivData2Add)
1025 {
1026     BOOL ret = FALSE;
1027
1028     TRACE("(%p, %p)\n", data, pPrivData2Add);
1029
1030     if (pPrivData2Add->cbStruct > sizeof(CRYPT_PROVIDER_PRIVDATA))
1031     {
1032         SetLastError(ERROR_INVALID_PARAMETER);
1033         WARN("invalid struct size\n");
1034         return FALSE;
1035     }
1036     if (data->csProvPrivData)
1037         data->pasProvPrivData = WINTRUST_ReAlloc(data->pasProvPrivData,
1038          (data->csProvPrivData + 1) * sizeof(CRYPT_PROVIDER_SGNR));
1039     else
1040     {
1041         data->pasProvPrivData = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR));
1042         data->csProvPrivData = 0;
1043     }
1044     if (data->pasProvPrivData)
1045     {
1046         DWORD i;
1047
1048         for (i = 0; i < data->csProvPrivData; i++)
1049             if (IsEqualGUID(&pPrivData2Add->gProviderID, &data->pasProvPrivData[i]))
1050                 break;
1051
1052         data->pasProvPrivData[i] = *pPrivData2Add;
1053         if (i == data->csProvPrivData)
1054             data->csProvPrivData++;
1055     }
1056     else
1057         SetLastError(ERROR_OUTOFMEMORY);
1058     return ret;
1059 }