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