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