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/cryptne…
==============================================================================
--- 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/cryptne…
==============================================================================
--- 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/cryptne…
==============================================================================
--- 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;
+}