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