ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sun May 27 2012 04:23:19 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.