~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/cryptnet/cryptnet_main.c

Version: ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright (C) 2006 Maarten Lankhorst
  3  * Copyright 2007 Juan Lang
  4  *
  5  * This library is free software; you can redistribute it and/or
  6  * modify it under the terms of the GNU Lesser General Public
  7  * License as published by the Free Software Foundation; either
  8  * version 2.1 of the License, or (at your option) any later version.
  9  *
 10  * This library is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  * Lesser General Public License for more details.
 14  *
 15  * You should have received a copy of the GNU Lesser General Public
 16  * License along with this library; if not, write to the Free Software
 17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 18  *
 19  */
 20 
 21 #include "config.h"
 22 #include "wine/port.h"
 23 #include <stdio.h>
 24 
 25 #define NONAMELESSUNION
 26 #define NONAMELESSSTRUCT
 27 
 28 #include "windef.h"
 29 #include "wine/debug.h"
 30 #include "winbase.h"
 31 #include "winnt.h"
 32 #include "winnls.h"
 33 #include "wininet.h"
 34 #include "objbase.h"
 35 #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
 36 #include "wincrypt.h"
 37 
 38 WINE_DEFAULT_DEBUG_CHANNEL(cryptnet);
 39 
 40 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 41 {
 42    TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
 43 
 44    switch (fdwReason) {
 45       case DLL_PROCESS_ATTACH:
 46          DisableThreadLibraryCalls(hinstDLL);
 47          break;
 48       case DLL_PROCESS_DETACH:
 49          /* Do uninitialisation here */
 50          break;
 51       default: break;
 52    }
 53    return TRUE;
 54 }
 55 
 56 static const WCHAR cryptNet[] = { 'c','r','y','p','t','n','e','t','.',
 57    'd','l','l',0 };
 58 static const WCHAR ldapProvOpenStore[] = { 'L','d','a','p','P','r','o','v',
 59    'O','p','e','S','t','o','r','e',0 };
 60 
 61 /***********************************************************************
 62  *    DllRegisterServer (CRYPTNET.@)
 63  */
 64 HRESULT WINAPI DllRegisterServer(void)
 65 {
 66    TRACE("\n");
 67    CryptRegisterDefaultOIDFunction(X509_ASN_ENCODING,
 68     CRYPT_OID_VERIFY_REVOCATION_FUNC, 0, cryptNet);
 69    CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap",
 70     cryptNet, "LdapProvOpenStore");
 71    CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC,
 72     CERT_STORE_PROV_LDAP_W, cryptNet, "LdapProvOpenStore");
 73    return S_OK;
 74 }
 75 
 76 /***********************************************************************
 77  *    DllUnregisterServer (CRYPTNET.@)
 78  */
 79 HRESULT WINAPI DllUnregisterServer(void)
 80 {
 81    TRACE("\n");
 82    CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING,
 83     CRYPT_OID_VERIFY_REVOCATION_FUNC, cryptNet);
 84    CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap");
 85    CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC,
 86     CERT_STORE_PROV_LDAP_W);
 87    return S_OK;
 88 }
 89 
 90 static const char *url_oid_to_str(LPCSTR oid)
 91 {
 92     if (HIWORD(oid))
 93         return oid;
 94     else
 95     {
 96         static char buf[10];
 97 
 98         switch (LOWORD(oid))
 99         {
100 #define _x(oid) case LOWORD(oid): return #oid
101         _x(URL_OID_CERTIFICATE_ISSUER);
102         _x(URL_OID_CERTIFICATE_CRL_DIST_POINT);
103         _x(URL_OID_CTL_ISSUER);
104         _x(URL_OID_CTL_NEXT_UPDATE);
105         _x(URL_OID_CRL_ISSUER);
106         _x(URL_OID_CERTIFICATE_FRESHEST_CRL);
107         _x(URL_OID_CRL_FRESHEST_CRL);
108         _x(URL_OID_CROSS_CERT_DIST_POINT);
109 #undef _x
110         default:
111             snprintf(buf, sizeof(buf), "%d", LOWORD(oid));
112             return buf;
113         }
114     }
115 }
116 
117 typedef BOOL (WINAPI *UrlDllGetObjectUrlFunc)(LPCSTR, LPVOID, DWORD,
118  PCRYPT_URL_ARRAY, DWORD *, PCRYPT_URL_INFO, DWORD *, LPVOID);
119 
120 static BOOL WINAPI CRYPT_GetUrlFromCertificateIssuer(LPCSTR pszUrlOid,
121  LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray,
122  PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved)
123 {
124     /* FIXME: This depends on the AIA (authority info access) extension being
125      * supported in crypt32.
126      */
127     FIXME("\n");
128     SetLastError(CRYPT_E_NOT_FOUND);
129     return FALSE;
130 }
131 
132 static BOOL WINAPI CRYPT_GetUrlFromCertificateCRLDistPoint(LPCSTR pszUrlOid,
133  LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray,
134  PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved)
135 {
136     PCCERT_CONTEXT cert = (PCCERT_CONTEXT)pvPara;
137     PCERT_EXTENSION ext;
138     BOOL ret = FALSE;
139 
140     /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */
141     if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION))
142     {
143         SetLastError(CRYPT_E_NOT_FOUND);
144         return FALSE;
145     }
146     if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS,
147      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
148     {
149         CRL_DIST_POINTS_INFO *info;
150         DWORD size;
151 
152         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CRL_DIST_POINTS,
153          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
154          &info, &size);
155         if (ret)
156         {
157             DWORD i, cUrl, bytesNeeded = sizeof(CRYPT_URL_ARRAY);
158 
159             for (i = 0, cUrl = 0; i < info->cDistPoint; i++)
160                 if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice
161                  == CRL_DIST_POINT_FULL_NAME)
162                 {
163                     DWORD j;
164                     CERT_ALT_NAME_INFO *name =
165                      &info->rgDistPoint[i].DistPointName.u.FullName;
166 
167                     for (j = 0; j < name->cAltEntry; j++)
168                         if (name->rgAltEntry[j].dwAltNameChoice ==
169                          CERT_ALT_NAME_URL)
170                         {
171                             if (name->rgAltEntry[j].u.pwszURL)
172                             {
173                                 cUrl++;
174                                 bytesNeeded += sizeof(LPWSTR) +
175                                  (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1)
176                                  * sizeof(WCHAR);
177                             }
178                         }
179                 }
180             if (!pcbUrlArray)
181             {
182                 SetLastError(E_INVALIDARG);
183                 ret = FALSE;
184             }
185             else if (!pUrlArray)
186                 *pcbUrlArray = bytesNeeded;
187             else if (*pcbUrlArray < bytesNeeded)
188             {
189                 SetLastError(ERROR_MORE_DATA);
190                 *pcbUrlArray = bytesNeeded;
191                 ret = FALSE;
192             }
193             else
194             {
195                 LPWSTR nextUrl;
196 
197                 *pcbUrlArray = bytesNeeded;
198                 pUrlArray->cUrl = 0;
199                 pUrlArray->rgwszUrl =
200                  (LPWSTR *)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY));
201                 nextUrl = (LPWSTR)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY)
202                  + cUrl * sizeof(LPWSTR));
203                 for (i = 0; i < info->cDistPoint; i++)
204                     if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice
205                      == CRL_DIST_POINT_FULL_NAME)
206                     {
207                         DWORD j;
208                         CERT_ALT_NAME_INFO *name =
209                          &info->rgDistPoint[i].DistPointName.u.FullName;
210 
211                         for (j = 0; j < name->cAltEntry; j++)
212                             if (name->rgAltEntry[j].dwAltNameChoice ==
213                              CERT_ALT_NAME_URL)
214                             {
215                                 if (name->rgAltEntry[j].u.pwszURL)
216                                 {
217                                     lstrcpyW(nextUrl,
218                                      name->rgAltEntry[j].u.pwszURL);
219                                     pUrlArray->rgwszUrl[pUrlArray->cUrl++] =
220                                      nextUrl;
221                                     nextUrl +=
222                                      (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1);
223                                 }
224                             }
225                     }
226             }
227             if (ret)
228             {
229                 if (pcbUrlInfo)
230                 {
231                     FIXME("url info: stub\n");
232                     if (!pUrlInfo)
233                         *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
234                     else if (*pcbUrlInfo < sizeof(CRYPT_URL_INFO))
235                     {
236                         *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
237                         SetLastError(ERROR_MORE_DATA);
238                         ret = FALSE;
239                     }
240                     else
241                     {
242                         *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
243                         memset(pUrlInfo, 0, sizeof(CRYPT_URL_INFO));
244                     }
245                 }
246             }
247             LocalFree(info);
248         }
249     }
250     else
251         SetLastError(CRYPT_E_NOT_FOUND);
252     return ret;
253 }
254 
255 /***********************************************************************
256  *    CryptGetObjectUrl (CRYPTNET.@)
257  */
258 BOOL WINAPI CryptGetObjectUrl(LPCSTR pszUrlOid, LPVOID pvPara, DWORD dwFlags,
259  PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo,
260  DWORD *pcbUrlInfo, LPVOID pvReserved)
261 {
262     UrlDllGetObjectUrlFunc func = NULL;
263     HCRYPTOIDFUNCADDR hFunc = NULL;
264     BOOL ret = FALSE;
265 
266     TRACE("(%s, %p, %08x, %p, %p, %p, %p, %p)\n", debugstr_a(pszUrlOid),
267      pvPara, dwFlags, pUrlArray, pcbUrlArray, pUrlInfo, pcbUrlInfo, pvReserved);
268 
269     if (!HIWORD(pszUrlOid))
270     {
271         switch (LOWORD(pszUrlOid))
272         {
273         case LOWORD(URL_OID_CERTIFICATE_ISSUER):
274             func = CRYPT_GetUrlFromCertificateIssuer;
275             break;
276         case LOWORD(URL_OID_CERTIFICATE_CRL_DIST_POINT):
277             func = CRYPT_GetUrlFromCertificateCRLDistPoint;
278             break;
279         default:
280             FIXME("unimplemented for %s\n", url_oid_to_str(pszUrlOid));
281             SetLastError(ERROR_FILE_NOT_FOUND);
282         }
283     }
284     else
285     {
286         static HCRYPTOIDFUNCSET set = NULL;
287 
288         if (!set)
289             set = CryptInitOIDFunctionSet(URL_OID_GET_OBJECT_URL_FUNC, 0);
290         CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszUrlOid, 0,
291          (void **)&func, &hFunc);
292     }
293     if (func)
294         ret = func(pszUrlOid, pvPara, dwFlags, pUrlArray, pcbUrlArray,
295          pUrlInfo, pcbUrlInfo, pvReserved);
296     if (hFunc)
297         CryptFreeOIDFunctionAddress(hFunc, 0);
298     return ret;
299 }
300 
301 /***********************************************************************
302  *    CryptRetrieveObjectByUrlA (CRYPTNET.@)
303  */
304 BOOL WINAPI CryptRetrieveObjectByUrlA(LPCSTR pszURL, LPCSTR pszObjectOid,
305  DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject,
306  HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify,
307  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
308 {
309     BOOL ret = FALSE;
310     int len;
311 
312     TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_a(pszURL),
313      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject,
314      hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo);
315 
316     if (!pszURL)
317     {
318         SetLastError(ERROR_INVALID_PARAMETER);
319         return FALSE;
320     }
321     len = MultiByteToWideChar(CP_ACP, 0, pszURL, -1, NULL, 0);
322     if (len)
323     {
324         LPWSTR url = CryptMemAlloc(len * sizeof(WCHAR));
325 
326         if (url)
327         {
328             MultiByteToWideChar(CP_ACP, 0, pszURL, -1, url, len);
329             ret = CryptRetrieveObjectByUrlW(url, pszObjectOid,
330              dwRetrievalFlags, dwTimeout, ppvObject, hAsyncRetrieve,
331              pCredentials, pvVerify, pAuxInfo);
332             CryptMemFree(url);
333         }
334         else
335             SetLastError(ERROR_OUTOFMEMORY);
336     }
337     return ret;
338 }
339 
340 static void WINAPI CRYPT_FreeBlob(LPCSTR pszObjectOid,
341  PCRYPT_BLOB_ARRAY pObject, void *pvFreeContext)
342 {
343     DWORD i;
344 
345     for (i = 0; i < pObject->cBlob; i++)
346         CryptMemFree(pObject->rgBlob[i].pbData);
347     CryptMemFree(pObject->rgBlob);
348 }
349 
350 static BOOL CRYPT_GetObjectFromFile(HANDLE hFile, PCRYPT_BLOB_ARRAY pObject)
351 {
352     BOOL ret;
353     LARGE_INTEGER size;
354 
355     if ((ret = GetFileSizeEx(hFile, &size)))
356     {
357         if (size.u.HighPart)
358         {
359             WARN("file too big\n");
360             SetLastError(ERROR_INVALID_DATA);
361             ret = FALSE;
362         }
363         else
364         {
365             CRYPT_DATA_BLOB blob;
366 
367             blob.pbData = CryptMemAlloc(size.u.LowPart);
368             if (blob.pbData)
369             {
370                 blob.cbData = size.u.LowPart;
371                 ret = ReadFile(hFile, blob.pbData, size.u.LowPart, &blob.cbData,
372                  NULL);
373                 if (ret)
374                 {
375                     pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB));
376                     if (pObject->rgBlob)
377                     {
378                         pObject->cBlob = 1;
379                         memcpy(pObject->rgBlob, &blob, sizeof(CRYPT_DATA_BLOB));
380                     }
381                     else
382                     {
383                         SetLastError(ERROR_OUTOFMEMORY);
384                         ret = FALSE;
385                     }
386                 }
387                 if (!ret)
388                     CryptMemFree(blob.pbData);
389             }
390             else
391             {
392                 SetLastError(ERROR_OUTOFMEMORY);
393                 ret = FALSE;
394             }
395         }
396     }
397     return ret;
398 }
399 
400 /* FIXME: should make wininet cache all downloads instead */
401 static BOOL CRYPT_GetObjectFromCache(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject,
402  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
403 {
404     BOOL ret = FALSE;
405     INTERNET_CACHE_ENTRY_INFOW cacheInfo = { sizeof(cacheInfo), 0 };
406     DWORD size = sizeof(cacheInfo);
407 
408     TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pObject, pAuxInfo);
409 
410     if (GetUrlCacheEntryInfoW(pszURL, &cacheInfo, &size) ||
411      GetLastError() == ERROR_INSUFFICIENT_BUFFER)
412     {
413         FILETIME ft;
414 
415         GetSystemTimeAsFileTime(&ft);
416         if (CompareFileTime(&cacheInfo.ExpireTime, &ft) >= 0)
417         {
418             LPINTERNET_CACHE_ENTRY_INFOW pCacheInfo = CryptMemAlloc(size);
419 
420             if (pCacheInfo)
421             {
422                 if (GetUrlCacheEntryInfoW(pszURL, pCacheInfo, &size))
423                 {
424                     HANDLE hFile = CreateFileW(pCacheInfo->lpszLocalFileName,
425                      GENERIC_READ, 0, NULL, OPEN_EXISTING,
426                      FILE_ATTRIBUTE_NORMAL, NULL);
427 
428                     if (hFile != INVALID_HANDLE_VALUE)
429                     {
430                         if ((ret = CRYPT_GetObjectFromFile(hFile, pObject)))
431                         {
432                             if (pAuxInfo && pAuxInfo->cbSize >=
433                              offsetof(CRYPT_RETRIEVE_AUX_INFO,
434                              pLastSyncTime) + sizeof(PFILETIME) &&
435                              pAuxInfo->pLastSyncTime)
436                                 memcpy(pAuxInfo->pLastSyncTime,
437                                  &pCacheInfo->LastSyncTime,
438                                  sizeof(FILETIME));
439                         }
440                         CloseHandle(hFile);
441                     }
442                 }
443                 CryptMemFree(pCacheInfo);
444             }
445             else
446                 SetLastError(ERROR_OUTOFMEMORY);
447         }
448         else
449             DeleteUrlCacheEntryW(pszURL);
450     }
451     TRACE("returning %d\n", ret);
452     return ret;
453 }
454 
455 /* Parses the URL, and sets components's lpszHostName and lpszUrlPath members
456  * to NULL-terminated copies of those portions of the URL (to be freed with
457  * CryptMemFree.)
458  */
459 static BOOL CRYPT_CrackUrl(LPCWSTR pszURL, URL_COMPONENTSW *components)
460 {
461     BOOL ret;
462 
463     TRACE("(%s, %p)\n", debugstr_w(pszURL), components);
464 
465     memset(components, 0, sizeof(*components));
466     components->dwStructSize = sizeof(*components);
467     components->lpszHostName = CryptMemAlloc(MAX_PATH * sizeof(WCHAR));
468     components->dwHostNameLength = MAX_PATH;
469     components->lpszUrlPath = CryptMemAlloc(MAX_PATH * 2 * sizeof(WCHAR));
470     components->dwUrlPathLength = 2 * MAX_PATH;
471     ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, components);
472     if (ret)
473     {
474         if ((components->dwUrlPathLength == 2 * MAX_PATH - 1) ||
475             (components->dwHostNameLength == MAX_PATH - 1))
476             FIXME("Buffers are too small\n");
477         switch (components->nScheme)
478         {
479         case INTERNET_SCHEME_FTP:
480             if (!components->nPort)
481                 components->nPort = INTERNET_DEFAULT_FTP_PORT;
482             break;
483         case INTERNET_SCHEME_HTTP:
484             if (!components->nPort)
485                 components->nPort = INTERNET_DEFAULT_HTTP_PORT;
486             break;
487         default:
488             ; /* do nothing */
489         }
490     }
491     TRACE("returning %d\n", ret);
492     return ret;
493 }
494 
495 struct InetContext
496 {
497     HANDLE event;
498     DWORD  timeout;
499     DWORD  error;
500 };
501 
502 static struct InetContext *CRYPT_MakeInetContext(DWORD dwTimeout)
503 {
504     struct InetContext *context = CryptMemAlloc(sizeof(struct InetContext));
505 
506     if (context)
507     {
508         context->event = CreateEventW(NULL, FALSE, FALSE, NULL);
509         if (!context->event)
510         {
511             CryptMemFree(context);
512             context = NULL;
513         }
514         else
515         {
516             context->timeout = dwTimeout;
517             context->error = ERROR_SUCCESS;
518         }
519     }
520     return context;
521 }
522 
523 static BOOL CRYPT_DownloadObject(DWORD dwRetrievalFlags, HINTERNET hHttp,
524  struct InetContext *context, PCRYPT_BLOB_ARRAY pObject,
525  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
526 {
527     CRYPT_DATA_BLOB object = { 0, NULL };
528     DWORD bytesAvailable;
529     BOOL ret;
530 
531     do {
532         if ((ret = InternetQueryDataAvailable(hHttp, &bytesAvailable, 0, 0)))
533         {
534             if (bytesAvailable)
535             {
536                 if (object.pbData)
537                     object.pbData = CryptMemRealloc(object.pbData,
538                      object.cbData + bytesAvailable);
539                 else
540                     object.pbData = CryptMemAlloc(bytesAvailable);
541                 if (object.pbData)
542                 {
543                     INTERNET_BUFFERSA buffer = { sizeof(buffer), 0 };
544 
545                     buffer.dwBufferLength = bytesAvailable;
546                     buffer.lpvBuffer = object.pbData + object.cbData;
547                     if (!(ret = InternetReadFileExA(hHttp, &buffer, IRF_NO_WAIT,
548                      (DWORD_PTR)context)))
549                     {
550                         if (GetLastError() == ERROR_IO_PENDING)
551                         {
552                             if (WaitForSingleObject(context->event,
553                              context->timeout) == WAIT_TIMEOUT)
554                                 SetLastError(ERROR_TIMEOUT);
555                             else if (context->error)
556                                 SetLastError(context->error);
557                             else
558                                 ret = TRUE;
559                         }
560                     }
561                     if (ret)
562                         object.cbData += bytesAvailable;
563                 }
564                 else
565                 {
566                     SetLastError(ERROR_OUTOFMEMORY);
567                     ret = FALSE;
568                 }
569             }
570         }
571         else if (GetLastError() == ERROR_IO_PENDING)
572         {
573             if (WaitForSingleObject(context->event, context->timeout) ==
574              WAIT_TIMEOUT)
575                 SetLastError(ERROR_TIMEOUT);
576             else
577                 ret = TRUE;
578         }
579     } while (ret && bytesAvailable);
580     if (ret)
581     {
582         pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB));
583         if (!pObject->rgBlob)
584         {
585             CryptMemFree(object.pbData);
586             SetLastError(ERROR_OUTOFMEMORY);
587             ret = FALSE;
588         }
589         else
590         {
591             pObject->rgBlob[0].cbData = object.cbData;
592             pObject->rgBlob[0].pbData = object.pbData;
593             pObject->cBlob = 1;
594         }
595     }
596     TRACE("returning %d\n", ret);
597     return ret;
598 }
599 
600 static void CRYPT_CacheURL(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject,
601  DWORD dwRetrievalFlags, FILETIME expires)
602 {
603     WCHAR cacheFileName[MAX_PATH];
604 
605     /* FIXME: let wininet directly cache instead */
606     if (CreateUrlCacheEntryW(pszURL, pObject->rgBlob[0].cbData, NULL,
607      cacheFileName, 0))
608     {
609         HANDLE hCacheFile = CreateFileW(cacheFileName, GENERIC_WRITE, 0, NULL,
610          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
611 
612         if (hCacheFile != INVALID_HANDLE_VALUE)
613         {
614             DWORD bytesWritten, entryType;
615             FILETIME ft = { 0 };
616 
617             if (!(dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL))
618                 entryType = NORMAL_CACHE_ENTRY;
619             else
620                 entryType = STICKY_CACHE_ENTRY;
621             WriteFile(hCacheFile, pObject->rgBlob[0].pbData,
622              pObject->rgBlob[0].cbData, &bytesWritten, NULL);
623             CloseHandle(hCacheFile);
624             CommitUrlCacheEntryW(pszURL, cacheFileName, expires, ft, entryType,
625              NULL, 0, NULL, NULL);
626         }
627     }
628 }
629 
630 static void CALLBACK CRYPT_InetStatusCallback(HINTERNET hInt,
631  DWORD_PTR dwContext, DWORD status, void *statusInfo, DWORD statusInfoLen)
632 {
633     struct InetContext *context = (struct InetContext *)dwContext;
634     LPINTERNET_ASYNC_RESULT result;
635 
636     switch (status)
637     {
638     case INTERNET_STATUS_REQUEST_COMPLETE:
639         result = (LPINTERNET_ASYNC_RESULT)statusInfo;
640         context->error = result->dwError;
641         SetEvent(context->event);
642     }
643 }
644 
645 static BOOL CRYPT_Connect(URL_COMPONENTSW *components,
646  struct InetContext *context, PCRYPT_CREDENTIALS pCredentials,
647  HINTERNET *phInt, HINTERNET *phHost)
648 {
649     BOOL ret;
650 
651     TRACE("(%s:%d, %p, %p, %p, %p)\n", debugstr_w(components->lpszHostName),
652      components->nPort, context, pCredentials, phInt, phInt);
653 
654     *phHost = NULL;
655     *phInt = InternetOpenW(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL,
656      context ? INTERNET_FLAG_ASYNC : 0);
657     if (*phInt)
658     {
659         DWORD service;
660 
661         if (context)
662             InternetSetStatusCallbackW(*phInt, CRYPT_InetStatusCallback);
663         switch (components->nScheme)
664         {
665         case INTERNET_SCHEME_FTP:
666             service = INTERNET_SERVICE_FTP;
667             break;
668         case INTERNET_SCHEME_HTTP:
669             service = INTERNET_SERVICE_HTTP;
670             break;
671         default:
672             service = 0;
673         }
674         /* FIXME: use pCredentials for username/password */
675         *phHost = InternetConnectW(*phInt, components->lpszHostName,
676          components->nPort, NULL, NULL, service, 0, (DWORD_PTR)context);
677         if (!*phHost)
678         {
679             InternetCloseHandle(*phInt);
680             *phInt = NULL;
681             ret = FALSE;
682         }
683         else
684             ret = TRUE;
685     }
686     else
687         ret = FALSE;
688     TRACE("returning %d\n", ret);
689     return ret;
690 }
691 
692 static BOOL WINAPI FTP_RetrieveEncodedObjectW(LPCWSTR pszURL,
693  LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout,
694  PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject,
695  void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve,
696  PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
697 {
698     FIXME("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL),
699      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject,
700      ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo);
701 
702     pObject->cBlob = 0;
703     pObject->rgBlob = NULL;
704     *ppfnFreeObject = CRYPT_FreeBlob;
705     *ppvFreeContext = NULL;
706     return FALSE;
707 }
708 
709 static const WCHAR x509cacert[] = { 'a','p','p','l','i','c','a','t','i','o','n',
710  '/','x','-','x','5','','9','-','c','a','-','c','e','r','t',0 };
711 static const WCHAR x509emailcert[] = { 'a','p','p','l','i','c','a','t','i','o',
712  'n','/','x','-','x','5','','9','-','e','m','a','i','l','-','c','e','r','t',
713  0 };
714 static const WCHAR x509servercert[] = { 'a','p','p','l','i','c','a','t','i','o',
715  'n','/','x','-','x','5','','9','-','s','e','r','v','e','r','-','c','e','r',
716  't',0 };
717 static const WCHAR x509usercert[] = { 'a','p','p','l','i','c','a','t','i','o',
718  'n','/','x','-','x','5','','9','-','u','s','e','r','-','c','e','r','t',0 };
719 static const WCHAR pkcs7cert[] = { 'a','p','p','l','i','c','a','t','i','o','n',
720  '/','x','-','p','k','c','s','7','-','c','e','r','t','i','f','c','a','t','e',
721  's',0 };
722 static const WCHAR pkixCRL[] = { 'a','p','p','l','i','c','a','t','i','o','n',
723  '/','p','k','i','x','-','c','r','l',0 };
724 static const WCHAR pkcs7CRL[] = { 'a','p','p','l','i','c','a','t','i','o','n',
725  '/','x','-','p','k','c','s','7','-','c','r','l',0 };
726 static const WCHAR pkcs7sig[] = { 'a','p','p','l','i','c','a','t','i','o','n',
727  '/','x','-','p','k','c','s','7','-','s','i','g','n','a','t','u','r','e',0 };
728 static const WCHAR pkcs7mime[] = { 'a','p','p','l','i','c','a','t','i','o','n',
729  '/','x','-','p','k','c','s','7','-','m','i','m','e',0 };
730 
731 static BOOL WINAPI HTTP_RetrieveEncodedObjectW(LPCWSTR pszURL,
732  LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout,
733  PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject,
734  void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve,
735  PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
736 {
737     BOOL ret = FALSE;
738 
739     TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL),
740      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject,
741      ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo);
742 
743     pObject->cBlob = 0;
744     pObject->rgBlob = NULL;
745     *ppfnFreeObject = CRYPT_FreeBlob;
746     *ppvFreeContext = NULL;
747 
748     if (!(dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL))
749         ret = CRYPT_GetObjectFromCache(pszURL, pObject, pAuxInfo);
750     if (!ret && (!(dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) ||
751      (dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL)))
752     {
753         URL_COMPONENTSW components;
754 
755         if ((ret = CRYPT_CrackUrl(pszURL, &components)))
756         {
757             HINTERNET hInt, hHost;
758             struct InetContext *context = NULL;
759 
760             if (dwTimeout)
761                 context = CRYPT_MakeInetContext(dwTimeout);
762             ret = CRYPT_Connect(&components, context, pCredentials, &hInt,
763              &hHost);
764             if (ret)
765             {
766                 static LPCWSTR types[] = { x509cacert, x509emailcert,
767                  x509servercert, x509usercert, pkcs7cert, pkixCRL, pkcs7CRL,
768                  pkcs7sig, pkcs7mime, NULL };
769                 HINTERNET hHttp = HttpOpenRequestW(hHost, NULL,
770                  components.lpszUrlPath, NULL, NULL, types,
771                  INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI,
772                  (DWORD_PTR)context);
773 
774                 if (hHttp)
775                 {
776                     if (dwTimeout)
777                     {
778                         InternetSetOptionW(hHttp,
779                          INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout,
780                          sizeof(dwTimeout));
781                         InternetSetOptionW(hHttp, INTERNET_OPTION_SEND_TIMEOUT,
782                          &dwTimeout, sizeof(dwTimeout));
783                     }
784                     ret = HttpSendRequestExW(hHttp, NULL, NULL, 0,
785                      (DWORD_PTR)context);
786                     if (!ret && GetLastError() == ERROR_IO_PENDING)
787                     {
788                         if (WaitForSingleObject(context->event,
789                          context->timeout) == WAIT_TIMEOUT)
790                             SetLastError(ERROR_TIMEOUT);
791                         else
792                             ret = TRUE;
793                     }
794                     /* We don't set ret to TRUE in this block to avoid masking
795                      * an error from HttpSendRequestExW.
796                      */
797                     if (!HttpEndRequestW(hHttp, NULL, 0, (DWORD_PTR)context) &&
798                      GetLastError() == ERROR_IO_PENDING)
799                     {
800                         if (WaitForSingleObject(context->event,
801                          context->timeout) == WAIT_TIMEOUT)
802                         {
803                             SetLastError(ERROR_TIMEOUT);
804                             ret = FALSE;
805                         }
806                     }
807                     if (ret)
808                         ret = CRYPT_DownloadObject(dwRetrievalFlags, hHttp,
809                          context, pObject, pAuxInfo);
810                     if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT))
811                     {
812                         SYSTEMTIME st;
813                         DWORD len = sizeof(st);
814 
815                         if (HttpQueryInfoW(hHttp,
816                          HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME, &st,
817                          &len, NULL))
818                         {
819                             FILETIME ft;
820 
821                             SystemTimeToFileTime(&st, &ft);
822                             CRYPT_CacheURL(pszURL, pObject, dwRetrievalFlags,
823                              ft);
824                         }
825                     }
826                     InternetCloseHandle(hHttp);
827                 }
828                 InternetCloseHandle(hHost);
829                 InternetCloseHandle(hInt);
830             }
831             if (context)
832             {
833                 CloseHandle(context->event);
834                 CryptMemFree(context);
835             }
836             CryptMemFree(components.lpszUrlPath);
837             CryptMemFree(components.lpszHostName);
838         }
839     }
840     TRACE("returning %d\n", ret);
841     return ret;
842 }
843 
844 static BOOL WINAPI File_RetrieveEncodedObjectW(LPCWSTR pszURL,
845  LPCSTR ps