wintrust: Remove a dead assignment (LLVM/Clang).
[wine] / dlls / wintrust / softpub.c
1 /*
2  * Copyright 2007 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 #include <stdarg.h>
19
20 #define NONAMELESSUNION
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wintrust.h"
25 #include "mssip.h"
26 #include "softpub.h"
27 #include "winnls.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
31
32 HRESULT WINAPI SoftpubDefCertInit(CRYPT_PROVIDER_DATA *data)
33 {
34     HRESULT ret = S_FALSE;
35
36     TRACE("(%p)\n", data);
37
38     if (data->padwTrustStepErrors &&
39      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
40         ret = S_OK;
41     TRACE("returning %08x\n", ret);
42     return ret;
43 }
44
45 HRESULT WINAPI SoftpubInitialize(CRYPT_PROVIDER_DATA *data)
46 {
47     HRESULT ret = S_FALSE;
48
49     TRACE("(%p)\n", data);
50
51     if (data->padwTrustStepErrors &&
52      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
53         ret = S_OK;
54     TRACE("returning %08x\n", ret);
55     return ret;
56 }
57
58 HRESULT WINAPI DriverInitializePolicy(CRYPT_PROVIDER_DATA *data)
59 {
60     FIXME("stub\n");
61     return S_OK;
62 }
63
64 HRESULT WINAPI DriverCleanupPolicy(CRYPT_PROVIDER_DATA *data)
65 {
66     FIXME("stub\n");
67     return S_OK;
68 }
69
70 HRESULT WINAPI DriverFinalPolicy(CRYPT_PROVIDER_DATA *data)
71 {
72     FIXME("stub\n");
73     return S_OK;
74 }
75
76 /* Assumes data->pWintrustData->u.pFile exists.  Makes sure a file handle is
77  * open for the file.
78  */
79 static DWORD SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA *data)
80 {
81     DWORD err = ERROR_SUCCESS;
82
83     /* PSDK implies that all values should be initialized to NULL, so callers
84      * typically have hFile as NULL rather than INVALID_HANDLE_VALUE.  Check
85      * for both.
86      */
87     if (!data->pWintrustData->u.pFile->hFile ||
88      data->pWintrustData->u.pFile->hFile == INVALID_HANDLE_VALUE)
89     {
90         data->pWintrustData->u.pFile->hFile =
91             CreateFileW(data->pWintrustData->u.pFile->pcwszFilePath, GENERIC_READ,
92           FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
93         if (data->pWintrustData->u.pFile->hFile != INVALID_HANDLE_VALUE)
94             data->fOpenedFile = TRUE;
95         else
96             err = GetLastError();
97     }
98     if (!err)
99         GetFileTime(data->pWintrustData->u.pFile->hFile, &data->sftSystemTime,
100          NULL, NULL);
101     TRACE("returning %d\n", err);
102     return err;
103 }
104
105 /* Assumes data->pWintrustData->u.pFile exists.  Sets data->pPDSip->gSubject to
106  * the file's subject GUID.
107  */
108 static DWORD SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA *data)
109 {
110     DWORD err = ERROR_SUCCESS;
111
112     if (!WVT_ISINSTRUCT(WINTRUST_FILE_INFO,
113      data->pWintrustData->u.pFile->cbStruct, pgKnownSubject) ||
114      !data->pWintrustData->u.pFile->pgKnownSubject)
115     {
116         if (!CryptSIPRetrieveSubjectGuid(
117          data->pWintrustData->u.pFile->pcwszFilePath,
118          data->pWintrustData->u.pFile->hFile,
119          &data->u.pPDSip->gSubject))
120             err = GetLastError();
121     }
122     else
123         data->u.pPDSip->gSubject = *data->pWintrustData->u.pFile->pgKnownSubject;
124     TRACE("returning %d\n", err);
125     return err;
126 }
127
128 /* Assumes data->u.pPDSip exists, and its gSubject member set.
129  * Allocates data->u.pPDSip->pSip and loads it, if possible.
130  */
131 static DWORD SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data)
132 {
133     DWORD err = ERROR_SUCCESS;
134
135     data->u.pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO));
136     if (data->u.pPDSip->pSip)
137     {
138         if (!CryptSIPLoad(&data->u.pPDSip->gSubject, 0, data->u.pPDSip->pSip))
139             err = GetLastError();
140     }
141     else
142         err = ERROR_OUTOFMEMORY;
143     TRACE("returning %d\n", err);
144     return err;
145 }
146
147 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated.
148  * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg.
149  */
150 static DWORD SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data, HANDLE file,
151  LPCWSTR filePath)
152 {
153     DWORD err = ERROR_SUCCESS;
154     BOOL ret;
155     LPBYTE buf = NULL;
156     DWORD size = 0;
157
158     data->u.pPDSip->psSipSubjectInfo =
159      data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO));
160     if (!data->u.pPDSip->psSipSubjectInfo)
161         return ERROR_OUTOFMEMORY;
162
163     data->u.pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO);
164     data->u.pPDSip->psSipSubjectInfo->pgSubjectType = &data->u.pPDSip->gSubject;
165     data->u.pPDSip->psSipSubjectInfo->hFile = file;
166     data->u.pPDSip->psSipSubjectInfo->pwsFileName = filePath;
167     data->u.pPDSip->psSipSubjectInfo->hProv = data->hProv;
168     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
169      &data->dwEncoding, 0, &size, 0);
170     if (!ret)
171         return TRUST_E_NOSIGNATURE;
172
173     buf = data->psPfns->pfnAlloc(size);
174     if (!buf)
175         return ERROR_OUTOFMEMORY;
176
177     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
178      &data->dwEncoding, 0, &size, buf);
179     if (ret)
180     {
181         data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv,
182          NULL, NULL);
183         if (data->hMsg)
184         {
185             ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE);
186             if (!ret)
187                 err = GetLastError();
188         }
189     }
190     else
191         err = GetLastError();
192
193     data->psPfns->pfnFree(buf);
194     TRACE("returning %d\n", err);
195     return err;
196 }
197
198 static DWORD SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data)
199 {
200     DWORD err = ERROR_SUCCESS;
201     HCERTSTORE store;
202
203     store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding,
204      data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg);
205     if (store)
206     {
207         if (!data->psPfns->pfnAddStore2Chain(data, store))
208             err = GetLastError();
209         CertCloseStore(store, 0);
210     }
211     else
212         err = GetLastError();
213     TRACE("returning %d\n", err);
214     return err;
215 }
216
217 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data)
218 {
219     BOOL ret;
220     DWORD size, err = ERROR_SUCCESS;
221     LPSTR oid = NULL;
222     LPBYTE buf = NULL;
223
224     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL,
225      &size);
226     if (!ret)
227     {
228         err = GetLastError();
229         goto error;
230     }
231     oid = data->psPfns->pfnAlloc(size);
232     if (!oid)
233     {
234         err = ERROR_OUTOFMEMORY;
235         goto error;
236     }
237     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, oid,
238      &size);
239     if (!ret)
240     {
241         err = GetLastError();
242         goto error;
243     }
244     ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size);
245     if (!ret)
246     {
247         err = GetLastError();
248         goto error;
249     }
250     buf = data->psPfns->pfnAlloc(size);
251     if (!buf)
252     {
253         err = ERROR_OUTOFMEMORY;
254         goto error;
255     }
256     ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size);
257     if (!ret)
258     {
259         err = GetLastError();
260         goto error;
261     }
262     ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0, NULL, &size);
263     if (!ret)
264     {
265         err = GetLastError();
266         goto error;
267     }
268     data->u.pPDSip->psIndirectData = data->psPfns->pfnAlloc(size);
269     if (!data->u.pPDSip->psIndirectData)
270     {
271         err = ERROR_OUTOFMEMORY;
272         goto error;
273     }
274     ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0,
275      data->u.pPDSip->psIndirectData, &size);
276     if (!ret)
277         err = GetLastError();
278
279 error:
280     TRACE("returning %d\n", err);
281     data->psPfns->pfnFree(oid);
282     data->psPfns->pfnFree(buf);
283     return err;
284 }
285
286 static DWORD SOFTPUB_LoadCertMessage(CRYPT_PROVIDER_DATA *data)
287 {
288     DWORD err = ERROR_SUCCESS;
289
290     if (data->pWintrustData->u.pCert &&
291      WVT_IS_CBSTRUCT_GT_MEMBEROFFSET(WINTRUST_CERT_INFO,
292      data->pWintrustData->u.pCert->cbStruct, psCertContext))
293     {
294         if (data->psPfns)
295         {
296             CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } };
297             DWORD i;
298             BOOL ret;
299
300             /* Add a signer with nothing but the time to verify, so we can
301              * add a cert to it
302              */
303             if (WVT_ISINSTRUCT(WINTRUST_CERT_INFO,
304              data->pWintrustData->u.pCert->cbStruct, psftVerifyAsOf) &&
305              data->pWintrustData->u.pCert->psftVerifyAsOf)
306                 data->sftSystemTime = signer.sftVerifyAsOf;
307             else
308             {
309                 SYSTEMTIME sysTime;
310
311                 GetSystemTime(&sysTime);
312                 SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf);
313             }
314             ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
315             if (ret)
316             {
317                 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
318                  data->pWintrustData->u.pCert->psCertContext);
319                 if (WVT_ISINSTRUCT(WINTRUST_CERT_INFO,
320                  data->pWintrustData->u.pCert->cbStruct, pahStores))
321                         for (i = 0;
322                          ret && i < data->pWintrustData->u.pCert->chStores; i++)
323                             ret = data->psPfns->pfnAddStore2Chain(data,
324                              data->pWintrustData->u.pCert->pahStores[i]);
325             }
326             if (!ret)
327                 err = GetLastError();
328         }
329     }
330     else
331         err = ERROR_INVALID_PARAMETER;
332     return err;
333 }
334
335 static DWORD SOFTPUB_LoadFileMessage(CRYPT_PROVIDER_DATA *data)
336 {
337     DWORD err = ERROR_SUCCESS;
338
339     if (!data->pWintrustData->u.pFile)
340     {
341         err = ERROR_INVALID_PARAMETER;
342         goto error;
343     }
344     err = SOFTPUB_OpenFile(data);
345     if (err)
346         goto error;
347     err = SOFTPUB_GetFileSubject(data);
348     if (err)
349         goto error;
350     err = SOFTPUB_GetSIP(data);
351     if (err)
352         goto error;
353     err = SOFTPUB_GetMessageFromFile(data, data->pWintrustData->u.pFile->hFile,
354      data->pWintrustData->u.pFile->pcwszFilePath);
355     if (err)
356         goto error;
357     err = SOFTPUB_CreateStoreFromMessage(data);
358     if (err)
359         goto error;
360     err = SOFTPUB_DecodeInnerContent(data);
361
362 error:
363     if (err && data->fOpenedFile && data->pWintrustData->u.pFile)
364     {
365         /* The caller won't expect the file to be open on failure, so close it.
366          */
367         CloseHandle(data->pWintrustData->u.pFile->hFile);
368         data->pWintrustData->u.pFile->hFile = INVALID_HANDLE_VALUE;
369         data->fOpenedFile = FALSE;
370     }
371     return err;
372 }
373
374 static DWORD SOFTPUB_LoadCatalogMessage(CRYPT_PROVIDER_DATA *data)
375 {
376     DWORD err;
377     HANDLE catalog = INVALID_HANDLE_VALUE;
378
379     if (!data->pWintrustData->u.pCatalog)
380     {
381         SetLastError(ERROR_INVALID_PARAMETER);
382         return FALSE;
383     }
384     catalog = CreateFileW(data->pWintrustData->u.pCatalog->pcwszCatalogFilePath,
385      GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
386      NULL);
387     if (catalog == INVALID_HANDLE_VALUE)
388         return GetLastError();
389     if (!CryptSIPRetrieveSubjectGuid(
390      data->pWintrustData->u.pCatalog->pcwszCatalogFilePath, catalog,
391      &data->u.pPDSip->gSubject))
392     {
393         err = GetLastError();
394         goto error;
395     }
396     err = SOFTPUB_GetSIP(data);
397     if (err)
398         goto error;
399     err = SOFTPUB_GetMessageFromFile(data, catalog,
400      data->pWintrustData->u.pCatalog->pcwszCatalogFilePath);
401     if (err)
402         goto error;
403     err = SOFTPUB_CreateStoreFromMessage(data);
404     if (err)
405         goto error;
406     err = SOFTPUB_DecodeInnerContent(data);
407     /* FIXME: this loads the catalog file, but doesn't validate the member. */
408 error:
409     CloseHandle(catalog);
410     return err;
411 }
412
413 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data)
414 {
415     DWORD err = ERROR_SUCCESS;
416
417     TRACE("(%p)\n", data);
418
419     if (!data->padwTrustStepErrors)
420         return S_FALSE;
421
422     switch (data->pWintrustData->dwUnionChoice)
423     {
424     case WTD_CHOICE_CERT:
425         err = SOFTPUB_LoadCertMessage(data);
426         break;
427     case WTD_CHOICE_FILE:
428         err = SOFTPUB_LoadFileMessage(data);
429         break;
430     case WTD_CHOICE_CATALOG:
431         err = SOFTPUB_LoadCatalogMessage(data);
432         break;
433     default:
434         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
435         err = ERROR_INVALID_PARAMETER;
436     }
437
438     if (err)
439         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] = err;
440     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
441      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
442     return !err ? S_OK : S_FALSE;
443 }
444
445 static CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data,
446  DWORD signerIdx)
447 {
448     BOOL ret;
449     CMSG_SIGNER_INFO *signerInfo = NULL;
450     DWORD size;
451
452     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx,
453      NULL, &size);
454     if (ret)
455     {
456         signerInfo = data->psPfns->pfnAlloc(size);
457         if (signerInfo)
458         {
459             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM,
460              signerIdx, signerInfo, &size);
461             if (!ret)
462             {
463                 data->psPfns->pfnFree(signerInfo);
464                 signerInfo = NULL;
465             }
466         }
467         else
468             SetLastError(ERROR_OUTOFMEMORY);
469     }
470     return signerInfo;
471 }
472
473 static BOOL WINTRUST_GetTimeFromCounterSigner(
474  const CMSG_CMS_SIGNER_INFO *counterSignerInfo, FILETIME *time)
475 {
476     DWORD i;
477     BOOL foundTimeStamp = FALSE;
478
479     for (i = 0; !foundTimeStamp && i < counterSignerInfo->AuthAttrs.cAttr; i++)
480     {
481         if (!strcmp(counterSignerInfo->AuthAttrs.rgAttr[i].pszObjId,
482          szOID_RSA_signingTime))
483         {
484             const CRYPT_ATTRIBUTE *attr =
485              &counterSignerInfo->AuthAttrs.rgAttr[i];
486             DWORD j;
487
488             for (j = 0; !foundTimeStamp && j < attr->cValue; j++)
489             {
490                 static const DWORD encoding = X509_ASN_ENCODING |
491                  PKCS_7_ASN_ENCODING;
492                 DWORD size = sizeof(FILETIME);
493
494                 foundTimeStamp = CryptDecodeObjectEx(encoding,
495                  X509_CHOICE_OF_TIME,
496                  attr->rgValue[j].pbData, attr->rgValue[j].cbData, 0, NULL,
497                  time, &size);
498             }
499         }
500     }
501     return foundTimeStamp;
502 }
503
504 static LPCSTR filetime_to_str(const FILETIME *time)
505 {
506     static char date[80];
507     char dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
508     SYSTEMTIME sysTime;
509
510     if (!time) return NULL;
511
512     GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
513      sizeof(dateFmt) / sizeof(dateFmt[0]));
514     FileTimeToSystemTime(time, &sysTime);
515     GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
516      sizeof(date) / sizeof(date[0]));
517     return date;
518 }
519
520 static FILETIME WINTRUST_GetTimeFromSigner(const CRYPT_PROVIDER_DATA *data,
521  const CMSG_SIGNER_INFO *signerInfo)
522 {
523     DWORD i;
524     FILETIME time;
525     BOOL foundTimeStamp = FALSE;
526
527     for (i = 0; !foundTimeStamp && i < signerInfo->UnauthAttrs.cAttr; i++)
528     {
529         if (!strcmp(signerInfo->UnauthAttrs.rgAttr[i].pszObjId,
530          szOID_RSA_counterSign))
531         {
532             const CRYPT_ATTRIBUTE *attr = &signerInfo->UnauthAttrs.rgAttr[i];
533             DWORD j;
534
535             for (j = 0; j < attr->cValue; j++)
536             {
537                 static const DWORD encoding = X509_ASN_ENCODING |
538                  PKCS_7_ASN_ENCODING;
539                 CMSG_CMS_SIGNER_INFO *counterSignerInfo;
540                 DWORD size;
541                 BOOL ret = CryptDecodeObjectEx(encoding, CMS_SIGNER_INFO,
542                  attr->rgValue[j].pbData, attr->rgValue[j].cbData,
543                  CRYPT_DECODE_ALLOC_FLAG, NULL, &counterSignerInfo, &size);
544                 if (ret)
545                 {
546                     /* FIXME: need to verify countersigner signature too */
547                     foundTimeStamp = WINTRUST_GetTimeFromCounterSigner(
548                      counterSignerInfo, &time);
549                     LocalFree(counterSignerInfo);
550                 }
551             }
552         }
553     }
554     if (!foundTimeStamp)
555     {
556         TRACE("returning system time %s\n",
557          filetime_to_str(&data->sftSystemTime));
558         time = data->sftSystemTime;
559     }
560     else
561         TRACE("returning time from message %s\n", filetime_to_str(&time));
562     return time;
563 }
564
565 static DWORD WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
566 {
567     DWORD err;
568     CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx);
569
570     if (signerInfo)
571     {
572         CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
573
574         sgnr.psSigner = signerInfo;
575         sgnr.sftVerifyAsOf = WINTRUST_GetTimeFromSigner(data, signerInfo);
576         if (!data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr))
577             err = GetLastError();
578         else
579             err = ERROR_SUCCESS;
580     }
581     else
582         err = GetLastError();
583     return err;
584 }
585
586 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
587  DWORD signerIdx)
588 {
589     BOOL ret;
590     CERT_INFO *certInfo = NULL;
591     DWORD size;
592
593     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
594      NULL, &size);
595     if (ret)
596     {
597         certInfo = data->psPfns->pfnAlloc(size);
598         if (certInfo)
599         {
600             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
601              signerIdx, certInfo, &size);
602             if (!ret)
603             {
604                 data->psPfns->pfnFree(certInfo);
605                 certInfo = NULL;
606             }
607         }
608         else
609             SetLastError(ERROR_OUTOFMEMORY);
610     }
611     return certInfo;
612 }
613
614 static DWORD WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
615 {
616     DWORD err;
617     CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx);
618
619     if (certInfo)
620     {
621         PCCERT_CONTEXT subject = CertGetSubjectCertificateFromStore(
622          data->pahStores[0], data->dwEncoding, certInfo);
623
624         if (subject)
625         {
626             CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0,
627              signerIdx, CMSG_VERIFY_SIGNER_CERT, (LPVOID)subject };
628
629             if (!CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX,
630              &para))
631                 err = TRUST_E_CERT_SIGNATURE;
632             else
633             {
634                 data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
635                  subject);
636                 err = ERROR_SUCCESS;
637             }
638             CertFreeCertificateContext(subject);
639         }
640         else
641             err = TRUST_E_NO_SIGNER_CERT;
642         data->psPfns->pfnFree(certInfo);
643     }
644     else
645         err = GetLastError();
646     return err;
647 }
648
649 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
650 {
651     DWORD err;
652
653     TRACE("(%p)\n", data);
654
655     if (!data->padwTrustStepErrors)
656         return S_FALSE;
657
658     if (data->hMsg)
659     {
660         DWORD signerCount, size;
661
662         size = sizeof(signerCount);
663         if (CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
664          &signerCount, &size))
665         {
666             DWORD i;
667
668             err = ERROR_SUCCESS;
669             for (i = 0; !err && i < signerCount; i++)
670             {
671                 if (!(err = WINTRUST_SaveSigner(data, i)))
672                     err = WINTRUST_VerifySigner(data, i);
673             }
674         }
675         else
676             err = TRUST_E_NOSIGNATURE;
677     }
678     else
679         err = ERROR_SUCCESS;
680     if (err)
681         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = err;
682     return !err ? S_OK : S_FALSE;
683 }
684
685 static DWORD WINTRUST_TrustStatusToConfidence(DWORD errorStatus)
686 {
687     DWORD confidence = 0;
688
689     confidence = 0;
690     if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
691         confidence |= CERT_CONFIDENCE_SIG;
692     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
693         confidence |= CERT_CONFIDENCE_TIME;
694     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
695         confidence |= CERT_CONFIDENCE_TIMENEST;
696     return confidence;
697 }
698
699 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
700  BOOL fCounterSignerChain, DWORD idxCounterSigner)
701 {
702     BOOL ret;
703
704     TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain,
705      idxCounterSigner);
706
707     if (fCounterSignerChain)
708     {
709         FIXME("unimplemented for counter signers\n");
710         ret = FALSE;
711     }
712     else
713     {
714         PCERT_SIMPLE_CHAIN simpleChain =
715          data->pasSigners[idxSigner].pChainContext->rgpChain[0];
716         DWORD i;
717
718         ret = TRUE;
719         for (i = 0; i < simpleChain->cElement; i++)
720         {
721             /* Set confidence */
722             data->pasSigners[idxSigner].pasCertChain[i].dwConfidence =
723              WINTRUST_TrustStatusToConfidence(
724              simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus);
725             /* Set additional flags */
726             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
727              CERT_TRUST_IS_UNTRUSTED_ROOT))
728                 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE;
729             if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus &
730              CERT_TRUST_IS_SELF_SIGNED)
731                 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE;
732             if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
733              CERT_TRUST_IS_CYCLIC)
734                 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE;
735         }
736     }
737     return ret;
738 }
739
740 static DWORD WINTRUST_TrustStatusToError(DWORD errorStatus)
741 {
742     DWORD error;
743
744     if (errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
745         error = TRUST_E_CERT_SIGNATURE;
746     else if (errorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT)
747         error = CERT_E_UNTRUSTEDROOT;
748     else if (errorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
749         error = CERT_E_EXPIRED;
750     else if (errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED)
751         error = CERT_E_VALIDITYPERIODNESTING;
752     else if (errorStatus & CERT_TRUST_IS_REVOKED)
753         error = CERT_E_REVOKED;
754     else if (errorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION ||
755      errorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
756         error = CERT_E_REVOCATION_FAILURE;
757     else if (errorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
758         error = CERT_E_WRONG_USAGE;
759     else if (errorStatus & CERT_TRUST_IS_CYCLIC)
760         error = CERT_E_CHAINING;
761     else if (errorStatus & CERT_TRUST_INVALID_EXTENSION)
762         error = CERT_E_CRITICAL;
763     else if (errorStatus & CERT_TRUST_INVALID_POLICY_CONSTRAINTS)
764         error = CERT_E_INVALID_POLICY;
765     else if (errorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
766         error = TRUST_E_BASIC_CONSTRAINTS;
767     else if (errorStatus & CERT_TRUST_INVALID_NAME_CONSTRAINTS ||
768      errorStatus & CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT ||
769      errorStatus & CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT ||
770      errorStatus & CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT ||
771      errorStatus & CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT)
772         error = CERT_E_INVALID_NAME;
773     else if (errorStatus & CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY)
774         error = CERT_E_INVALID_POLICY;
775     else if (errorStatus)
776     {
777         FIXME("unknown error status %08x\n", errorStatus);
778         error = TRUST_E_SYSTEM_ERROR;
779     }
780     else
781         error = S_OK;
782     return error;
783 }
784
785 static DWORD WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
786 {
787     DWORD err, i;
788     PCERT_SIMPLE_CHAIN simpleChain =
789      data->pasSigners[signerIdx].pChainContext->rgpChain[0];
790
791     data->pasSigners[signerIdx].pasCertChain[0].dwConfidence =
792      WINTRUST_TrustStatusToConfidence(
793      simpleChain->rgpElement[0]->TrustStatus.dwErrorStatus);
794     data->pasSigners[signerIdx].pasCertChain[0].pChainElement =
795      simpleChain->rgpElement[0];
796     err = ERROR_SUCCESS;
797     for (i = 1; !err && i < simpleChain->cElement; i++)
798     {
799         if (data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
800          simpleChain->rgpElement[i]->pCertContext))
801         {
802             data->pasSigners[signerIdx].pasCertChain[i].pChainElement =
803              simpleChain->rgpElement[i];
804             data->pasSigners[signerIdx].pasCertChain[i].dwConfidence =
805              WINTRUST_TrustStatusToConfidence(
806              simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus);
807         }
808         else
809             err = GetLastError();
810     }
811     data->pasSigners[signerIdx].pasCertChain[simpleChain->cElement - 1].dwError
812      = WINTRUST_TrustStatusToError(
813      simpleChain->rgpElement[simpleChain->cElement - 1]->
814      TrustStatus.dwErrorStatus);
815     return err;
816 }
817
818 static void WINTRUST_CreateChainPolicyCreateInfo(
819  const CRYPT_PROVIDER_DATA *data, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO info,
820  PCERT_CHAIN_PARA chainPara)
821 {
822     chainPara->cbSize = sizeof(CERT_CHAIN_PARA);
823     if (data->pRequestUsage)
824         chainPara->RequestedUsage = *data->pRequestUsage;
825     else
826     {
827         chainPara->RequestedUsage.dwType = 0;
828         chainPara->RequestedUsage.Usage.cUsageIdentifier = 0;
829     }
830     info->u.cbSize = sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO);
831     info->hChainEngine = NULL;
832     info->pChainPara = chainPara;
833     if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT)
834         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
835     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN)
836         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
837     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
838         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
839     else
840         info->dwFlags = 0;
841     info->pvReserved = NULL;
842 }
843
844 static DWORD WINTRUST_CreateChainForSigner(CRYPT_PROVIDER_DATA *data,
845  DWORD signer, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo,
846  PCERT_CHAIN_PARA chainPara)
847 {
848     DWORD err = ERROR_SUCCESS;
849     HCERTSTORE store = NULL;
850
851     if (data->chStores)
852     {
853         store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
854          CERT_STORE_CREATE_NEW_FLAG, NULL);
855         if (store)
856         {
857             DWORD i;
858
859             for (i = 0; i < data->chStores; i++)
860                 CertAddStoreToCollection(store, data->pahStores[i], 0, 0);
861         }
862         else
863             err = GetLastError();
864     }
865     if (!err)
866     {
867         /* Expect the end certificate for each signer to be the only cert in
868          * the chain:
869          */
870         if (data->pasSigners[signer].csCertChain)
871         {
872             BOOL ret;
873
874             /* Create a certificate chain for each signer */
875             ret = CertGetCertificateChain(createInfo->hChainEngine,
876              data->pasSigners[signer].pasCertChain[0].pCert,
877              &data->pasSigners[signer].sftVerifyAsOf, store,
878              chainPara, createInfo->dwFlags, createInfo->pvReserved,
879              &data->pasSigners[signer].pChainContext);
880             if (ret)
881             {
882                 if (data->pasSigners[signer].pChainContext->cChain != 1)
883                 {
884                     FIXME("unimplemented for more than 1 simple chain\n");
885                     err = E_NOTIMPL;
886                 }
887                 else
888                 {
889                     if (!(err = WINTRUST_CopyChain(data, signer)))
890                     {
891                         if (data->psPfns->pfnCertCheckPolicy)
892                         {
893                             ret = data->psPfns->pfnCertCheckPolicy(data, signer,
894                              FALSE, 0);
895                             if (!ret)
896                                 err = GetLastError();
897                         }
898                         else
899                             TRACE(
900                              "no cert check policy, skipping policy check\n");
901                     }
902                 }
903             }
904             else
905                 err = GetLastError();
906         }
907         CertCloseStore(store, 0);
908     }
909     return err;
910 }
911
912 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data)
913 {
914     DWORD err;
915
916     TRACE("(%p)\n", data);
917
918     if (!data->csSigners)
919         err = TRUST_E_NOSIGNATURE;
920     else
921     {
922         DWORD i;
923         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo;
924         CERT_CHAIN_PARA chainPara;
925
926         WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
927         err = ERROR_SUCCESS;
928         for (i = 0; !err && i < data->csSigners; i++)
929             err = WINTRUST_CreateChainForSigner(data, i, &createInfo,
930              &chainPara);
931     }
932     if (err)
933         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = err;
934     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
935      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
936     return !err ? S_OK : S_FALSE;
937 }
938
939 HRESULT WINAPI GenericChainCertificateTrust(CRYPT_PROVIDER_DATA *data)
940 {
941     DWORD err;
942     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
943      data->pWintrustData->pPolicyCallbackData;
944
945     TRACE("(%p)\n", data);
946
947     if (policyData && policyData->u.cbSize !=
948      sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO))
949     {
950         err = ERROR_INVALID_PARAMETER;
951         goto end;
952     }
953     if (!data->csSigners)
954         err = TRUST_E_NOSIGNATURE;
955     else
956     {
957         DWORD i;
958         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo, *pCreateInfo;
959         CERT_CHAIN_PARA chainPara, *pChainPara;
960
961         if (policyData)
962         {
963             pCreateInfo = policyData->pSignerChainInfo;
964             pChainPara = pCreateInfo->pChainPara;
965         }
966         else
967         {
968             WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
969             pChainPara = &chainPara;
970             pCreateInfo = &createInfo;
971         }
972         err = ERROR_SUCCESS;
973         for (i = 0; !err && i < data->csSigners; i++)
974             err = WINTRUST_CreateChainForSigner(data, i, pCreateInfo,
975              pChainPara);
976     }
977
978 end:
979     if (err)
980         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = err;
981     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
982      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
983     return !err ? S_OK : S_FALSE;
984 }
985
986 HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data)
987 {
988     BOOL ret;
989     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
990
991     TRACE("(%p)\n", data);
992
993     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
994         FIXME("unimplemented for UI choice %d\n",
995          data->pWintrustData->dwUIChoice);
996     if (!data->csSigners)
997     {
998         ret = FALSE;
999         policyStatus.dwError = TRUST_E_NOSIGNATURE;
1000     }
1001     else
1002     {
1003         DWORD i;
1004
1005         ret = TRUE;
1006         for (i = 0; ret && i < data->csSigners; i++)
1007         {
1008             BYTE hash[20];
1009             DWORD size = sizeof(hash);
1010
1011             /* First make sure cert isn't disallowed */
1012             if ((ret = CertGetCertificateContextProperty(
1013              data->pasSigners[i].pasCertChain[0].pCert,
1014              CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
1015             {
1016                 static const WCHAR disallowedW[] =
1017                  { 'D','i','s','a','l','l','o','w','e','d',0 };
1018                 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
1019                  X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER,
1020                  disallowedW);
1021
1022                 if (disallowed)
1023                 {
1024                     PCCERT_CONTEXT found = CertFindCertificateInStore(
1025                      disallowed, X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH,
1026                      hash, NULL);
1027
1028                     if (found)
1029                     {
1030                         /* Disallowed!  Can't verify it. */
1031                         policyStatus.dwError = TRUST_E_SUBJECT_NOT_TRUSTED;
1032                         ret = FALSE;
1033                         CertFreeCertificateContext(found);
1034                     }
1035                     CertCloseStore(disallowed, 0);
1036                 }
1037             }
1038             if (ret)
1039             {
1040                 CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
1041
1042                 if (data->dwRegPolicySettings & WTPF_TRUSTTEST)
1043                     policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG;
1044                 if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID)
1045                     policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG;
1046                 if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
1047                     policyPara.dwFlags |=
1048                      CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
1049                      CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
1050                      CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
1051                 if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION)
1052                     policyPara.dwFlags |=
1053                      CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
1054                      CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
1055                      CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
1056                      CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
1057                 CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE,
1058                  data->pasSigners[i].pChainContext, &policyPara, &policyStatus);
1059                 if (policyStatus.dwError != NO_ERROR)
1060                     ret = FALSE;
1061             }
1062         }
1063     }
1064     if (!ret)
1065         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] =
1066          policyStatus.dwError;
1067     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
1068      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
1069     return ret ? S_OK : S_FALSE;
1070 }
1071
1072 static HRESULT WINAPI WINTRUST_DefaultPolicy(CRYPT_PROVIDER_DATA *pProvData,
1073  DWORD dwStepError, DWORD dwRegPolicySettings, DWORD cSigner,
1074  PWTD_GENERIC_CHAIN_POLICY_SIGNER_INFO rgpSigner, void *pvPolicyArg)
1075 {
1076     DWORD i;
1077     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
1078
1079     for (i = 0; !policyStatus.dwError && i < cSigner; i++)
1080     {
1081         CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
1082
1083         if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
1084             policyPara.dwFlags |=
1085              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
1086              CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
1087              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
1088         if (dwRegPolicySettings & WTPF_IGNOREREVOKATION)
1089             policyPara.dwFlags |=
1090              CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
1091              CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
1092              CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
1093              CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
1094         CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
1095          rgpSigner[i].pChainContext, &policyPara, &policyStatus);
1096     }
1097     return policyStatus.dwError;
1098 }
1099
1100 HRESULT WINAPI GenericChainFinalProv(CRYPT_PROVIDER_DATA *data)
1101 {
1102     HRESULT err = NO_ERROR; /* not a typo, MS confused the types */
1103     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
1104      data->pWintrustData->pPolicyCallbackData;
1105
1106     TRACE("(%p)\n", data);
1107
1108     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
1109         FIXME("unimplemented for UI choice %d\n",
1110          data->pWintrustData->dwUIChoice);
1111     if (!data->csSigners)
1112         err = TRUST_E_NOSIGNATURE;
1113     else
1114     {
1115         PFN_WTD_GENERIC_CHAIN_POLICY_CALLBACK policyCallback;
1116         void *policyArg;
1117         WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO *signers = NULL;
1118
1119         if (policyData)
1120         {
1121             policyCallback = policyData->pfnPolicyCallback;
1122             policyArg = policyData->pvPolicyArg;
1123         }
1124         else
1125         {
1126             policyCallback = WINTRUST_DefaultPolicy;
1127             policyArg = NULL;
1128         }
1129         if (data->csSigners)
1130         {
1131             DWORD i;
1132
1133             signers = data->psPfns->pfnAlloc(
1134              data->csSigners * sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO));
1135             if (signers)
1136             {
1137                 for (i = 0; i < data->csSigners; i++)
1138                 {
1139                     signers[i].u.cbSize =
1140                      sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO);
1141                     signers[i].pChainContext =
1142                      data->pasSigners[i].pChainContext;
1143                     signers[i].dwSignerType = data->pasSigners[i].dwSignerType;
1144                     signers[i].pMsgSignerInfo = data->pasSigners[i].psSigner;
1145                     signers[i].dwError = data->pasSigners[i].dwError;
1146                     if (data->pasSigners[i].csCounterSigners)
1147                         FIXME("unimplemented for counter signers\n");
1148                     signers[i].cCounterSigner = 0;
1149                     signers[i].rgpCounterSigner = NULL;
1150                 }
1151             }
1152             else
1153                 err = ERROR_OUTOFMEMORY;
1154         }
1155         if (err == NO_ERROR)
1156             err = policyCallback(data, TRUSTERROR_STEP_FINAL_POLICYPROV,
1157              data->dwRegPolicySettings, data->csSigners, signers, policyArg);
1158         data->psPfns->pfnFree(signers);
1159     }
1160     if (err != NO_ERROR)
1161         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = err;
1162     TRACE("returning %d (%08x)\n", err == NO_ERROR ? S_OK : S_FALSE,
1163      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
1164     return err == NO_ERROR ? S_OK : S_FALSE;
1165 }
1166
1167 HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data)
1168 {
1169     DWORD i, j;
1170
1171     for (i = 0; i < data->csSigners; i++)
1172     {
1173         for (j = 0; j < data->pasSigners[i].csCertChain; j++)
1174             CertFreeCertificateContext(data->pasSigners[i].pasCertChain[j].pCert);
1175         data->psPfns->pfnFree(data->pasSigners[i].pasCertChain);
1176         data->psPfns->pfnFree(data->pasSigners[i].psSigner);
1177         CertFreeCertificateChain(data->pasSigners[i].pChainContext);
1178     }
1179     data->psPfns->pfnFree(data->pasSigners);
1180
1181     for (i = 0; i < data->chStores; i++)
1182         CertCloseStore(data->pahStores[i], 0);
1183     data->psPfns->pfnFree(data->pahStores);
1184
1185     if (data->u.pPDSip)
1186     {
1187         data->psPfns->pfnFree(data->u.pPDSip->pSip);
1188         data->psPfns->pfnFree(data->u.pPDSip->pCATSip);
1189         data->psPfns->pfnFree(data->u.pPDSip->psSipSubjectInfo);
1190         data->psPfns->pfnFree(data->u.pPDSip->psSipCATSubjectInfo);
1191         data->psPfns->pfnFree(data->u.pPDSip->psIndirectData);
1192     }
1193
1194     CryptMsgClose(data->hMsg);
1195
1196     if (data->fOpenedFile &&
1197      data->pWintrustData->dwUnionChoice == WTD_CHOICE_FILE)
1198         CloseHandle(data->pWintrustData->u.pFile->hFile);
1199
1200     return S_OK;
1201 }
1202
1203 HRESULT WINAPI HTTPSCertificateTrust(CRYPT_PROVIDER_DATA *data)
1204 {
1205     FIXME("(%p)\n", data);
1206     return S_OK;
1207 }
1208
1209 HRESULT WINAPI HTTPSFinalProv(CRYPT_PROVIDER_DATA *data)
1210 {
1211     FIXME("(%p)\n", data);
1212     return S_OK;
1213 }