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