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