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