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