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 ¶)) 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