winspool.drv: Fix the character count passed into RegEnumKeyExW in get_local_monitors.
[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 "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
30
31 HRESULT WINAPI SoftpubDefCertInit(CRYPT_PROVIDER_DATA *data)
32 {
33     HRESULT ret = S_FALSE;
34
35     TRACE("(%p)\n", data);
36
37     if (data->padwTrustStepErrors &&
38      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
39         ret = S_OK;
40     TRACE("returning %08x\n", ret);
41     return ret;
42 }
43
44 HRESULT WINAPI SoftpubInitialize(CRYPT_PROVIDER_DATA *data)
45 {
46     HRESULT ret = S_FALSE;
47
48     TRACE("(%p)\n", data);
49
50     if (data->padwTrustStepErrors &&
51      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
52         ret = S_OK;
53     TRACE("returning %08x\n", ret);
54     return ret;
55 }
56
57 /* Assumes data->pWintrustData->u.pFile exists.  Makes sure a file handle is
58  * open for the file.
59  */
60 static BOOL SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA *data)
61 {
62     BOOL ret = TRUE;
63
64     /* PSDK implies that all values should be initialized to NULL, so callers
65      * typically have hFile as NULL rather than INVALID_HANDLE_VALUE.  Check
66      * for both.
67      */
68     if (!data->pWintrustData->u.pFile->hFile ||
69      data->pWintrustData->u.pFile->hFile == INVALID_HANDLE_VALUE)
70     {
71         data->pWintrustData->u.pFile->hFile =
72             CreateFileW(data->pWintrustData->u.pFile->pcwszFilePath, GENERIC_READ,
73           FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
74         if (data->pWintrustData->u.pFile->hFile != INVALID_HANDLE_VALUE)
75             data->fOpenedFile = TRUE;
76         else
77             ret = FALSE;
78     }
79     if (ret)
80         GetFileTime(data->pWintrustData->u.pFile->hFile, &data->sftSystemTime,
81          NULL, NULL);
82     TRACE("returning %d\n", ret);
83     return ret;
84 }
85
86 /* Assumes data->pWintrustData->u.pFile exists.  Sets data->pPDSip->gSubject to
87  * the file's subject GUID.
88  */
89 static BOOL SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA *data)
90 {
91     BOOL ret;
92
93     if (!data->pWintrustData->u.pFile->pgKnownSubject)
94     {
95         ret = CryptSIPRetrieveSubjectGuid(
96          data->pWintrustData->u.pFile->pcwszFilePath,
97          data->pWintrustData->u.pFile->hFile,
98          &data->u.pPDSip->gSubject);
99     }
100     else
101     {
102         memcpy(&data->u.pPDSip->gSubject,
103          data->pWintrustData->u.pFile->pgKnownSubject, sizeof(GUID));
104         ret = TRUE;
105     }
106     TRACE("returning %d\n", ret);
107     return ret;
108 }
109
110 /* Assumes data->u.pPDSip exists, and its gSubject member set.
111  * Allocates data->u.pPDSip->pSip and loads it, if possible.
112  */
113 static BOOL SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data)
114 {
115     BOOL ret;
116
117     data->u.pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO));
118     if (data->u.pPDSip->pSip)
119         ret = CryptSIPLoad(&data->u.pPDSip->gSubject, 0, data->u.pPDSip->pSip);
120     else
121     {
122         SetLastError(ERROR_OUTOFMEMORY);
123         ret = FALSE;
124     }
125     TRACE("returning %d\n", ret);
126     return ret;
127 }
128
129 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated.
130  * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg.
131  */
132 static BOOL SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data)
133 {
134     BOOL ret;
135     LPBYTE buf = NULL;
136     DWORD size = 0;
137
138     data->u.pPDSip->psSipSubjectInfo =
139      data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO));
140     if (!data->u.pPDSip->psSipSubjectInfo)
141     {
142         SetLastError(ERROR_OUTOFMEMORY);
143         return FALSE;
144     }
145
146     data->u.pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO);
147     data->u.pPDSip->psSipSubjectInfo->pgSubjectType = &data->u.pPDSip->gSubject;
148     data->u.pPDSip->psSipSubjectInfo->hFile = data->pWintrustData->u.pFile->hFile;
149     data->u.pPDSip->psSipSubjectInfo->pwsFileName =
150      data->pWintrustData->u.pFile->pcwszFilePath;
151     data->u.pPDSip->psSipSubjectInfo->hProv = data->hProv;
152     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
153      &data->dwEncoding, 0, &size, 0);
154     if (!ret)
155     {
156         SetLastError(TRUST_E_NOSIGNATURE);
157         return FALSE;
158     }
159
160     buf = data->psPfns->pfnAlloc(size);
161     if (!buf)
162     {
163         SetLastError(ERROR_OUTOFMEMORY);
164         return FALSE;
165     }
166
167     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
168      &data->dwEncoding, 0, &size, buf);
169     if (ret)
170     {
171         data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv,
172          NULL, NULL);
173         if (data->hMsg)
174             ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE);
175     }
176
177     data->psPfns->pfnFree(buf);
178     TRACE("returning %d\n", ret);
179     return ret;
180 }
181
182 static BOOL SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data)
183 {
184     BOOL ret = FALSE;
185     HCERTSTORE store;
186
187     store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding,
188      data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg);
189     if (store)
190     {
191         ret = data->psPfns->pfnAddStore2Chain(data, store);
192         CertCloseStore(store, 0);
193     }
194     TRACE("returning %d\n", ret);
195     return ret;
196 }
197
198 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data)
199 {
200     BOOL ret;
201     DWORD size;
202     LPBYTE buf = NULL;
203
204     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL,
205      &size);
206     if (!ret)
207         goto error;
208     buf = data->psPfns->pfnAlloc(size);
209     if (!buf)
210     {
211         SetLastError(ERROR_OUTOFMEMORY);
212         ret = FALSE;
213         goto error;
214     }
215     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, buf,
216      &size);
217     if (!ret)
218         goto error;
219     if (!strcmp((LPCSTR)buf, SPC_INDIRECT_DATA_OBJID))
220     {
221         data->psPfns->pfnFree(buf);
222         buf = NULL;
223         ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size);
224         if (!ret)
225             goto error;
226         buf = data->psPfns->pfnAlloc(size);
227         if (!buf)
228         {
229             SetLastError(ERROR_OUTOFMEMORY);
230             ret = FALSE;
231             goto error;
232         }
233         ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size);
234         if (!ret)
235             goto error;
236         ret = CryptDecodeObject(data->dwEncoding,
237          SPC_INDIRECT_DATA_CONTENT_STRUCT, buf, size, 0, NULL, &size);
238         if (!ret)
239             goto error;
240         data->u.pPDSip->psIndirectData = data->psPfns->pfnAlloc(size);
241         if (!data->u.pPDSip->psIndirectData)
242         {
243             SetLastError(ERROR_OUTOFMEMORY);
244             ret = FALSE;
245             goto error;
246         }
247         ret = CryptDecodeObject(data->dwEncoding,
248          SPC_INDIRECT_DATA_CONTENT_STRUCT, buf, size, 0,
249          data->u.pPDSip->psIndirectData, &size);
250     }
251     else
252     {
253         FIXME("unimplemented for OID %s\n", (LPCSTR)buf);
254         SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN);
255         ret = FALSE;
256     }
257
258 error:
259     TRACE("returning %d\n", ret);
260     return ret;
261 }
262
263 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data)
264 {
265     BOOL ret;
266
267     TRACE("(%p)\n", data);
268
269     if (!data->padwTrustStepErrors)
270         return S_FALSE;
271
272     switch (data->pWintrustData->dwUnionChoice)
273     {
274     case WTD_CHOICE_CERT:
275         if (data->pWintrustData->u.pCert &&
276          data->pWintrustData->u.pCert->cbStruct == sizeof(WINTRUST_CERT_INFO))
277         {
278             if (data->psPfns)
279             {
280                 CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } };
281                 DWORD i;
282
283                 /* Add a signer with nothing but the time to verify, so we can
284                  * add a cert to it
285                  */
286                 if (data->pWintrustData->u.pCert->psftVerifyAsOf)
287                     memcpy(&data->sftSystemTime, &signer.sftVerifyAsOf,
288                      sizeof(FILETIME));
289                 else
290                 {
291                     SYSTEMTIME sysTime;
292
293                     GetSystemTime(&sysTime);
294                     SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf);
295                 }
296                 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
297                 if (!ret)
298                     goto error;
299                 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
300                  data->pWintrustData->u.pCert->psCertContext);
301                 if (!ret)
302                     goto error;
303                 for (i = 0; ret && i < data->pWintrustData->u.pCert->chStores;
304                  i++)
305                     ret = data->psPfns->pfnAddStore2Chain(data,
306                      data->pWintrustData->u.pCert->pahStores[i]);
307             }
308             else
309             {
310                 /* Do nothing!?  See the tests */
311                 ret = TRUE;
312             }
313         }
314         else
315         {
316             SetLastError(ERROR_INVALID_PARAMETER);
317             ret = FALSE;
318         }
319         break;
320     case WTD_CHOICE_FILE:
321         if (!data->pWintrustData->u.pFile)
322         {
323             SetLastError(ERROR_INVALID_PARAMETER);
324             ret = FALSE;
325             goto error;
326         }
327         ret = SOFTPUB_OpenFile(data);
328         if (!ret)
329             goto error;
330         ret = SOFTPUB_GetFileSubject(data);
331         if (!ret)
332             goto error;
333         ret = SOFTPUB_GetSIP(data);
334         if (!ret)
335             goto error;
336         ret = SOFTPUB_GetMessageFromFile(data);
337         if (!ret)
338             goto error;
339         ret = SOFTPUB_CreateStoreFromMessage(data);
340         if (!ret)
341             goto error;
342         ret = SOFTPUB_DecodeInnerContent(data);
343         break;
344     default:
345         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
346         SetLastError(ERROR_INVALID_PARAMETER);
347         ret = FALSE;
348     }
349
350 error:
351     if (!ret)
352         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
353          GetLastError();
354     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
355      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
356     return ret ? S_OK : S_FALSE;
357 }
358
359 static CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data,
360  DWORD signerIdx)
361 {
362     BOOL ret;
363     CMSG_SIGNER_INFO *signerInfo = NULL;
364     DWORD size;
365
366     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx,
367      NULL, &size);
368     if (ret)
369     {
370         signerInfo = data->psPfns->pfnAlloc(size);
371         if (signerInfo)
372         {
373             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM,
374              signerIdx, signerInfo, &size);
375             if (!ret)
376             {
377                 data->psPfns->pfnFree(signerInfo);
378                 signerInfo = NULL;
379             }
380         }
381         else
382             SetLastError(ERROR_OUTOFMEMORY);
383     }
384     return signerInfo;
385 }
386
387 static BOOL WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
388 {
389     BOOL ret;
390     CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx);
391
392     if (signerInfo)
393     {
394         CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
395
396         sgnr.psSigner = signerInfo;
397         memcpy(&sgnr.sftVerifyAsOf, &data->sftSystemTime, sizeof(FILETIME));
398         ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr);
399     }
400     else
401         ret = FALSE;
402     return ret;
403 }
404
405 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
406  DWORD signerIdx)
407 {
408     BOOL ret;
409     CERT_INFO *certInfo = NULL;
410     DWORD size;
411
412     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
413      NULL, &size);
414     if (ret)
415     {
416         certInfo = data->psPfns->pfnAlloc(size);
417         if (certInfo)
418         {
419             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
420              signerIdx, certInfo, &size);
421             if (!ret)
422             {
423                 data->psPfns->pfnFree(certInfo);
424                 certInfo = NULL;
425             }
426         }
427         else
428             SetLastError(ERROR_OUTOFMEMORY);
429     }
430     return certInfo;
431 }
432
433 static BOOL WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
434 {
435     BOOL ret;
436     CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx);
437
438     if (certInfo)
439     {
440         PCCERT_CONTEXT subject = CertGetSubjectCertificateFromStore(
441          data->pahStores[0], data->dwEncoding, certInfo);
442
443         if (subject)
444         {
445             CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0,
446              signerIdx, CMSG_VERIFY_SIGNER_CERT, (LPVOID)subject };
447
448             ret = CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX,
449              &para);
450             if (!ret)
451                 SetLastError(TRUST_E_CERT_SIGNATURE);
452             else
453                 data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
454                  subject);
455             CertFreeCertificateContext(subject);
456         }
457         else
458         {
459             SetLastError(TRUST_E_NO_SIGNER_CERT);
460             ret = FALSE;
461         }
462         data->psPfns->pfnFree(certInfo);
463     }
464     else
465         ret = FALSE;
466     return ret;
467 }
468
469 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
470 {
471     BOOL ret;
472
473     TRACE("(%p)\n", data);
474
475     if (!data->padwTrustStepErrors)
476         return S_FALSE;
477
478     if (data->hMsg)
479     {
480         DWORD signerCount, size;
481
482         size = sizeof(signerCount);
483         ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
484          &signerCount, &size);
485         if (ret)
486         {
487             DWORD i;
488
489             for (i = 0; ret && i < signerCount; i++)
490             {
491                 if ((ret = WINTRUST_SaveSigner(data, i)))
492                     ret = WINTRUST_VerifySigner(data, i);
493             }
494         }
495         else
496             SetLastError(TRUST_E_NOSIGNATURE);
497     }
498     else
499         ret = TRUE;
500     if (!ret)
501         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
502          GetLastError();
503     return ret ? S_OK : S_FALSE;
504 }
505
506 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
507  BOOL fCounterSignerChain, DWORD idxCounterSigner)
508 {
509     BOOL ret;
510
511     TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain,
512      idxCounterSigner);
513
514     if (fCounterSignerChain)
515     {
516         FIXME("unimplemented for counter signers\n");
517         ret = FALSE;
518     }
519     else
520     {
521         PCERT_SIMPLE_CHAIN simpleChain =
522          data->pasSigners[idxSigner].pChainContext->rgpChain[0];
523         DWORD i;
524
525         ret = TRUE;
526         for (i = 0; i < simpleChain->cElement; i++)
527         {
528             /* Set confidence */
529             data->pasSigners[idxSigner].pasCertChain[i].dwConfidence = 0;
530             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
531              CERT_TRUST_IS_NOT_TIME_VALID))
532                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
533                  |= CERT_CONFIDENCE_TIME;
534             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
535              CERT_TRUST_IS_NOT_TIME_NESTED))
536                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
537                  |= CERT_CONFIDENCE_TIMENEST;
538             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
539              CERT_TRUST_IS_NOT_SIGNATURE_VALID))
540                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
541                  |= CERT_CONFIDENCE_SIG;
542             /* Set additional flags */
543             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
544              CERT_TRUST_IS_UNTRUSTED_ROOT))
545                 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE;
546             if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus &
547              CERT_TRUST_IS_SELF_SIGNED)
548                 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE;
549             if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
550              CERT_TRUST_IS_CYCLIC)
551                 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE;
552         }
553     }
554     return ret;
555 }
556
557 static BOOL WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
558 {
559     BOOL ret;
560     PCERT_SIMPLE_CHAIN simpleChain =
561      data->pasSigners[signerIdx].pChainContext->rgpChain[0];
562     DWORD i;
563
564     data->pasSigners[signerIdx].pasCertChain[0].pChainElement =
565      simpleChain->rgpElement[0];
566     ret = TRUE;
567     for (i = 1; ret && i < simpleChain->cElement; i++)
568     {
569         ret = data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
570          simpleChain->rgpElement[i]->pCertContext);
571         if (ret)
572             data->pasSigners[signerIdx].pasCertChain[i].pChainElement =
573              simpleChain->rgpElement[i];
574     }
575     return ret;
576 }
577
578 static void WINTRUST_CreateChainPolicyCreateInfo(
579  const CRYPT_PROVIDER_DATA *data, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO info,
580  PCERT_CHAIN_PARA chainPara)
581 {
582     chainPara->cbSize = sizeof(CERT_CHAIN_PARA);
583     if (data->pRequestUsage)
584         memcpy(&chainPara->RequestedUsage, data->pRequestUsage,
585          sizeof(CERT_USAGE_MATCH));
586     info->u.cbSize = sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO);
587     info->hChainEngine = NULL;
588     info->pChainPara = chainPara;
589     if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT)
590         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
591     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN)
592         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
593     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
594         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
595     else
596         info->dwFlags = 0;
597     info->pvReserved = NULL;
598 }
599
600 static BOOL WINTRUST_CreateChainForSigner(CRYPT_PROVIDER_DATA *data,
601  DWORD signer, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo,
602  PCERT_CHAIN_PARA chainPara)
603 {
604     BOOL ret = TRUE;
605
606     /* Expect the end certificate for each signer to be the only cert in the
607      * chain:
608      */
609     if (data->pasSigners[signer].csCertChain)
610     {
611         /* Create a certificate chain for each signer */
612         ret = CertGetCertificateChain(createInfo->hChainEngine,
613          data->pasSigners[signer].pasCertChain[0].pCert,
614          &data->pasSigners[signer].sftVerifyAsOf,
615          data->chStores ? data->pahStores[0] : NULL,
616          chainPara, createInfo->dwFlags, createInfo->pvReserved,
617          &data->pasSigners[signer].pChainContext);
618         if (ret)
619         {
620             if (data->pasSigners[signer].pChainContext->cChain != 1)
621             {
622                 FIXME("unimplemented for more than 1 simple chain\n");
623                 ret = FALSE;
624             }
625             else
626             {
627                 if ((ret = WINTRUST_CopyChain(data, signer)))
628                     ret = data->psPfns->pfnCertCheckPolicy(data, signer, FALSE,
629                      0);
630             }
631         }
632     }
633     return ret;
634 }
635
636 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data)
637 {
638     BOOL ret;
639
640     TRACE("(%p)\n", data);
641
642     if (!data->csSigners)
643     {
644         ret = FALSE;
645         SetLastError(TRUST_E_NOSIGNATURE);
646     }
647     else
648     {
649         DWORD i;
650         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo;
651         CERT_CHAIN_PARA chainPara;
652
653         WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
654         ret = TRUE;
655         for (i = 0; i < data->csSigners; i++)
656             ret = WINTRUST_CreateChainForSigner(data, i, &createInfo,
657              &chainPara);
658     }
659     if (!ret)
660         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
661          GetLastError();
662     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
663      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
664     return ret ? S_OK : S_FALSE;
665 }
666
667 HRESULT WINAPI GenericChainCertificateTrust(CRYPT_PROVIDER_DATA *data)
668 {
669     BOOL ret;
670     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
671      (WTD_GENERIC_CHAIN_POLICY_DATA *)data->pWintrustData->pPolicyCallbackData;
672
673     TRACE("(%p)\n", data);
674
675     if (policyData && policyData->u.cbSize !=
676      sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO))
677     {
678         SetLastError(ERROR_INVALID_PARAMETER);
679         ret = FALSE;
680         goto end;
681     }
682     if (!data->csSigners)
683     {
684         ret = FALSE;
685         SetLastError(TRUST_E_NOSIGNATURE);
686     }
687     else
688     {
689         DWORD i;
690         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo, *pCreateInfo;
691         CERT_CHAIN_PARA chainPara, *pChainPara;
692
693         if (policyData)
694         {
695             pCreateInfo = policyData->pSignerChainInfo;
696             pChainPara = pCreateInfo->pChainPara;
697         }
698         else
699         {
700             WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
701             pChainPara = &chainPara;
702             pCreateInfo = &createInfo;
703         }
704         ret = TRUE;
705         for (i = 0; i < data->csSigners; i++)
706             ret = WINTRUST_CreateChainForSigner(data, i, pCreateInfo,
707              pChainPara);
708     }
709
710 end:
711     if (!ret)
712         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
713          GetLastError();
714     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
715      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
716     return ret ? S_OK : S_FALSE;
717 }
718
719 HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data)
720 {
721     BOOL ret;
722     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
723
724     TRACE("(%p)\n", data);
725
726     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
727         FIXME("unimplemented for UI choice %d\n",
728          data->pWintrustData->dwUIChoice);
729     if (!data->csSigners)
730     {
731         ret = FALSE;
732         policyStatus.dwError = TRUST_E_NOSIGNATURE;
733     }
734     else
735     {
736         DWORD i;
737
738         ret = TRUE;
739         for (i = 0; ret && i < data->csSigners; i++)
740         {
741             CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
742
743             if (data->dwRegPolicySettings & WTPF_TRUSTTEST)
744                 policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG;
745             if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID)
746                 policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG;
747             if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
748                 policyPara.dwFlags |=
749                  CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
750                  CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
751                  CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
752             if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION)
753                 policyPara.dwFlags |=
754                  CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
755                  CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
756                  CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
757                  CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
758             CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE,
759              data->pasSigners[i].pChainContext, &policyPara, &policyStatus);
760             if (policyStatus.dwError != NO_ERROR)
761                 ret = FALSE;
762         }
763     }
764     if (!ret)
765         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] =
766          policyStatus.dwError;
767     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
768      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
769     return ret ? S_OK : S_FALSE;
770 }
771
772 static HRESULT WINAPI WINTRUST_DefaultPolicy(CRYPT_PROVIDER_DATA *pProvData,
773  DWORD dwStepError, DWORD dwRegPolicySettings, DWORD cSigner,
774  PWTD_GENERIC_CHAIN_POLICY_SIGNER_INFO rgpSigner, void *pvPolicyArg)
775 {
776     DWORD i;
777     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
778
779     for (i = 0; !policyStatus.dwError && i < cSigner; i++)
780     {
781         CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
782
783         if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
784             policyPara.dwFlags |=
785              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
786              CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
787              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
788         if (dwRegPolicySettings & WTPF_IGNOREREVOKATION)
789             policyPara.dwFlags |=
790              CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
791              CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
792              CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
793              CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
794         CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
795          rgpSigner[i].pChainContext, &policyPara, &policyStatus);
796     }
797     return policyStatus.dwError;
798 }
799
800 HRESULT WINAPI GenericChainFinalProv(CRYPT_PROVIDER_DATA *data)
801 {
802     HRESULT err = NO_ERROR; /* not a typo, MS confused the types */
803     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
804      (WTD_GENERIC_CHAIN_POLICY_DATA *)data->pWintrustData->pPolicyCallbackData;
805
806     TRACE("(%p)\n", data);
807
808     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
809         FIXME("unimplemented for UI choice %d\n",
810          data->pWintrustData->dwUIChoice);
811     if (!data->csSigners)
812         err = TRUST_E_NOSIGNATURE;
813     else
814     {
815         PFN_WTD_GENERIC_CHAIN_POLICY_CALLBACK policyCallback;
816         void *policyArg;
817         WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO *signers = NULL;
818
819         if (policyData)
820         {
821             policyCallback = policyData->pfnPolicyCallback;
822             policyArg = policyData->pvPolicyArg;
823         }
824         else
825         {
826             policyCallback = WINTRUST_DefaultPolicy;
827             policyArg = NULL;
828         }
829         if (data->csSigners)
830         {
831             DWORD i;
832
833             signers = data->psPfns->pfnAlloc(
834              data->csSigners * sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO));
835             if (signers)
836             {
837                 for (i = 0; i < data->csSigners; i++)
838                 {
839                     signers[i].u.cbSize =
840                      sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO);
841                     signers[i].pChainContext =
842                      data->pasSigners[i].pChainContext;
843                     signers[i].dwSignerType = data->pasSigners[i].dwSignerType;
844                     signers[i].pMsgSignerInfo = data->pasSigners[i].psSigner;
845                     signers[i].dwError = data->pasSigners[i].dwError;
846                     if (data->pasSigners[i].csCounterSigners)
847                         FIXME("unimplemented for counter signers\n");
848                     signers[i].cCounterSigner = 0;
849                     signers[i].rgpCounterSigner = NULL;
850                 }
851             }
852             else
853                 err = ERROR_OUTOFMEMORY;
854         }
855         if (!err)
856             err = policyCallback(data, TRUSTERROR_STEP_FINAL_POLICYPROV,
857              data->dwRegPolicySettings, data->csSigners, signers, policyArg);
858         data->psPfns->pfnFree(signers);
859     }
860     if (err)
861         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = err;
862     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
863      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
864     return err == NO_ERROR ? S_OK : S_FALSE;
865 }
866
867 HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data)
868 {
869     DWORD i, j;
870
871     for (i = 0; i < data->csSigners; i++)
872     {
873         for (j = 0; j < data->pasSigners[i].csCertChain; j++)
874             CertFreeCertificateContext(data->pasSigners[i].pasCertChain[j].pCert);
875         data->psPfns->pfnFree(data->pasSigners[i].pasCertChain);
876         data->psPfns->pfnFree(data->pasSigners[i].psSigner);
877         CertFreeCertificateChain(data->pasSigners[i].pChainContext);
878     }
879     data->psPfns->pfnFree(data->pasSigners);
880
881     for (i = 0; i < data->chStores; i++)
882         CertCloseStore(data->pahStores[i], 0);
883     data->psPfns->pfnFree(data->pahStores);
884
885     if (data->u.pPDSip)
886     {
887         data->psPfns->pfnFree(data->u.pPDSip->pSip);
888         data->psPfns->pfnFree(data->u.pPDSip->pCATSip);
889         data->psPfns->pfnFree(data->u.pPDSip->psSipSubjectInfo);
890         data->psPfns->pfnFree(data->u.pPDSip->psSipCATSubjectInfo);
891         data->psPfns->pfnFree(data->u.pPDSip->psIndirectData);
892     }
893
894     CryptMsgClose(data->hMsg);
895
896     if (data->fOpenedFile)
897         CloseHandle(data->pWintrustData->u.pFile->hFile);
898
899     return S_OK;
900 }