Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensoftpub.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2007 Juan Lang 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 #include <stdarg.h> 00019 00020 #define NONAMELESSUNION 00021 00022 #include "windef.h" 00023 #include "winbase.h" 00024 #include "wintrust.h" 00025 #include "mssip.h" 00026 #include "softpub.h" 00027 #include "wine/debug.h" 00028 00029 WINE_DEFAULT_DEBUG_CHANNEL(wintrust); 00030 00031 HRESULT WINAPI SoftpubDefCertInit(CRYPT_PROVIDER_DATA *data) 00032 { 00033 HRESULT ret = S_FALSE; 00034 00035 TRACE("(%p)\n", data); 00036 00037 if (data->padwTrustStepErrors && 00038 !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT]) 00039 ret = S_OK; 00040 TRACE("returning %08x\n", ret); 00041 return ret; 00042 } 00043 00044 HRESULT WINAPI SoftpubInitialize(CRYPT_PROVIDER_DATA *data) 00045 { 00046 HRESULT ret = S_FALSE; 00047 00048 TRACE("(%p)\n", data); 00049 00050 if (data->padwTrustStepErrors && 00051 !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT]) 00052 ret = S_OK; 00053 TRACE("returning %08x\n", ret); 00054 return ret; 00055 } 00056 00057 HRESULT WINAPI DriverInitializePolicy(CRYPT_PROVIDER_DATA *data) 00058 { 00059 FIXME("stub\n"); 00060 return S_OK; 00061 } 00062 00063 HRESULT WINAPI DriverCleanupPolicy(CRYPT_PROVIDER_DATA *data) 00064 { 00065 FIXME("stub\n"); 00066 return S_OK; 00067 } 00068 00069 HRESULT WINAPI DriverFinalPolicy(CRYPT_PROVIDER_DATA *data) 00070 { 00071 FIXME("stub\n"); 00072 return S_OK; 00073 } 00074 00075 /* Assumes data->pWintrustData->u.pFile exists. Makes sure a file handle is 00076 * open for the file. 00077 */ 00078 static DWORD SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA *data) 00079 { 00080 DWORD err = ERROR_SUCCESS; 00081 00082 /* PSDK implies that all values should be initialized to NULL, so callers 00083 * typically have hFile as NULL rather than INVALID_HANDLE_VALUE. Check 00084 * for both. 00085 */ 00086 if (!data->pWintrustData->u.pFile->hFile || 00087 data->pWintrustData->u.pFile->hFile == INVALID_HANDLE_VALUE) 00088 { 00089 data->pWintrustData->u.pFile->hFile = 00090 CreateFileW(data->pWintrustData->u.pFile->pcwszFilePath, GENERIC_READ, 00091 FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00092 if (data->pWintrustData->u.pFile->hFile != INVALID_HANDLE_VALUE) 00093 data->fOpenedFile = TRUE; 00094 else 00095 err = GetLastError(); 00096 } 00097 if (!err) 00098 GetFileTime(data->pWintrustData->u.pFile->hFile, &data->sftSystemTime, 00099 NULL, NULL); 00100 TRACE("returning %d\n", err); 00101 return err; 00102 } 00103 00104 /* Assumes data->pWintrustData->u.pFile exists. Sets data->pPDSip->gSubject to 00105 * the file's subject GUID. 00106 */ 00107 static DWORD SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA *data) 00108 { 00109 DWORD err = ERROR_SUCCESS; 00110 00111 if (!WVT_ISINSTRUCT(WINTRUST_FILE_INFO, 00112 data->pWintrustData->u.pFile->cbStruct, pgKnownSubject) || 00113 !data->pWintrustData->u.pFile->pgKnownSubject) 00114 { 00115 if (!CryptSIPRetrieveSubjectGuid( 00116 data->pWintrustData->u.pFile->pcwszFilePath, 00117 data->pWintrustData->u.pFile->hFile, 00118 &data->u.pPDSip->gSubject)) 00119 err = GetLastError(); 00120 } 00121 else 00122 data->u.pPDSip->gSubject = *data->pWintrustData->u.pFile->pgKnownSubject; 00123 TRACE("returning %d\n", err); 00124 return err; 00125 } 00126 00127 /* Assumes data->u.pPDSip exists, and its gSubject member set. 00128 * Allocates data->u.pPDSip->pSip and loads it, if possible. 00129 */ 00130 static DWORD SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data) 00131 { 00132 DWORD err = ERROR_SUCCESS; 00133 00134 data->u.pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO)); 00135 if (data->u.pPDSip->pSip) 00136 { 00137 if (!CryptSIPLoad(&data->u.pPDSip->gSubject, 0, data->u.pPDSip->pSip)) 00138 err = GetLastError(); 00139 } 00140 else 00141 err = ERROR_OUTOFMEMORY; 00142 TRACE("returning %d\n", err); 00143 return err; 00144 } 00145 00146 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated. 00147 * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg. 00148 */ 00149 static DWORD SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data, HANDLE file, 00150 LPCWSTR filePath) 00151 { 00152 DWORD err = ERROR_SUCCESS; 00153 BOOL ret; 00154 LPBYTE buf = NULL; 00155 DWORD size = 0; 00156 00157 data->u.pPDSip->psSipSubjectInfo = 00158 data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO)); 00159 if (!data->u.pPDSip->psSipSubjectInfo) 00160 return ERROR_OUTOFMEMORY; 00161 00162 data->u.pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO); 00163 data->u.pPDSip->psSipSubjectInfo->pgSubjectType = &data->u.pPDSip->gSubject; 00164 data->u.pPDSip->psSipSubjectInfo->hFile = file; 00165 data->u.pPDSip->psSipSubjectInfo->pwsFileName = filePath; 00166 data->u.pPDSip->psSipSubjectInfo->hProv = data->hProv; 00167 ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo, 00168 &data->dwEncoding, 0, &size, 0); 00169 if (!ret) 00170 return TRUST_E_NOSIGNATURE; 00171 00172 buf = data->psPfns->pfnAlloc(size); 00173 if (!buf) 00174 return ERROR_OUTOFMEMORY; 00175 00176 ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo, 00177 &data->dwEncoding, 0, &size, buf); 00178 if (ret) 00179 { 00180 data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv, 00181 NULL, NULL); 00182 if (data->hMsg) 00183 { 00184 ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE); 00185 if (!ret) 00186 err = GetLastError(); 00187 } 00188 } 00189 else 00190 err = GetLastError(); 00191 00192 data->psPfns->pfnFree(buf); 00193 TRACE("returning %d\n", err); 00194 return err; 00195 } 00196 00197 static DWORD SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data) 00198 { 00199 DWORD err = ERROR_SUCCESS; 00200 HCERTSTORE store; 00201 00202 store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding, 00203 data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg); 00204 if (store) 00205 { 00206 if (!data->psPfns->pfnAddStore2Chain(data, store)) 00207 err = GetLastError(); 00208 CertCloseStore(store, 0); 00209 } 00210 else 00211 err = GetLastError(); 00212 TRACE("returning %d\n", err); 00213 return err; 00214 } 00215 00216 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data) 00217 { 00218 BOOL ret; 00219 DWORD size, err = ERROR_SUCCESS; 00220 LPSTR oid = NULL; 00221 LPBYTE buf = NULL; 00222 00223 ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, 00224 &size); 00225 if (!ret) 00226 { 00227 err = GetLastError(); 00228 goto error; 00229 } 00230 oid = data->psPfns->pfnAlloc(size); 00231 if (!oid) 00232 { 00233 err = ERROR_OUTOFMEMORY; 00234 goto error; 00235 } 00236 ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, oid, 00237 &size); 00238 if (!ret) 00239 { 00240 err = GetLastError(); 00241 goto error; 00242 } 00243 ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size); 00244 if (!ret) 00245 { 00246 err = GetLastError(); 00247 goto error; 00248 } 00249 buf = data->psPfns->pfnAlloc(size); 00250 if (!buf) 00251 { 00252 err = ERROR_OUTOFMEMORY; 00253 goto error; 00254 } 00255 ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size); 00256 if (!ret) 00257 { 00258 err = GetLastError(); 00259 goto error; 00260 } 00261 ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0, NULL, &size); 00262 if (!ret) 00263 { 00264 err = GetLastError(); 00265 goto error; 00266 } 00267 data->u.pPDSip->psIndirectData = data->psPfns->pfnAlloc(size); 00268 if (!data->u.pPDSip->psIndirectData) 00269 { 00270 err = ERROR_OUTOFMEMORY; 00271 goto error; 00272 } 00273 ret = CryptDecodeObject(data->dwEncoding, oid, buf, size, 0, 00274 data->u.pPDSip->psIndirectData, &size); 00275 if (!ret) 00276 err = GetLastError(); 00277 00278 error: 00279 TRACE("returning %d\n", err); 00280 data->psPfns->pfnFree(oid); 00281 data->psPfns->pfnFree(buf); 00282 return err; 00283 } 00284 00285 static DWORD SOFTPUB_LoadCertMessage(CRYPT_PROVIDER_DATA *data) 00286 { 00287 DWORD err = ERROR_SUCCESS; 00288 00289 if (data->pWintrustData->u.pCert && 00290 WVT_IS_CBSTRUCT_GT_MEMBEROFFSET(WINTRUST_CERT_INFO, 00291 data->pWintrustData->u.pCert->cbStruct, psCertContext)) 00292 { 00293 if (data->psPfns) 00294 { 00295 CRYPT_PROVIDER_SGNR signer = { sizeof(signer), { 0 } }; 00296 DWORD i; 00297 BOOL ret; 00298 00299 /* Add a signer with nothing but the time to verify, so we can 00300 * add a cert to it 00301 */ 00302 if (WVT_ISINSTRUCT(WINTRUST_CERT_INFO, 00303 data->pWintrustData->u.pCert->cbStruct, psftVerifyAsOf) && 00304 data->pWintrustData->u.pCert->psftVerifyAsOf) 00305 data->sftSystemTime = signer.sftVerifyAsOf; 00306 else 00307 { 00308 SYSTEMTIME sysTime; 00309 00310 GetSystemTime(&sysTime); 00311 SystemTimeToFileTime(&sysTime, &signer.sftVerifyAsOf); 00312 } 00313 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer); 00314 if (ret) 00315 { 00316 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0, 00317 data->pWintrustData->u.pCert->psCertContext); 00318 if (WVT_ISINSTRUCT(WINTRUST_CERT_INFO, 00319 data->pWintrustData->u.pCert->cbStruct, pahStores)) 00320 for (i = 0; 00321 ret && i < data->pWintrustData->u.pCert->chStores; i++) 00322 ret = data->psPfns->pfnAddStore2Chain(data, 00323 data->pWintrustData->u.pCert->pahStores[i]); 00324 } 00325 if (!ret) 00326 err = GetLastError(); 00327 } 00328 } 00329 else 00330 err = ERROR_INVALID_PARAMETER; 00331 return err; 00332 } 00333 00334 static DWORD SOFTPUB_LoadFileMessage(CRYPT_PROVIDER_DATA *data) 00335 { 00336 DWORD err = ERROR_SUCCESS; 00337 00338 if (!data->pWintrustData->u.pFile) 00339 { 00340 err = ERROR_INVALID_PARAMETER; 00341 goto error; 00342 } 00343 err = SOFTPUB_OpenFile(data); 00344 if (err) 00345 goto error; 00346 err = SOFTPUB_GetFileSubject(data); 00347 if (err) 00348 goto error; 00349 err = SOFTPUB_GetSIP(data); 00350 if (err) 00351 goto error; 00352 err = SOFTPUB_GetMessageFromFile(data, data->pWintrustData->u.pFile->hFile, 00353 data->pWintrustData->u.pFile->pcwszFilePath); 00354 if (err) 00355 goto error; 00356 err = SOFTPUB_CreateStoreFromMessage(data); 00357 if (err) 00358 goto error; 00359 err = SOFTPUB_DecodeInnerContent(data); 00360 00361 error: 00362 if (err && data->fOpenedFile && data->pWintrustData->u.pFile) 00363 { 00364 /* The caller won't expect the file to be open on failure, so close it. 00365 */ 00366 CloseHandle(data->pWintrustData->u.pFile->hFile); 00367 data->pWintrustData->u.pFile->hFile = INVALID_HANDLE_VALUE; 00368 data->fOpenedFile = FALSE; 00369 } 00370 return err; 00371 } 00372 00373 static DWORD SOFTPUB_LoadCatalogMessage(CRYPT_PROVIDER_DATA *data) 00374 { 00375 DWORD err; 00376 HANDLE catalog = INVALID_HANDLE_VALUE; 00377 00378 if (!data->pWintrustData->u.pCatalog) 00379 { 00380 SetLastError(ERROR_INVALID_PARAMETER); 00381 return FALSE; 00382 } 00383 catalog = CreateFileW(data->pWintrustData->u.pCatalog->pcwszCatalogFilePath, 00384 GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 00385 NULL); 00386 if (catalog == INVALID_HANDLE_VALUE) 00387 return GetLastError(); 00388 if (!CryptSIPRetrieveSubjectGuid( 00389 data->pWintrustData->u.pCatalog->pcwszCatalogFilePath, catalog, 00390 &data->u.pPDSip->gSubject)) 00391 { 00392 err = GetLastError(); 00393 goto error; 00394 } 00395 err = SOFTPUB_GetSIP(data); 00396 if (err) 00397 goto error; 00398 err = SOFTPUB_GetMessageFromFile(data, catalog, 00399 data->pWintrustData->u.pCatalog->pcwszCatalogFilePath); 00400 if (err) 00401 goto error; 00402 err = SOFTPUB_CreateStoreFromMessage(data); 00403 if (err) 00404 goto error; 00405 err = SOFTPUB_DecodeInnerContent(data); 00406 /* FIXME: this loads the catalog file, but doesn't validate the member. */ 00407 error: 00408 CloseHandle(catalog); 00409 return err; 00410 } 00411 00412 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data) 00413 { 00414 DWORD err = ERROR_SUCCESS; 00415 00416 TRACE("(%p)\n", data); 00417 00418 if (!data->padwTrustStepErrors) 00419 return S_FALSE; 00420 00421 switch (data->pWintrustData->dwUnionChoice) 00422 { 00423 case WTD_CHOICE_CERT: 00424 err = SOFTPUB_LoadCertMessage(data); 00425 break; 00426 case WTD_CHOICE_FILE: 00427 err = SOFTPUB_LoadFileMessage(data); 00428 break; 00429 case WTD_CHOICE_CATALOG: 00430 err = SOFTPUB_LoadCatalogMessage(data); 00431 break; 00432 default: 00433 FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice); 00434 err = ERROR_INVALID_PARAMETER; 00435 } 00436 00437 if (err) 00438 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] = err; 00439 TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE, 00440 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]); 00441 return !err ? S_OK : S_FALSE; 00442 } 00443 00444 static CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data, 00445 DWORD signerIdx) 00446 { 00447 BOOL ret; 00448 CMSG_SIGNER_INFO *signerInfo = NULL; 00449 DWORD size; 00450 00451 ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx, 00452 NULL, &size); 00453 if (ret) 00454 { 00455 signerInfo = data->psPfns->pfnAlloc(size); 00456 if (signerInfo) 00457 { 00458 ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, 00459 signerIdx, signerInfo, &size); 00460 if (!ret) 00461 { 00462 data->psPfns->pfnFree(signerInfo); 00463 signerInfo = NULL; 00464 } 00465 } 00466 else 00467 SetLastError(ERROR_OUTOFMEMORY); 00468 } 00469 return signerInfo; 00470 } 00471 00472 static DWORD WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx) 00473 { 00474 DWORD err; 00475 CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx); 00476 00477 if (signerInfo) 00478 { 00479 CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } }; 00480 00481 sgnr.psSigner = signerInfo; 00482 sgnr.sftVerifyAsOf = data->sftSystemTime; 00483 if (!data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr)) 00484 err = GetLastError(); 00485 else 00486 err = ERROR_SUCCESS; 00487 } 00488 else 00489 err = GetLastError(); 00490 return err; 00491 } 00492 00493 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data, 00494 DWORD signerIdx) 00495 { 00496 BOOL ret; 00497 CERT_INFO *certInfo = NULL; 00498 DWORD size; 00499 00500 ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx, 00501 NULL, &size); 00502 if (ret) 00503 { 00504 certInfo = data->psPfns->pfnAlloc(size); 00505 if (certInfo) 00506 { 00507 ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 00508 signerIdx, certInfo, &size); 00509 if (!ret) 00510 { 00511 data->psPfns->pfnFree(certInfo); 00512 certInfo = NULL; 00513 } 00514 } 00515 else 00516 SetLastError(ERROR_OUTOFMEMORY); 00517 } 00518 return certInfo; 00519 } 00520 00521 static DWORD WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx) 00522 { 00523 DWORD err; 00524 CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx); 00525 00526 if (certInfo) 00527 { 00528 PCCERT_CONTEXT subject = CertGetSubjectCertificateFromStore( 00529 data->pahStores[0], data->dwEncoding, certInfo); 00530 00531 if (subject) 00532 { 00533 CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0, 00534 signerIdx, CMSG_VERIFY_SIGNER_CERT, (LPVOID)subject }; 00535 00536 if (!CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX, 00537 ¶)) 00538 err = TRUST_E_CERT_SIGNATURE; 00539 else 00540 { 00541 data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0, 00542 subject); 00543 err = ERROR_SUCCESS; 00544 } 00545 CertFreeCertificateContext(subject); 00546 } 00547 else 00548 err = TRUST_E_NO_SIGNER_CERT; 00549 data->psPfns->pfnFree(certInfo); 00550 } 00551 else 00552 err = GetLastError(); 00553 return err; 00554 } 00555 00556 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data) 00557 { 00558 DWORD err; 00559 00560 TRACE("(%p)\n", data); 00561 00562 if (!data->padwTrustStepErrors) 00563 return S_FALSE; 00564 00565 if (data->hMsg) 00566 { 00567 DWORD signerCount, size; 00568 00569 size = sizeof(signerCount); 00570 if (CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0, 00571 &signerCount, &size)) 00572 { 00573 DWORD i; 00574 00575 err = ERROR_SUCCESS; 00576 for (i = 0; !err && i < signerCount; i++) 00577 { 00578 if (!(err = WINTRUST_SaveSigner(data, i))) 00579 err = WINTRUST_VerifySigner(data, i); 00580 } 00581 } 00582 else 00583 err = TRUST_E_NOSIGNATURE; 00584 } 00585 else 00586 err = ERROR_SUCCESS; 00587 if (err) 00588 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_SIGPROV] = err; 00589 return !err ? S_OK : S_FALSE; 00590 } 00591 00592 static DWORD WINTRUST_TrustStatusToConfidence(DWORD errorStatus) 00593 { 00594 DWORD confidence = 0; 00595 00596 confidence = 0; 00597 if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)) 00598 confidence |= CERT_CONFIDENCE_SIG; 00599 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID)) 00600 confidence |= CERT_CONFIDENCE_TIME; 00601 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED)) 00602 confidence |= CERT_CONFIDENCE_TIMENEST; 00603 return confidence; 00604 } 00605 00606 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner, 00607 BOOL fCounterSignerChain, DWORD idxCounterSigner) 00608 { 00609 BOOL ret; 00610 00611 TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain, 00612 idxCounterSigner); 00613 00614 if (fCounterSignerChain) 00615 { 00616 FIXME("unimplemented for counter signers\n"); 00617 ret = FALSE; 00618 } 00619 else 00620 { 00621 PCERT_SIMPLE_CHAIN simpleChain = 00622 data->pasSigners[idxSigner].pChainContext->rgpChain[0]; 00623 DWORD i; 00624 00625 ret = TRUE; 00626 for (i = 0; i < simpleChain->cElement; i++) 00627 { 00628 /* Set confidence */ 00629 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence = 00630 WINTRUST_TrustStatusToConfidence( 00631 simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus); 00632 /* Set additional flags */ 00633 if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus & 00634 CERT_TRUST_IS_UNTRUSTED_ROOT)) 00635 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE; 00636 if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus & 00637 CERT_TRUST_IS_SELF_SIGNED) 00638 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE; 00639 if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus & 00640 CERT_TRUST_IS_CYCLIC) 00641 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE; 00642 } 00643 } 00644 return ret; 00645 } 00646 00647 static DWORD WINTRUST_TrustStatusToError(DWORD errorStatus) 00648 { 00649 DWORD error; 00650 00651 if (errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) 00652 error = TRUST_E_CERT_SIGNATURE; 00653 else if (errorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) 00654 error = CERT_E_UNTRUSTEDROOT; 00655 else if (errorStatus & CERT_TRUST_IS_NOT_TIME_VALID) 00656 error = CERT_E_EXPIRED; 00657 else if (errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED) 00658 error = CERT_E_VALIDITYPERIODNESTING; 00659 else if (errorStatus & CERT_TRUST_IS_REVOKED) 00660 error = CERT_E_REVOKED; 00661 else if (errorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION || 00662 errorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) 00663 error = CERT_E_REVOCATION_FAILURE; 00664 else if (errorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) 00665 error = CERT_E_WRONG_USAGE; 00666 else if (errorStatus & CERT_TRUST_IS_CYCLIC) 00667 error = CERT_E_CHAINING; 00668 else if (errorStatus & CERT_TRUST_INVALID_EXTENSION) 00669 error = CERT_E_CRITICAL; 00670 else if (errorStatus & CERT_TRUST_INVALID_POLICY_CONSTRAINTS) 00671 error = CERT_E_INVALID_POLICY; 00672 else if (errorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) 00673 error = TRUST_E_BASIC_CONSTRAINTS; 00674 else if (errorStatus & CERT_TRUST_INVALID_NAME_CONSTRAINTS || 00675 errorStatus & CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT || 00676 errorStatus & CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT || 00677 errorStatus & CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT || 00678 errorStatus & CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT) 00679 error = CERT_E_INVALID_NAME; 00680 else if (errorStatus & CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY) 00681 error = CERT_E_INVALID_POLICY; 00682 else if (errorStatus) 00683 { 00684 FIXME("unknown error status %08x\n", errorStatus); 00685 error = TRUST_E_SYSTEM_ERROR; 00686 } 00687 else 00688 error = S_OK; 00689 return error; 00690 } 00691 00692 static DWORD WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx) 00693 { 00694 DWORD err, i; 00695 PCERT_SIMPLE_CHAIN simpleChain = 00696 data->pasSigners[signerIdx].pChainContext->rgpChain[0]; 00697 00698 data->pasSigners[signerIdx].pasCertChain[0].dwConfidence = 00699 WINTRUST_TrustStatusToConfidence( 00700 simpleChain->rgpElement[0]->TrustStatus.dwErrorStatus); 00701 data->pasSigners[signerIdx].pasCertChain[0].pChainElement = 00702 simpleChain->rgpElement[0]; 00703 err = ERROR_SUCCESS; 00704 for (i = 1; !err && i < simpleChain->cElement; i++) 00705 { 00706 if (data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0, 00707 simpleChain->rgpElement[i]->pCertContext)) 00708 { 00709 data->pasSigners[signerIdx].pasCertChain[i].pChainElement = 00710 simpleChain->rgpElement[i]; 00711 data->pasSigners[signerIdx].pasCertChain[i].dwConfidence = 00712 WINTRUST_TrustStatusToConfidence( 00713 simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus); 00714 } 00715 else 00716 err = GetLastError(); 00717 } 00718 data->pasSigners[signerIdx].pasCertChain[simpleChain->cElement - 1].dwError 00719 = WINTRUST_TrustStatusToError( 00720 simpleChain->rgpElement[simpleChain->cElement - 1]-> 00721 TrustStatus.dwErrorStatus); 00722 return err; 00723 } 00724 00725 static void WINTRUST_CreateChainPolicyCreateInfo( 00726 const CRYPT_PROVIDER_DATA *data, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO info, 00727 PCERT_CHAIN_PARA chainPara) 00728 { 00729 chainPara->cbSize = sizeof(CERT_CHAIN_PARA); 00730 if (data->pRequestUsage) 00731 chainPara->RequestedUsage = *data->pRequestUsage; 00732 else 00733 { 00734 chainPara->RequestedUsage.dwType = 0; 00735 chainPara->RequestedUsage.Usage.cUsageIdentifier = 0; 00736 } 00737 info->u.cbSize = sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO); 00738 info->hChainEngine = NULL; 00739 info->pChainPara = chainPara; 00740 if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT) 00741 info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_END_CERT; 00742 else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN) 00743 info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN; 00744 else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT) 00745 info->dwFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; 00746 else 00747 info->dwFlags = 0; 00748 info->pvReserved = NULL; 00749 } 00750 00751 static DWORD WINTRUST_CreateChainForSigner(CRYPT_PROVIDER_DATA *data, 00752 DWORD signer, PWTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo, 00753 PCERT_CHAIN_PARA chainPara) 00754 { 00755 DWORD err = ERROR_SUCCESS; 00756 HCERTSTORE store = NULL; 00757 00758 if (data->chStores) 00759 { 00760 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 00761 CERT_STORE_CREATE_NEW_FLAG, NULL); 00762 if (store) 00763 { 00764 DWORD i; 00765 00766 for (i = 0; i < data->chStores; i++) 00767 CertAddStoreToCollection(store, data->pahStores[i], 0, 0); 00768 } 00769 else 00770 err = GetLastError(); 00771 } 00772 if (!err) 00773 { 00774 /* Expect the end certificate for each signer to be the only cert in 00775 * the chain: 00776 */ 00777 if (data->pasSigners[signer].csCertChain) 00778 { 00779 BOOL ret; 00780 00781 /* Create a certificate chain for each signer */ 00782 ret = CertGetCertificateChain(createInfo->hChainEngine, 00783 data->pasSigners[signer].pasCertChain[0].pCert, 00784 &data->pasSigners[signer].sftVerifyAsOf, store, 00785 chainPara, createInfo->dwFlags, createInfo->pvReserved, 00786 &data->pasSigners[signer].pChainContext); 00787 if (ret) 00788 { 00789 if (data->pasSigners[signer].pChainContext->cChain != 1) 00790 { 00791 FIXME("unimplemented for more than 1 simple chain\n"); 00792 err = E_NOTIMPL; 00793 } 00794 else 00795 { 00796 if (!(err = WINTRUST_CopyChain(data, signer))) 00797 { 00798 if (data->psPfns->pfnCertCheckPolicy) 00799 { 00800 ret = data->psPfns->pfnCertCheckPolicy(data, signer, 00801 FALSE, 0); 00802 if (!ret) 00803 err = GetLastError(); 00804 } 00805 else 00806 TRACE( 00807 "no cert check policy, skipping policy check\n"); 00808 } 00809 } 00810 } 00811 else 00812 err = GetLastError(); 00813 } 00814 CertCloseStore(store, 0); 00815 } 00816 return err; 00817 } 00818 00819 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data) 00820 { 00821 DWORD err; 00822 00823 TRACE("(%p)\n", data); 00824 00825 if (!data->csSigners) 00826 err = TRUST_E_NOSIGNATURE; 00827 else 00828 { 00829 DWORD i; 00830 WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo; 00831 CERT_CHAIN_PARA chainPara; 00832 00833 WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara); 00834 err = ERROR_SUCCESS; 00835 for (i = 0; !err && i < data->csSigners; i++) 00836 err = WINTRUST_CreateChainForSigner(data, i, &createInfo, 00837 &chainPara); 00838 } 00839 if (err) 00840 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = err; 00841 TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE, 00842 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]); 00843 return !err ? S_OK : S_FALSE; 00844 } 00845 00846 HRESULT WINAPI GenericChainCertificateTrust(CRYPT_PROVIDER_DATA *data) 00847 { 00848 DWORD err; 00849 WTD_GENERIC_CHAIN_POLICY_DATA *policyData = 00850 data->pWintrustData->pPolicyCallbackData; 00851 00852 TRACE("(%p)\n", data); 00853 00854 if (policyData && policyData->u.cbSize != 00855 sizeof(WTD_GENERIC_CHAIN_POLICY_CREATE_INFO)) 00856 { 00857 err = ERROR_INVALID_PARAMETER; 00858 goto end; 00859 } 00860 if (!data->csSigners) 00861 err = TRUST_E_NOSIGNATURE; 00862 else 00863 { 00864 DWORD i; 00865 WTD_GENERIC_CHAIN_POLICY_CREATE_INFO createInfo, *pCreateInfo; 00866 CERT_CHAIN_PARA chainPara, *pChainPara; 00867 00868 if (policyData) 00869 { 00870 pCreateInfo = policyData->pSignerChainInfo; 00871 pChainPara = pCreateInfo->pChainPara; 00872 } 00873 else 00874 { 00875 WINTRUST_CreateChainPolicyCreateInfo(data, &createInfo, &chainPara); 00876 pChainPara = &chainPara; 00877 pCreateInfo = &createInfo; 00878 } 00879 err = ERROR_SUCCESS; 00880 for (i = 0; !err && i < data->csSigners; i++) 00881 err = WINTRUST_CreateChainForSigner(data, i, pCreateInfo, 00882 pChainPara); 00883 } 00884 00885 end: 00886 if (err) 00887 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] = err; 00888 TRACE("returning %d (%08x)\n", !err ? S_OK : S_FALSE, 00889 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]); 00890 return !err ? S_OK : S_FALSE; 00891 } 00892 00893 HRESULT WINAPI SoftpubAuthenticode(CRYPT_PROVIDER_DATA *data) 00894 { 00895 BOOL ret; 00896 CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 }; 00897 00898 TRACE("(%p)\n", data); 00899 00900 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) 00901 FIXME("unimplemented for UI choice %d\n", 00902 data->pWintrustData->dwUIChoice); 00903 if (!data->csSigners) 00904 { 00905 ret = FALSE; 00906 policyStatus.dwError = TRUST_E_NOSIGNATURE; 00907 } 00908 else 00909 { 00910 DWORD i; 00911 00912 ret = TRUE; 00913 for (i = 0; ret && i < data->csSigners; i++) 00914 { 00915 BYTE hash[20]; 00916 DWORD size = sizeof(hash); 00917 00918 /* First make sure cert isn't disallowed */ 00919 if ((ret = CertGetCertificateContextProperty( 00920 data->pasSigners[i].pasCertChain[0].pCert, 00921 CERT_SIGNATURE_HASH_PROP_ID, hash, &size))) 00922 { 00923 static const WCHAR disallowedW[] = 00924 { 'D','i','s','a','l','l','o','w','e','d',0 }; 00925 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 00926 X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, 00927 disallowedW); 00928 00929 if (disallowed) 00930 { 00931 PCCERT_CONTEXT found = CertFindCertificateInStore( 00932 disallowed, X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, 00933 hash, NULL); 00934 00935 if (found) 00936 { 00937 /* Disallowed! Can't verify it. */ 00938 policyStatus.dwError = TRUST_E_SUBJECT_NOT_TRUSTED; 00939 ret = FALSE; 00940 CertFreeCertificateContext(found); 00941 } 00942 CertCloseStore(disallowed, 0); 00943 } 00944 } 00945 if (ret) 00946 { 00947 CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 }; 00948 00949 if (data->dwRegPolicySettings & WTPF_TRUSTTEST) 00950 policyPara.dwFlags |= CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG; 00951 if (data->dwRegPolicySettings & WTPF_TESTCANBEVALID) 00952 policyPara.dwFlags |= CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG; 00953 if (data->dwRegPolicySettings & WTPF_IGNOREEXPIRATION) 00954 policyPara.dwFlags |= 00955 CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | 00956 CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | 00957 CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; 00958 if (data->dwRegPolicySettings & WTPF_IGNOREREVOKATION) 00959 policyPara.dwFlags |= 00960 CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG | 00961 CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG | 00962 CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG | 00963 CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG; 00964 CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_AUTHENTICODE, 00965 data->pasSigners[i].pChainContext, &policyPara, &policyStatus); 00966 if (policyStatus.dwError != NO_ERROR) 00967 ret = FALSE; 00968 } 00969 } 00970 } 00971 if (!ret) 00972 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = 00973 policyStatus.dwError; 00974 TRACE("returning %d (%08x)\n", ret ? S_OK : S_FALSE, 00975 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]); 00976 return ret ? S_OK : S_FALSE; 00977 } 00978 00979 static HRESULT WINAPI WINTRUST_DefaultPolicy(CRYPT_PROVIDER_DATA *pProvData, 00980 DWORD dwStepError, DWORD dwRegPolicySettings, DWORD cSigner, 00981 PWTD_GENERIC_CHAIN_POLICY_SIGNER_INFO rgpSigner, void *pvPolicyArg) 00982 { 00983 DWORD i; 00984 CERT_CHAIN_POLICY_STATUS policyStatus = { sizeof(policyStatus), 0 }; 00985 00986 for (i = 0; !policyStatus.dwError && i < cSigner; i++) 00987 { 00988 CERT_CHAIN_POLICY_PARA policyPara = { sizeof(policyPara), 0 }; 00989 00990 if (dwRegPolicySettings & WTPF_IGNOREEXPIRATION) 00991 policyPara.dwFlags |= 00992 CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | 00993 CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | 00994 CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; 00995 if (dwRegPolicySettings & WTPF_IGNOREREVOKATION) 00996 policyPara.dwFlags |= 00997 CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG | 00998 CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG | 00999 CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG | 01000 CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG; 01001 CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, 01002 rgpSigner[i].pChainContext, &policyPara, &policyStatus); 01003 } 01004 return policyStatus.dwError; 01005 } 01006 01007 HRESULT WINAPI GenericChainFinalProv(CRYPT_PROVIDER_DATA *data) 01008 { 01009 HRESULT err = NO_ERROR; /* not a typo, MS confused the types */ 01010 WTD_GENERIC_CHAIN_POLICY_DATA *policyData = 01011 data->pWintrustData->pPolicyCallbackData; 01012 01013 TRACE("(%p)\n", data); 01014 01015 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) 01016 FIXME("unimplemented for UI choice %d\n", 01017 data->pWintrustData->dwUIChoice); 01018 if (!data->csSigners) 01019 err = TRUST_E_NOSIGNATURE; 01020 else 01021 { 01022 PFN_WTD_GENERIC_CHAIN_POLICY_CALLBACK policyCallback; 01023 void *policyArg; 01024 WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO *signers = NULL; 01025 01026 if (policyData) 01027 { 01028 policyCallback = policyData->pfnPolicyCallback; 01029 policyArg = policyData->pvPolicyArg; 01030 } 01031 else 01032 { 01033 policyCallback = WINTRUST_DefaultPolicy; 01034 policyArg = NULL; 01035 } 01036 if (data->csSigners) 01037 { 01038 DWORD i; 01039 01040 signers = data->psPfns->pfnAlloc( 01041 data->csSigners * sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO)); 01042 if (signers) 01043 { 01044 for (i = 0; i < data->csSigners; i++) 01045 { 01046 signers[i].u.cbSize = 01047 sizeof(WTD_GENERIC_CHAIN_POLICY_SIGNER_INFO); 01048 signers[i].pChainContext = 01049 data->pasSigners[i].pChainContext; 01050 signers[i].dwSignerType = data->pasSigners[i].dwSignerType; 01051 signers[i].pMsgSignerInfo = data->pasSigners[i].psSigner; 01052 signers[i].dwError = data->pasSigners[i].dwError; 01053 if (data->pasSigners[i].csCounterSigners) 01054 FIXME("unimplemented for counter signers\n"); 01055 signers[i].cCounterSigner = 0; 01056 signers[i].rgpCounterSigner = NULL; 01057 } 01058 } 01059 else 01060 err = ERROR_OUTOFMEMORY; 01061 } 01062 if (err == NO_ERROR) 01063 err = policyCallback(data, TRUSTERROR_STEP_FINAL_POLICYPROV, 01064 data->dwRegPolicySettings, data->csSigners, signers, policyArg); 01065 data->psPfns->pfnFree(signers); 01066 } 01067 if (err != NO_ERROR) 01068 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV] = err; 01069 TRACE("returning %d (%08x)\n", err == NO_ERROR ? S_OK : S_FALSE, 01070 data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_POLICYPROV]); 01071 return err == NO_ERROR ? S_OK : S_FALSE; 01072 } 01073 01074 HRESULT WINAPI SoftpubCleanup(CRYPT_PROVIDER_DATA *data) 01075 { 01076 DWORD i, j; 01077 01078 for (i = 0; i < data->csSigners; i++) 01079 { 01080 for (j = 0; j < data->pasSigners[i].csCertChain; j++) 01081 CertFreeCertificateContext(data->pasSigners[i].pasCertChain[j].pCert); 01082 data->psPfns->pfnFree(data->pasSigners[i].pasCertChain); 01083 data->psPfns->pfnFree(data->pasSigners[i].psSigner); 01084 CertFreeCertificateChain(data->pasSigners[i].pChainContext); 01085 } 01086 data->psPfns->pfnFree(data->pasSigners); 01087 01088 for (i = 0; i < data->chStores; i++) 01089 CertCloseStore(data->pahStores[i], 0); 01090 data->psPfns->pfnFree(data->pahStores); 01091 01092 if (data->u.pPDSip) 01093 { 01094 data->psPfns->pfnFree(data->u.pPDSip->pSip); 01095 data->psPfns->pfnFree(data->u.pPDSip->pCATSip); 01096 data->psPfns->pfnFree(data->u.pPDSip->psSipSubjectInfo); 01097 data->psPfns->pfnFree(data->u.pPDSip->psSipCATSubjectInfo); 01098 data->psPfns->pfnFree(data->u.pPDSip->psIndirectData); 01099 } 01100 01101 CryptMsgClose(data->hMsg); 01102 01103 if (data->fOpenedFile && 01104 data->pWintrustData->dwUnionChoice == WTD_CHOICE_FILE) 01105 CloseHandle(data->pWintrustData->u.pFile->hFile); 01106 01107 return S_OK; 01108 } 01109 01110 HRESULT WINAPI HTTPSCertificateTrust(CRYPT_PROVIDER_DATA *data) 01111 { 01112 FIXME("(%p)\n", data); 01113 return S_OK; 01114 } 01115 01116 HRESULT WINAPI HTTPSFinalProv(CRYPT_PROVIDER_DATA *data) 01117 { 01118 FIXME("(%p)\n", data); 01119 return S_OK; 01120 } Generated on Sun May 27 2012 04:27:02 for ReactOS by
1.7.6.1
|