Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencryptnet_main.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2006 Maarten Lankhorst 00003 * Copyright 2007 Juan Lang 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00018 * 00019 */ 00020 00021 #include "config.h" 00022 #include "wine/port.h" 00023 00024 #define NONAMELESSUNION 00025 #define NONAMELESSSTRUCT 00026 #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS 00027 00028 #include <stdio.h> 00029 #include <stdarg.h> 00030 00031 #include "windef.h" 00032 #include "winbase.h" 00033 #include "winnt.h" 00034 #include "winnls.h" 00035 #include "wininet.h" 00036 #include "objbase.h" 00037 #include "wincrypt.h" 00038 00039 #include "wine/debug.h" 00040 00041 WINE_DEFAULT_DEBUG_CHANNEL(cryptnet); 00042 00043 #define IS_INTOID(x) (((ULONG_PTR)(x) >> 16) == 0) 00044 00045 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 00046 { 00047 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); 00048 00049 switch (fdwReason) { 00050 case DLL_PROCESS_ATTACH: 00051 DisableThreadLibraryCalls(hinstDLL); 00052 break; 00053 case DLL_PROCESS_DETACH: 00054 /* Do uninitialisation here */ 00055 break; 00056 default: break; 00057 } 00058 return TRUE; 00059 } 00060 00061 static const WCHAR cryptNet[] = { 'c','r','y','p','t','n','e','t','.', 00062 'd','l','l',0 }; 00063 00064 /*********************************************************************** 00065 * DllRegisterServer (CRYPTNET.@) 00066 */ 00067 HRESULT WINAPI DllRegisterServer(void) 00068 { 00069 TRACE("\n"); 00070 CryptRegisterDefaultOIDFunction(X509_ASN_ENCODING, 00071 CRYPT_OID_VERIFY_REVOCATION_FUNC, 0, cryptNet); 00072 CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap", 00073 cryptNet, "LdapProvOpenStore"); 00074 CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, 00075 CERT_STORE_PROV_LDAP_W, cryptNet, "LdapProvOpenStore"); 00076 return S_OK; 00077 } 00078 00079 /*********************************************************************** 00080 * DllUnregisterServer (CRYPTNET.@) 00081 */ 00082 HRESULT WINAPI DllUnregisterServer(void) 00083 { 00084 TRACE("\n"); 00085 CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING, 00086 CRYPT_OID_VERIFY_REVOCATION_FUNC, cryptNet); 00087 CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap"); 00088 CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, 00089 CERT_STORE_PROV_LDAP_W); 00090 return S_OK; 00091 } 00092 00093 static const char *url_oid_to_str(LPCSTR oid) 00094 { 00095 if (IS_INTOID(oid)) 00096 { 00097 static char buf[10]; 00098 00099 switch (LOWORD(oid)) 00100 { 00101 #define _x(oid) case LOWORD(oid): return #oid 00102 _x(URL_OID_CERTIFICATE_ISSUER); 00103 _x(URL_OID_CERTIFICATE_CRL_DIST_POINT); 00104 _x(URL_OID_CTL_ISSUER); 00105 _x(URL_OID_CTL_NEXT_UPDATE); 00106 _x(URL_OID_CRL_ISSUER); 00107 _x(URL_OID_CERTIFICATE_FRESHEST_CRL); 00108 _x(URL_OID_CRL_FRESHEST_CRL); 00109 _x(URL_OID_CROSS_CERT_DIST_POINT); 00110 #undef _x 00111 default: 00112 snprintf(buf, sizeof(buf), "%d", LOWORD(oid)); 00113 return buf; 00114 } 00115 } 00116 else 00117 return oid; 00118 } 00119 00120 typedef BOOL (WINAPI *UrlDllGetObjectUrlFunc)(LPCSTR, LPVOID, DWORD, 00121 PCRYPT_URL_ARRAY, DWORD *, PCRYPT_URL_INFO, DWORD *, LPVOID); 00122 00123 static BOOL WINAPI CRYPT_GetUrlFromCertificateIssuer(LPCSTR pszUrlOid, 00124 LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, 00125 PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved) 00126 { 00127 PCCERT_CONTEXT cert = pvPara; 00128 PCERT_EXTENSION ext; 00129 BOOL ret = FALSE; 00130 00131 /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */ 00132 if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION)) 00133 { 00134 SetLastError(CRYPT_E_NOT_FOUND); 00135 return FALSE; 00136 } 00137 if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, 00138 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 00139 { 00140 CERT_AUTHORITY_INFO_ACCESS *aia; 00141 DWORD size; 00142 00143 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_INFO_ACCESS, 00144 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, 00145 &aia, &size); 00146 if (ret) 00147 { 00148 DWORD i, cUrl, bytesNeeded = sizeof(CRYPT_URL_ARRAY); 00149 00150 for (i = 0, cUrl = 0; i < aia->cAccDescr; i++) 00151 if (!strcmp(aia->rgAccDescr[i].pszAccessMethod, 00152 szOID_PKIX_CA_ISSUERS)) 00153 { 00154 if (aia->rgAccDescr[i].AccessLocation.dwAltNameChoice == 00155 CERT_ALT_NAME_URL) 00156 { 00157 if (aia->rgAccDescr[i].AccessLocation.u.pwszURL) 00158 { 00159 cUrl++; 00160 bytesNeeded += sizeof(LPWSTR) + 00161 (lstrlenW(aia->rgAccDescr[i].AccessLocation.u. 00162 pwszURL) + 1) * sizeof(WCHAR); 00163 } 00164 } 00165 else 00166 FIXME("unsupported alt name type %d\n", 00167 aia->rgAccDescr[i].AccessLocation.dwAltNameChoice); 00168 } 00169 if (!pcbUrlArray) 00170 { 00171 SetLastError(E_INVALIDARG); 00172 ret = FALSE; 00173 } 00174 else if (!pUrlArray) 00175 *pcbUrlArray = bytesNeeded; 00176 else if (*pcbUrlArray < bytesNeeded) 00177 { 00178 SetLastError(ERROR_MORE_DATA); 00179 *pcbUrlArray = bytesNeeded; 00180 ret = FALSE; 00181 } 00182 else 00183 { 00184 LPWSTR nextUrl; 00185 00186 *pcbUrlArray = bytesNeeded; 00187 pUrlArray->cUrl = 0; 00188 pUrlArray->rgwszUrl = 00189 (LPWSTR *)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY)); 00190 nextUrl = (LPWSTR)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY) 00191 + cUrl * sizeof(LPWSTR)); 00192 for (i = 0; i < aia->cAccDescr; i++) 00193 if (!strcmp(aia->rgAccDescr[i].pszAccessMethod, 00194 szOID_PKIX_CA_ISSUERS)) 00195 { 00196 if (aia->rgAccDescr[i].AccessLocation.dwAltNameChoice 00197 == CERT_ALT_NAME_URL) 00198 { 00199 if (aia->rgAccDescr[i].AccessLocation.u.pwszURL) 00200 { 00201 lstrcpyW(nextUrl, 00202 aia->rgAccDescr[i].AccessLocation.u.pwszURL); 00203 pUrlArray->rgwszUrl[pUrlArray->cUrl++] = 00204 nextUrl; 00205 nextUrl += (lstrlenW(nextUrl) + 1); 00206 } 00207 } 00208 } 00209 } 00210 if (ret) 00211 { 00212 if (pcbUrlInfo) 00213 { 00214 FIXME("url info: stub\n"); 00215 if (!pUrlInfo) 00216 *pcbUrlInfo = sizeof(CRYPT_URL_INFO); 00217 else if (*pcbUrlInfo < sizeof(CRYPT_URL_INFO)) 00218 { 00219 *pcbUrlInfo = sizeof(CRYPT_URL_INFO); 00220 SetLastError(ERROR_MORE_DATA); 00221 ret = FALSE; 00222 } 00223 else 00224 { 00225 *pcbUrlInfo = sizeof(CRYPT_URL_INFO); 00226 memset(pUrlInfo, 0, sizeof(CRYPT_URL_INFO)); 00227 } 00228 } 00229 } 00230 LocalFree(aia); 00231 } 00232 } 00233 else 00234 SetLastError(CRYPT_E_NOT_FOUND); 00235 return ret; 00236 } 00237 00238 static BOOL CRYPT_GetUrlFromCRLDistPointsExt(const CRYPT_DATA_BLOB *value, 00239 PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo, 00240 DWORD *pcbUrlInfo) 00241 { 00242 BOOL ret; 00243 CRL_DIST_POINTS_INFO *info; 00244 DWORD size; 00245 00246 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CRL_DIST_POINTS, 00247 value->pbData, value->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); 00248 if (ret) 00249 { 00250 DWORD i, cUrl, bytesNeeded = sizeof(CRYPT_URL_ARRAY); 00251 00252 for (i = 0, cUrl = 0; i < info->cDistPoint; i++) 00253 if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice 00254 == CRL_DIST_POINT_FULL_NAME) 00255 { 00256 DWORD j; 00257 CERT_ALT_NAME_INFO *name = 00258 &info->rgDistPoint[i].DistPointName.u.FullName; 00259 00260 for (j = 0; j < name->cAltEntry; j++) 00261 if (name->rgAltEntry[j].dwAltNameChoice == 00262 CERT_ALT_NAME_URL) 00263 { 00264 if (name->rgAltEntry[j].u.pwszURL) 00265 { 00266 cUrl++; 00267 bytesNeeded += sizeof(LPWSTR) + 00268 (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1) 00269 * sizeof(WCHAR); 00270 } 00271 } 00272 } 00273 if (!pcbUrlArray) 00274 { 00275 SetLastError(E_INVALIDARG); 00276 ret = FALSE; 00277 } 00278 else if (!pUrlArray) 00279 *pcbUrlArray = bytesNeeded; 00280 else if (*pcbUrlArray < bytesNeeded) 00281 { 00282 SetLastError(ERROR_MORE_DATA); 00283 *pcbUrlArray = bytesNeeded; 00284 ret = FALSE; 00285 } 00286 else 00287 { 00288 LPWSTR nextUrl; 00289 00290 *pcbUrlArray = bytesNeeded; 00291 pUrlArray->cUrl = 0; 00292 pUrlArray->rgwszUrl = 00293 (LPWSTR *)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY)); 00294 nextUrl = (LPWSTR)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY) 00295 + cUrl * sizeof(LPWSTR)); 00296 for (i = 0; i < info->cDistPoint; i++) 00297 if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice 00298 == CRL_DIST_POINT_FULL_NAME) 00299 { 00300 DWORD j; 00301 CERT_ALT_NAME_INFO *name = 00302 &info->rgDistPoint[i].DistPointName.u.FullName; 00303 00304 for (j = 0; j < name->cAltEntry; j++) 00305 if (name->rgAltEntry[j].dwAltNameChoice == 00306 CERT_ALT_NAME_URL) 00307 { 00308 if (name->rgAltEntry[j].u.pwszURL) 00309 { 00310 lstrcpyW(nextUrl, 00311 name->rgAltEntry[j].u.pwszURL); 00312 pUrlArray->rgwszUrl[pUrlArray->cUrl++] = 00313 nextUrl; 00314 nextUrl += 00315 (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1); 00316 } 00317 } 00318 } 00319 } 00320 if (ret) 00321 { 00322 if (pcbUrlInfo) 00323 { 00324 FIXME("url info: stub\n"); 00325 if (!pUrlInfo) 00326 *pcbUrlInfo = sizeof(CRYPT_URL_INFO); 00327 else if (*pcbUrlInfo < sizeof(CRYPT_URL_INFO)) 00328 { 00329 *pcbUrlInfo = sizeof(CRYPT_URL_INFO); 00330 SetLastError(ERROR_MORE_DATA); 00331 ret = FALSE; 00332 } 00333 else 00334 { 00335 *pcbUrlInfo = sizeof(CRYPT_URL_INFO); 00336 memset(pUrlInfo, 0, sizeof(CRYPT_URL_INFO)); 00337 } 00338 } 00339 } 00340 LocalFree(info); 00341 } 00342 return ret; 00343 } 00344 00345 static BOOL WINAPI CRYPT_GetUrlFromCertificateCRLDistPoint(LPCSTR pszUrlOid, 00346 LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, 00347 PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved) 00348 { 00349 PCCERT_CONTEXT cert = pvPara; 00350 PCERT_EXTENSION ext; 00351 BOOL ret = FALSE; 00352 00353 /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */ 00354 if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION)) 00355 { 00356 SetLastError(CRYPT_E_NOT_FOUND); 00357 return FALSE; 00358 } 00359 if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, 00360 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 00361 ret = CRYPT_GetUrlFromCRLDistPointsExt(&ext->Value, pUrlArray, 00362 pcbUrlArray, pUrlInfo, pcbUrlInfo); 00363 else 00364 SetLastError(CRYPT_E_NOT_FOUND); 00365 return ret; 00366 } 00367 00368 /*********************************************************************** 00369 * CryptGetObjectUrl (CRYPTNET.@) 00370 */ 00371 BOOL WINAPI CryptGetObjectUrl(LPCSTR pszUrlOid, LPVOID pvPara, DWORD dwFlags, 00372 PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo, 00373 DWORD *pcbUrlInfo, LPVOID pvReserved) 00374 { 00375 UrlDllGetObjectUrlFunc func = NULL; 00376 HCRYPTOIDFUNCADDR hFunc = NULL; 00377 BOOL ret = FALSE; 00378 00379 TRACE("(%s, %p, %08x, %p, %p, %p, %p, %p)\n", debugstr_a(pszUrlOid), 00380 pvPara, dwFlags, pUrlArray, pcbUrlArray, pUrlInfo, pcbUrlInfo, pvReserved); 00381 00382 if (IS_INTOID(pszUrlOid)) 00383 { 00384 switch (LOWORD(pszUrlOid)) 00385 { 00386 case LOWORD(URL_OID_CERTIFICATE_ISSUER): 00387 func = CRYPT_GetUrlFromCertificateIssuer; 00388 break; 00389 case LOWORD(URL_OID_CERTIFICATE_CRL_DIST_POINT): 00390 func = CRYPT_GetUrlFromCertificateCRLDistPoint; 00391 break; 00392 default: 00393 FIXME("unimplemented for %s\n", url_oid_to_str(pszUrlOid)); 00394 SetLastError(ERROR_FILE_NOT_FOUND); 00395 } 00396 } 00397 else 00398 { 00399 static HCRYPTOIDFUNCSET set = NULL; 00400 00401 if (!set) 00402 set = CryptInitOIDFunctionSet(URL_OID_GET_OBJECT_URL_FUNC, 0); 00403 CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszUrlOid, 0, 00404 (void **)&func, &hFunc); 00405 } 00406 if (func) 00407 ret = func(pszUrlOid, pvPara, dwFlags, pUrlArray, pcbUrlArray, 00408 pUrlInfo, pcbUrlInfo, pvReserved); 00409 if (hFunc) 00410 CryptFreeOIDFunctionAddress(hFunc, 0); 00411 return ret; 00412 } 00413 00414 /*********************************************************************** 00415 * CryptRetrieveObjectByUrlA (CRYPTNET.@) 00416 */ 00417 BOOL WINAPI CryptRetrieveObjectByUrlA(LPCSTR pszURL, LPCSTR pszObjectOid, 00418 DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject, 00419 HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, 00420 PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 00421 { 00422 BOOL ret = FALSE; 00423 int len; 00424 00425 TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_a(pszURL), 00426 debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject, 00427 hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo); 00428 00429 if (!pszURL) 00430 { 00431 SetLastError(ERROR_INVALID_PARAMETER); 00432 return FALSE; 00433 } 00434 len = MultiByteToWideChar(CP_ACP, 0, pszURL, -1, NULL, 0); 00435 if (len) 00436 { 00437 LPWSTR url = CryptMemAlloc(len * sizeof(WCHAR)); 00438 00439 if (url) 00440 { 00441 MultiByteToWideChar(CP_ACP, 0, pszURL, -1, url, len); 00442 ret = CryptRetrieveObjectByUrlW(url, pszObjectOid, 00443 dwRetrievalFlags, dwTimeout, ppvObject, hAsyncRetrieve, 00444 pCredentials, pvVerify, pAuxInfo); 00445 CryptMemFree(url); 00446 } 00447 else 00448 SetLastError(ERROR_OUTOFMEMORY); 00449 } 00450 return ret; 00451 } 00452 00453 static void WINAPI CRYPT_FreeBlob(LPCSTR pszObjectOid, 00454 PCRYPT_BLOB_ARRAY pObject, void *pvFreeContext) 00455 { 00456 DWORD i; 00457 00458 for (i = 0; i < pObject->cBlob; i++) 00459 CryptMemFree(pObject->rgBlob[i].pbData); 00460 CryptMemFree(pObject->rgBlob); 00461 } 00462 00463 static BOOL CRYPT_GetObjectFromFile(HANDLE hFile, PCRYPT_BLOB_ARRAY pObject) 00464 { 00465 BOOL ret; 00466 LARGE_INTEGER size; 00467 00468 if ((ret = GetFileSizeEx(hFile, &size))) 00469 { 00470 if (size.u.HighPart) 00471 { 00472 WARN("file too big\n"); 00473 SetLastError(ERROR_INVALID_DATA); 00474 ret = FALSE; 00475 } 00476 else 00477 { 00478 CRYPT_DATA_BLOB blob; 00479 00480 blob.pbData = CryptMemAlloc(size.u.LowPart); 00481 if (blob.pbData) 00482 { 00483 blob.cbData = size.u.LowPart; 00484 ret = ReadFile(hFile, blob.pbData, size.u.LowPart, &blob.cbData, 00485 NULL); 00486 if (ret) 00487 { 00488 pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB)); 00489 if (pObject->rgBlob) 00490 { 00491 pObject->cBlob = 1; 00492 memcpy(pObject->rgBlob, &blob, sizeof(CRYPT_DATA_BLOB)); 00493 } 00494 else 00495 { 00496 SetLastError(ERROR_OUTOFMEMORY); 00497 ret = FALSE; 00498 } 00499 } 00500 if (!ret) 00501 CryptMemFree(blob.pbData); 00502 } 00503 else 00504 { 00505 SetLastError(ERROR_OUTOFMEMORY); 00506 ret = FALSE; 00507 } 00508 } 00509 } 00510 return ret; 00511 } 00512 00513 static BOOL CRYPT_GetObjectFromCache(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject, 00514 PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 00515 { 00516 BOOL ret = FALSE; 00517 INTERNET_CACHE_ENTRY_INFOW *pCacheInfo = NULL; 00518 DWORD size = 0; 00519 00520 TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pObject, pAuxInfo); 00521 00522 ret = GetUrlCacheEntryInfoW(pszURL, NULL, &size); 00523 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 00524 { 00525 pCacheInfo = CryptMemAlloc(size); 00526 if (pCacheInfo) 00527 ret = TRUE; 00528 else 00529 SetLastError(ERROR_OUTOFMEMORY); 00530 } 00531 if (ret && (ret = GetUrlCacheEntryInfoW(pszURL, pCacheInfo, &size))) 00532 { 00533 FILETIME ft; 00534 00535 GetSystemTimeAsFileTime(&ft); 00536 if (CompareFileTime(&pCacheInfo->ExpireTime, &ft) >= 0) 00537 { 00538 HANDLE hFile = CreateFileW(pCacheInfo->lpszLocalFileName, 00539 GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00540 00541 if (hFile != INVALID_HANDLE_VALUE) 00542 { 00543 if ((ret = CRYPT_GetObjectFromFile(hFile, pObject))) 00544 { 00545 if (pAuxInfo && pAuxInfo->cbSize >= 00546 offsetof(CRYPT_RETRIEVE_AUX_INFO, 00547 pLastSyncTime) + sizeof(PFILETIME) && 00548 pAuxInfo->pLastSyncTime) 00549 memcpy(pAuxInfo->pLastSyncTime, 00550 &pCacheInfo->LastSyncTime, 00551 sizeof(FILETIME)); 00552 } 00553 CloseHandle(hFile); 00554 } 00555 else 00556 { 00557 DeleteUrlCacheEntryW(pszURL); 00558 ret = FALSE; 00559 } 00560 } 00561 else 00562 { 00563 DeleteUrlCacheEntryW(pszURL); 00564 ret = FALSE; 00565 } 00566 } 00567 CryptMemFree(pCacheInfo); 00568 TRACE("returning %d\n", ret); 00569 return ret; 00570 } 00571 00572 /* Parses the URL, and sets components' lpszHostName and lpszUrlPath members 00573 * to NULL-terminated copies of those portions of the URL (to be freed with 00574 * CryptMemFree.) 00575 */ 00576 static BOOL CRYPT_CrackUrl(LPCWSTR pszURL, URL_COMPONENTSW *components) 00577 { 00578 BOOL ret; 00579 00580 TRACE("(%s, %p)\n", debugstr_w(pszURL), components); 00581 00582 memset(components, 0, sizeof(*components)); 00583 components->dwStructSize = sizeof(*components); 00584 components->lpszHostName = CryptMemAlloc(INTERNET_MAX_HOST_NAME_LENGTH * sizeof(WCHAR)); 00585 components->dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH; 00586 if (!components->lpszHostName) 00587 { 00588 SetLastError(ERROR_OUTOFMEMORY); 00589 return FALSE; 00590 } 00591 components->lpszUrlPath = CryptMemAlloc(INTERNET_MAX_PATH_LENGTH * sizeof(WCHAR)); 00592 components->dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; 00593 if (!components->lpszUrlPath) 00594 { 00595 CryptMemFree(components->lpszHostName); 00596 SetLastError(ERROR_OUTOFMEMORY); 00597 return FALSE; 00598 } 00599 00600 ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, components); 00601 if (ret) 00602 { 00603 switch (components->nScheme) 00604 { 00605 case INTERNET_SCHEME_FTP: 00606 if (!components->nPort) 00607 components->nPort = INTERNET_DEFAULT_FTP_PORT; 00608 break; 00609 case INTERNET_SCHEME_HTTP: 00610 if (!components->nPort) 00611 components->nPort = INTERNET_DEFAULT_HTTP_PORT; 00612 break; 00613 default: 00614 ; /* do nothing */ 00615 } 00616 } 00617 TRACE("returning %d\n", ret); 00618 return ret; 00619 } 00620 00621 struct InetContext 00622 { 00623 HANDLE event; 00624 DWORD timeout; 00625 DWORD error; 00626 }; 00627 00628 static struct InetContext *CRYPT_MakeInetContext(DWORD dwTimeout) 00629 { 00630 struct InetContext *context = CryptMemAlloc(sizeof(struct InetContext)); 00631 00632 if (context) 00633 { 00634 context->event = CreateEventW(NULL, FALSE, FALSE, NULL); 00635 if (!context->event) 00636 { 00637 CryptMemFree(context); 00638 context = NULL; 00639 } 00640 else 00641 { 00642 context->timeout = dwTimeout; 00643 context->error = ERROR_SUCCESS; 00644 } 00645 } 00646 return context; 00647 } 00648 00649 static BOOL CRYPT_DownloadObject(DWORD dwRetrievalFlags, HINTERNET hHttp, 00650 struct InetContext *context, PCRYPT_BLOB_ARRAY pObject, 00651 PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 00652 { 00653 CRYPT_DATA_BLOB object = { 0, NULL }; 00654 DWORD bytesAvailable; 00655 BOOL ret; 00656 00657 do { 00658 if ((ret = InternetQueryDataAvailable(hHttp, &bytesAvailable, 0, 0))) 00659 { 00660 if (bytesAvailable) 00661 { 00662 if (object.pbData) 00663 object.pbData = CryptMemRealloc(object.pbData, 00664 object.cbData + bytesAvailable); 00665 else 00666 object.pbData = CryptMemAlloc(bytesAvailable); 00667 if (object.pbData) 00668 { 00669 INTERNET_BUFFERSA buffer = { sizeof(buffer), 0 }; 00670 00671 buffer.dwBufferLength = bytesAvailable; 00672 buffer.lpvBuffer = object.pbData + object.cbData; 00673 if (!(ret = InternetReadFileExA(hHttp, &buffer, IRF_NO_WAIT, 00674 (DWORD_PTR)context))) 00675 { 00676 if (GetLastError() == ERROR_IO_PENDING) 00677 { 00678 if (WaitForSingleObject(context->event, 00679 context->timeout) == WAIT_TIMEOUT) 00680 SetLastError(ERROR_TIMEOUT); 00681 else if (context->error) 00682 SetLastError(context->error); 00683 else 00684 ret = TRUE; 00685 } 00686 } 00687 if (ret) 00688 object.cbData += buffer.dwBufferLength; 00689 } 00690 else 00691 { 00692 SetLastError(ERROR_OUTOFMEMORY); 00693 ret = FALSE; 00694 } 00695 } 00696 } 00697 else if (GetLastError() == ERROR_IO_PENDING) 00698 { 00699 if (WaitForSingleObject(context->event, context->timeout) == 00700 WAIT_TIMEOUT) 00701 SetLastError(ERROR_TIMEOUT); 00702 else 00703 ret = TRUE; 00704 } 00705 } while (ret && bytesAvailable); 00706 if (ret) 00707 { 00708 pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB)); 00709 if (!pObject->rgBlob) 00710 { 00711 CryptMemFree(object.pbData); 00712 SetLastError(ERROR_OUTOFMEMORY); 00713 ret = FALSE; 00714 } 00715 else 00716 { 00717 pObject->rgBlob[0].cbData = object.cbData; 00718 pObject->rgBlob[0].pbData = object.pbData; 00719 pObject->cBlob = 1; 00720 } 00721 } 00722 TRACE("returning %d\n", ret); 00723 return ret; 00724 } 00725 00726 /* Finds the object specified by pszURL in the cache. If it's not found, 00727 * creates a new cache entry for the object and writes the object to it. 00728 * Sets the expiration time of the cache entry to expires. 00729 */ 00730 static void CRYPT_CacheURL(LPCWSTR pszURL, const CRYPT_BLOB_ARRAY *pObject, 00731 DWORD dwRetrievalFlags, FILETIME expires) 00732 { 00733 WCHAR cacheFileName[MAX_PATH]; 00734 DWORD size = 0; 00735 BOOL ret, create = FALSE; 00736 00737 GetUrlCacheEntryInfoW(pszURL, NULL, &size); 00738 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 00739 { 00740 INTERNET_CACHE_ENTRY_INFOW *info = CryptMemAlloc(size); 00741 00742 if (info) 00743 { 00744 FILETIME ft; 00745 00746 ret = GetUrlCacheEntryInfoW(pszURL, info, &size); 00747 if (ret) 00748 lstrcpyW(cacheFileName, info->lpszLocalFileName); 00749 /* Check if the existing cache entry is up to date. If it isn't, 00750 * remove the existing cache entry, and create a new one with the 00751 * new value. 00752 */ 00753 GetSystemTimeAsFileTime(&ft); 00754 if (CompareFileTime(&info->ExpireTime, &ft) < 0) 00755 { 00756 create = TRUE; 00757 DeleteUrlCacheEntryW(pszURL); 00758 } 00759 CryptMemFree(info); 00760 } 00761 else 00762 ret = FALSE; 00763 } 00764 else 00765 { 00766 ret = CreateUrlCacheEntryW(pszURL, pObject->rgBlob[0].cbData, NULL, 00767 cacheFileName, 0); 00768 create = TRUE; 00769 } 00770 if (ret) 00771 { 00772 DWORD entryType; 00773 FILETIME ft = { 0 }; 00774 00775 if (create) 00776 { 00777 HANDLE hCacheFile = CreateFileW(cacheFileName, GENERIC_WRITE, 0, 00778 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 00779 00780 if (hCacheFile != INVALID_HANDLE_VALUE) 00781 { 00782 DWORD bytesWritten; 00783 00784 WriteFile(hCacheFile, pObject->rgBlob[0].pbData, 00785 pObject->rgBlob[0].cbData, &bytesWritten, NULL); 00786 CloseHandle(hCacheFile); 00787 } 00788 else 00789 ret = FALSE; 00790 } 00791 if (ret) 00792 { 00793 if (!(dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL)) 00794 entryType = NORMAL_CACHE_ENTRY; 00795 else 00796 entryType = STICKY_CACHE_ENTRY; 00797 CommitUrlCacheEntryW(pszURL, cacheFileName, expires, ft, entryType, 00798 NULL, 0, NULL, NULL); 00799 } 00800 } 00801 } 00802 00803 static void CALLBACK CRYPT_InetStatusCallback(HINTERNET hInt, 00804 DWORD_PTR dwContext, DWORD status, void *statusInfo, DWORD statusInfoLen) 00805 { 00806 struct InetContext *context = (struct InetContext *)dwContext; 00807 LPINTERNET_ASYNC_RESULT result; 00808 00809 switch (status) 00810 { 00811 case INTERNET_STATUS_REQUEST_COMPLETE: 00812 result = statusInfo; 00813 context->error = result->dwError; 00814 SetEvent(context->event); 00815 } 00816 } 00817 00818 static BOOL CRYPT_Connect(const URL_COMPONENTSW *components, 00819 struct InetContext *context, PCRYPT_CREDENTIALS pCredentials, 00820 HINTERNET *phInt, HINTERNET *phHost) 00821 { 00822 BOOL ret; 00823 00824 TRACE("(%s:%d, %p, %p, %p, %p)\n", debugstr_w(components->lpszHostName), 00825 components->nPort, context, pCredentials, phInt, phInt); 00826 00827 *phHost = NULL; 00828 *phInt = InternetOpenW(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 00829 context ? INTERNET_FLAG_ASYNC : 0); 00830 if (*phInt) 00831 { 00832 DWORD service; 00833 00834 if (context) 00835 InternetSetStatusCallbackW(*phInt, CRYPT_InetStatusCallback); 00836 switch (components->nScheme) 00837 { 00838 case INTERNET_SCHEME_FTP: 00839 service = INTERNET_SERVICE_FTP; 00840 break; 00841 case INTERNET_SCHEME_HTTP: 00842 service = INTERNET_SERVICE_HTTP; 00843 break; 00844 default: 00845 service = 0; 00846 } 00847 /* FIXME: use pCredentials for username/password */ 00848 *phHost = InternetConnectW(*phInt, components->lpszHostName, 00849 components->nPort, NULL, NULL, service, 0, (DWORD_PTR)context); 00850 if (!*phHost) 00851 { 00852 InternetCloseHandle(*phInt); 00853 *phInt = NULL; 00854 ret = FALSE; 00855 } 00856 else 00857 ret = TRUE; 00858 } 00859 else 00860 ret = FALSE; 00861 TRACE("returning %d\n", ret); 00862 return ret; 00863 } 00864 00865 static BOOL WINAPI FTP_RetrieveEncodedObjectW(LPCWSTR pszURL, 00866 LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, 00867 PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, 00868 void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, 00869 PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 00870 { 00871 FIXME("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), 00872 debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject, 00873 ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo); 00874 00875 pObject->cBlob = 0; 00876 pObject->rgBlob = NULL; 00877 *ppfnFreeObject = CRYPT_FreeBlob; 00878 *ppvFreeContext = NULL; 00879 return FALSE; 00880 } 00881 00882 static const WCHAR x509cacert[] = { 'a','p','p','l','i','c','a','t','i','o','n', 00883 '/','x','-','x','5','0','9','-','c','a','-','c','e','r','t',0 }; 00884 static const WCHAR x509emailcert[] = { 'a','p','p','l','i','c','a','t','i','o', 00885 'n','/','x','-','x','5','0','9','-','e','m','a','i','l','-','c','e','r','t', 00886 0 }; 00887 static const WCHAR x509servercert[] = { 'a','p','p','l','i','c','a','t','i','o', 00888 'n','/','x','-','x','5','0','9','-','s','e','r','v','e','r','-','c','e','r', 00889 't',0 }; 00890 static const WCHAR x509usercert[] = { 'a','p','p','l','i','c','a','t','i','o', 00891 'n','/','x','-','x','5','0','9','-','u','s','e','r','-','c','e','r','t',0 }; 00892 static const WCHAR pkcs7cert[] = { 'a','p','p','l','i','c','a','t','i','o','n', 00893 '/','x','-','p','k','c','s','7','-','c','e','r','t','i','f','c','a','t','e', 00894 's',0 }; 00895 static const WCHAR pkixCRL[] = { 'a','p','p','l','i','c','a','t','i','o','n', 00896 '/','p','k','i','x','-','c','r','l',0 }; 00897 static const WCHAR pkcs7CRL[] = { 'a','p','p','l','i','c','a','t','i','o','n', 00898 '/','x','-','p','k','c','s','7','-','c','r','l',0 }; 00899 static const WCHAR pkcs7sig[] = { 'a','p','p','l','i','c','a','t','i','o','n', 00900 '/','x','-','p','k','c','s','7','-','s','i','g','n','a','t','u','r','e',0 }; 00901 static const WCHAR pkcs7mime[] = { 'a','p','p','l','i','c','a','t','i','o','n', 00902 '/','x','-','p','k','c','s','7','-','m','i','m','e',0 }; 00903 00904 static BOOL WINAPI HTTP_RetrieveEncodedObjectW(LPCWSTR pszURL, 00905 LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, 00906 PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, 00907 void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, 00908 PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 00909 { 00910 BOOL ret = FALSE; 00911 00912 TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), 00913 debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject, 00914 ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo); 00915 00916 pObject->cBlob = 0; 00917 pObject->rgBlob = NULL; 00918 *ppfnFreeObject = CRYPT_FreeBlob; 00919 *ppvFreeContext = NULL; 00920 00921 if (!(dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL)) 00922 ret = CRYPT_GetObjectFromCache(pszURL, pObject, pAuxInfo); 00923 if (!ret && (!(dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) || 00924 (dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL))) 00925 { 00926 URL_COMPONENTSW components; 00927 00928 if ((ret = CRYPT_CrackUrl(pszURL, &components))) 00929 { 00930 HINTERNET hInt, hHost; 00931 struct InetContext *context = NULL; 00932 00933 if (dwTimeout) 00934 context = CRYPT_MakeInetContext(dwTimeout); 00935 ret = CRYPT_Connect(&components, context, pCredentials, &hInt, 00936 &hHost); 00937 if (ret) 00938 { 00939 static LPCWSTR types[] = { x509cacert, x509emailcert, 00940 x509servercert, x509usercert, pkcs7cert, pkixCRL, pkcs7CRL, 00941 pkcs7sig, pkcs7mime, NULL }; 00942 HINTERNET hHttp = HttpOpenRequestW(hHost, NULL, 00943 components.lpszUrlPath, NULL, NULL, types, 00944 INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI, 00945 (DWORD_PTR)context); 00946 00947 if (hHttp) 00948 { 00949 if (dwTimeout) 00950 { 00951 InternetSetOptionW(hHttp, 00952 INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, 00953 sizeof(dwTimeout)); 00954 InternetSetOptionW(hHttp, INTERNET_OPTION_SEND_TIMEOUT, 00955 &dwTimeout, sizeof(dwTimeout)); 00956 } 00957 ret = HttpSendRequestExW(hHttp, NULL, NULL, 0, 00958 (DWORD_PTR)context); 00959 if (!ret && GetLastError() == ERROR_IO_PENDING) 00960 { 00961 if (WaitForSingleObject(context->event, 00962 context->timeout) == WAIT_TIMEOUT) 00963 SetLastError(ERROR_TIMEOUT); 00964 else 00965 ret = TRUE; 00966 } 00967 /* We don't set ret to TRUE in this block to avoid masking 00968 * an error from HttpSendRequestExW. 00969 */ 00970 if (!HttpEndRequestW(hHttp, NULL, 0, (DWORD_PTR)context) && 00971 GetLastError() == ERROR_IO_PENDING) 00972 { 00973 if (WaitForSingleObject(context->event, 00974 context->timeout) == WAIT_TIMEOUT) 00975 { 00976 SetLastError(ERROR_TIMEOUT); 00977 ret = FALSE; 00978 } 00979 } 00980 if (ret) 00981 ret = CRYPT_DownloadObject(dwRetrievalFlags, hHttp, 00982 context, pObject, pAuxInfo); 00983 if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT)) 00984 { 00985 SYSTEMTIME st; 00986 DWORD len = sizeof(st); 00987 00988 if (HttpQueryInfoW(hHttp, 00989 HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME, &st, 00990 &len, NULL)) 00991 { 00992 FILETIME ft; 00993 00994 SystemTimeToFileTime(&st, &ft); 00995 CRYPT_CacheURL(pszURL, pObject, dwRetrievalFlags, 00996 ft); 00997 } 00998 } 00999 InternetCloseHandle(hHttp); 01000 } 01001 InternetCloseHandle(hHost); 01002 InternetCloseHandle(hInt); 01003 } 01004 if (context) 01005 { 01006 CloseHandle(context->event); 01007 CryptMemFree(context); 01008 } 01009 CryptMemFree(components.lpszUrlPath); 01010 CryptMemFree(components.lpszHostName); 01011 } 01012 } 01013 TRACE("returning %d\n", ret); 01014 return ret; 01015 } 01016 01017 static BOOL WINAPI File_RetrieveEncodedObjectW(LPCWSTR pszURL, 01018 LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, 01019 PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, 01020 void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, 01021 PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 01022 { 01023 URL_COMPONENTSW components = { sizeof(components), 0 }; 01024 BOOL ret; 01025 01026 TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), 01027 debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject, 01028 ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo); 01029 01030 pObject->cBlob = 0; 01031 pObject->rgBlob = NULL; 01032 *ppfnFreeObject = CRYPT_FreeBlob; 01033 *ppvFreeContext = NULL; 01034 01035 components.lpszUrlPath = CryptMemAlloc(INTERNET_MAX_PATH_LENGTH * sizeof(WCHAR)); 01036 components.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; 01037 if (!components.lpszUrlPath) 01038 { 01039 SetLastError(ERROR_OUTOFMEMORY); 01040 return FALSE; 01041 } 01042 01043 ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, &components); 01044 if (ret) 01045 { 01046 LPWSTR path; 01047 01048 /* 3 == lstrlenW(L"c:") + 1 */ 01049 path = CryptMemAlloc((components.dwUrlPathLength + 3) * sizeof(WCHAR)); 01050 if (path) 01051 { 01052 HANDLE hFile; 01053 01054 /* Try to create the file directly - Wine handles / in pathnames */ 01055 lstrcpynW(path, components.lpszUrlPath, 01056 components.dwUrlPathLength + 1); 01057 hFile = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 01058 FILE_ATTRIBUTE_NORMAL, NULL); 01059 if (hFile == INVALID_HANDLE_VALUE) 01060 { 01061 /* Try again on the current drive */ 01062 GetCurrentDirectoryW(components.dwUrlPathLength, path); 01063 if (path[1] == ':') 01064 { 01065 lstrcpynW(path + 2, components.lpszUrlPath, 01066 components.dwUrlPathLength + 1); 01067 hFile = CreateFileW(path, GENERIC_READ, 0, NULL, 01068 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 01069 } 01070 if (hFile == INVALID_HANDLE_VALUE) 01071 { 01072 /* Try again on the Windows drive */ 01073 GetWindowsDirectoryW(path, components.dwUrlPathLength); 01074 if (path[1] == ':') 01075 { 01076 lstrcpynW(path + 2, components.lpszUrlPath, 01077 components.dwUrlPathLength + 1); 01078 hFile = CreateFileW(path, GENERIC_READ, 0, NULL, 01079 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 01080 } 01081 } 01082 } 01083 if (hFile != INVALID_HANDLE_VALUE) 01084 { 01085 if ((ret = CRYPT_GetObjectFromFile(hFile, pObject))) 01086 { 01087 if (pAuxInfo && pAuxInfo->cbSize >= 01088 offsetof(CRYPT_RETRIEVE_AUX_INFO, 01089 pLastSyncTime) + sizeof(PFILETIME) && 01090 pAuxInfo->pLastSyncTime) 01091 GetFileTime(hFile, NULL, NULL, 01092 pAuxInfo->pLastSyncTime); 01093 } 01094 CloseHandle(hFile); 01095 } 01096 else 01097 ret = FALSE; 01098 CryptMemFree(path); 01099 } 01100 else 01101 { 01102 SetLastError(ERROR_OUTOFMEMORY); 01103 ret = FALSE; 01104 } 01105 } 01106 CryptMemFree(components.lpszUrlPath); 01107 return ret; 01108 } 01109 01110 typedef BOOL (WINAPI *SchemeDllRetrieveEncodedObjectW)(LPCWSTR pwszUrl, 01111 LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, 01112 PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, 01113 void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, 01114 PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo); 01115 01116 static BOOL CRYPT_GetRetrieveFunction(LPCWSTR pszURL, 01117 SchemeDllRetrieveEncodedObjectW *pFunc, HCRYPTOIDFUNCADDR *phFunc) 01118 { 01119 URL_COMPONENTSW components = { sizeof(components), 0 }; 01120 BOOL ret; 01121 01122 TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pFunc, phFunc); 01123 01124 *pFunc = NULL; 01125 *phFunc = 0; 01126 components.dwSchemeLength = 1; 01127 ret = InternetCrackUrlW(pszURL, 0, 0, &components); 01128 if (ret) 01129 { 01130 /* Microsoft always uses CryptInitOIDFunctionSet/ 01131 * CryptGetOIDFunctionAddress, but there doesn't seem to be a pressing 01132 * reason to do so for builtin schemes. 01133 */ 01134 switch (components.nScheme) 01135 { 01136 case INTERNET_SCHEME_FTP: 01137 *pFunc = FTP_RetrieveEncodedObjectW; 01138 break; 01139 case INTERNET_SCHEME_HTTP: 01140 *pFunc = HTTP_RetrieveEncodedObjectW; 01141 break; 01142 case INTERNET_SCHEME_FILE: 01143 *pFunc = File_RetrieveEncodedObjectW; 01144 break; 01145 default: 01146 { 01147 int len = WideCharToMultiByte(CP_ACP, 0, components.lpszScheme, 01148 components.dwSchemeLength, NULL, 0, NULL, NULL); 01149 01150 if (len) 01151 { 01152 LPSTR scheme = CryptMemAlloc(len); 01153 01154 if (scheme) 01155 { 01156 static HCRYPTOIDFUNCSET set = NULL; 01157 01158 if (!set) 01159 set = CryptInitOIDFunctionSet( 01160 SCHEME_OID_RETRIEVE_ENCODED_OBJECTW_FUNC, 0); 01161 WideCharToMultiByte(CP_ACP, 0, components.lpszScheme, 01162 components.dwSchemeLength, scheme, len, NULL, NULL); 01163 ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 01164 scheme, 0, (void **)pFunc, phFunc); 01165 CryptMemFree(scheme); 01166 } 01167 else 01168 { 01169 SetLastError(ERROR_OUTOFMEMORY); 01170 ret = FALSE; 01171 } 01172 } 01173 else 01174 ret = FALSE; 01175 } 01176 } 01177 } 01178 TRACE("returning %d\n", ret); 01179 return ret; 01180 } 01181 01182 static BOOL WINAPI CRYPT_CreateBlob(LPCSTR pszObjectOid, 01183 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext) 01184 { 01185 DWORD size, i; 01186 CRYPT_BLOB_ARRAY *context; 01187 BOOL ret = FALSE; 01188 01189 size = sizeof(CRYPT_BLOB_ARRAY) + pObject->cBlob * sizeof(CRYPT_DATA_BLOB); 01190 for (i = 0; i < pObject->cBlob; i++) 01191 size += pObject->rgBlob[i].cbData; 01192 context = CryptMemAlloc(size); 01193 if (context) 01194 { 01195 LPBYTE nextData; 01196 01197 context->cBlob = 0; 01198 context->rgBlob = 01199 (CRYPT_DATA_BLOB *)((LPBYTE)context + sizeof(CRYPT_BLOB_ARRAY)); 01200 nextData = 01201 (LPBYTE)context->rgBlob + pObject->cBlob * sizeof(CRYPT_DATA_BLOB); 01202 for (i = 0; i < pObject->cBlob; i++) 01203 { 01204 memcpy(nextData, pObject->rgBlob[i].pbData, 01205 pObject->rgBlob[i].cbData); 01206 context->rgBlob[i].pbData = nextData; 01207 context->rgBlob[i].cbData = pObject->rgBlob[i].cbData; 01208 nextData += pObject->rgBlob[i].cbData; 01209 context->cBlob++; 01210 } 01211 *ppvContext = context; 01212 ret = TRUE; 01213 } 01214 return ret; 01215 } 01216 01217 typedef BOOL (WINAPI *AddContextToStore)(HCERTSTORE hCertStore, 01218 const void *pContext, DWORD dwAddDisposition, const void **ppStoreContext); 01219 01220 static BOOL CRYPT_CreateContext(const CRYPT_BLOB_ARRAY *pObject, 01221 DWORD dwExpectedContentTypeFlags, AddContextToStore addFunc, void **ppvContext) 01222 { 01223 BOOL ret = TRUE; 01224 01225 if (!pObject->cBlob) 01226 { 01227 SetLastError(ERROR_INVALID_DATA); 01228 *ppvContext = NULL; 01229 ret = FALSE; 01230 } 01231 else if (pObject->cBlob == 1) 01232 { 01233 if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pObject->rgBlob[0], 01234 dwExpectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, 01235 NULL, NULL, NULL, NULL, (const void **)ppvContext)) 01236 { 01237 SetLastError(CRYPT_E_NO_MATCH); 01238 ret = FALSE; 01239 } 01240 } 01241 else 01242 { 01243 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 01244 CERT_STORE_CREATE_NEW_FLAG, NULL); 01245 01246 if (store) 01247 { 01248 DWORD i; 01249 const void *context; 01250 01251 for (i = 0; i < pObject->cBlob; i++) 01252 { 01253 if (CryptQueryObject(CERT_QUERY_OBJECT_BLOB, 01254 &pObject->rgBlob[i], dwExpectedContentTypeFlags, 01255 CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, NULL, 01256 NULL, &context)) 01257 { 01258 if (!addFunc(store, context, CERT_STORE_ADD_ALWAYS, NULL)) 01259 ret = FALSE; 01260 } 01261 else 01262 { 01263 SetLastError(CRYPT_E_NO_MATCH); 01264 ret = FALSE; 01265 } 01266 } 01267 } 01268 else 01269 ret = FALSE; 01270 *ppvContext = store; 01271 } 01272 return ret; 01273 } 01274 01275 static BOOL WINAPI CRYPT_CreateCert(LPCSTR pszObjectOid, 01276 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext) 01277 { 01278 return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CERT, 01279 (AddContextToStore)CertAddCertificateContextToStore, ppvContext); 01280 } 01281 01282 static BOOL WINAPI CRYPT_CreateCRL(LPCSTR pszObjectOid, 01283 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext) 01284 { 01285 return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CRL, 01286 (AddContextToStore)CertAddCRLContextToStore, ppvContext); 01287 } 01288 01289 static BOOL WINAPI CRYPT_CreateCTL(LPCSTR pszObjectOid, 01290 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext) 01291 { 01292 return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CTL, 01293 (AddContextToStore)CertAddCTLContextToStore, ppvContext); 01294 } 01295 01296 static BOOL WINAPI CRYPT_CreatePKCS7(LPCSTR pszObjectOid, 01297 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext) 01298 { 01299 BOOL ret; 01300 01301 if (!pObject->cBlob) 01302 { 01303 SetLastError(ERROR_INVALID_DATA); 01304 *ppvContext = NULL; 01305 ret = FALSE; 01306 } 01307 else if (pObject->cBlob == 1) 01308 ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pObject->rgBlob[0], 01309 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | 01310 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED, CERT_QUERY_FORMAT_FLAG_BINARY, 01311 0, NULL, NULL, NULL, ppvContext, NULL, NULL); 01312 else 01313 { 01314 FIXME("multiple messages unimplemented\n"); 01315 ret = FALSE; 01316 } 01317 return ret; 01318 } 01319 01320 static BOOL WINAPI CRYPT_CreateAny(LPCSTR pszObjectOid, 01321 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext) 01322 { 01323 BOOL ret; 01324 01325 if (!pObject->cBlob) 01326 { 01327 SetLastError(ERROR_INVALID_DATA); 01328 *ppvContext = NULL; 01329 ret = FALSE; 01330 } 01331 else 01332 { 01333 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 01334 CERT_STORE_CREATE_NEW_FLAG, NULL); 01335 01336 if (store) 01337 { 01338 HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 01339 CERT_STORE_CREATE_NEW_FLAG, NULL); 01340 01341 if (memStore) 01342 { 01343 CertAddStoreToCollection(store, memStore, 01344 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); 01345 CertCloseStore(memStore, 0); 01346 } 01347 else 01348 { 01349 CertCloseStore(store, 0); 01350 store = NULL; 01351 } 01352 } 01353 if (store) 01354 { 01355 DWORD i; 01356 01357 ret = TRUE; 01358 for (i = 0; i < pObject->cBlob; i++) 01359 { 01360 DWORD contentType, expectedContentTypes = 01361 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | 01362 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED | 01363 CERT_QUERY_CONTENT_FLAG_CERT | 01364 CERT_QUERY_CONTENT_FLAG_CRL | 01365 CERT_QUERY_CONTENT_FLAG_CTL; 01366 HCERTSTORE contextStore; 01367 const void *context; 01368 01369 if (CryptQueryObject(CERT_QUERY_OBJECT_BLOB, 01370 &pObject->rgBlob[i], expectedContentTypes, 01371 CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, &contentType, NULL, 01372 &contextStore, NULL, &context)) 01373 { 01374 switch (contentType) 01375 { 01376 case CERT_QUERY_CONTENT_CERT: 01377 if (!CertAddCertificateContextToStore(store, 01378 context, CERT_STORE_ADD_ALWAYS, NULL)) 01379 ret = FALSE; 01380 CertFreeCertificateContext(context); 01381 break; 01382 case CERT_QUERY_CONTENT_CRL: 01383 if (!CertAddCRLContextToStore(store, 01384 context, CERT_STORE_ADD_ALWAYS, NULL)) 01385 ret = FALSE; 01386 CertFreeCRLContext(context); 01387 break; 01388 case CERT_QUERY_CONTENT_CTL: 01389 if (!CertAddCTLContextToStore(store, 01390 context, CERT_STORE_ADD_ALWAYS, NULL)) 01391 ret = FALSE; 01392 CertFreeCTLContext(context); 01393 break; 01394 default: 01395 CertAddStoreToCollection(store, contextStore, 0, 0); 01396 } 01397 CertCloseStore(contextStore, 0); 01398 } 01399 else 01400 ret = FALSE; 01401 } 01402 } 01403 else 01404 ret = FALSE; 01405 *ppvContext = store; 01406 } 01407 return ret; 01408 } 01409 01410 typedef BOOL (WINAPI *ContextDllCreateObjectContext)(LPCSTR pszObjectOid, 01411 DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext); 01412 01413 static BOOL CRYPT_GetCreateFunction(LPCSTR pszObjectOid, 01414 ContextDllCreateObjectContext *pFunc, HCRYPTOIDFUNCADDR *phFunc) 01415 { 01416 BOOL ret = TRUE; 01417 01418 TRACE("(%s, %p, %p)\n", debugstr_a(pszObjectOid), pFunc, phFunc); 01419 01420 *pFunc = NULL; 01421 *phFunc = 0; 01422 if (IS_INTOID(pszObjectOid)) 01423 { 01424 switch (LOWORD(pszObjectOid)) 01425 { 01426 case 0: 01427 *pFunc = CRYPT_CreateBlob; 01428 break; 01429 case LOWORD(CONTEXT_OID_CERTIFICATE): 01430 *pFunc = CRYPT_CreateCert; 01431 break; 01432 case LOWORD(CONTEXT_OID_CRL): 01433 *pFunc = CRYPT_CreateCRL; 01434 break; 01435 case LOWORD(CONTEXT_OID_CTL): 01436 *pFunc = CRYPT_CreateCTL; 01437 break; 01438 case LOWORD(CONTEXT_OID_PKCS7): 01439 *pFunc = CRYPT_CreatePKCS7; 01440 break; 01441 case LOWORD(CONTEXT_OID_CAPI2_ANY): 01442 *pFunc = CRYPT_CreateAny; 01443 break; 01444 } 01445 } 01446 if (!*pFunc) 01447 { 01448 static HCRYPTOIDFUNCSET set = NULL; 01449 01450 if (!set) 01451 set = CryptInitOIDFunctionSet( 01452 CONTEXT_OID_CREATE_OBJECT_CONTEXT_FUNC, 0); 01453 ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszObjectOid, 01454 0, (void **)pFunc, phFunc); 01455 } 01456 TRACE("returning %d\n", ret); 01457 return ret; 01458 } 01459 01460 typedef BOOL (*get_object_expiration_func)(const void *pvContext, 01461 FILETIME *expiration); 01462 01463 static BOOL CRYPT_GetExpirationFromCert(const void *pvObject, FILETIME *expiration) 01464 { 01465 PCCERT_CONTEXT cert = pvObject; 01466 01467 *expiration = cert->pCertInfo->NotAfter; 01468 return TRUE; 01469 } 01470 01471 static BOOL CRYPT_GetExpirationFromCRL(const void *pvObject, FILETIME *expiration) 01472 { 01473 PCCRL_CONTEXT cert = pvObject; 01474 01475 *expiration = cert->pCrlInfo->NextUpdate; 01476 return TRUE; 01477 } 01478 01479 static BOOL CRYPT_GetExpirationFromCTL(const void *pvObject, FILETIME *expiration) 01480 { 01481 PCCTL_CONTEXT cert = pvObject; 01482 01483 *expiration = cert->pCtlInfo->NextUpdate; 01484 return TRUE; 01485 } 01486 01487 static BOOL CRYPT_GetExpirationFunction(LPCSTR pszObjectOid, 01488 get_object_expiration_func *getExpiration) 01489 { 01490 BOOL ret; 01491 01492 if (IS_INTOID(pszObjectOid)) 01493 { 01494 switch (LOWORD(pszObjectOid)) 01495 { 01496 case LOWORD(CONTEXT_OID_CERTIFICATE): 01497 *getExpiration = CRYPT_GetExpirationFromCert; 01498 ret = TRUE; 01499 break; 01500 case LOWORD(CONTEXT_OID_CRL): 01501 *getExpiration = CRYPT_GetExpirationFromCRL; 01502 ret = TRUE; 01503 break; 01504 case LOWORD(CONTEXT_OID_CTL): 01505 *getExpiration = CRYPT_GetExpirationFromCTL; 01506 ret = TRUE; 01507 break; 01508 default: 01509 ret = FALSE; 01510 } 01511 } 01512 else 01513 ret = FALSE; 01514 return ret; 01515 } 01516 01517 /*********************************************************************** 01518 * CryptRetrieveObjectByUrlW (CRYPTNET.@) 01519 */ 01520 BOOL WINAPI CryptRetrieveObjectByUrlW(LPCWSTR pszURL, LPCSTR pszObjectOid, 01521 DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject, 01522 HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, 01523 PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) 01524 { 01525 BOOL ret; 01526 SchemeDllRetrieveEncodedObjectW retrieve; 01527 ContextDllCreateObjectContext create; 01528 HCRYPTOIDFUNCADDR hRetrieve = 0, hCreate = 0; 01529 01530 TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), 01531 debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject, 01532 hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo); 01533 01534 if (!pszURL) 01535 { 01536 SetLastError(ERROR_INVALID_PARAMETER); 01537 return FALSE; 01538 } 01539 ret = CRYPT_GetRetrieveFunction(pszURL, &retrieve, &hRetrieve); 01540 if (ret) 01541 ret = CRYPT_GetCreateFunction(pszObjectOid, &create, &hCreate); 01542 if (ret) 01543 { 01544 CRYPT_BLOB_ARRAY object = { 0, NULL }; 01545 PFN_FREE_ENCODED_OBJECT_FUNC freeObject; 01546 void *freeContext; 01547 01548 ret = retrieve(pszURL, pszObjectOid, dwRetrievalFlags, dwTimeout, 01549 &object, &freeObject, &freeContext, hAsyncRetrieve, pCredentials, 01550 pAuxInfo); 01551 if (ret) 01552 { 01553 get_object_expiration_func getExpiration; 01554 01555 ret = create(pszObjectOid, dwRetrievalFlags, &object, ppvObject); 01556 if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT) && 01557 CRYPT_GetExpirationFunction(pszObjectOid, &getExpiration)) 01558 { 01559 FILETIME expires; 01560 01561 if (getExpiration(*ppvObject, &expires)) 01562 CRYPT_CacheURL(pszURL, &object, dwRetrievalFlags, expires); 01563 } 01564 freeObject(pszObjectOid, &object, freeContext); 01565 } 01566 } 01567 if (hCreate) 01568 CryptFreeOIDFunctionAddress(hCreate, 0); 01569 if (hRetrieve) 01570 CryptFreeOIDFunctionAddress(hRetrieve, 0); 01571 TRACE("returning %d\n", ret); 01572 return ret; 01573 } 01574 01575 static DWORD verify_cert_revocation_with_crl_online(PCCERT_CONTEXT cert, 01576 PCCRL_CONTEXT crl, DWORD index, FILETIME *pTime, 01577 PCERT_REVOCATION_STATUS pRevStatus) 01578 { 01579 DWORD error; 01580 PCRL_ENTRY entry = NULL; 01581 01582 CertFindCertificateInCRL(cert, crl, 0, NULL, &entry); 01583 if (entry) 01584 { 01585 error = CRYPT_E_REVOKED; 01586 pRevStatus->dwIndex = index; 01587 } 01588 else 01589 { 01590 /* Since the CRL was retrieved for the cert being checked, then it's 01591 * guaranteed to be fresh, and the cert is not revoked. 01592 */ 01593 error = ERROR_SUCCESS; 01594 } 01595 return error; 01596 } 01597 01598 static DWORD verify_cert_revocation_from_dist_points_ext( 01599 const CRYPT_DATA_BLOB *value, PCCERT_CONTEXT cert, DWORD index, 01600 FILETIME *pTime, DWORD dwFlags, const CERT_REVOCATION_PARA *pRevPara, 01601 PCERT_REVOCATION_STATUS pRevStatus) 01602 { 01603 DWORD error = ERROR_SUCCESS, cbUrlArray; 01604 01605 if (CRYPT_GetUrlFromCRLDistPointsExt(value, NULL, &cbUrlArray, NULL, NULL)) 01606 { 01607 CRYPT_URL_ARRAY *urlArray = CryptMemAlloc(cbUrlArray); 01608 01609 if (urlArray) 01610 { 01611 DWORD j, retrievalFlags = 0, startTime, endTime, timeout; 01612 BOOL ret; 01613 01614 ret = CRYPT_GetUrlFromCRLDistPointsExt(value, urlArray, 01615 &cbUrlArray, NULL, NULL); 01616 if (dwFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION) 01617 retrievalFlags |= CRYPT_CACHE_ONLY_RETRIEVAL; 01618 if (dwFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG && 01619 pRevPara && pRevPara->cbSize >= offsetof(CERT_REVOCATION_PARA, 01620 dwUrlRetrievalTimeout) + sizeof(DWORD)) 01621 { 01622 startTime = GetTickCount(); 01623 endTime = startTime + pRevPara->dwUrlRetrievalTimeout; 01624 timeout = pRevPara->dwUrlRetrievalTimeout; 01625 } 01626 else 01627 endTime = timeout = 0; 01628 if (!ret) 01629 error = GetLastError(); 01630 for (j = 0; !error && j < urlArray->cUrl; j++) 01631 { 01632 PCCRL_CONTEXT crl; 01633 01634 ret = CryptRetrieveObjectByUrlW(urlArray->rgwszUrl[j], 01635 CONTEXT_OID_CRL, retrievalFlags, timeout, (void **)&crl, 01636 NULL, NULL, NULL, NULL); 01637 if (ret) 01638 { 01639 error = verify_cert_revocation_with_crl_online(cert, crl, 01640 index, pTime, pRevStatus); 01641 if (!error && timeout) 01642 { 01643 DWORD time = GetTickCount(); 01644 01645 if ((int)(endTime - time) <= 0) 01646 { 01647 error = ERROR_TIMEOUT; 01648 pRevStatus->dwIndex = index; 01649 } 01650 else 01651 timeout = endTime - time; 01652 } 01653 CertFreeCRLContext(crl); 01654 } 01655 else 01656 error = CRYPT_E_REVOCATION_OFFLINE; 01657 } 01658 CryptMemFree(urlArray); 01659 } 01660 else 01661 { 01662 error = ERROR_OUTOFMEMORY; 01663 pRevStatus->dwIndex = index; 01664 } 01665 } 01666 else 01667 { 01668 error = GetLastError(); 01669 pRevStatus->dwIndex = index; 01670 } 01671 return error; 01672 } 01673 01674 static DWORD verify_cert_revocation_from_aia_ext( 01675 const CRYPT_DATA_BLOB *value, PCCERT_CONTEXT cert, DWORD index, 01676 FILETIME *pTime, DWORD dwFlags, PCERT_REVOCATION_PARA pRevPara, 01677 PCERT_REVOCATION_STATUS pRevStatus) 01678 { 01679 BOOL ret; 01680 DWORD error, size; 01681 CERT_AUTHORITY_INFO_ACCESS *aia; 01682 01683 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_INFO_ACCESS, 01684 value->pbData, value->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &aia, &size); 01685 if (ret) 01686 { 01687 DWORD i; 01688 01689 for (i = 0; i < aia->cAccDescr; i++) 01690 if (!strcmp(aia->rgAccDescr[i].pszAccessMethod, 01691 szOID_PKIX_OCSP)) 01692 { 01693 if (aia->rgAccDescr[i].AccessLocation.dwAltNameChoice == 01694 CERT_ALT_NAME_URL) 01695 FIXME("OCSP URL = %s\n", 01696 debugstr_w(aia->rgAccDescr[i].AccessLocation.u.pwszURL)); 01697 else 01698 FIXME("unsupported AccessLocation type %d\n", 01699 aia->rgAccDescr[i].AccessLocation.dwAltNameChoice); 01700 } 01701 LocalFree(aia); 01702 /* FIXME: lie and pretend OCSP validated the cert */ 01703 error = ERROR_SUCCESS; 01704 } 01705 else 01706 error = GetLastError(); 01707 return error; 01708 } 01709 01710 static DWORD verify_cert_revocation_with_crl_offline(PCCERT_CONTEXT cert, 01711 PCCRL_CONTEXT crl, DWORD index, FILETIME *pTime, 01712 PCERT_REVOCATION_STATUS pRevStatus) 01713 { 01714 DWORD error; 01715 LONG valid; 01716 01717 valid = CompareFileTime(pTime, &crl->pCrlInfo->ThisUpdate); 01718 if (valid <= 0) 01719 { 01720 /* If this CRL is not older than the time being verified, there's no 01721 * way to know whether the certificate was revoked. 01722 */ 01723 TRACE("CRL not old enough\n"); 01724 error = CRYPT_E_REVOCATION_OFFLINE; 01725 } 01726 else 01727 { 01728 PCRL_ENTRY entry = NULL; 01729 01730 CertFindCertificateInCRL(cert, crl, 0, NULL, &entry); 01731 if (entry) 01732 { 01733 error = CRYPT_E_REVOKED; 01734 pRevStatus->dwIndex = index; 01735 } 01736 else 01737 { 01738 /* Since the CRL was not retrieved for the cert being checked, 01739 * there's no guarantee it's fresh, so the cert *might* be okay, 01740 * but it's safer not to guess. 01741 */ 01742 TRACE("certificate not found\n"); 01743 error = CRYPT_E_REVOCATION_OFFLINE; 01744 } 01745 } 01746 return error; 01747 } 01748 01749 static DWORD verify_cert_revocation(PCCERT_CONTEXT cert, DWORD index, 01750 FILETIME *pTime, DWORD dwFlags, PCERT_REVOCATION_PARA pRevPara, 01751 PCERT_REVOCATION_STATUS pRevStatus) 01752 { 01753 DWORD error = ERROR_SUCCESS; 01754 PCERT_EXTENSION ext; 01755 01756 if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, 01757 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 01758 error = verify_cert_revocation_from_dist_points_ext(&ext->Value, cert, 01759 index, pTime, dwFlags, pRevPara, pRevStatus); 01760 else if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, 01761 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 01762 error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, 01763 index, pTime, dwFlags, pRevPara, pRevStatus); 01764 else 01765 { 01766 if (pRevPara && pRevPara->hCrlStore && pRevPara->pIssuerCert) 01767 { 01768 PCCRL_CONTEXT crl = NULL; 01769 BOOL canSignCRLs; 01770 01771 /* If the caller told us about the issuer, make sure the issuer 01772 * can sign CRLs before looking for one. 01773 */ 01774 if ((ext = CertFindExtension(szOID_KEY_USAGE, 01775 pRevPara->pIssuerCert->pCertInfo->cExtension, 01776 pRevPara->pIssuerCert->pCertInfo->rgExtension))) 01777 { 01778 CRYPT_BIT_BLOB usage; 01779 DWORD size = sizeof(usage); 01780 01781 if (!CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS, 01782 ext->Value.pbData, ext->Value.cbData, 01783 CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size)) 01784 canSignCRLs = FALSE; 01785 else if (usage.cbData > 2) 01786 { 01787 /* The key usage extension only defines 9 bits => no more 01788 * than 2 bytes are needed to encode all known usages. 01789 */ 01790 canSignCRLs = FALSE; 01791 } 01792 else 01793 { 01794 BYTE usageBits = usage.pbData[usage.cbData - 1]; 01795 01796 canSignCRLs = usageBits & CERT_CRL_SIGN_KEY_USAGE; 01797 } 01798 } 01799 else 01800 canSignCRLs = TRUE; 01801 if (canSignCRLs) 01802 { 01803 /* If the caller was helpful enough to tell us where to find a 01804 * CRL for the cert, look for one and check it. 01805 */ 01806 crl = CertFindCRLInStore(pRevPara->hCrlStore, 01807 cert->dwCertEncodingType, 01808 CRL_FIND_ISSUED_BY_SIGNATURE_FLAG | 01809 CRL_FIND_ISSUED_BY_AKI_FLAG, 01810 CRL_FIND_ISSUED_BY, pRevPara->pIssuerCert, NULL); 01811 } 01812 if (crl) 01813 { 01814 error = verify_cert_revocation_with_crl_offline(cert, crl, 01815 index, pTime, pRevStatus); 01816 CertFreeCRLContext(crl); 01817 } 01818 else 01819 { 01820 TRACE("no CRL found\n"); 01821 error = CRYPT_E_NO_REVOCATION_CHECK; 01822 pRevStatus->dwIndex = index; 01823 } 01824 } 01825 else 01826 { 01827 if (!pRevPara) 01828 WARN("no CERT_REVOCATION_PARA\n"); 01829 else if (!pRevPara->hCrlStore) 01830 WARN("no dist points/aia extension and no CRL store\n"); 01831 else if (!pRevPara->pIssuerCert) 01832 WARN("no dist points/aia extension and no issuer\n"); 01833 error = CRYPT_E_NO_REVOCATION_CHECK; 01834 pRevStatus->dwIndex = index; 01835 } 01836 } 01837 return error; 01838 } 01839 01840 typedef struct _CERT_REVOCATION_PARA_NO_EXTRA_FIELDS { 01841 DWORD cbSize; 01842 PCCERT_CONTEXT pIssuerCert; 01843 DWORD cCertStore; 01844 HCERTSTORE *rgCertStore; 01845 HCERTSTORE hCrlStore; 01846 LPFILETIME pftTimeToUse; 01847 } CERT_REVOCATION_PARA_NO_EXTRA_FIELDS, *PCERT_REVOCATION_PARA_NO_EXTRA_FIELDS; 01848 01849 typedef struct _OLD_CERT_REVOCATION_STATUS { 01850 DWORD cbSize; 01851 DWORD dwIndex; 01852 DWORD dwError; 01853 DWORD dwReason; 01854 } OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS; 01855 01856 /*********************************************************************** 01857 * CertDllVerifyRevocation (CRYPTNET.@) 01858 */ 01859 BOOL WINAPI CertDllVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, 01860 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags, 01861 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus) 01862 { 01863 DWORD error = 0, i; 01864 FILETIME now; 01865 LPFILETIME pTime = NULL; 01866 01867 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType, 01868 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus); 01869 01870 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) && 01871 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS)) 01872 { 01873 SetLastError(E_INVALIDARG); 01874 return FALSE; 01875 } 01876 if (!cContext) 01877 { 01878 SetLastError(E_INVALIDARG); 01879 return FALSE; 01880 } 01881 if (pRevPara && pRevPara->cbSize >= 01882 sizeof(CERT_REVOCATION_PARA_NO_EXTRA_FIELDS)) 01883 pTime = pRevPara->pftTimeToUse; 01884 if (!pTime) 01885 { 01886 GetSystemTimeAsFileTime(&now); 01887 pTime = &now; 01888 } 01889 memset(&pRevStatus->dwIndex, 0, pRevStatus->cbSize - sizeof(DWORD)); 01890 if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE) 01891 error = CRYPT_E_NO_REVOCATION_CHECK; 01892 else 01893 { 01894 for (i = 0; !error && i < cContext; i++) 01895 error = verify_cert_revocation(rgpvContext[i], i, pTime, dwFlags, 01896 pRevPara, pRevStatus); 01897 } 01898 if (error) 01899 { 01900 SetLastError(error); 01901 pRevStatus->dwError = error; 01902 } 01903 TRACE("returning %d (%08x)\n", !error, error); 01904 return !error; 01905 } Generated on Sun May 27 2012 04:23:19 for ReactOS by
1.7.6.1
|