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