diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 3f44aeb8e0..7a79371d5a 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -400,7 +400,6 @@ static BOOL CRYPT_GetObjectFromFile(HANDLE hFile, PCRYPT_BLOB_ARRAY pObject) return ret; } -/* FIXME: should make wininet cache all downloads instead */ static BOOL CRYPT_GetObjectFromCache(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) { @@ -605,30 +604,73 @@ static BOOL CRYPT_DownloadObject(DWORD dwRetrievalFlags, HINTERNET hHttp, return ret; } +/* Finds the object specified by pszURL in the cache. If it's not found, + * creates a new cache entry for the object and writes the object to it. + * Sets the expiration time of the cache entry to expires. + */ static void CRYPT_CacheURL(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject, DWORD dwRetrievalFlags, FILETIME expires) { WCHAR cacheFileName[MAX_PATH]; + DWORD size = 0; + BOOL ret, create = FALSE; - /* FIXME: let wininet directly cache instead */ - if (CreateUrlCacheEntryW(pszURL, pObject->rgBlob[0].cbData, NULL, - cacheFileName, 0)) + GetUrlCacheEntryInfoW(pszURL, NULL, &size); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - HANDLE hCacheFile = CreateFileW(cacheFileName, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + INTERNET_CACHE_ENTRY_INFOW *info = CryptMemAlloc(size); - if (hCacheFile != INVALID_HANDLE_VALUE) + if (info) { - DWORD bytesWritten, entryType; - FILETIME ft = { 0 }; + FILETIME ft; + ret = GetUrlCacheEntryInfoW(pszURL, info, &size); + if (ret) + lstrcpyW(cacheFileName, info->lpszLocalFileName); + /* Check if the existing cache entry is up to date. If it isn't, + * overwite it with the new value. + */ + GetSystemTimeAsFileTime(&ft); + if (CompareFileTime(&info->ExpireTime, &ft) < 0) + create = TRUE; + CryptMemFree(info); + } + else + ret = FALSE; + } + else + { + ret = CreateUrlCacheEntryW(pszURL, pObject->rgBlob[0].cbData, NULL, + cacheFileName, 0); + create = TRUE; + } + if (ret) + { + DWORD entryType; + FILETIME ft = { 0 }; + + if (create) + { + HANDLE hCacheFile = CreateFileW(cacheFileName, GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hCacheFile != INVALID_HANDLE_VALUE) + { + DWORD bytesWritten; + + WriteFile(hCacheFile, pObject->rgBlob[0].pbData, + pObject->rgBlob[0].cbData, &bytesWritten, NULL); + CloseHandle(hCacheFile); + } + else + ret = FALSE; + } + if (ret) + { if (!(dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL)) entryType = NORMAL_CACHE_ENTRY; else entryType = STICKY_CACHE_ENTRY; - WriteFile(hCacheFile, pObject->rgBlob[0].pbData, - pObject->rgBlob[0].cbData, &bytesWritten, NULL); - CloseHandle(hCacheFile); CommitUrlCacheEntryW(pszURL, cacheFileName, expires, ft, entryType, NULL, 0, NULL, NULL); } @@ -1280,6 +1322,63 @@ static BOOL CRYPT_GetCreateFunction(LPCSTR pszObjectOid, return ret; } +typedef BOOL (*get_object_expiration_func)(void *pvContext, + FILETIME *expiration); + +static BOOL CRYPT_GetExpirationFromCert(void *pvObject, FILETIME *expiration) +{ + PCCERT_CONTEXT cert = (PCCERT_CONTEXT)pvObject; + + *expiration = cert->pCertInfo->NotAfter; + return TRUE; +} + +static BOOL CRYPT_GetExpirationFromCRL(void *pvObject, FILETIME *expiration) +{ + PCCRL_CONTEXT cert = (PCCRL_CONTEXT)pvObject; + + *expiration = cert->pCrlInfo->NextUpdate; + return TRUE; +} + +static BOOL CRYPT_GetExpirationFromCTL(void *pvObject, FILETIME *expiration) +{ + PCCTL_CONTEXT cert = (PCCTL_CONTEXT)pvObject; + + *expiration = cert->pCtlInfo->NextUpdate; + return TRUE; +} + +static BOOL CRYPT_GetExpirationFunction(LPCSTR pszObjectOid, + get_object_expiration_func *getExpiration) +{ + BOOL ret; + + if (!HIWORD(pszObjectOid)) + { + switch (LOWORD(pszObjectOid)) + { + case LOWORD(CONTEXT_OID_CERTIFICATE): + *getExpiration = CRYPT_GetExpirationFromCert; + ret = TRUE; + break; + case LOWORD(CONTEXT_OID_CRL): + *getExpiration = CRYPT_GetExpirationFromCRL; + ret = TRUE; + break; + case LOWORD(CONTEXT_OID_CTL): + *getExpiration = CRYPT_GetExpirationFromCTL; + ret = TRUE; + break; + default: + ret = FALSE; + } + } + else + ret = FALSE; + return ret; +} + /*********************************************************************** * CryptRetrieveObjectByUrlW (CRYPTNET.@) */ @@ -1316,7 +1415,17 @@ BOOL WINAPI CryptRetrieveObjectByUrlW(LPCWSTR pszURL, LPCSTR pszObjectOid, pAuxInfo); if (ret) { + get_object_expiration_func getExpiration; + ret = create(pszObjectOid, dwRetrievalFlags, &object, ppvObject); + if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT) && + CRYPT_GetExpirationFunction(pszObjectOid, &getExpiration)) + { + FILETIME expires; + + if (getExpiration(*ppvObject, &expires)) + CRYPT_CacheURL(pszURL, &object, dwRetrievalFlags, expires); + } freeObject(pszObjectOid, &object, freeContext); } }