xref: /reactos/dll/win32/wintrust/softpub.c (revision d5399189)
1 /*
2  * Copyright 2007 Juan Lang
3  * Copyright 2016 Mark Jansen
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 #include <stdarg.h>
20 
21 #define NONAMELESSUNION
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winternl.h"
26 #include "wintrust.h"
27 #include "mssip.h"
28 #include "softpub.h"
29 #include "winnls.h"
30 #include "wine/debug.h"
31 
32 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
33 
34 HRESULT WINAPI SoftpubDefCertInit(CRYPT_PROVIDER_DATA *data)
35 {
36     HRESULT ret = S_FALSE;
37 
38     TRACE("(%p)\n", data);
39 
40     if (data->padwTrustStepErrors &&
41      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
42         ret = S_OK;
43     TRACE("returning %08x\n", ret);
44     return ret;
45 }
46 
47 HRESULT WINAPI SoftpubInitialize(CRYPT_PROVIDER_DATA *data)
48 {
49     HRESULT ret = S_FALSE;
50 
51     TRACE("(%p)\n", data);
52 
53     if (data->padwTrustStepErrors &&
54      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
55         ret = S_OK;
56     TRACE("returning %08x\n", ret);
57     return ret;
58 }
59 
60 HRESULT WINAPI DriverInitializePolicy(CRYPT_PROVIDER_DATA *data)
61 {
62     FIXME("stub\n");
63     return S_OK;
64 }
65 
66 HRESULT WINAPI DriverCleanupPolicy(CRYPT_PROVIDER_DATA *data)
67 {
68     FIXME("stub\n");
69     return S_OK;
70 }
71 
72 HRESULT WINAPI DriverFinalPolicy(CRYPT_PROVIDER_DATA *data)
73 {
74     FIXME("stub\n");
75     return S_OK;
76 }
77 
78 /* Assumes data->pWintrustData->u.pFile exists.  Makes sure a file handle is
79  * open for the file.
80  */
81 static DWORD SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA *data)
82 {
83     DWORD err = ERROR_SUCCESS;
84 
85     /* PSDK implies that all values should be initialized to NULL, so callers
86      * typically have hFile as NULL rather than INVALID_HANDLE_VALUE.  Check
87      * for both.
88      */
89     if (!data->pWintrustData->u.pFile->hFile ||
90      data->pWintrustData->u.pFile->hFile == INVALID_HANDLE_VALUE)
91     {
92         data->pWintrustData->u.pFile->hFile =
93             CreateFileW(data->pWintrustData->u.pFile->pcwszFilePath, GENERIC_READ,
94           FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
95         if (data->pWintrustData->u.pFile->hFile != INVALID_HANDLE_VALUE)
96             data->fOpenedFile = TRUE;
97         else
98             err = GetLastError();
99     }
100     if (!err)
101         GetFileTime(data->pWintrustData->u.pFile->hFile, &data->sftSystemTime,
102          NULL, NULL);
103     TRACE("returning %d\n", err);
104     return err;
105 }
106 
107 /* Assumes data->pWintrustData->u.pFile exists.  Sets data->pPDSip->gSubject to
108  * the file's subject GUID.
109  */
110 static DWORD SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA *data)
111 {
112     DWORD err = ERROR_SUCCESS;
113 
114     if (!WVT_ISINSTRUCT(WINTRUST_FILE_INFO,
115      data->pWintrustData->u.pFile->cbStruct, pgKnownSubject) ||
116      !data->pWintrustData->u.pFile->pgKnownSubject)
117     {
118         if (!CryptSIPRetrieveSubjectGuid(
119          data->pWintrustData->u.pFile->pcwszFilePath,
120          data->pWintrustData->u.pFile->hFile,
121          &data->u.pPDSip->gSubject))
122         {
123             LARGE_INTEGER fileSize;
124             DWORD sipError = GetLastError();
125 
126             /* Special case for empty files: the error is expected to be
127              * TRUST_E_SUBJECT_FORM_UNKNOWN, rather than whatever
128              * CryptSIPRetrieveSubjectGuid returns.
129              */
130             if (GetFileSizeEx(data->pWintrustData->u.pFile->hFile, &fileSize)
131              && !fileSize.QuadPart)
132                 err = TRUST_E_SUBJECT_FORM_UNKNOWN;
133             else
134                 err = sipError;
135         }
136     }
137     else
138         data->u.pPDSip->gSubject = *data->pWintrustData->u.pFile->pgKnownSubject;
139     TRACE("returning %d\n", err);
140     return err;
141 }
142 
143 /* Assumes data->u.pPDSip exists, and its gSubject member set.
144  * Allocates data->u.pPDSip->pSip and loads it, if possible.
145  */
146 static DWORD SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data)
147 {
148     DWORD err = ERROR_SUCCESS;
149 
150     data->u.pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO));
151     if (data->u.pPDSip->pSip)
152     {
153         if (!CryptSIPLoad(&data->u.pPDSip->gSubject, 0, data->u.pPDSip->pSip))
154             err = GetLastError();
155     }
156     else
157         err = ERROR_OUTOFMEMORY;
158     TRACE("returning %d\n", err);
159     return err;
160 }
161 
162 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated.
163  * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg.
164  */
165 static DWORD SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data, HANDLE file,
166  LPCWSTR filePath)
167 {
168     DWORD err = ERROR_SUCCESS;
169     BOOL ret;
170     LPBYTE buf = NULL;
171     DWORD size = 0;
172 
173     data->u.pPDSip->psSipSubjectInfo =
174      data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO));
175     if (!data->u.pPDSip->psSipSubjectInfo)
176         return ERROR_OUTOFMEMORY;
177 
178     data->u.pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO);
179     data->u.pPDSip->psSipSubjectInfo->pgSubjectType = &data->u.pPDSip->gSubject;
180     data->u.pPDSip->psSipSubjectInfo->hFile = file;
181     data->u.pPDSip->psSipSubjectInfo->pwsFileName = filePath;
182     data->u.pPDSip->psSipSubjectInfo->hProv = data->hProv;
183     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
184      &data->dwEncoding, 0, &size, 0);
185     if (!ret)
186         return TRUST_E_NOSIGNATURE;
187 
188     buf = data->psPfns->pfnAlloc(size);
189     if (!buf)
190         return ERROR_OUTOFMEMORY;
191 
192     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
193      &data->dwEncoding, 0, &size, buf);
194     if (ret)
195     {
196         data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv,
197          NULL, NULL);
198         if (data->hMsg)
199         {
200             ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE);
201             if (!ret)
202                 err = GetLastError();
203         }
204     }
205     else
206         err = GetLastError();
207 
208     data->psPfns->pfnFree(buf);
209     TRACE("returning %d\n", err);
210     return err;
211 }
212 
213 /* See https://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
214  * for details about the hashing.
215  */
216 static BOOL SOFTPUB_HashPEFile(HANDLE file, HCRYPTHASH hash)
217 {
218     DWORD pos, checksum, security_dir;
219     IMAGE_DOS_HEADER dos_header;
220     union
221     {
222         IMAGE_NT_HEADERS32 nt32;
223         IMAGE_NT_HEADERS64 nt64;
224     } nt_header;
225     IMAGE_DATA_DIRECTORY secdir;
226     LARGE_INTEGER file_size;
227     DWORD bytes_read;
228     BYTE buffer[1024];
229     BOOL ret;
230 
231     if (!GetFileSizeEx(file, &file_size))
232         return FALSE;
233 
234     SetFilePointer(file, 0, NULL, FILE_BEGIN);
235     ret = ReadFile(file, &dos_header, sizeof(dos_header), &bytes_read, NULL);
236     if (!ret || bytes_read != sizeof(dos_header))
237         return FALSE;
238 
239     if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
240     {
241         ERR("Unrecognized IMAGE_DOS_HEADER magic %04x\n", dos_header.e_magic);
242         return FALSE;
243     }
244     if (dos_header.e_lfanew >= 256 * 1024 * 1024) /* see RtlImageNtHeaderEx */
245         return FALSE;
246     if (dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader.MajorLinkerVersion) > file_size.QuadPart)
247         return FALSE;
248 
249     SetFilePointer(file, dos_header.e_lfanew, NULL, FILE_BEGIN);
250     ret = ReadFile(file, &nt_header, sizeof(nt_header), &bytes_read, NULL);
251     if (!ret || bytes_read < FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.Magic) +
252                              sizeof(nt_header.nt32.OptionalHeader.Magic))
253         return FALSE;
254 
255     if (nt_header.nt32.Signature != IMAGE_NT_SIGNATURE)
256     {
257         ERR("Unrecognized IMAGE_NT_HEADERS signature %08x\n", nt_header.nt32.Signature);
258         return FALSE;
259     }
260 
261     if (nt_header.nt32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
262     {
263         if (bytes_read < sizeof(nt_header.nt32))
264             return FALSE;
265 
266         checksum     = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
267         security_dir = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
268         secdir       = nt_header.nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
269     }
270     else if (nt_header.nt32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
271     {
272         if (bytes_read < sizeof(nt_header.nt64))
273             return FALSE;
274 
275         checksum     = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);
276         security_dir = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
277         secdir       = nt_header.nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
278     }
279     else
280     {
281         ERR("Unrecognized OptionalHeader magic %04x\n", nt_header.nt32.OptionalHeader.Magic);
282         return FALSE;
283     }
284 
285     if (secdir.VirtualAddress < security_dir + sizeof(IMAGE_DATA_DIRECTORY))
286         return FALSE;
287     if (secdir.VirtualAddress > file_size.QuadPart)
288         return FALSE;
289     if (secdir.VirtualAddress + secdir.Size != file_size.QuadPart)
290         return FALSE;
291 
292     /* Hash until checksum. */
293     SetFilePointer(file, 0, NULL, FILE_BEGIN);
294     for (pos = 0; pos < checksum; pos += bytes_read)
295     {
296         ret = ReadFile(file, buffer, min(sizeof(buffer), checksum - pos), &bytes_read, NULL);
297         if (!ret || !bytes_read)
298             return FALSE;
299         if (!CryptHashData(hash, buffer, bytes_read, 0))
300             return FALSE;
301     }
302 
303     /* Hash until the DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] entry. */
304     checksum += sizeof(DWORD);
305     SetFilePointer(file, checksum, NULL, FILE_BEGIN);
306     for (pos = checksum; pos < security_dir; pos += bytes_read)
307     {
308         ret = ReadFile(file, buffer, min(sizeof(buffer), security_dir - pos), &bytes_read, NULL);
309         if (!ret || !bytes_read)
310             return FALSE;
311         if (!CryptHashData(hash, buffer, bytes_read, 0))
312             return FALSE;
313     }
314 
315     /* Hash until the end of the file. */
316     security_dir += sizeof(IMAGE_DATA_DIRECTORY);
317     SetFilePointer(file, security_dir, NULL, FILE_BEGIN);
318     for (pos = security_dir; pos < secdir.VirtualAddress; pos += bytes_read)
319     {
320         ret = ReadFile(file, buffer, min(sizeof(buffer), secdir.VirtualAddress - pos), &bytes_read, NULL);
321         if (!ret || !bytes_read)
322             return FALSE;
323         if (!CryptHashData(hash, buffer, bytes_read, 0))
324             return FALSE;
325     }
326 
327     return TRUE;
328 }
329 
330 static DWORD SOFTPUB_VerifyImageHash(CRYPT_PROVIDER_DATA *data, HANDLE file)
331 {
332     SPC_INDIRECT_DATA_CONTENT *indirect = (SPC_INDIRECT_DATA_CONTENT *)data->u.pPDSip->psIndirectData;
333     DWORD err, hash_size, length;
334     BYTE *hash_data;
335     BOOL release_prov = FALSE;
336     HCRYPTPROV prov = data->hProv;
337     HCRYPTHASH hash = 0;
338     ALG_ID algID;
339 
340     if (((ULONG_PTR)indirect->Data.pszObjId >> 16) == 0 ||
341         strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID))
342     {
343         FIXME("Cannot verify hash for pszObjId=%s\n", debugstr_a(indirect->Data.pszObjId));
344         return ERROR_SUCCESS;
345     }
346 
347     if (!(algID = CertOIDToAlgId(indirect->DigestAlgorithm.pszObjId)))
348         return TRUST_E_SYSTEM_ERROR; /* FIXME */
349 
350     if (!prov)
351     {
352         if (!CryptAcquireContextW(&prov, NULL, MS_ENH_RSA_AES_PROV_W, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
353             return GetLastError();
354         release_prov = TRUE;
355     }
356 
357     if (!CryptCreateHash(prov, algID, 0, 0, &hash))
358     {
359         err = GetLastError();
360         goto done;
361     }
362 
363     if (!SOFTPUB_HashPEFile(file, hash))
364     {
365         err = TRUST_E_NOSIGNATURE;
366         goto done;
367     }
368 
369     length = sizeof(hash_size);
370     if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *)&hash_size, &length, 0))
371     {
372         err = GetLastError();
373         goto done;
374     }
375 
376     if (!(hash_data = data->psPfns->pfnAlloc(hash_size)))
377     {
378         err = ERROR_OUTOFMEMORY;
379         goto done;
380     }
381 
382     if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, &hash_size, 0))
383     {
384         err = GetLastError();
385         data->psPfns->pfnFree(hash_data);
386         goto done;
387     }
388 
389     err = (hash_size == indirect->Digest.cbData &&
390            !memcmp(hash_data, indirect->Digest.pbData, hash_size)) ? S_OK : TRUST_E_BAD_DIGEST;
391     data->psPfns->pfnFree(hash_data);
392 
393 done:
394     if (hash)
395         CryptDestroyHash(hash);
396     if (release_prov)
397         CryptReleaseContext(prov, 0);
398     return err;
399 }
400 
401 
402 static DWORD SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data)
403 {
404     DWORD err = ERROR_SUCCESS;
405     HCERTSTORE store;
406 
407     store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding,
408      data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg);
409     if (store)
410     {
411         if (!data->psPfns->pfnAddStore2Chain(data, store))
412             err = GetLastError();
413         CertCloseStore(store, 0);
414     }
415     else
416         err = GetLastError();
417     TRACE("returning %d\n", err);
418     return err;
419 }
420 
421 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data)
422 {
423     BOOL ret;
424     DWORD size, err = ERROR_SUCCESS;
425     LPSTR oid = NULL;
426     LPBYTE buf = NULL;
427 
428     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL,
429      &size);
430     if (!ret)
431     {
432         err = GetLastError();
433         goto error;
434     }
435     oid = data->psPfns->pfnAlloc(size);
436     if (!oid)
437     {
438         err = ERROR_OUTOFMEMORY;
439         goto error;
440     }
441     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, oid,
442      &size);
443     if (!ret)
444     {
445         err = GetLastError();
446         goto error;
447     }
448     ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size);
449     if (!ret)
450     {
451         err = GetLastError();
452         goto error;
453     }
454     buf = data->psPfns->pfnAlloc(size);
455     if (!buf)
456     {
457         err = ERROR_OUTOFMEMORY;
458         goto error;
459     }
460     ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size);
461     if (!ret)
462     {
463         err = GetLastError();
464         goto error;
465     }
466     ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0, NULL, &size);
467     if (!ret)
468     {
469         err = GetLastError();
470         goto error;
471     }
472     data->u.pPDSip->psIndirectData = data->psPfns->pfnAlloc(size);
473     if (!data->u.pPDSip->psIndirectData)
474     {
475         err = ERROR_OUTOFMEMORY;
476         goto error;
477     }
478     ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0,
479      data->u.pPDSip->psIndirectData, &size);
480     if (!ret)
481         err = GetLastError();
482 
483 error:
484     TRACE("returning %d\n", err);
485     data->psPfns->pfnFree(oid);
486     data->psPfns->pfnFree(buf);
487     return err;
488 }
489 
490 static DWORD SOFTPUB_LoadCertMessage(CRYPT_PROVIDER_DATA *data)
491 {
492     DWORD err = ERROR_SUCCESS;
493 
494     if (data->pWintrustData->u.pCert &&
495      WVT_IS_CBSTRUCT_GT_MEMBEROFFSET(WINTRUST_CERT_INFO,
496      data->pWintrustData->u.pCert->cbStruct, psCertContext))
497     {
498         if (data->psPfns)
499         {
500             CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } };
501             DWORD i;
502             BOOL ret;
503 
504             /* Add a signer with nothing but the time to verify, so we can
505              * add a cert to it
506              */
507             if (WVT_ISINSTRUCT(WINTRUST_CERT_INFO,
508              data->pWintrustData->u.pCert->cbStruct, psftVerifyAsOf) &&
509              data->pWintrustData->u.pCert->psftVerifyAsOf)
510                 data->sftSystemTime = signer.sftVerifyAsOf;
511             else
512             {
513                 SYSTEMTIME sysTime;
514 
515                 GetSystemTime(&sysTime);
516                 SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf);
517             }
518             ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
519             if (ret)
520             {
521                 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
522                  data->pWintrustData->u.pCert->psCertContext);
523                 if (WVT_ISINSTRUCT(WINTRUST_CERT_INFO,
524                  data->pWintrustData->u.pCert->cbStruct, pahStores))
525                         for (i = 0;
526                          ret && i < data->pWintrustData->u.pCert->chStores; i++)
527                             ret = data->psPfns->pfnAddStore2Chain(data,
528                              data->pWintrustData->u.pCert->pahStores[i]);
529             }
530             if (!ret)
531                 err = GetLastError();
532         }
533     }
534     else
535         err = ERROR_INVALID_PARAMETER;
536     return err;
537 }
538 
539 static DWORD SOFTPUB_LoadFileMessage(CRYPT_PROVIDER_DATA *data)
540 {
541     DWORD err = ERROR_SUCCESS;
542 
543     if (!data->pWintrustData->u.pFile)
544     {
545         err = ERROR_INVALID_PARAMETER;
546         goto error;
547     }
548     err = SOFTPUB_OpenFile(data);
549     if (err)
550         goto error;
551     err = SOFTPUB_GetFileSubject(data);
552     if (err)
553         goto error;
554     err = SOFTPUB_GetSIP(data);
555     if (err)
556         goto error;
557     err = SOFTPUB_GetMessageFromFile(data, data->pWintrustData->u.pFile->hFile,
558      data->pWintrustData->u.pFile->pcwszFilePath);
559     if (err)
560         goto error;
561     err = SOFTPUB_CreateStoreFromMessage(data);
562     if (err)
563         goto error;
564     err = SOFTPUB_DecodeInnerContent(data);
565     if (err)
566         goto error;
567     err = SOFTPUB_VerifyImageHash(data, data->pWintrustData->u.pFile->hFile);
568 
569 error:
570     if (err && data->fOpenedFile && data->pWintrustData->u.pFile)
571     {
572         /* The caller won't expect the file to be open on failure, so close it.
573          */
574         CloseHandle(data->pWintrustData->u.pFile->hFile);
575         data->pWintrustData->u.pFile->hFile = INVALID_HANDLE_VALUE;
576         data->fOpenedFile = FALSE;
577     }
578     return err;
579 }
580 
581 static DWORD SOFTPUB_LoadCatalogMessage(CRYPT_PROVIDER_DATA *data)
582 {
583     DWORD err;
584     HANDLE catalog = INVALID_HANDLE_VALUE;
585 
586     if (!data->pWintrustData->u.pCatalog)
587     {
588         SetLastError(ERROR_INVALID_PARAMETER);
589         return FALSE;
590     }
591     catalog = CreateFileW(data->pWintrustData->u.pCatalog->pcwszCatalogFilePath,
592      GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
593      NULL);
594     if (catalog == INVALID_HANDLE_VALUE)
595         return GetLastError();
596     if (!CryptSIPRetrieveSubjectGuid(
597      data->pWintrustData->u.pCatalog->pcwszCatalogFilePath, catalog,
598      &data->u.pPDSip->gSubject))
599     {
600         err = GetLastError();
601         goto error;
602     }
603     err = SOFTPUB_GetSIP(data);
604     if (err)
605         goto error;
606     err = SOFTPUB_GetMessageFromFile(data, catalog,
607      data->pWintrustData->u.pCatalog->pcwszCatalogFilePath);
608     if (err)
609         goto error;
610     err = SOFTPUB_CreateStoreFromMessage(data);
611     if (err)
612         goto error;
613     err = SOFTPUB_DecodeInnerContent(data);
614     /* FIXME: this loads the catalog file, but doesn't validate the member. */
615 error:
616     CloseHandle(catalog);
617     return err;
618 }
619 
620 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data)
621 {
622     DWORD err = ERROR_SUCCESS;
623 
624     TRACE("(%p)\n", data);
625 
626     if (!data->padwTrustStepErrors)
627         return S_FALSE;
628 
629     switch (data->pWintrustData->dwUnionChoice)
630     {
631     case WTD_CHOICE_CERT:
632         err = SOFTPUB_LoadCertMessage(data);
633         break;
634     case WTD_CHOICE_FILE:
635         err = SOFTPUB_LoadFileMessage(data);
636         break;
637     case WTD_CHOICE_CATALOG:
638         err = SOFTPUB_LoadCatalogMessage(data);
639         break;
640     default:
641         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
642         err = ERROR_INVALID_PARAMETER;
643     }
644 
645     if (err)
646         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] = err;
647     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
648      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
649     return !err ? S_OK : S_FALSE;
650 }
651 
652 static CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data,
653  DWORD signerIdx)
654 {
655     BOOL ret;
656     CMSG_SIGNER_INFO *signerInfo = NULL;
657     DWORD size;
658 
659     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx,
660      NULL, &size);
661     if (ret)
662     {
663         signerInfo = data->psPfns->pfnAlloc(size);
664         if (signerInfo)
665         {
666             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM,
667              signerIdx, signerInfo, &size);
668             if (!ret)
669             {
670                 data->psPfns->pfnFree(signerInfo);
671                 signerInfo = NULL;
672             }
673         }
674         else
675             SetLastError(ERROR_OUTOFMEMORY);
676     }
677     return signerInfo;
678 }
679 
680 static BOOL WINTRUST_GetTimeFromCounterSigner(
681  const CMSG_CMS_SIGNER_INFO *counterSignerInfo, FILETIME *time)
682 {
683     DWORD i;
684     BOOL foundTimeStamp = FALSE;
685 
686     for (i = 0; !foundTimeStamp && i < counterSignerInfo->AuthAttrs.cAttr; i++)
687     {
688         if (!strcmp(counterSignerInfo->AuthAttrs.rgAttr[i].pszObjId,
689          szOID_RSA_signingTime))
690         {
691             const CRYPT_ATTRIBUTE *attr =
692              &counterSignerInfo->AuthAttrs.rgAttr[i];
693             DWORD j;
694 
695             for (j = 0; !foundTimeStamp && j < attr->cValue; j++)
696             {
697                 static const DWORD encoding = X509_ASN_ENCODING |
698                  PKCS_7_ASN_ENCODING;
699                 DWORD size = sizeof(FILETIME);
700 
701                 foundTimeStamp = CryptDecodeObjectEx(encoding,
702                  X509_CHOICE_OF_TIME,
703                  attr->rgValue[j].pbData, attr->rgValue[j].cbData, 0, NULL,
704                  time, &size);
705             }
706         }
707     }
708     return foundTimeStamp;
709 }
710 
711 static LPCSTR filetime_to_str(const FILETIME *time)
712 {
713     static char date[80];
714     char dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
715     SYSTEMTIME sysTime;
716 
717     if (!time) return NULL;
718 
719     GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
720      sizeof(dateFmt) / sizeof(dateFmt[0]));
721     FileTimeToSystemTime(time, &sysTime);
722     GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
723      sizeof(date) / sizeof(date[0]));
724     return date;
725 }
726 
727 static FILETIME WINTRUST_GetTimeFromSigner(const CRYPT_PROVIDER_DATA *data,
728  const CMSG_SIGNER_INFO *signerInfo)
729 {
730     DWORD i;
731     FILETIME time;
732     BOOL foundTimeStamp = FALSE;
733 
734     for (i = 0; !foundTimeStamp && i < signerInfo->UnauthAttrs.cAttr; i++)
735     {
736         if (!strcmp(signerInfo->UnauthAttrs.rgAttr[i].pszObjId,
737          szOID_RSA_counterSign))
738         {
739             const CRYPT_ATTRIBUTE *attr = &signerInfo->UnauthAttrs.rgAttr[i];
740             DWORD j;
741 
742             for (j = 0; j < attr->cValue; j++)
743             {
744                 static const DWORD encoding = X509_ASN_ENCODING |
745                  PKCS_7_ASN_ENCODING;
746                 CMSG_CMS_SIGNER_INFO *counterSignerInfo;
747                 DWORD size;
748                 BOOL ret = CryptDecodeObjectEx(encoding, CMS_SIGNER_INFO,
749                  attr->rgValue[j].pbData, attr->rgValue[j].cbData,
750                  CRYPT_DECODE_ALLOC_FLAG, NULL, &counterSignerInfo, &size);
751                 if (ret)
752                 {
753                     /* FIXME: need to verify countersigner signature too */
754                     foundTimeStamp = WINTRUST_GetTimeFromCounterSigner(
755                      counterSignerInfo, &time);
756                     LocalFree(counterSignerInfo);
757                 }
758             }
759         }
760     }
761     if (!foundTimeStamp)
762     {
763         TRACE("returning system time %s\n",
764          filetime_to_str(&data->sftSystemTime));
765         time = data->sftSystemTime;
766     }
767     else
768         TRACE("returning time from message %s\n", filetime_to_str(&time));
769     return time;
770 }
771 
772 static DWORD WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
773 {
774     DWORD err;
775     CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx);
776 
777     if (signerInfo)
778     {
779         CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
780 
781         sgnr.psSigner = signerInfo;
782         sgnr.sftVerifyAsOf = WINTRUST_GetTimeFromSigner(data, signerInfo);
783         if (!data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr))
784             err = GetLastError();
785         else
786             err = ERROR_SUCCESS;
787     }
788     else
789         err = GetLastError();
790     return err;
791 }
792 
793 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
794  DWORD signerIdx)
795 {
796     BOOL ret;
797     CERT_INFO *certInfo = NULL;
798     DWORD size;
799 
800     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
801      NULL, &size);
802     if (ret)
803     {
804         certInfo = data->psPfns->pfnAlloc(size);
805         if (certInfo)
806         {
807             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
808              signerIdx, certInfo, &size);
809             if (!ret)
810             {
811                 data->psPfns->pfnFree(certInfo);
812                 certInfo = NULL;
813             }
814         }
815         else
816             SetLastError(ERROR_OUTOFMEMORY);
817     }
818     return certInfo;
819 }
820 
821 static DWORD WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
822 {
823     DWORD err;
824     CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx);
825 
826     if (certInfo)
827     {
828         PCCERT_CONTEXT subject = CertGetSubjectCertificateFromStore(
829          data->pahStores[0], data->dwEncoding, certInfo);
830 
831         if (subject)
832         {
833             CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0,
834              signerIdx, CMSG_VERIFY_SIGNER_CERT, (LPVOID)subject };
835 
836             if (!CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX,
837              &para))
838                 err = TRUST_E_CERT_SIGNATURE;
839             else
840             {
841                 data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
842                  subject);
843                 err = ERROR_SUCCESS;
844             }
845             CertFreeCertificateContext(subject);
846         }
847         else
848             err = TRUST_E_NO_SIGNER_CERT;
849         data->psPfns->pfnFree(certInfo);
850     }
851     else
852         err = GetLastError();
853     return err;
854 }
855 
856 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
857 {
858     DWORD err;
859 
860     TRACE("(%p)\n", data);
861 
862     if (!data->padwTrustStepErrors)
863         return S_FALSE;
864 
865     if (data->hMsg)
866     {
867         DWORD signerCount, size;
868 
869         size = sizeof(signerCount);
870         if (CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
871          &signerCount, &size))
872         {
873             DWORD i;
874 
875             err = ERROR_SUCCESS;
876             for (i = 0; !err && i < signerCount; i++)
877             {
878                 if (!(err = WINTRUST_SaveSigner(data, i)))
879                     err = WINTRUST_VerifySigner(data, i);
880             }
881         }
882         else
883             err = TRUST_E_NOSIGNATURE;
884     }
885     else
886         err = ERROR_SUCCESS;
887     if (err)
888         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = err;
889     return !err ? S_OK : S_FALSE;
890 }
891 
892 static DWORD WINTRUST_TrustStatusToConfidence(DWORD errorStatus)
893 {
894     DWORD confidence = 0;
895 
896     confidence = 0;
897     if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
898         confidence |= CERT_CONFIDENCE_SIG;
899     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
900         confidence |= CERT_CONFIDENCE_TIME;
901     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
902         confidence |= CERT_CONFIDENCE_TIMENEST;
903     return confidence;
904 }
905 
906 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
907  BOOL fCounterSignerChain, DWORD idxCounterSigner)
908 {
909     BOOL ret;
910 
911     TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain,
912      idxCounterSigner);
913 
914     if (fCounterSignerChain)
915     {
916         FIXME("unimplemented for counter signers\n");
917         ret = FALSE;
918     }
919     else
920     {
921         PCERT_SIMPLE_CHAIN simpleChain =
922          data->pasSigners[idxSigner].pChainContext->rgpChain[0];
923         DWORD i;
924 
925         ret = TRUE;
926         for (i = 0; i < simpleChain->cElement; i++)
927         {
928             /* Set confidence */
929             data->pasSigners[idxSigner].pasCertChain[i].dwConfidence =
930              WINTRUST_TrustStatusToConfidence(
931              simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus);
932             /* Set additional flags */
933             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
934              CERT_TRUST_IS_UNTRUSTED_ROOT))
935                 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE;
936             if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus &
937              CERT_TRUST_IS_SELF_SIGNED)
938                 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE;
939             if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
940              CERT_TRUST_IS_CYCLIC)
941                 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE;
942         }
943     }
944     return ret;
945 }
946 
947 static DWORD WINTRUST_TrustStatusToError(DWORD errorStatus)
948 {
949     DWORD error;
950 
951     if (errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)
952         error = TRUST_E_CERT_SIGNATURE;
953     else if (errorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT)
954         error = CERT_E_UNTRUSTEDROOT;
955     else if (errorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
956         error = CERT_E_EXPIRED;
957     else if (errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED)
958         error = CERT_E_VALIDITYPERIODNESTING;
959     else if (errorStatus & CERT_TRUST_IS_REVOKED)
960         error = CERT_E_REVOKED;
961     else if (errorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION ||
962      errorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
963         error = CERT_E_REVOCATION_FAILURE;
964     else if (errorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
965         error = CERT_E_WRONG_USAGE;
966     else if (errorStatus & CERT_TRUST_IS_CYCLIC)
967         error = CERT_E_CHAINING;
968     else if (errorStatus & CERT_TRUST_INVALID_EXTENSION)
969         error = CERT_E_CRITICAL;
970     else if (errorStatus & CERT_TRUST_INVALID_POLICY_CONSTRAINTS)
971         error = CERT_E_INVALID_POLICY;
972     else if (errorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
973         error = TRUST_E_BASIC_CONSTRAINTS;
974     else if (errorStatus & CERT_TRUST_INVALID_NAME_CONSTRAINTS ||
975      errorStatus & CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT ||
976      errorStatus & CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT ||
977      errorStatus & CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT ||
978      errorStatus & CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT)
979         error = CERT_E_INVALID_NAME;
980     else if (errorStatus & CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY)
981         error = CERT_E_INVALID_POLICY;
982     else if (errorStatus)
983     {
984         FIXME("unknown error status %08x\n", errorStatus);
985         error = TRUST_E_SYSTEM_ERROR;
986     }
987     else
988         error = S_OK;
989     return error;
990 }
991 
992 static DWORD WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
993 {
994     DWORD err, i;
995     PCERT_SIMPLE_CHAIN simpleChain =
996      data->pasSigners[signerIdx].pChainContext->rgpChain[0];
997 
998     data->pasSigners[signerIdx].pasCertChain[0].dwConfidence =
999      WINTRUST_TrustStatusToConfidence(
1000      simpleChain->rgpElement[0]->TrustStatus.dwErrorStatus);
1001     data->pasSigners[signerIdx].pasCertChain[0].pChainElement =
1002      simpleChain->rgpElement[0];
1003     err = ERROR_SUCCESS;
1004     for (i = 1; !err && i < simpleChain->cElement; i++)
1005     {
1006         if (data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
1007          simpleChain->rgpElement[i]->pCertContext))
1008         {
1009             data->pasSigners[signerIdx].pasCertChain[i].pChainElement =
1010              simpleChain->rgpElement[i];
1011             data->pasSigners[signerIdx].pasCertChain[i].dwConfidence =
1012              WINTRUST_TrustStatusToConfidence(
1013              simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus);
1014         }
1015         else
1016             err = GetLastError();
1017     }
1018     data->pasSigners[signerIdx].pasCertChain[simpleChain->cElement - 1].dwError
1019      = WINTRUST_TrustStatusToError(
1020      simpleChain->rgpElement[simpleChain->cElement - 1]->
1021      TrustStatus.dwErrorStatus);
1022     return err;
1023 }
1024 
1025 static void WINTRUST_CreateChainPolicyCreateInfo(
1026  const CRYPT_PROVIDER_DATA *data, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO info,
1027  PCERT_CHAIN_PARA chainPara)
1028 {
1029     chainPara->cbSize = sizeof(CERT_CHAIN_PARA);
1030     if (data->pRequestUsage)
1031         chainPara->RequestedUsage = *data->pRequestUsage;
1032     else
1033     {
1034         chainPara->RequestedUsage.dwType = 0;
1035         chainPara->RequestedUsage.Usage.cUsageIdentifier = 0;
1036     }
1037     info->u.cbSize = sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO);
1038     info->hChainEngine = NULL;
1039     info->pChainPara = chainPara;
1040     if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT)
1041         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
1042     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN)
1043         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
1044     else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
1045         info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
1046     else
1047         info->dwFlags = 0;
1048     info->pvReserved = NULL;
1049 }
1050 
1051 static DWORD WINTRUST_CreateChainForSigner(CRYPT_PROVIDER_DATA *data,
1052  DWORD signer, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo,
1053  PCERT_CHAIN_PARA chainPara)
1054 {
1055     DWORD err = ERROR_SUCCESS;
1056     HCERTSTORE store = NULL;
1057 
1058     if (data->chStores)
1059     {
1060         store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1061          CERT_STORE_CREATE_NEW_FLAG, NULL);
1062         if (store)
1063         {
1064             DWORD i;
1065 
1066             for (i = 0; i < data->chStores; i++)
1067                 CertAddStoreToCollection(store, data->pahStores[i], 0, 0);
1068         }
1069         else
1070             err = GetLastError();
1071     }
1072     if (!err)
1073     {
1074         /* Expect the end certificate for each signer to be the only cert in
1075          * the chain:
1076          */
1077         if (data->pasSigners[signer].csCertChain)
1078         {
1079             BOOL ret;
1080 
1081             /* Create a certificate chain for each signer */
1082             ret = CertGetCertificateChain(createInfo->hChainEngine,
1083              data->pasSigners[signer].pasCertChain[0].pCert,
1084              &data->pasSigners[signer].sftVerifyAsOf, store,
1085              chainPara, createInfo->dwFlags, createInfo->pvReserved,
1086              &data->pasSigners[signer].pChainContext);
1087             if (ret)
1088             {
1089                 if (data->pasSigners[signer].pChainContext->cChain != 1)
1090                 {
1091                     FIXME("unimplemented for more than 1 simple chain\n");
1092                     err = E_NOTIMPL;
1093                 }
1094                 else
1095                 {
1096                     if (!(err = WINTRUST_CopyChain(data, signer)))
1097                     {
1098                         if (data->psPfns->pfnCertCheckPolicy)
1099                         {
1100                             ret = data->psPfns->pfnCertCheckPolicy(data, signer,
1101                              FALSE, 0);
1102                             if (!ret)
1103                                 err = GetLastError();
1104                         }
1105                         else
1106                             TRACE(
1107                              "no cert check policy, skipping policy check\n");
1108                     }
1109                 }
1110             }
1111             else
1112                 err = GetLastError();
1113         }
1114         CertCloseStore(store, 0);
1115     }
1116     return err;
1117 }
1118 
1119 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data)
1120 {
1121     DWORD err;
1122 
1123     TRACE("(%p)\n", data);
1124 
1125     if (!data->csSigners)
1126         err = TRUST_E_NOSIGNATURE;
1127     else
1128     {
1129         DWORD i;
1130         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo;
1131         CERT_CHAIN_PARA chainPara;
1132 
1133         WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
1134         err = ERROR_SUCCESS;
1135         for (i = 0; !err && i < data->csSigners; i++)
1136             err = WINTRUST_CreateChainForSigner(data, i, &createInfo,
1137              &chainPara);
1138     }
1139     if (err)
1140         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = err;
1141     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
1142      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
1143     return !err ? S_OK : S_FALSE;
1144 }
1145 
1146 HRESULT WINAPI GenericChainCertificateTrust(CRYPT_PROVIDER_DATA *data)
1147 {
1148     DWORD err;
1149     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
1150      data->pWintrustData->pPolicyCallbackData;
1151 
1152     TRACE("(%p)\n", data);
1153 
1154     if (policyData && policyData->u.cbSize !=
1155      sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO))
1156     {
1157         err = ERROR_INVALID_PARAMETER;
1158         goto end;
1159     }
1160     if (!data->csSigners)
1161         err = TRUST_E_NOSIGNATURE;
1162     else
1163     {
1164         DWORD i;
1165         WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo, *pCreateInfo;
1166         CERT_CHAIN_PARA chainPara, *pChainPara;
1167 
1168         if (policyData)
1169         {
1170             pCreateInfo = policyData->pSignerChainInfo;
1171             pChainPara = pCreateInfo->pChainPara;
1172         }
1173         else
1174         {
1175             WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara);
1176             pChainPara = &chainPara;
1177             pCreateInfo = &createInfo;
1178         }
1179         err = ERROR_SUCCESS;
1180         for (i = 0; !err && i < data->csSigners; i++)
1181             err = WINTRUST_CreateChainForSigner(data, i, pCreateInfo,
1182              pChainPara);
1183     }
1184 
1185 end:
1186     if (err)
1187         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = err;
1188     TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE,
1189      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
1190     return !err ? S_OK : S_FALSE;
1191 }
1192 
1193 HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data)
1194 {
1195     BOOL ret;
1196     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
1197 
1198     TRACE("(%p)\n", data);
1199 
1200     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
1201         FIXME("unimplemented for UI choice %d\n",
1202          data->pWintrustData->dwUIChoice);
1203     if (!data->csSigners)
1204     {
1205         ret = FALSE;
1206         policyStatus.dwError = TRUST_E_NOSIGNATURE;
1207     }
1208     else
1209     {
1210         DWORD i;
1211 
1212         ret = TRUE;
1213         for (i = 0; ret && i < data->csSigners; i++)
1214         {
1215             BYTE hash[20];
1216             DWORD size = sizeof(hash);
1217 
1218             /* First make sure cert isn't disallowed */
1219             if ((ret = CertGetCertificateContextProperty(
1220              data->pasSigners[i].pasCertChain[0].pCert,
1221              CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
1222             {
1223                 static const WCHAR disallowedW[] =
1224                  { 'D','i','s','a','l','l','o','w','e','d',0 };
1225                 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
1226                  X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER,
1227                  disallowedW);
1228 
1229                 if (disallowed)
1230                 {
1231                     PCCERT_CONTEXT found = CertFindCertificateInStore(
1232                      disallowed, X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH,
1233                      hash, NULL);
1234 
1235                     if (found)
1236                     {
1237                         /* Disallowed!  Can't verify it. */
1238                         policyStatus.dwError = TRUST_E_SUBJECT_NOT_TRUSTED;
1239                         ret = FALSE;
1240                         CertFreeCertificateContext(found);
1241                     }
1242                     CertCloseStore(disallowed, 0);
1243                 }
1244             }
1245             if (ret)
1246             {
1247                 CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
1248 
1249                 if (data->dwRegPolicySettings & WTPF_TRUSTTEST)
1250                     policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG;
1251                 if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID)
1252                     policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG;
1253                 if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
1254                     policyPara.dwFlags |=
1255                      CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
1256                      CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
1257                      CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
1258                 if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION)
1259                     policyPara.dwFlags |=
1260                      CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
1261                      CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
1262                      CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
1263                      CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
1264                 CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE,
1265                  data->pasSigners[i].pChainContext, &policyPara, &policyStatus);
1266                 if (policyStatus.dwError != NO_ERROR)
1267                     ret = FALSE;
1268             }
1269         }
1270     }
1271     if (!ret)
1272         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] =
1273          policyStatus.dwError;
1274     TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE,
1275      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
1276     return ret ? S_OK : S_FALSE;
1277 }
1278 
1279 static HRESULT WINAPI WINTRUST_DefaultPolicy(CRYPT_PROVIDER_DATA *pProvData,
1280  DWORD dwStepError, DWORD dwRegPolicySettings, DWORD cSigner,
1281  PWTD_GENERIC_CHAIN_POLICY_SIGNER_INFO rgpSigner, void *pvPolicyArg)
1282 {
1283     DWORD i;
1284     CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 };
1285 
1286     for (i = 0; !policyStatus.dwError && i < cSigner; i++)
1287     {
1288         CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 };
1289 
1290         if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION)
1291             policyPara.dwFlags |=
1292              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG |
1293              CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG |
1294              CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
1295         if (dwRegPolicySettings & WTPF_IGNOREREVOKATION)
1296             policyPara.dwFlags |=
1297              CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG |
1298              CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG |
1299              CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG |
1300              CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG;
1301         CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
1302          rgpSigner[i].pChainContext, &policyPara, &policyStatus);
1303     }
1304     return policyStatus.dwError;
1305 }
1306 
1307 HRESULT WINAPI GenericChainFinalProv(CRYPT_PROVIDER_DATA *data)
1308 {
1309     HRESULT err = NO_ERROR; /* not a typo, MS confused the types */
1310     WTD_GENERIC_CHAIN_POLICY_DATA *policyData =
1311      data->pWintrustData->pPolicyCallbackData;
1312 
1313     TRACE("(%p)\n", data);
1314 
1315     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
1316         FIXME("unimplemented for UI choice %d\n",
1317          data->pWintrustData->dwUIChoice);
1318     if (!data->csSigners)
1319         err = TRUST_E_NOSIGNATURE;
1320     else
1321     {
1322         PFN_WTD_GENERIC_CHAIN_POLICY_CALLBACK policyCallback;
1323         void *policyArg;
1324         WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO *signers = NULL;
1325 
1326         if (policyData)
1327         {
1328             policyCallback = policyData->pfnPolicyCallback;
1329             policyArg = policyData->pvPolicyArg;
1330         }
1331         else
1332         {
1333             policyCallback = WINTRUST_DefaultPolicy;
1334             policyArg = NULL;
1335         }
1336         if (data->csSigners)
1337         {
1338             DWORD i;
1339 
1340             signers = data->psPfns->pfnAlloc(
1341              data->csSigners * sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO));
1342             if (signers)
1343             {
1344                 for (i = 0; i < data->csSigners; i++)
1345                 {
1346                     signers[i].u.cbSize =
1347                      sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO);
1348                     signers[i].pChainContext =
1349                      data->pasSigners[i].pChainContext;
1350                     signers[i].dwSignerType = data->pasSigners[i].dwSignerType;
1351                     signers[i].pMsgSignerInfo = data->pasSigners[i].psSigner;
1352                     signers[i].dwError = data->pasSigners[i].dwError;
1353                     if (data->pasSigners[i].csCounterSigners)
1354                         FIXME("unimplemented for counter signers\n");
1355                     signers[i].cCounterSigner = 0;
1356                     signers[i].rgpCounterSigner = NULL;
1357                 }
1358             }
1359             else
1360                 err = ERROR_OUTOFMEMORY;
1361         }
1362         if (err == NO_ERROR)
1363             err = policyCallback(data, TRUSTERROR_STEP_FINAL_POLICYPROV,
1364              data->dwRegPolicySettings, data->csSigners, signers, policyArg);
1365         data->psPfns->pfnFree(signers);
1366     }
1367     if (err != NO_ERROR)
1368         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = err;
1369     TRACE("returning %d (%08x)\n", err == NO_ERROR ? S_OK : S_FALSE,
1370      data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]);
1371     return err == NO_ERROR ? S_OK : S_FALSE;
1372 }
1373 
1374 HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data)
1375 {
1376     DWORD i, j;
1377 
1378     for (i = 0; i < data->csSigners; i++)
1379     {
1380         for (j = 0; j < data->pasSigners[i].csCertChain; j++)
1381             CertFreeCertificateContext(data->pasSigners[i].pasCertChain[j].pCert);
1382         data->psPfns->pfnFree(data->pasSigners[i].pasCertChain);
1383         data->psPfns->pfnFree(data->pasSigners[i].psSigner);
1384         CertFreeCertificateChain(data->pasSigners[i].pChainContext);
1385     }
1386     data->psPfns->pfnFree(data->pasSigners);
1387 
1388     for (i = 0; i < data->chStores; i++)
1389         CertCloseStore(data->pahStores[i], 0);
1390     data->psPfns->pfnFree(data->pahStores);
1391 
1392     if (data->u.pPDSip)
1393     {
1394         data->psPfns->pfnFree(data->u.pPDSip->pSip);
1395         data->psPfns->pfnFree(data->u.pPDSip->pCATSip);
1396         data->psPfns->pfnFree(data->u.pPDSip->psSipSubjectInfo);
1397         data->psPfns->pfnFree(data->u.pPDSip->psSipCATSubjectInfo);
1398         data->psPfns->pfnFree(data->u.pPDSip->psIndirectData);
1399     }
1400 
1401     CryptMsgClose(data->hMsg);
1402 
1403     if (data->fOpenedFile &&
1404      data->pWintrustData->dwUnionChoice == WTD_CHOICE_FILE &&
1405      data->pWintrustData->u.pFile)
1406     {
1407         CloseHandle(data->pWintrustData->u.pFile->hFile);
1408         data->pWintrustData->u.pFile->hFile = INVALID_HANDLE_VALUE;
1409         data->fOpenedFile = FALSE;
1410     }
1411 
1412     return S_OK;
1413 }
1414 
1415 HRESULT WINAPI HTTPSCertificateTrust(CRYPT_PROVIDER_DATA *data)
1416 {
1417     FIXME("(%p)\n", data);
1418     return S_OK;
1419 }
1420 
1421 HRESULT WINAPI HTTPSFinalProv(CRYPT_PROVIDER_DATA *data)
1422 {
1423     FIXME("(%p)\n", data);
1424     return S_OK;
1425 }
1426