Author: winesync Date: Thu Nov 29 13:28:12 2007 New Revision: 30864
URL: http://svn.reactos.org/svn/reactos?rev=30864&view=rev Log: Autosyncing with Wine HEAD
Modified: trunk/reactos/dll/win32/cryptnet/cryptnet.rbuild trunk/reactos/dll/win32/cryptnet/cryptnet.spec trunk/reactos/dll/win32/cryptnet/cryptnet_main.c
Modified: trunk/reactos/dll/win32/cryptnet/cryptnet.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptnet/cryptnet... ============================================================================== --- trunk/reactos/dll/win32/cryptnet/cryptnet.rbuild (original) +++ trunk/reactos/dll/win32/cryptnet/cryptnet.rbuild Thu Nov 29 13:28:12 2007 @@ -1,16 +1,17 @@ +<?xml version="1.0"?> +<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd"> <module name="cryptnet" type="win32dll" baseaddress="${BASEADDRESS_CRYPTNET}" installbase="system32" installname="cryptnet.dll" allowwarnings="true"> <autoregister infsection="OleControlDlls" type="DllRegisterServer" /> <importlibrary definition="cryptnet.spec.def" /> <include base="cryptnet">.</include> <include base="ReactOS">include/reactos/wine</include> - <define name="__REACTOS__" /> <define name="__WINESRC__" /> - <define name="__USE_W32API" /> - <define name="_WIN32_IE">0x600</define> - <define name="_WIN32_WINNT">0x501</define> - <define name="WINVER">0x501</define> + <define name="WINVER">0x600</define> + <define name="_WIN32_WINNT">0x600</define> <library>wine</library> + <library>crypt32</library> <library>kernel32</library> + <library>wininet</library> <library>ntdll</library> <file>cryptnet_main.c</file> <file>cryptnet.spec</file>
Modified: trunk/reactos/dll/win32/cryptnet/cryptnet.spec URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptnet/cryptnet... ============================================================================== --- trunk/reactos/dll/win32/cryptnet/cryptnet.spec (original) +++ trunk/reactos/dll/win32/cryptnet/cryptnet.spec Thu Nov 29 13:28:12 2007 @@ -1,14 +1,14 @@ @ stub CertDllVerifyCTLUsage -@ stub CertDllVerifyRevocation +@ stdcall CertDllVerifyRevocation(long long long ptr long ptr ptr) @ stub CryptnetWlxLogoffEvent @ stub LdapProvOpenStore @ stub CryptCancelAsyncRetrieval @ stub CryptFlushTimeValidObject -@ stub CryptGetObjectUrl +@ stdcall CryptGetObjectUrl(ptr ptr long ptr ptr ptr ptr ptr) @ stub CryptGetTimeValidObject @ stub CryptInstallCancelRetrieval -@ stub CryptRetrieveObjectByUrlA -@ stub CryptRetrieveObjectByUrlW +@ stdcall CryptRetrieveObjectByUrlA(str str long long ptr ptr ptr ptr ptr) +@ stdcall CryptRetrieveObjectByUrlW(wstr str long long ptr ptr ptr ptr ptr) @ stub CryptUninstallCancelRetrieval @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer()
Modified: trunk/reactos/dll/win32/cryptnet/cryptnet_main.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/cryptnet/cryptnet... ============================================================================== --- trunk/reactos/dll/win32/cryptnet/cryptnet_main.c (original) +++ trunk/reactos/dll/win32/cryptnet/cryptnet_main.c Thu Nov 29 13:28:12 2007 @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Maarten Lankhorst + * Copyright 2007 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,10 +19,21 @@ */
#include "config.h" +#include "wine/port.h" +#include <stdio.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + #include "windef.h" #include "wine/debug.h" #include "winbase.h" #include "winnt.h" +#include "winnls.h" +#include "wininet.h" +#include "objbase.h" +#define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS +#include "wincrypt.h"
WINE_DEFAULT_DEBUG_CHANNEL(cryptnet);
@@ -30,8 +42,6 @@ TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
switch (fdwReason) { - case DLL_WINE_PREATTACH: - return FALSE; /* prefer native version */ case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); break; @@ -43,13 +53,23 @@ return TRUE; }
+static const WCHAR cryptNet[] = { 'c','r','y','p','t','n','e','t','.', + 'd','l','l',0 }; +static const WCHAR ldapProvOpenStore[] = { 'L','d','a','p','P','r','o','v', + 'O','p','e','S','t','o','r','e',0 }; + /*********************************************************************** * DllRegisterServer (CRYPTNET.@) */ HRESULT WINAPI DllRegisterServer(void) { - FIXME("stub\n"); - + TRACE("\n"); + CryptRegisterDefaultOIDFunction(X509_ASN_ENCODING, + CRYPT_OID_VERIFY_REVOCATION_FUNC, 0, cryptNet); + CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap", + cryptNet, "LdapProvOpenStore"); + CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, + CERT_STORE_PROV_LDAP_W, cryptNet, "LdapProvOpenStore"); return S_OK; }
@@ -58,7 +78,1383 @@ */ HRESULT WINAPI DllUnregisterServer(void) { - FIXME("stub\n"); - + TRACE("\n"); + CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING, + CRYPT_OID_VERIFY_REVOCATION_FUNC, cryptNet); + CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap"); + CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, + CERT_STORE_PROV_LDAP_W); return S_OK; } + +static const char *url_oid_to_str(LPCSTR oid) +{ + if (HIWORD(oid)) + return oid; + else + { + static char buf[10]; + + switch (LOWORD(oid)) + { +#define _x(oid) case LOWORD(oid): return #oid + _x(URL_OID_CERTIFICATE_ISSUER); + _x(URL_OID_CERTIFICATE_CRL_DIST_POINT); + _x(URL_OID_CTL_ISSUER); + _x(URL_OID_CTL_NEXT_UPDATE); + _x(URL_OID_CRL_ISSUER); + _x(URL_OID_CERTIFICATE_FRESHEST_CRL); + _x(URL_OID_CRL_FRESHEST_CRL); + _x(URL_OID_CROSS_CERT_DIST_POINT); +#undef _x + default: + snprintf(buf, sizeof(buf), "%d", LOWORD(oid)); + return buf; + } + } +} + +typedef BOOL (WINAPI *UrlDllGetObjectUrlFunc)(LPCSTR, LPVOID, DWORD, + PCRYPT_URL_ARRAY, DWORD *, PCRYPT_URL_INFO, DWORD *, LPVOID); + +static BOOL WINAPI CRYPT_GetUrlFromCertificateIssuer(LPCSTR pszUrlOid, + LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, + PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved) +{ + /* FIXME: This depends on the AIA (authority info access) extension being + * supported in crypt32. + */ + FIXME("\n"); + SetLastError(CRYPT_E_NOT_FOUND); + return FALSE; +} + +static BOOL WINAPI CRYPT_GetUrlFromCertificateCRLDistPoint(LPCSTR pszUrlOid, + LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, + PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved) +{ + PCCERT_CONTEXT cert = (PCCERT_CONTEXT)pvPara; + PCERT_EXTENSION ext; + BOOL ret = FALSE; + + /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */ + if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION)) + { + SetLastError(CRYPT_E_NOT_FOUND); + return FALSE; + } + if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, + cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) + { + CRL_DIST_POINTS_INFO *info; + DWORD size; + + ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CRL_DIST_POINTS, + ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, + &info, &size); + if (ret) + { + DWORD i, cUrl, bytesNeeded = sizeof(CRYPT_URL_ARRAY); + + for (i = 0, cUrl = 0; i < info->cDistPoint; i++) + if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice + == CRL_DIST_POINT_FULL_NAME) + { + DWORD j; + CERT_ALT_NAME_INFO *name = + &info->rgDistPoint[i].DistPointName.u.FullName; + + for (j = 0; j < name->cAltEntry; j++) + if (name->rgAltEntry[j].dwAltNameChoice == + CERT_ALT_NAME_URL) + { + if (name->rgAltEntry[j].u.pwszURL) + { + cUrl++; + bytesNeeded += sizeof(LPWSTR) + + (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1) + * sizeof(WCHAR); + } + } + } + if (!pcbUrlArray) + { + SetLastError(E_INVALIDARG); + ret = FALSE; + } + else if (!pUrlArray) + *pcbUrlArray = bytesNeeded; + else if (*pcbUrlArray < bytesNeeded) + { + SetLastError(ERROR_MORE_DATA); + *pcbUrlArray = bytesNeeded; + ret = FALSE; + } + else + { + LPWSTR nextUrl; + + *pcbUrlArray = bytesNeeded; + pUrlArray->cUrl = 0; + pUrlArray->rgwszUrl = + (LPWSTR *)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY)); + nextUrl = (LPWSTR)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY) + + cUrl * sizeof(LPWSTR)); + for (i = 0; i < info->cDistPoint; i++) + if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice + == CRL_DIST_POINT_FULL_NAME) + { + DWORD j; + CERT_ALT_NAME_INFO *name = + &info->rgDistPoint[i].DistPointName.u.FullName; + + for (j = 0; j < name->cAltEntry; j++) + if (name->rgAltEntry[j].dwAltNameChoice == + CERT_ALT_NAME_URL) + { + if (name->rgAltEntry[j].u.pwszURL) + { + lstrcpyW(nextUrl, + name->rgAltEntry[j].u.pwszURL); + pUrlArray->rgwszUrl[pUrlArray->cUrl++] = + nextUrl; + nextUrl += + (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1) + * sizeof(WCHAR); + } + } + } + } + if (ret) + { + if (pcbUrlInfo) + { + FIXME("url info: stub\n"); + if (!pUrlInfo) + *pcbUrlInfo = sizeof(CRYPT_URL_INFO); + else if (*pcbUrlInfo < sizeof(CRYPT_URL_INFO)) + { + *pcbUrlInfo = sizeof(CRYPT_URL_INFO); + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + *pcbUrlInfo = sizeof(CRYPT_URL_INFO); + memset(pUrlInfo, 0, sizeof(CRYPT_URL_INFO)); + } + } + } + LocalFree(info); + } + } + else + SetLastError(CRYPT_E_NOT_FOUND); + return ret; +} + +/*********************************************************************** + * CryptGetObjectUrl (CRYPTNET.@) + */ +BOOL WINAPI CryptGetObjectUrl(LPCSTR pszUrlOid, LPVOID pvPara, DWORD dwFlags, + PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo, + DWORD *pcbUrlInfo, LPVOID pvReserved) +{ + UrlDllGetObjectUrlFunc func = NULL; + HCRYPTOIDFUNCADDR hFunc = NULL; + BOOL ret = FALSE; + + TRACE("(%s, %p, %08x, %p, %p, %p, %p, %p)\n", debugstr_a(pszUrlOid), + pvPara, dwFlags, pUrlArray, pcbUrlArray, pUrlInfo, pcbUrlInfo, pvReserved); + + if (!HIWORD(pszUrlOid)) + { + switch (LOWORD(pszUrlOid)) + { + case LOWORD(URL_OID_CERTIFICATE_ISSUER): + func = CRYPT_GetUrlFromCertificateIssuer; + break; + case LOWORD(URL_OID_CERTIFICATE_CRL_DIST_POINT): + func = CRYPT_GetUrlFromCertificateCRLDistPoint; + break; + default: + FIXME("unimplemented for %s\n", url_oid_to_str(pszUrlOid)); + SetLastError(ERROR_FILE_NOT_FOUND); + } + } + else + { + static HCRYPTOIDFUNCSET set = NULL; + + if (!set) + set = CryptInitOIDFunctionSet(URL_OID_GET_OBJECT_URL_FUNC, 0); + CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszUrlOid, 0, + (void **)&func, &hFunc); + } + if (func) + ret = func(pszUrlOid, pvPara, dwFlags, pUrlArray, pcbUrlArray, + pUrlInfo, pcbUrlInfo, pvReserved); + if (hFunc) + CryptFreeOIDFunctionAddress(hFunc, 0); + return ret; +} + +/*********************************************************************** + * CryptRetrieveObjectByUrlA (CRYPTNET.@) + */ +BOOL WINAPI CryptRetrieveObjectByUrlA(LPCSTR pszURL, LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject, + HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, + PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) +{ + BOOL ret = FALSE; + int len; + + TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_a(pszURL), + debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject, + hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo); + + if (!pszURL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + len = MultiByteToWideChar(CP_ACP, 0, pszURL, -1, NULL, 0); + if (len) + { + LPWSTR url = CryptMemAlloc(len * sizeof(WCHAR)); + + if (url) + { + MultiByteToWideChar(CP_ACP, 0, pszURL, -1, url, len); + ret = CryptRetrieveObjectByUrlW(url, pszObjectOid, + dwRetrievalFlags, dwTimeout, ppvObject, hAsyncRetrieve, + pCredentials, pvVerify, pAuxInfo); + CryptMemFree(url); + } + else + SetLastError(ERROR_OUTOFMEMORY); + } + return ret; +} + +static void WINAPI CRYPT_FreeBlob(LPCSTR pszObjectOid, + PCRYPT_BLOB_ARRAY pObject, void *pvFreeContext) +{ + DWORD i; + + for (i = 0; i < pObject->cBlob; i++) + CryptMemFree(pObject->rgBlob[i].pbData); + CryptMemFree(pObject->rgBlob); +} + +static BOOL CRYPT_GetObjectFromFile(HANDLE hFile, PCRYPT_BLOB_ARRAY pObject) +{ + BOOL ret; + LARGE_INTEGER size; + + if ((ret = GetFileSizeEx(hFile, &size))) + { + if (size.u.HighPart) + { + WARN("file too big\n"); + SetLastError(ERROR_INVALID_DATA); + ret = FALSE; + } + else + { + CRYPT_DATA_BLOB blob; + + blob.pbData = CryptMemAlloc(size.u.LowPart); + if (blob.pbData) + { + blob.cbData = size.u.LowPart; + ret = ReadFile(hFile, blob.pbData, size.u.LowPart, &blob.cbData, + NULL); + if (ret) + { + pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB)); + if (pObject->rgBlob) + { + pObject->cBlob = 1; + memcpy(pObject->rgBlob, &blob, sizeof(CRYPT_DATA_BLOB)); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + if (!ret) + CryptMemFree(blob.pbData); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + } + 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) +{ + BOOL ret = FALSE; + INTERNET_CACHE_ENTRY_INFOW cacheInfo = { sizeof(cacheInfo), 0 }; + DWORD size = sizeof(cacheInfo); + + TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pObject, pAuxInfo); + + if (GetUrlCacheEntryInfoW(pszURL, &cacheInfo, &size) || + GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + if (CompareFileTime(&cacheInfo.ExpireTime, &ft) >= 0) + { + LPINTERNET_CACHE_ENTRY_INFOW pCacheInfo = CryptMemAlloc(size); + + if (pCacheInfo) + { + if (GetUrlCacheEntryInfoW(pszURL, pCacheInfo, &size)) + { + HANDLE hFile = CreateFileW(pCacheInfo->lpszLocalFileName, + GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile != INVALID_HANDLE_VALUE) + { + if ((ret = CRYPT_GetObjectFromFile(hFile, pObject))) + { + if (pAuxInfo && pAuxInfo->cbSize >= + offsetof(CRYPT_RETRIEVE_AUX_INFO, + pLastSyncTime) + sizeof(PFILETIME) && + pAuxInfo->pLastSyncTime) + memcpy(pAuxInfo->pLastSyncTime, + &pCacheInfo->LastSyncTime, + sizeof(FILETIME)); + } + CloseHandle(hFile); + } + } + CryptMemFree(pCacheInfo); + } + else + SetLastError(ERROR_OUTOFMEMORY); + } + else + DeleteUrlCacheEntryW(pszURL); + } + TRACE("returning %d\n", ret); + return ret; +} + +static inline LPWSTR strndupW(LPWSTR string, int len) +{ + LPWSTR ret = NULL; + if (string && (ret = CryptMemAlloc((len + 1) * sizeof(WCHAR))) != NULL) + { + memcpy(ret, string, len * sizeof(WCHAR)); + ret[len] = 0; + } + return ret; +} + +/* Parses the URL, and sets components's lpszHostName and lpszUrlPath members + * to NULL-terminated copies of those portions of the URL (to be freed with + * CryptMemFree.) + */ +static BOOL CRYPT_CrackUrl(LPCWSTR pszURL, URL_COMPONENTSW *components) +{ + BOOL ret; + + TRACE("(%s, %p)\n", debugstr_w(pszURL), components); + + memset(components, 0, sizeof(*components)); + components->dwStructSize = sizeof(*components); + components->dwHostNameLength = 1; + components->dwUrlPathLength = 1; + ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, components); + if (ret) + { + LPWSTR hostname = strndupW(components->lpszHostName, + components->dwHostNameLength); + LPWSTR path = strndupW(components->lpszUrlPath, + components->dwUrlPathLength); + + components->lpszHostName = hostname; + components->lpszUrlPath = path; + switch (components->nScheme) + { + case INTERNET_SCHEME_FTP: + if (!components->nPort) + components->nPort = INTERNET_DEFAULT_FTP_PORT; + break; + case INTERNET_SCHEME_HTTP: + if (!components->nPort) + components->nPort = INTERNET_DEFAULT_HTTP_PORT; + break; + default: + ; /* do nothing */ + } + } + TRACE("returning %d\n", ret); + return ret; +} + +struct InetContext +{ + HANDLE event; + DWORD timeout; + DWORD error; +}; + +static struct InetContext *CRYPT_MakeInetContext(DWORD dwTimeout) +{ + struct InetContext *context = CryptMemAlloc(sizeof(struct InetContext)); + + if (context) + { + context->event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!context->event) + { + CryptMemFree(context); + context = NULL; + } + else + { + context->timeout = dwTimeout; + context->error = ERROR_SUCCESS; + } + } + return context; +} + +static BOOL CRYPT_DownloadObject(DWORD dwRetrievalFlags, HINTERNET hHttp, + struct InetContext *context, PCRYPT_BLOB_ARRAY pObject, + PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) +{ + CRYPT_DATA_BLOB object = { 0, NULL }; + DWORD bytesAvailable; + BOOL ret; + + do { + if ((ret = InternetQueryDataAvailable(hHttp, &bytesAvailable, 0, 0))) + { + if (bytesAvailable) + { + if (object.pbData) + object.pbData = CryptMemRealloc(object.pbData, + object.cbData + bytesAvailable); + else + object.pbData = CryptMemAlloc(bytesAvailable); + if (object.pbData) + { + INTERNET_BUFFERSA buffer = { sizeof(buffer), 0 }; + + buffer.dwBufferLength = bytesAvailable; + buffer.lpvBuffer = object.pbData + object.cbData; + if (!(ret = InternetReadFileExA(hHttp, &buffer, IRF_NO_WAIT, + (DWORD_PTR)context))) + { + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(context->event, + context->timeout) == WAIT_TIMEOUT) + SetLastError(ERROR_TIMEOUT); + else if (context->error) + SetLastError(context->error); + else + ret = TRUE; + } + } + if (ret) + object.cbData += bytesAvailable; + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + } + else if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(context->event, context->timeout) == + WAIT_TIMEOUT) + SetLastError(ERROR_TIMEOUT); + else + ret = TRUE; + } + } while (ret && bytesAvailable); + if (ret) + { + pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB)); + if (!pObject->rgBlob) + { + CryptMemFree(object.pbData); + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + else + { + pObject->rgBlob[0].cbData = object.cbData; + pObject->rgBlob[0].pbData = object.pbData; + pObject->cBlob = 1; + } + } + TRACE("returning %d\n", ret); + return ret; +} + +static void CRYPT_CacheURL(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject, + DWORD dwRetrievalFlags, FILETIME expires) +{ + WCHAR cacheFileName[MAX_PATH]; + + /* FIXME: let wininet directly cache instead */ + if (CreateUrlCacheEntryW(pszURL, pObject->rgBlob[0].cbData, NULL, + cacheFileName, 0)) + { + HANDLE hCacheFile = CreateFileW(cacheFileName, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hCacheFile != INVALID_HANDLE_VALUE) + { + DWORD bytesWritten, entryType; + FILETIME ft = { 0 }; + + 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); + } + } +} + +static void CALLBACK CRYPT_InetStatusCallback(HINTERNET hInt, + DWORD_PTR dwContext, DWORD status, void *statusInfo, DWORD statusInfoLen) +{ + struct InetContext *context = (struct InetContext *)dwContext; + LPINTERNET_ASYNC_RESULT result; + + switch (status) + { + case INTERNET_STATUS_REQUEST_COMPLETE: + result = (LPINTERNET_ASYNC_RESULT)statusInfo; + context->error = result->dwError; + SetEvent(context->event); + } +} + +static BOOL CRYPT_Connect(URL_COMPONENTSW *components, + struct InetContext *context, PCRYPT_CREDENTIALS pCredentials, + HINTERNET *phInt, HINTERNET *phHost) +{ + BOOL ret; + + TRACE("(%s:%d, %p, %p, %p, %p)\n", debugstr_w(components->lpszHostName), + components->nPort, context, pCredentials, phInt, phInt); + + *phHost = NULL; + *phInt = InternetOpenW(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, + context ? INTERNET_FLAG_ASYNC : 0); + if (*phInt) + { + DWORD service; + + if (context) + InternetSetStatusCallbackW(*phInt, CRYPT_InetStatusCallback); + switch (components->nScheme) + { + case INTERNET_SCHEME_FTP: + service = INTERNET_SERVICE_FTP; + break; + case INTERNET_SCHEME_HTTP: + service = INTERNET_SERVICE_HTTP; + break; + default: + service = 0; + } + /* FIXME: use pCredentials for username/password */ + *phHost = InternetConnectW(*phInt, components->lpszHostName, + components->nPort, NULL, NULL, service, 0, (DWORD_PTR)context); + if (!*phHost) + { + InternetCloseHandle(*phInt); + *phInt = NULL; + ret = FALSE; + } + else + ret = TRUE; + } + else + ret = FALSE; + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL WINAPI FTP_RetrieveEncodedObjectW(LPCWSTR pszURL, + LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, + PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, + void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, + PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) +{ + FIXME("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), + debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject, + ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo); + + pObject->cBlob = 0; + pObject->rgBlob = NULL; + *ppfnFreeObject = CRYPT_FreeBlob; + *ppvFreeContext = NULL; + return FALSE; +} + +static const WCHAR x509cacert[] = { 'a','p','p','l','i','c','a','t','i','o','n', + '/','x','-','x','5','0','9','-','c','a','-','c','e','r','t',0 }; +static const WCHAR x509emailcert[] = { 'a','p','p','l','i','c','a','t','i','o', + 'n','/','x','-','x','5','0','9','-','e','m','a','i','l','-','c','e','r','t', + 0 }; +static const WCHAR x509servercert[] = { 'a','p','p','l','i','c','a','t','i','o', + 'n','/','x','-','x','5','0','9','-','s','e','r','v','e','r','-','c','e','r', + 't',0 }; +static const WCHAR x509usercert[] = { 'a','p','p','l','i','c','a','t','i','o', + 'n','/','x','-','x','5','0','9','-','u','s','e','r','-','c','e','r','t',0 }; +static const WCHAR pkcs7cert[] = { 'a','p','p','l','i','c','a','t','i','o','n', + '/','x','-','p','k','c','s','7','-','c','e','r','t','i','f','c','a','t','e', + 's',0 }; +static const WCHAR pkixCRL[] = { 'a','p','p','l','i','c','a','t','i','o','n', + '/','p','k','i','x','-','c','r','l',0 }; +static const WCHAR pkcs7CRL[] = { 'a','p','p','l','i','c','a','t','i','o','n', + '/','x','-','p','k','c','s','7','-','c','r','l',0 }; +static const WCHAR pkcs7sig[] = { 'a','p','p','l','i','c','a','t','i','o','n', + '/','x','-','p','k','c','s','7','-','s','i','g','n','a','t','u','r','e',0 }; +static const WCHAR pkcs7mime[] = { 'a','p','p','l','i','c','a','t','i','o','n', + '/','x','-','p','k','c','s','7','-','m','i','m','e',0 }; + +static BOOL WINAPI HTTP_RetrieveEncodedObjectW(LPCWSTR pszURL, + LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, + PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, + void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, + PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) +{ + BOOL ret = FALSE; + + TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), + debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject, + ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo); + + pObject->cBlob = 0; + pObject->rgBlob = NULL; + *ppfnFreeObject = CRYPT_FreeBlob; + *ppvFreeContext = NULL; + + if (!(dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL)) + ret = CRYPT_GetObjectFromCache(pszURL, pObject, pAuxInfo); + if (!ret && (!(dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) || + (dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL))) + { + URL_COMPONENTSW components; + + if ((ret = CRYPT_CrackUrl(pszURL, &components))) + { + HINTERNET hInt, hHost; + struct InetContext *context = NULL; + + if (dwTimeout) + context = CRYPT_MakeInetContext(dwTimeout); + ret = CRYPT_Connect(&components, context, pCredentials, &hInt, + &hHost); + if (ret) + { + static LPCWSTR types[] = { x509cacert, x509emailcert, + x509servercert, x509usercert, pkcs7cert, pkixCRL, pkcs7CRL, + pkcs7sig, pkcs7mime, NULL }; + HINTERNET hHttp = HttpOpenRequestW(hHost, NULL, + components.lpszUrlPath, NULL, NULL, types, + INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI, + (DWORD_PTR)context); + + if (hHttp) + { + if (dwTimeout) + { + InternetSetOptionW(hHttp, + INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, + sizeof(dwTimeout)); + InternetSetOptionW(hHttp, INTERNET_OPTION_SEND_TIMEOUT, + &dwTimeout, sizeof(dwTimeout)); + } + ret = HttpSendRequestExW(hHttp, NULL, NULL, 0, + (DWORD_PTR)context); + if (!ret && GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(context->event, + context->timeout) == WAIT_TIMEOUT) + SetLastError(ERROR_TIMEOUT); + else + ret = TRUE; + } + /* We don't set ret to TRUE in this block to avoid masking + * an error from HttpSendRequestExW. + */ + if (!HttpEndRequestW(hHttp, NULL, 0, (DWORD_PTR)context) && + GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(context->event, + context->timeout) == WAIT_TIMEOUT) + { + SetLastError(ERROR_TIMEOUT); + ret = FALSE; + } + } + if (ret) + ret = CRYPT_DownloadObject(dwRetrievalFlags, hHttp, + context, pObject, pAuxInfo); + if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT)) + { + SYSTEMTIME st; + DWORD len = sizeof(st); + + if (HttpQueryInfoW(hHttp, + HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME, &st, + &len, NULL)) + { + FILETIME ft; + + SystemTimeToFileTime(&st, &ft); + CRYPT_CacheURL(pszURL, pObject, dwRetrievalFlags, + ft); + } + } + InternetCloseHandle(hHttp); + } + InternetCloseHandle(hHost); + InternetCloseHandle(hInt); + } + if (context) + { + CloseHandle(context->event); + CryptMemFree(context); + } + CryptMemFree(components.lpszUrlPath); + CryptMemFree(components.lpszHostName); + } + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL WINAPI File_RetrieveEncodedObjectW(LPCWSTR pszURL, + LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, + PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, + void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, + PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) +{ + URL_COMPONENTSW components = { sizeof(components), 0 }; + BOOL ret; + + TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), + debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject, + ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo); + + pObject->cBlob = 0; + pObject->rgBlob = NULL; + *ppfnFreeObject = CRYPT_FreeBlob; + *ppvFreeContext = NULL; + + components.dwUrlPathLength = 1; + ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, &components); + if (ret) + { + LPWSTR path; + + /* 3 == lstrlenW(L"c:") + 1 */ + path = CryptMemAlloc((components.dwUrlPathLength + 3) * sizeof(WCHAR)); + if (path) + { + HANDLE hFile; + + /* Try to create the file directly - Wine handles / in pathnames */ + lstrcpynW(path, components.lpszUrlPath, + components.dwUrlPathLength + 1); + hFile = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + /* Try again on the current drive */ + GetCurrentDirectoryW(components.dwUrlPathLength, path); + if (path[1] == ':') + { + lstrcpynW(path + 2, components.lpszUrlPath, + components.dwUrlPathLength + 1); + hFile = CreateFileW(path, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + if (hFile == INVALID_HANDLE_VALUE) + { + /* Try again on the Windows drive */ + GetWindowsDirectoryW(path, components.dwUrlPathLength); + if (path[1] == ':') + { + lstrcpynW(path + 2, components.lpszUrlPath, + components.dwUrlPathLength + 1); + hFile = CreateFileW(path, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + } + if (hFile != INVALID_HANDLE_VALUE) + { + if ((ret = CRYPT_GetObjectFromFile(hFile, pObject))) + { + if (pAuxInfo && pAuxInfo->cbSize >= + offsetof(CRYPT_RETRIEVE_AUX_INFO, + pLastSyncTime) + sizeof(PFILETIME) && + pAuxInfo->pLastSyncTime) + GetFileTime(hFile, NULL, NULL, + pAuxInfo->pLastSyncTime); + } + CloseHandle(hFile); + } + else + ret = FALSE; + CryptMemFree(path); + } + } + return ret; +} + +typedef BOOL (WINAPI *SchemeDllRetrieveEncodedObjectW)(LPCWSTR pwszUrl, + LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, + PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject, + void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, + PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo); + +static BOOL CRYPT_GetRetrieveFunction(LPCWSTR pszURL, + SchemeDllRetrieveEncodedObjectW *pFunc, HCRYPTOIDFUNCADDR *phFunc) +{ + URL_COMPONENTSW components = { sizeof(components), 0 }; + BOOL ret; + + TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pFunc, phFunc); + + *pFunc = NULL; + *phFunc = 0; + components.dwSchemeLength = 1; + ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, &components); + if (ret) + { + /* Microsoft always uses CryptInitOIDFunctionSet/ + * CryptGetOIDFunctionAddress, but there doesn't seem to be a pressing + * reason to do so for builtin schemes. + */ + switch (components.nScheme) + { + case INTERNET_SCHEME_FTP: + *pFunc = FTP_RetrieveEncodedObjectW; + break; + case INTERNET_SCHEME_HTTP: + *pFunc = HTTP_RetrieveEncodedObjectW; + break; + case INTERNET_SCHEME_FILE: + *pFunc = File_RetrieveEncodedObjectW; + break; + default: + { + int len = WideCharToMultiByte(CP_ACP, 0, components.lpszScheme, + components.dwSchemeLength, NULL, 0, NULL, NULL); + + if (len) + { + LPSTR scheme = CryptMemAlloc(len); + + if (scheme) + { + static HCRYPTOIDFUNCSET set = NULL; + + if (!set) + set = CryptInitOIDFunctionSet( + SCHEME_OID_RETRIEVE_ENCODED_OBJECTW_FUNC, 0); + WideCharToMultiByte(CP_ACP, 0, components.lpszScheme, + components.dwSchemeLength, scheme, len, NULL, NULL); + ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, + scheme, 0, (void **)pFunc, phFunc); + CryptMemFree(scheme); + } + else + { + SetLastError(ERROR_OUTOFMEMORY); + ret = FALSE; + } + } + else + ret = FALSE; + } + } + } + TRACE("returning %d\n", ret); + return ret; +} + +static BOOL WINAPI CRYPT_CreateBlob(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext) +{ + DWORD size, i; + CRYPT_BLOB_ARRAY *context; + BOOL ret = FALSE; + + size = sizeof(CRYPT_BLOB_ARRAY) + pObject->cBlob * sizeof(CRYPT_DATA_BLOB); + for (i = 0; i < pObject->cBlob; i++) + size += pObject->rgBlob[i].cbData; + context = CryptMemAlloc(size); + if (context) + { + LPBYTE nextData; + + context->cBlob = 0; + context->rgBlob = + (CRYPT_DATA_BLOB *)((LPBYTE)context + sizeof(CRYPT_BLOB_ARRAY)); + nextData = + (LPBYTE)context->rgBlob + pObject->cBlob * sizeof(CRYPT_DATA_BLOB); + for (i = 0; i < pObject->cBlob; i++) + { + memcpy(nextData, pObject->rgBlob[i].pbData, + pObject->rgBlob[i].cbData); + context->rgBlob[i].pbData = nextData; + context->rgBlob[i].cbData = pObject->rgBlob[i].cbData; + nextData += pObject->rgBlob[i].cbData; + context->cBlob++; + } + *ppvContext = context; + ret = TRUE; + } + return ret; +} + +typedef BOOL (WINAPI *AddContextToStore)(HCERTSTORE hCertStore, + const void *pContext, DWORD dwAddDisposition, const void **ppStoreContext); + +static BOOL CRYPT_CreateContext(PCRYPT_BLOB_ARRAY pObject, + DWORD dwExpectedContentTypeFlags, AddContextToStore addFunc, void **ppvContext) +{ + BOOL ret = TRUE; + + if (!pObject->cBlob) + { + SetLastError(ERROR_INVALID_DATA); + *ppvContext = NULL; + ret = FALSE; + } + else if (pObject->cBlob == 1) + { + if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pObject->rgBlob[0], + dwExpectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, + NULL, NULL, NULL, NULL, (const void **)ppvContext)) + { + SetLastError(CRYPT_E_NO_MATCH); + ret = FALSE; + } + } + else + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (store) + { + DWORD i; + const void *context; + + for (i = 0; i < pObject->cBlob; i++) + { + if (CryptQueryObject(CERT_QUERY_OBJECT_BLOB, + &pObject->rgBlob[i], dwExpectedContentTypeFlags, + CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, NULL, + NULL, &context)) + { + if (!addFunc(store, context, CERT_STORE_ADD_ALWAYS, NULL)) + ret = FALSE; + } + else + { + SetLastError(CRYPT_E_NO_MATCH); + ret = FALSE; + } + } + } + else + ret = FALSE; + *ppvContext = store; + } + return ret; +} + +static BOOL WINAPI CRYPT_CreateCert(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext) +{ + return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CERT, + (AddContextToStore)CertAddCertificateContextToStore, ppvContext); +} + +static BOOL WINAPI CRYPT_CreateCRL(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext) +{ + return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CRL, + (AddContextToStore)CertAddCRLContextToStore, ppvContext); +} + +static BOOL WINAPI CRYPT_CreateCTL(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext) +{ + return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CTL, + (AddContextToStore)CertAddCTLContextToStore, ppvContext); +} + +static BOOL WINAPI CRYPT_CreatePKCS7(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext) +{ + BOOL ret; + + if (!pObject->cBlob) + { + SetLastError(ERROR_INVALID_DATA); + *ppvContext = NULL; + ret = FALSE; + } + else if (pObject->cBlob == 1) + ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pObject->rgBlob[0], + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | + CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED, CERT_QUERY_FORMAT_FLAG_BINARY, + 0, NULL, NULL, NULL, (HCERTSTORE *)ppvContext, NULL, NULL); + else + { + FIXME("multiple messages unimplemented\n"); + ret = FALSE; + } + return ret; +} + +static BOOL WINAPI CRYPT_CreateAny(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext) +{ + BOOL ret; + + if (!pObject->cBlob) + { + SetLastError(ERROR_INVALID_DATA); + *ppvContext = NULL; + ret = FALSE; + } + else + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (store) + { + HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (memStore) + { + CertAddStoreToCollection(store, memStore, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + CertCloseStore(memStore, 0); + } + else + { + CertCloseStore(store, 0); + store = NULL; + } + } + if (store) + { + DWORD i; + + ret = TRUE; + for (i = 0; i < pObject->cBlob; i++) + { + DWORD contentType, expectedContentTypes = + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | + CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED | + CERT_QUERY_CONTENT_FLAG_CERT | + CERT_QUERY_CONTENT_FLAG_CRL | + CERT_QUERY_CONTENT_FLAG_CTL; + HCERTSTORE contextStore; + const void *context; + + if (CryptQueryObject(CERT_QUERY_OBJECT_BLOB, + &pObject->rgBlob[i], expectedContentTypes, + CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, &contentType, NULL, + &contextStore, NULL, &context)) + { + switch (contentType) + { + case CERT_QUERY_CONTENT_CERT: + if (!CertAddCertificateContextToStore(store, + (PCCERT_CONTEXT)context, CERT_STORE_ADD_ALWAYS, NULL)) + ret = FALSE; + break; + case CERT_QUERY_CONTENT_CRL: + if (!CertAddCRLContextToStore(store, + (PCCRL_CONTEXT)context, CERT_STORE_ADD_ALWAYS, NULL)) + ret = FALSE; + break; + case CERT_QUERY_CONTENT_CTL: + if (!CertAddCTLContextToStore(store, + (PCCTL_CONTEXT)context, CERT_STORE_ADD_ALWAYS, NULL)) + ret = FALSE; + break; + default: + CertAddStoreToCollection(store, contextStore, 0, 0); + } + } + else + ret = FALSE; + } + } + else + ret = FALSE; + *ppvContext = store; + } + return ret; +} + +typedef BOOL (WINAPI *ContextDllCreateObjectContext)(LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, void **ppvContext); + +static BOOL CRYPT_GetCreateFunction(LPCSTR pszObjectOid, + ContextDllCreateObjectContext *pFunc, HCRYPTOIDFUNCADDR *phFunc) +{ + BOOL ret = TRUE; + + TRACE("(%s, %p, %p)\n", debugstr_a(pszObjectOid), pFunc, phFunc); + + *pFunc = NULL; + *phFunc = 0; + if (!HIWORD(pszObjectOid)) + { + switch (LOWORD(pszObjectOid)) + { + case 0: + *pFunc = CRYPT_CreateBlob; + break; + case LOWORD(CONTEXT_OID_CERTIFICATE): + *pFunc = CRYPT_CreateCert; + break; + case LOWORD(CONTEXT_OID_CRL): + *pFunc = CRYPT_CreateCRL; + break; + case LOWORD(CONTEXT_OID_CTL): + *pFunc = CRYPT_CreateCTL; + break; + case LOWORD(CONTEXT_OID_PKCS7): + *pFunc = CRYPT_CreatePKCS7; + break; + case LOWORD(CONTEXT_OID_CAPI2_ANY): + *pFunc = CRYPT_CreateAny; + break; + } + } + if (!*pFunc) + { + static HCRYPTOIDFUNCSET set = NULL; + + if (!set) + set = CryptInitOIDFunctionSet( + CONTEXT_OID_CREATE_OBJECT_CONTEXT_FUNC, 0); + ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszObjectOid, + 0, (void **)pFunc, phFunc); + } + TRACE("returning %d\n", ret); + return ret; +} + +/*********************************************************************** + * CryptRetrieveObjectByUrlW (CRYPTNET.@) + */ +BOOL WINAPI CryptRetrieveObjectByUrlW(LPCWSTR pszURL, LPCSTR pszObjectOid, + DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject, + HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, + PCRYPT_RETRIEVE_AUX_INFO pAuxInfo) +{ + BOOL ret; + SchemeDllRetrieveEncodedObjectW retrieve; + ContextDllCreateObjectContext create; + HCRYPTOIDFUNCADDR hRetrieve = 0, hCreate = 0; + + TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL), + debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject, + hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo); + + if (!pszURL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + ret = CRYPT_GetRetrieveFunction(pszURL, &retrieve, &hRetrieve); + if (ret) + ret = CRYPT_GetCreateFunction(pszObjectOid, &create, &hCreate); + if (ret) + { + CRYPT_BLOB_ARRAY object = { 0, NULL }; + PFN_FREE_ENCODED_OBJECT_FUNC freeObject; + void *freeContext; + + ret = retrieve(pszURL, pszObjectOid, dwRetrievalFlags, dwTimeout, + &object, &freeObject, &freeContext, hAsyncRetrieve, pCredentials, + pAuxInfo); + if (ret) + { + ret = create(pszObjectOid, dwRetrievalFlags, &object, ppvObject); + freeObject(pszObjectOid, &object, freeContext); + } + } + if (hCreate) + CryptFreeOIDFunctionAddress(hCreate, 0); + if (hRetrieve) + CryptFreeOIDFunctionAddress(hRetrieve, 0); + TRACE("returning %d\n", ret); + return ret; +} + +typedef struct _OLD_CERT_REVOCATION_STATUS { + DWORD cbSize; + DWORD dwIndex; + DWORD dwError; + DWORD dwReason; +} OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS; + +/*********************************************************************** + * CertDllVerifyRevocation (CRYPTNET.@) + */ +BOOL WINAPI CertDllVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType, + DWORD cContext, PVOID rgpvContext[], DWORD dwFlags, + PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus) +{ + DWORD error = 0, i; + BOOL ret; + + TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType, + cContext, rgpvContext, dwFlags, pRevPara, pRevStatus); + + if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) && + pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS)) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + memset(&pRevStatus->dwIndex, 0, pRevStatus->cbSize - sizeof(DWORD)); + if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE) + { + error = CRYPT_E_NO_REVOCATION_CHECK; + ret = FALSE; + } + else + { + ret = TRUE; + for (i = 0; ret && i < cContext; i++) + { + DWORD cbUrlArray; + + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + rgpvContext[i], 0, NULL, &cbUrlArray, NULL, NULL, NULL); + if (!ret && GetLastError() == CRYPT_E_NOT_FOUND) + { + error = CRYPT_E_NO_REVOCATION_CHECK; + pRevStatus->dwIndex = i; + } + else if (ret) + { + CRYPT_URL_ARRAY *urlArray = CryptMemAlloc(cbUrlArray); + + if (urlArray) + { + DWORD j, retrievalFlags = 0, startTime, endTime, timeout; + + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + rgpvContext[i], 0, urlArray, &cbUrlArray, NULL, NULL, + NULL); + if (dwFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION) + retrievalFlags |= CRYPT_CACHE_ONLY_RETRIEVAL; + if (dwFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG && + pRevPara->cbSize >= offsetof(CERT_REVOCATION_PARA, + dwUrlRetrievalTimeout) + sizeof(DWORD)) + { + startTime = GetTickCount(); + endTime = startTime + pRevPara->dwUrlRetrievalTimeout; + timeout = pRevPara->dwUrlRetrievalTimeout; + } + else + endTime = timeout = 0; + for (j = 0; ret && j < urlArray->cUrl; j++) + { + PCCRL_CONTEXT crl; + + ret = CryptRetrieveObjectByUrlW(urlArray->rgwszUrl[j], + CONTEXT_OID_CRL, retrievalFlags, timeout, + (void **)&crl, NULL, NULL, NULL, NULL); + if (ret) + { + PCRL_ENTRY entry = NULL; + + CertFindCertificateInCRL( + (PCCERT_CONTEXT)rgpvContext[i], crl, 0, NULL, + &entry); + if (entry) + { + error = CRYPT_E_REVOKED; + pRevStatus->dwIndex = i; + ret = FALSE; + } + else if (timeout) + { + DWORD time = GetTickCount(); + + if ((int)(endTime - time) <= 0) + { + error = ERROR_TIMEOUT; + pRevStatus->dwIndex = i; + ret = FALSE; + } + else + timeout = endTime - time; + } + CertFreeCRLContext(crl); + } + else + error = CRYPT_E_REVOCATION_OFFLINE; + } + CryptMemFree(urlArray); + } + else + { + error = ERROR_OUTOFMEMORY; + pRevStatus->dwIndex = i; + ret = FALSE; + } + } + else + pRevStatus->dwIndex = i; + } + } + + if (!ret) + { + SetLastError(error); + pRevStatus->dwError = error; + } + TRACE("returning %d (%08x)\n", ret, error); + return ret; +}