wintrust: Support the CERT_CERTIFICATE_ACTION_VERIFY action.
[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 const WCHAR Software_Publishing[] = {
739  'S','o','f','t','w','a','r','e','\\',
740  'M','i','c','r','o','s','o','f','t','\\',
741  'W','i','n','d','o','w','s','\\',
742  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
743  'W','i','n','t','r','u','s','t','\\',
744  'T','r','u','s','t',' ','P','r','o','v','i','d','e','r','s','\\',
745  'S','o','f','t','w','a','r','e',' ',
746  'P','u','b','l','i','s','h','i','n','g',0 };
747 static const WCHAR State[] = { 'S','t','a','t','e',0 };
748
749 /***********************************************************************
750  *              WintrustGetRegPolicyFlags (WINTRUST.@)
751  */
752 void WINAPI WintrustGetRegPolicyFlags( DWORD* pdwPolicyFlags )
753 {
754     HKEY key;
755     LONG r;
756
757     TRACE("%p\n", pdwPolicyFlags);
758
759     *pdwPolicyFlags = 0;
760     r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0, NULL, 0,
761      KEY_READ, NULL, &key, NULL);
762     if (!r)
763     {
764         DWORD size = sizeof(DWORD);
765
766         r = RegQueryValueExW(key, State, NULL, NULL, (LPBYTE)pdwPolicyFlags,
767          &size);
768         RegCloseKey(key);
769         if (r)
770         {
771             /* Failed to query, create and return default value */
772             *pdwPolicyFlags = WTPF_IGNOREREVOCATIONONTS |
773              WTPF_OFFLINEOKNBU_COM |
774              WTPF_OFFLINEOKNBU_IND |
775              WTPF_OFFLINEOK_COM |
776              WTPF_OFFLINEOK_IND;
777             WintrustSetRegPolicyFlags(*pdwPolicyFlags);
778         }
779     }
780 }
781
782 /***********************************************************************
783  *              WintrustSetRegPolicyFlags (WINTRUST.@)
784  */
785 BOOL WINAPI WintrustSetRegPolicyFlags( DWORD dwPolicyFlags)
786 {
787     HKEY key;
788     LONG r;
789
790     TRACE("%x\n", dwPolicyFlags);
791
792     r = RegCreateKeyExW(HKEY_CURRENT_USER, Software_Publishing, 0,
793      NULL, 0, KEY_WRITE, NULL, &key, NULL);
794     if (!r)
795     {
796         r = RegSetValueExW(key, State, 0, REG_DWORD, (LPBYTE)&dwPolicyFlags,
797          sizeof(DWORD));
798         RegCloseKey(key);
799     }
800     if (r) SetLastError(r);
801     return r == ERROR_SUCCESS;
802 }
803
804 /* Utility functions */
805 void * WINAPI WINTRUST_Alloc(DWORD cb)
806 {
807     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
808 }
809
810 void * WINAPI WINTRUST_ReAlloc(void *ptr, DWORD cb)
811 {
812     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, cb);
813 }
814
815 void WINAPI WINTRUST_Free(void *p)
816 {
817     HeapFree(GetProcessHeap(), 0, p);
818 }
819
820 BOOL WINAPI WINTRUST_AddStore(CRYPT_PROVIDER_DATA *data, HCERTSTORE store)
821 {
822     BOOL ret = FALSE;
823
824     TRACE("(%p, %p)\n", data, store);
825
826     if (data->chStores)
827         data->pahStores = WINTRUST_ReAlloc(data->pahStores,
828          (data->chStores + 1) * sizeof(HCERTSTORE));
829     else
830     {
831         data->pahStores = WINTRUST_Alloc(sizeof(HCERTSTORE));
832         data->chStores = 0;
833     }
834     if (data->pahStores)
835     {
836         data->pahStores[data->chStores++] = CertDuplicateStore(store);
837         ret = TRUE;
838     }
839     else
840         SetLastError(ERROR_OUTOFMEMORY);
841     return ret;
842 }
843
844 BOOL WINAPI WINTRUST_AddSgnr(CRYPT_PROVIDER_DATA *data,
845  BOOL fCounterSigner, DWORD idxSigner, CRYPT_PROVIDER_SGNR *sgnr)
846 {
847     BOOL ret = FALSE;
848
849     TRACE("(%p, %d, %d, %p)\n", data, fCounterSigner, idxSigner, sgnr);
850
851     if (sgnr->cbStruct > sizeof(CRYPT_PROVIDER_SGNR))
852     {
853         SetLastError(ERROR_INVALID_PARAMETER);
854         return FALSE;
855     }
856     if (fCounterSigner)
857     {
858         FIXME("unimplemented for counter signers\n");
859         SetLastError(ERROR_INVALID_PARAMETER);
860         return FALSE;
861     }
862     if (data->csSigners)
863         data->pasSigners = WINTRUST_ReAlloc(data->pasSigners,
864          (data->csSigners + 1) * sizeof(CRYPT_PROVIDER_SGNR));
865     else
866     {
867         data->pasSigners = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR));
868         data->csSigners = 0;
869     }
870     if (data->pasSigners)
871     {
872         if (idxSigner < data->csSigners)
873             memmove(&data->pasSigners[idxSigner],
874              &data->pasSigners[idxSigner + 1],
875              (data->csSigners - idxSigner) * sizeof(CRYPT_PROVIDER_SGNR));
876         ret = TRUE;
877         if (sgnr->cbStruct == sizeof(CRYPT_PROVIDER_SGNR))
878         {
879             /* The PSDK says psSigner should be allocated using pfnAlloc, but
880              * it doesn't say anything about ownership.  Since callers are
881              * internal, assume ownership is passed, and just store the
882              * pointer.
883              */
884             memcpy(&data->pasSigners[idxSigner], sgnr,
885              sizeof(CRYPT_PROVIDER_SGNR));
886         }
887         else
888             memset(&data->pasSigners[idxSigner], 0,
889              sizeof(CRYPT_PROVIDER_SGNR));
890         data->csSigners++;
891     }
892     else
893         SetLastError(ERROR_OUTOFMEMORY);
894     return ret;
895 }
896
897 BOOL WINAPI WINTRUST_AddCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
898  BOOL fCounterSigner, DWORD idxCounterSigner, PCCERT_CONTEXT pCert2Add)
899 {
900     BOOL ret = FALSE;
901
902     TRACE("(%p, %d, %d, %d, %p)\n", data, idxSigner, fCounterSigner,
903      idxSigner, pCert2Add);
904
905     if (fCounterSigner)
906     {
907         FIXME("unimplemented for counter signers\n");
908         SetLastError(ERROR_INVALID_PARAMETER);
909         return FALSE;
910     }
911     if (data->pasSigners[idxSigner].csCertChain)
912         data->pasSigners[idxSigner].pasCertChain =
913          WINTRUST_ReAlloc(data->pasSigners[idxSigner].pasCertChain,
914          (data->pasSigners[idxSigner].csCertChain + 1) *
915          sizeof(CRYPT_PROVIDER_CERT));
916     else
917     {
918         data->pasSigners[idxSigner].pasCertChain =
919          WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_CERT));
920         data->pasSigners[idxSigner].csCertChain = 0;
921     }
922     if (data->pasSigners[idxSigner].pasCertChain)
923     {
924         CRYPT_PROVIDER_CERT *cert = &data->pasSigners[idxSigner].pasCertChain[
925          data->pasSigners[idxSigner].csCertChain];
926
927         cert->cbStruct = sizeof(CRYPT_PROVIDER_CERT);
928         cert->pCert = CertDuplicateCertificateContext(pCert2Add);
929         data->pasSigners[idxSigner].csCertChain++;
930         ret = TRUE;
931     }
932     else
933         SetLastError(ERROR_OUTOFMEMORY);
934     return ret;
935 }
936
937 BOOL WINAPI WINTRUST_AddPrivData(CRYPT_PROVIDER_DATA *data,
938  CRYPT_PROVIDER_PRIVDATA *pPrivData2Add)
939 {
940     BOOL ret = FALSE;
941
942     TRACE("(%p, %p)\n", data, pPrivData2Add);
943
944     if (pPrivData2Add->cbStruct > sizeof(CRYPT_PROVIDER_PRIVDATA))
945     {
946         SetLastError(ERROR_INVALID_PARAMETER);
947         WARN("invalid struct size\n");
948         return FALSE;
949     }
950     if (data->csProvPrivData)
951         data->pasProvPrivData = WINTRUST_ReAlloc(data->pasProvPrivData,
952          (data->csProvPrivData + 1) * sizeof(CRYPT_PROVIDER_SGNR));
953     else
954     {
955         data->pasProvPrivData = WINTRUST_Alloc(sizeof(CRYPT_PROVIDER_SGNR));
956         data->csProvPrivData = 0;
957     }
958     if (data->pasProvPrivData)
959     {
960         DWORD i;
961
962         for (i = 0; i < data->csProvPrivData; i++)
963             if (IsEqualGUID(&pPrivData2Add->gProviderID, &data->pasProvPrivData[i]))
964                 break;
965
966         data->pasProvPrivData[i] = *pPrivData2Add;
967         if (i == data->csProvPrivData)
968             data->csProvPrivData++;
969     }
970     else
971         SetLastError(ERROR_OUTOFMEMORY);
972     return ret;
973 }