winmm: Fix a failing mixer test on 98 and ME.
[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         data->u.pPDSip->gSubject = *data->pWintrustData->u.pFile->pgKnownSubject;
103         ret = TRUE;
104     }
105     TRACE("returning %d\n", ret);
106     return ret;
107 }
108
109 /* Assumes data->u.pPDSip exists, and its gSubject member set.
110  * Allocates data->u.pPDSip->pSip and loads it, if possible.
111  */
112 static BOOL SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data)
113 {
114     BOOL ret;
115
116     data->u.pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO));
117     if (data->u.pPDSip->pSip)
118         ret = CryptSIPLoad(&data->u.pPDSip->gSubject, 0, data->u.pPDSip->pSip);
119     else
120     {
121         SetLastError(ERROR_OUTOFMEMORY);
122         ret = FALSE;
123     }
124     TRACE("returning %d\n", ret);
125     return ret;
126 }
127
128 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated.
129  * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg.
130  */
131 static BOOL SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data)
132 {
133     BOOL ret;
134     LPBYTE buf = NULL;
135     DWORD size = 0;
136
137     data->u.pPDSip->psSipSubjectInfo =
138      data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO));
139     if (!data->u.pPDSip->psSipSubjectInfo)
140     {
141         SetLastError(ERROR_OUTOFMEMORY);
142         return FALSE;
143     }
144
145     data->u.pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO);
146     data->u.pPDSip->psSipSubjectInfo->pgSubjectType = &data->u.pPDSip->gSubject;
147     data->u.pPDSip->psSipSubjectInfo->hFile = data->pWintrustData->u.pFile->hFile;
148     data->u.pPDSip->psSipSubjectInfo->pwsFileName =
149      data->pWintrustData->u.pFile->pcwszFilePath;
150     data->u.pPDSip->psSipSubjectInfo->hProv = data->hProv;
151     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
152      &data->dwEncoding, 0, &size, 0);
153     if (!ret)
154     {
155         SetLastError(TRUST_E_NOSIGNATURE);
156         return FALSE;
157     }
158
159     buf = data->psPfns->pfnAlloc(size);
160     if (!buf)
161     {
162         SetLastError(ERROR_OUTOFMEMORY);
163         return FALSE;
164     }
165
166     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
167      &data->dwEncoding, 0, &size, buf);
168     if (ret)
169     {
170         data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv,
171          NULL, NULL);
172         if (data->hMsg)
173             ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE);
174     }
175
176     data->psPfns->pfnFree(buf);
177     TRACE("returning %d\n", ret);
178     return ret;
179 }
180
181 static BOOL SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data)
182 {
183     BOOL ret = FALSE;
184     HCERTSTORE store;
185
186     store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding,
187      data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg);
188     if (store)
189     {
190         ret = data->psPfns->pfnAddStore2Chain(data, store);
191         CertCloseStore(store, 0);
192     }
193     TRACE("returning %d\n", ret);
194     return ret;
195 }
196
197 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data)
198 {
199     BOOL ret;
200     DWORD size;
201     LPSTR oid = NULL;
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     oid = data->psPfns->pfnAlloc(size);
209     if (!oid)
210     {
211         SetLastError(ERROR_OUTOFMEMORY);
212         ret = FALSE;
213         goto error;
214     }
215     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, oid,
216      &size);
217     if (!ret)
218         goto error;
219     ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size);
220     if (!ret)
221         goto error;
222     buf = data->psPfns->pfnAlloc(size);
223     if (!buf)
224     {
225         SetLastError(ERROR_OUTOFMEMORY);
226         ret = FALSE;
227         goto error;
228     }
229     ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size);
230     if (!ret)
231         goto error;
232     ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0, NULL, &size);
233     if (!ret)
234         goto error;
235     data->u.pPDSip->psIndirectData = data->psPfns->pfnAlloc(size);
236     if (!data->u.pPDSip->psIndirectData)
237     {
238         SetLastError(ERROR_OUTOFMEMORY);
239         ret = FALSE;
240         goto error;
241     }
242     ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0,
243      data->u.pPDSip->psIndirectData, &size);
244
245 error:
246     TRACE("returning %d\n", ret);
247     data->psPfns->pfnFree(oid);
248     data->psPfns->pfnFree(buf);
249     return ret;
250 }
251
252 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data)
253 {
254     BOOL ret;
255
256     TRACE("(%p)\n", data);
257
258     if (!data->padwTrustStepErrors)
259         return S_FALSE;
260
261     switch (data->pWintrustData->dwUnionChoice)
262     {
263     case WTD_CHOICE_CERT:
264         if (data->pWintrustData->u.pCert &&
265          data->pWintrustData->u.pCert->cbStruct == sizeof(WINTRUST_CERT_INFO))
266         {
267             if (data->psPfns)
268             {
269                 CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } };
270                 DWORD i;
271
272                 /* Add a signer with nothing but the time to verify, so we can
273                  * add a cert to it
274                  */
275                 if (data->pWintrustData->u.pCert->psftVerifyAsOf)
276                     data->sftSystemTime = signer.sftVerifyAsOf;
277                 else
278                 {
279                     SYSTEMTIME sysTime;
280
281                     GetSystemTime(&sysTime);
282                     SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf);
283                 }
284                 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
285                 if (!ret)
286                     goto error;
287                 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
288                  data->pWintrustData->u.pCert->psCertContext);
289                 if (!ret)
290                     goto error;
291                 for (i = 0; ret && i < data->pWintrustData->u.pCert->chStores;
292                  i++)
293                     ret = data->psPfns->pfnAddStore2Chain(data,
294                      data->pWintrustData->u.pCert->pahStores[i]);
295             }
296             else
297             {
298                 /* Do nothing!?  See the tests */
299                 ret = TRUE;
300             }
301         }
302         else
303         {
304             SetLastError(ERROR_INVALID_PARAMETER);
305             ret = FALSE;
306         }
307         break;
308     case WTD_CHOICE_FILE:
309         if (!data->pWintrustData->u.pFile)
310         {
311             SetLastError(ERROR_INVALID_PARAMETER);
312             ret = FALSE;
313             goto error;
314         }
315         ret = SOFTPUB_OpenFile(data);
316         if (!ret)
317             goto error;
318         ret = SOFTPUB_GetFileSubject(data);
319         if (!ret)
320             goto error;
321         ret = SOFTPUB_GetSIP(data);
322         if (!ret)
323             goto error;
324         ret = SOFTPUB_GetMessageFromFile(data);
325         if (!ret)
326             goto error;
327         ret = SOFTPUB_CreateStoreFromMessage(data);
328         if (!ret)
329             goto error;
330         ret = SOFTPUB_DecodeInnerContent(data);
331         break;
332     default:
333         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
334         SetLastError(ERROR_INVALID_PARAMETER);
335         ret = FALSE;
336     }
337
338 error:
339     if (!ret)
340         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
341          GetLastError();
342     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
343      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
344     return ret ? S_OK : S_FALSE;
345 }
346
347 static CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data,
348  DWORD signerIdx)
349 {
350     BOOL ret;
351     CMSG_SIGNER_INFO *signerInfo = NULL;
352     DWORD size;
353
354     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx,
355      NULL, &size);
356     if (ret)
357     {
358         signerInfo = data->psPfns->pfnAlloc(size);
359         if (signerInfo)
360         {
361             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM,
362              signerIdx, signerInfo, &size);
363             if (!ret)
364             {
365                 data->psPfns->pfnFree(signerInfo);
366                 signerInfo = NULL;
367             }
368         }
369         else
370             SetLastError(ERROR_OUTOFMEMORY);
371     }
372     return signerInfo;
373 }
374
375 static BOOL WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
376 {
377     BOOL ret;
378     CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx);
379
380     if (signerInfo)
381     {
382         CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
383
384         sgnr.psSigner = signerInfo;
385         sgnr.sftVerifyAsOf = data->sftSystemTime;
386         ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr);
387     }
388     else
389         ret = FALSE;
390     return ret;
391 }
392
393 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
394  DWORD signerIdx)
395 {
396     BOOL ret;
397     CERT_INFO *certInfo = NULL;
398     DWORD size;
399
400     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
401      NULL, &size);
402     if (ret)
403     {
404         certInfo = data->psPfns->pfnAlloc(size);
405         if (certInfo)
406         {
407             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
408              signerIdx, certInfo, &size);
409             if (!ret)
410             {
411                 data->psPfns->pfnFree(certInfo);
412                 certInfo = NULL;
413             }
414         }
415         else
416             SetLastError(ERROR_OUTOFMEMORY);
417     }
418     return certInfo;
419 }
420
421 static BOOL WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
422 {
423     BOOL ret;
424     CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx);
425
426     if (certInfo)
427     {
428         PCCERT_CONTEXT subject = CertGetSubjectCertificateFromStore(
429          data->pahStores[0], data->dwEncoding, certInfo);
430
431         if (subject)
432         {
433             CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0,
434              signerIdx, CMSG_VERIFY_SIGNER_CERT, (LPVOID)subject };
435
436             ret = CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX,
437              &para);
438             if (!ret)
439                 SetLastError(TRUST_E_CERT_SIGNATURE);
440             else
441                 data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
442                  subject);
443             CertFreeCertificateContext(subject);
444         }
445         else
446         {
447             SetLastError(TRUST_E_NO_SIGNER_CERT);
448             ret = FALSE;
449         }
450         data->psPfns->pfnFree(certInfo);
451     }
452     else
453         ret = FALSE;
454     return ret;
455 }
456
457 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
458 {
459     BOOL ret;
460
461     TRACE("(%p)\n", data);
462
463     if (!data->padwTrustStepErrors)
464         return S_FALSE;
465
466     if (data->hMsg)
467     {
468         DWORD signerCount, size;
469
470         size = sizeof(signerCount);
471         ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
472          &signerCount, &size);
473         if (ret)
474         {
475             DWORD i;
476
477             for (i = 0; ret && i < signerCount; i++)
478             {
479                 if ((ret = WINTRUST_SaveSigner(data, i)))
480                     ret = WINTRUST_VerifySigner(data, i);
481             }
482         }
483         else
484             SetLastError(TRUST_E_NOSIGNATURE);
485     }
486     else
487         ret = TRUE;
488     if (!ret)
489         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] =
490          GetLastError();
491     return ret ? S_OK : S_FALSE;
492 }
493
494 static DWORD WINTRUST_TrustStatusToConfidence(DWORD errorStatus)
495 {
496     DWORD confidence = 0;
497
498     confidence = 0;
499     if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
500         confidence |= CERT_CONFIDENCE_SIG;
501     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
502         confidence |= CERT_CONFIDENCE_TIME;
503     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
504         confidence |= CERT_CONFIDENCE_TIMENEST;
505     return confidence;
506 }
507
508 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
509  BOOL fCounterSignerChain, DWORD idxCounterSigner)
510 {
511     BOOL ret;
512
513     TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain,
514      idxCounterSigner);
515
516     if (fCounterSignerChain)
517     {
518         FIXME("unimplemented for counter signers\n");
519         ret = FALSE;
520     }
521     else
522     {
523         PCERT_SIMPLE_CHAIN simpleChain =
524          data->pasSigners[idxSigner].pChainContext->rgpChain[0];
525         DWORD i;
526
527         ret = TRUE;
528         for (i = 0; i < simpleChain->cElement; i++)
529         {
530             /* Set confidence */
531             data->pasSigners[idxSigner].pasCertChain[i].dwConfidence =
532              WINTRUST_TrustStatusToConfidence(
533              simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus);
534             /* Set additional flags */
535             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
536              CERT_TRUST_IS_UNTRUSTED_ROOT))
537                 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE;
538             if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus &
539              CERT_TRUST_IS_SELF_SIGNED)
540                 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE;
541             if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
542              CERT_TRUST_IS_CYCLIC)
543                 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE;
544         }
545     }
546     return ret;
547 }
548
549 static DWORD WINTRUST_TrustStatusToError(DWORD errorStatus)
550 {
551     DWORD error;
552
553     if (errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
554         error = TRUST_E_CERT_SIGNATURE;
555     else if (errorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT)
556         error = CERT_E_UNTRUSTEDROOT;
557     else if (errorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
558         error = CERT_E_EXPIRED;
559     else if (errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED)
560         error = CERT_E_VALIDITYPERIODNESTING;
561     else if (errorStatus & CERT_TRUST_IS_REVOKED)
562         error = CERT_E_REVOKED;
563     else if (errorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION ||
564      errorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
565         error = CERT_E_REVOCATION_FAILURE;
566     else if (errorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
567         error = CERT_E_WRONG_USAGE;
568     else if (errorStatus & CERT_TRUST_IS_CYCLIC)
569         error = CERT_E_CHAINING;
570     else if (errorStatus & CERT_TRUST_INVALID_EXTENSION)
571         error = CERT_E_CRITICAL;
572     else if (errorStatus & CERT_TRUST_INVALID_POLICY_CONSTRAINTS)
573         error = CERT_E_INVALID_POLICY;
574     else if (errorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
575         error = TRUST_E_BASIC_CONSTRAINTS;
576     else if (errorStatus & CERT_TRUST_INVALID_NAME_CONSTRAINTS ||
577      errorStatus & CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT ||
578      errorStatus & CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT ||
579      errorStatus & CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT ||
580      errorStatus & CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT)
581         error = CERT_E_INVALID_NAME;
582     else if (errorStatus & CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY)
583         error = CERT_E_INVALID_POLICY;
584     else if (errorStatus)
585     {
586         FIXME("unknown error status %08x\n", errorStatus);
587         error = TRUST_E_SYSTEM_ERROR;
588     }
589     else
590         error = S_OK;
591     return error;
592 }
593
594 static BOOL WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
595 {
596     BOOL ret;
597     PCERT_SIMPLE_CHAIN simpleChain =
598      data->pasSigners[signerIdx].pChainContext->rgpChain[0];
599     DWORD i;
600
601     data->pasSigners[signerIdx].pasCertChain[0].dwConfidence =
602      WINTRUST_TrustStatusToConfidence(
603      simpleChain->rgpElement[0]->TrustStatus.dwErrorStatus);
604     data->pasSigners[signerIdx].pasCertChain[0].pChainElement =
605      simpleChain->rgpElement[0];
606     ret = TRUE;
607     for (i = 1; ret && i < simpleChain->cElement; i++)
608     {
609         ret = data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
610          simpleChain->rgpElement[i]->pCertContext);
611         if (ret)
612         {
613             data->pasSigners[signerIdx].pasCertChain[i].pChainElement =
614              simpleChain->rgpElement[i];
615             data->pasSigners[signerIdx].pasCertChain[i].dwConfidence =
616              WINTRUST_TrustStatusToConfidence(
617              simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus);
618         }
619     }
620     data->pasSigners[signerIdx].pasCertChain[simpleChain->cElement - 1].dwError
621      = WINTRUST_TrustStatusToError(
622      simpleChain->rgpElement[simpleChain->cElement - 1]->
623      TrustStatus.dwErrorStatus);
624     return ret;
625 }
626
627 static void WINTRUST_CreateChainPolicyCreateInfo(
628  const CRYPT_PROVIDER_DATA *data, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO info,
629  PCERT_CHAIN_PARA chainPara)
630 {
631     chainPara->cbSize = sizeof(CERT_CHAIN_PARA);
632     if (data->pRequestUsage)
633         chainPara->RequestedUsage = *data->pRequestUsage;
634     else
635     {
636         chainPara->RequestedUsage.dwType = 0;
637         chainPara->RequestedUsage.Usage.cUsageIdentifier = 0;
638     }
639     info->u.cbSize = sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO);
640     info->hChainEngine = NULL;
641     info->pChainPara = chainPara;
642     if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT)
643         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
644     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN)
645         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
646     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
647         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
648     else
649         info->dwFlags = 0;
650     info->pvReserved = NULL;
651 }
652
653 static BOOL WINTRUST_CreateChainForSigner(CRYPT_PROVIDER_DATA *data,
654  DWORD signer, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo,
655  PCERT_CHAIN_PARA chainPara)
656 {
657     BOOL ret = TRUE;
658     HCERTSTORE store = NULL;
659
660     if (data->chStores)
661     {
662         store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
663          CERT_STORE_CREATE_NEW_FLAG, NULL);
664         if (store)
665         {
666             DWORD i;
667
668             for (i = 0; i < data->chStores; i++)
669                 CertAddStoreToCollection(store, data->pahStores[i], 0, 0);
670         }
671     }
672     /* Expect the end certificate for each signer to be the only cert in the
673      * chain:
674      */
675     if (data->pasSigners[signer].csCertChain)
676     {
677         /* Create a certificate chain for each signer */
678         ret = CertGetCertificateChain(createInfo->hChainEngine,
679          data->pasSigners[signer].pasCertChain[0].pCert,
680          &data->pasSigners[signer].sftVerifyAsOf, store,
681          chainPara, createInfo->dwFlags, createInfo->pvReserved,
682          &data->pasSigners[signer].pChainContext);
683         if (ret)
684         {
685             if (data->pasSigners[signer].pChainContext->cChain != 1)
686             {
687                 FIXME("unimplemented for more than 1 simple chain\n");
688                 ret = FALSE;
689             }
690             else
691             {
692                 if ((ret = WINTRUST_CopyChain(data, signer)))
693                 {
694                     if (data->psPfns->pfnCertCheckPolicy)
695                         ret = data->psPfns->pfnCertCheckPolicy(data, signer,
696                          FALSE, 0);
697                     else
698                         TRACE("no cert check policy, skipping policy check\n");
699                 }
700             }
701         }
702     }
703     CertCloseStore(store, 0);
704     return ret;
705 }
706
707 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data)
708 {
709     BOOL ret;
710
711     TRACE("(%p)\n", data);
712
713     if (!data->csSigners)
714     {
715         ret = FALSE;
716         SetLastError(TRUST_E_NOSIGNATURE);
717     }
718     else
719     {
720         DWORD i;
721         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo;
722         CERT_CHAIN_PARA chainPara;
723
724         WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
725         ret = TRUE;
726         for (i = 0; i < data->csSigners; i++)
727             ret = WINTRUST_CreateChainForSigner(data, i, &createInfo,
728              &chainPara);
729     }
730     if (!ret)
731         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
732          GetLastError();
733     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
734      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
735     return ret ? S_OK : S_FALSE;
736 }
737
738 HRESULT WINAPI GenericChainCertificateTrust(CRYPT_PROVIDER_DATA *data)
739 {
740     BOOL ret;
741     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
742      (WTD_GENERIC_CHAIN_POLICY_DATA *)data->pWintrustData->pPolicyCallbackData;
743
744     TRACE("(%p)\n", data);
745
746     if (policyData && policyData->u.cbSize !=
747      sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO))
748     {
749         SetLastError(ERROR_INVALID_PARAMETER);
750         ret = FALSE;
751         goto end;
752     }
753     if (!data->csSigners)
754     {
755         ret = FALSE;
756         SetLastError(TRUST_E_NOSIGNATURE);
757     }
758     else
759     {
760         DWORD i;
761         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo, *pCreateInfo;
762         CERT_CHAIN_PARA chainPara, *pChainPara;
763
764         if (policyData)
765         {
766             pCreateInfo = policyData->pSignerChainInfo;
767             pChainPara = pCreateInfo->pChainPara;
768         }
769         else
770         {
771             WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
772             pChainPara = &chainPara;
773             pCreateInfo = &createInfo;
774         }
775         ret = TRUE;
776         for (i = 0; i < data->csSigners; i++)
777             ret = WINTRUST_CreateChainForSigner(data, i, pCreateInfo,
778              pChainPara);
779     }
780
781 end:
782     if (!ret)
783         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
784          GetLastError();
785     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
786      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
787     return ret ? S_OK : S_FALSE;
788 }
789
790 HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data)
791 {
792     BOOL ret;
793     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
794
795     TRACE("(%p)\n", data);
796
797     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
798         FIXME("unimplemented for UI choice %d\n",
799          data->pWintrustData->dwUIChoice);
800     if (!data->csSigners)
801     {
802         ret = FALSE;
803         policyStatus.dwError = TRUST_E_NOSIGNATURE;
804     }
805     else
806     {
807         DWORD i;
808
809         ret = TRUE;
810         for (i = 0; ret && i < data->csSigners; i++)
811         {
812             BYTE hash[20];
813             DWORD size = sizeof(hash);
814
815             /* First make sure cert isn't disallowed */
816             if ((ret = CertGetCertificateContextProperty(
817              data->pasSigners[i].pasCertChain[0].pCert,
818              CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
819             {
820                 static const WCHAR disallowedW[] =
821                  { 'D','i','s','a','l','l','o','w','e','d',0 };
822                 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
823                  X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER,
824                  disallowedW);
825
826                 if (disallowed)
827                 {
828                     PCCERT_CONTEXT found = CertFindCertificateInStore(
829                      disallowed, X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH,
830                      hash, NULL);
831
832                     if (found)
833                     {
834                         /* Disallowed!  Can't verify it. */
835                         policyStatus.dwError = TRUST_E_SUBJECT_NOT_TRUSTED;
836                         ret = FALSE;
837                         CertFreeCertificateContext(found);
838                     }
839                     CertCloseStore(disallowed, 0);
840                 }
841             }
842             if (ret)
843             {
844                 CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
845
846                 if (data->dwRegPolicySettings & WTPF_TRUSTTEST)
847                     policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG;
848                 if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID)
849                     policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG;
850                 if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
851                     policyPara.dwFlags |=
852                      CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
853                      CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
854                      CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
855                 if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION)
856                     policyPara.dwFlags |=
857                      CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
858                      CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
859                      CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
860                      CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
861                 CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE,
862                  data->pasSigners[i].pChainContext, &policyPara, &policyStatus);
863                 if (policyStatus.dwError != NO_ERROR)
864                     ret = FALSE;
865             }
866         }
867     }
868     if (!ret)
869         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] =
870          policyStatus.dwError;
871     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
872      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
873     return ret ? S_OK : S_FALSE;
874 }
875
876 static HRESULT WINAPI WINTRUST_DefaultPolicy(CRYPT_PROVIDER_DATA *pProvData,
877  DWORD dwStepError, DWORD dwRegPolicySettings, DWORD cSigner,
878  PWTD_GENERIC_CHAIN_POLICY_SIGNER_INFO rgpSigner, void *pvPolicyArg)
879 {
880     DWORD i;
881     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
882
883     for (i = 0; !policyStatus.dwError && i < cSigner; i++)
884     {
885         CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
886
887         if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
888             policyPara.dwFlags |=
889              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
890              CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
891              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
892         if (dwRegPolicySettings & WTPF_IGNOREREVOKATION)
893             policyPara.dwFlags |=
894              CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
895              CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
896              CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
897              CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
898         CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
899          rgpSigner[i].pChainContext, &policyPara, &policyStatus);
900     }
901     return policyStatus.dwError;
902 }
903
904 HRESULT WINAPI GenericChainFinalProv(CRYPT_PROVIDER_DATA *data)
905 {
906     HRESULT err = NO_ERROR; /* not a typo, MS confused the types */
907     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
908      (WTD_GENERIC_CHAIN_POLICY_DATA *)data->pWintrustData->pPolicyCallbackData;
909
910     TRACE("(%p)\n", data);
911
912     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
913         FIXME("unimplemented for UI choice %d\n",
914          data->pWintrustData->dwUIChoice);
915     if (!data->csSigners)
916         err = TRUST_E_NOSIGNATURE;
917     else
918     {
919         PFN_WTD_GENERIC_CHAIN_POLICY_CALLBACK policyCallback;
920         void *policyArg;
921         WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO *signers = NULL;
922
923         if (policyData)
924         {
925             policyCallback = policyData->pfnPolicyCallback;
926             policyArg = policyData->pvPolicyArg;
927         }
928         else
929         {
930             policyCallback = WINTRUST_DefaultPolicy;
931             policyArg = NULL;
932         }
933         if (data->csSigners)
934         {
935             DWORD i;
936
937             signers = data->psPfns->pfnAlloc(
938              data->csSigners * sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO));
939             if (signers)
940             {
941                 for (i = 0; i < data->csSigners; i++)
942                 {
943                     signers[i].u.cbSize =
944                      sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO);
945                     signers[i].pChainContext =
946                      data->pasSigners[i].pChainContext;
947                     signers[i].dwSignerType = data->pasSigners[i].dwSignerType;
948                     signers[i].pMsgSignerInfo = data->pasSigners[i].psSigner;
949                     signers[i].dwError = data->pasSigners[i].dwError;
950                     if (data->pasSigners[i].csCounterSigners)
951                         FIXME("unimplemented for counter signers\n");
952                     signers[i].cCounterSigner = 0;
953                     signers[i].rgpCounterSigner = NULL;
954                 }
955             }
956             else
957                 err = ERROR_OUTOFMEMORY;
958         }
959         if (err == NO_ERROR)
960             err = policyCallback(data, TRUSTERROR_STEP_FINAL_POLICYPROV,
961              data->dwRegPolicySettings, data->csSigners, signers, policyArg);
962         data->psPfns->pfnFree(signers);
963     }
964     if (err != NO_ERROR)
965         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = err;
966     TRACE("returning %d (%08x)\n", err == NO_ERROR ? S_OK : S_FALSE,
967      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
968     return err == NO_ERROR ? S_OK : S_FALSE;
969 }
970
971 HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data)
972 {
973     DWORD i, j;
974
975     for (i = 0; i < data->csSigners; i++)
976     {
977         for (j = 0; j < data->pasSigners[i].csCertChain; j++)
978             CertFreeCertificateContext(data->pasSigners[i].pasCertChain[j].pCert);
979         data->psPfns->pfnFree(data->pasSigners[i].pasCertChain);
980         data->psPfns->pfnFree(data->pasSigners[i].psSigner);
981         CertFreeCertificateChain(data->pasSigners[i].pChainContext);
982     }
983     data->psPfns->pfnFree(data->pasSigners);
984
985     for (i = 0; i < data->chStores; i++)
986         CertCloseStore(data->pahStores[i], 0);
987     data->psPfns->pfnFree(data->pahStores);
988
989     if (data->u.pPDSip)
990     {
991         data->psPfns->pfnFree(data->u.pPDSip->pSip);
992         data->psPfns->pfnFree(data->u.pPDSip->pCATSip);
993         data->psPfns->pfnFree(data->u.pPDSip->psSipSubjectInfo);
994         data->psPfns->pfnFree(data->u.pPDSip->psSipCATSubjectInfo);
995         data->psPfns->pfnFree(data->u.pPDSip->psIndirectData);
996     }
997
998     CryptMsgClose(data->hMsg);
999
1000     if (data->fOpenedFile)
1001         CloseHandle(data->pWintrustData->u.pFile->hFile);
1002
1003     return S_OK;
1004 }