xref: /reactos/dll/win32/cryptnet/cryptnet_main.c (revision f4663f8e)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright (C) 2006 Maarten Lankhorst
3c2c66affSColin Finck  * Copyright 2007 Juan Lang
4c2c66affSColin Finck  *
5c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
6c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
7c2c66affSColin Finck  * License as published by the Free Software Foundation; either
8c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
9c2c66affSColin Finck  *
10c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
11c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13c2c66affSColin Finck  * Lesser General Public License for more details.
14c2c66affSColin Finck  *
15c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
16c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
17c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18c2c66affSColin Finck  *
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21c2c66affSColin Finck #define NONAMELESSUNION
22c2c66affSColin Finck #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
23c2c66affSColin Finck 
24c2c66affSColin Finck #include <stdio.h>
25*18075aa0SAmine Khaldi #include <stdarg.h>
26c2c66affSColin Finck 
27*18075aa0SAmine Khaldi #include "windef.h"
28*18075aa0SAmine Khaldi #include "winbase.h"
29*18075aa0SAmine Khaldi #include "winnt.h"
30*18075aa0SAmine Khaldi #include "winnls.h"
31*18075aa0SAmine Khaldi #include "wininet.h"
32*18075aa0SAmine Khaldi #include "objbase.h"
33*18075aa0SAmine Khaldi #include "wincrypt.h"
34c2c66affSColin Finck 
35*18075aa0SAmine Khaldi #include "wine/debug.h"
36c2c66affSColin Finck 
37c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(cryptnet);
38c2c66affSColin Finck 
39c2c66affSColin Finck #define IS_INTOID(x)    (((ULONG_PTR)(x) >> 16) == 0)
40c2c66affSColin Finck 
41c2c66affSColin Finck static const WCHAR cryptNet[] = { 'c','r','y','p','t','n','e','t','.',
42c2c66affSColin Finck    'd','l','l',0 };
43c2c66affSColin Finck 
44c2c66affSColin Finck /***********************************************************************
45c2c66affSColin Finck  *    DllRegisterServer (CRYPTNET.@)
46c2c66affSColin Finck  */
DllRegisterServer(void)47c2c66affSColin Finck HRESULT WINAPI DllRegisterServer(void)
48c2c66affSColin Finck {
49c2c66affSColin Finck    TRACE("\n");
50c2c66affSColin Finck    CryptRegisterDefaultOIDFunction(X509_ASN_ENCODING,
51c2c66affSColin Finck     CRYPT_OID_VERIFY_REVOCATION_FUNC, 0, cryptNet);
52c2c66affSColin Finck    CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap",
53c2c66affSColin Finck     cryptNet, "LdapProvOpenStore");
54c2c66affSColin Finck    CryptRegisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC,
55c2c66affSColin Finck     CERT_STORE_PROV_LDAP_W, cryptNet, "LdapProvOpenStore");
56c2c66affSColin Finck    return S_OK;
57c2c66affSColin Finck }
58c2c66affSColin Finck 
59c2c66affSColin Finck /***********************************************************************
60c2c66affSColin Finck  *    DllUnregisterServer (CRYPTNET.@)
61c2c66affSColin Finck  */
DllUnregisterServer(void)62c2c66affSColin Finck HRESULT WINAPI DllUnregisterServer(void)
63c2c66affSColin Finck {
64c2c66affSColin Finck    TRACE("\n");
65c2c66affSColin Finck    CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING,
66c2c66affSColin Finck     CRYPT_OID_VERIFY_REVOCATION_FUNC, cryptNet);
67c2c66affSColin Finck    CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC, "Ldap");
68c2c66affSColin Finck    CryptUnregisterOIDFunction(0, CRYPT_OID_OPEN_STORE_PROV_FUNC,
69c2c66affSColin Finck     CERT_STORE_PROV_LDAP_W);
70c2c66affSColin Finck    return S_OK;
71c2c66affSColin Finck }
72c2c66affSColin Finck 
url_oid_to_str(LPCSTR oid)73c2c66affSColin Finck static const char *url_oid_to_str(LPCSTR oid)
74c2c66affSColin Finck {
75c2c66affSColin Finck     if (IS_INTOID(oid))
76c2c66affSColin Finck     {
77c2c66affSColin Finck         static char buf[10];
78c2c66affSColin Finck 
79c2c66affSColin Finck         switch (LOWORD(oid))
80c2c66affSColin Finck         {
81c2c66affSColin Finck #define _x(oid) case LOWORD(oid): return #oid
82c2c66affSColin Finck         _x(URL_OID_CERTIFICATE_ISSUER);
83c2c66affSColin Finck         _x(URL_OID_CERTIFICATE_CRL_DIST_POINT);
84c2c66affSColin Finck         _x(URL_OID_CTL_ISSUER);
85c2c66affSColin Finck         _x(URL_OID_CTL_NEXT_UPDATE);
86c2c66affSColin Finck         _x(URL_OID_CRL_ISSUER);
87c2c66affSColin Finck         _x(URL_OID_CERTIFICATE_FRESHEST_CRL);
88c2c66affSColin Finck         _x(URL_OID_CRL_FRESHEST_CRL);
89c2c66affSColin Finck         _x(URL_OID_CROSS_CERT_DIST_POINT);
90c2c66affSColin Finck #undef _x
91c2c66affSColin Finck         default:
92c2c66affSColin Finck             snprintf(buf, sizeof(buf), "%d", LOWORD(oid));
93c2c66affSColin Finck             return buf;
94c2c66affSColin Finck         }
95c2c66affSColin Finck     }
96c2c66affSColin Finck     else
97c2c66affSColin Finck         return oid;
98c2c66affSColin Finck }
99c2c66affSColin Finck 
100c2c66affSColin Finck typedef BOOL (WINAPI *UrlDllGetObjectUrlFunc)(LPCSTR, LPVOID, DWORD,
101c2c66affSColin Finck  PCRYPT_URL_ARRAY, DWORD *, PCRYPT_URL_INFO, DWORD *, LPVOID);
102c2c66affSColin Finck 
CRYPT_GetUrlFromCertificateIssuer(LPCSTR pszUrlOid,LPVOID pvPara,DWORD dwFlags,PCRYPT_URL_ARRAY pUrlArray,DWORD * pcbUrlArray,PCRYPT_URL_INFO pUrlInfo,DWORD * pcbUrlInfo,LPVOID pvReserved)103c2c66affSColin Finck static BOOL WINAPI CRYPT_GetUrlFromCertificateIssuer(LPCSTR pszUrlOid,
104c2c66affSColin Finck  LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray,
105c2c66affSColin Finck  PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved)
106c2c66affSColin Finck {
107c2c66affSColin Finck     PCCERT_CONTEXT cert = pvPara;
108c2c66affSColin Finck     PCERT_EXTENSION ext;
109c2c66affSColin Finck     BOOL ret = FALSE;
110c2c66affSColin Finck 
111c2c66affSColin Finck     /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */
112c2c66affSColin Finck     if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION))
113c2c66affSColin Finck     {
114c2c66affSColin Finck         SetLastError(CRYPT_E_NOT_FOUND);
115c2c66affSColin Finck         return FALSE;
116c2c66affSColin Finck     }
117c2c66affSColin Finck     if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS,
118c2c66affSColin Finck      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
119c2c66affSColin Finck     {
120c2c66affSColin Finck         CERT_AUTHORITY_INFO_ACCESS *aia;
121c2c66affSColin Finck         DWORD size;
122c2c66affSColin Finck 
123c2c66affSColin Finck         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_INFO_ACCESS,
124c2c66affSColin Finck          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
125c2c66affSColin Finck          &aia, &size);
126c2c66affSColin Finck         if (ret)
127c2c66affSColin Finck         {
128c2c66affSColin Finck             DWORD i, cUrl, bytesNeeded = sizeof(CRYPT_URL_ARRAY);
129c2c66affSColin Finck 
130c2c66affSColin Finck             for (i = 0, cUrl = 0; i < aia->cAccDescr; i++)
131c2c66affSColin Finck                 if (!strcmp(aia->rgAccDescr[i].pszAccessMethod,
132c2c66affSColin Finck                  szOID_PKIX_CA_ISSUERS))
133c2c66affSColin Finck                 {
134c2c66affSColin Finck                     if (aia->rgAccDescr[i].AccessLocation.dwAltNameChoice ==
135c2c66affSColin Finck                      CERT_ALT_NAME_URL)
136c2c66affSColin Finck                     {
137c2c66affSColin Finck                         if (aia->rgAccDescr[i].AccessLocation.u.pwszURL)
138c2c66affSColin Finck                         {
139c2c66affSColin Finck                             cUrl++;
140c2c66affSColin Finck                             bytesNeeded += sizeof(LPWSTR) +
141c2c66affSColin Finck                              (lstrlenW(aia->rgAccDescr[i].AccessLocation.u.
142c2c66affSColin Finck                              pwszURL) + 1) * sizeof(WCHAR);
143c2c66affSColin Finck                         }
144c2c66affSColin Finck                     }
145c2c66affSColin Finck                     else
146c2c66affSColin Finck                         FIXME("unsupported alt name type %d\n",
147c2c66affSColin Finck                          aia->rgAccDescr[i].AccessLocation.dwAltNameChoice);
148c2c66affSColin Finck                 }
149c2c66affSColin Finck             if (!pcbUrlArray)
150c2c66affSColin Finck             {
151c2c66affSColin Finck                 SetLastError(E_INVALIDARG);
152c2c66affSColin Finck                 ret = FALSE;
153c2c66affSColin Finck             }
154c2c66affSColin Finck             else if (!pUrlArray)
155c2c66affSColin Finck                 *pcbUrlArray = bytesNeeded;
156c2c66affSColin Finck             else if (*pcbUrlArray < bytesNeeded)
157c2c66affSColin Finck             {
158c2c66affSColin Finck                 SetLastError(ERROR_MORE_DATA);
159c2c66affSColin Finck                 *pcbUrlArray = bytesNeeded;
160c2c66affSColin Finck                 ret = FALSE;
161c2c66affSColin Finck             }
162c2c66affSColin Finck             else
163c2c66affSColin Finck             {
164c2c66affSColin Finck                 LPWSTR nextUrl;
165c2c66affSColin Finck 
166c2c66affSColin Finck                 *pcbUrlArray = bytesNeeded;
167c2c66affSColin Finck                 pUrlArray->cUrl = 0;
168c2c66affSColin Finck                 pUrlArray->rgwszUrl =
169c2c66affSColin Finck                  (LPWSTR *)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY));
170c2c66affSColin Finck                 nextUrl = (LPWSTR)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY)
171c2c66affSColin Finck                  + cUrl * sizeof(LPWSTR));
172c2c66affSColin Finck                 for (i = 0; i < aia->cAccDescr; i++)
173c2c66affSColin Finck                     if (!strcmp(aia->rgAccDescr[i].pszAccessMethod,
174c2c66affSColin Finck                      szOID_PKIX_CA_ISSUERS))
175c2c66affSColin Finck                     {
176c2c66affSColin Finck                         if (aia->rgAccDescr[i].AccessLocation.dwAltNameChoice
177c2c66affSColin Finck                          == CERT_ALT_NAME_URL)
178c2c66affSColin Finck                         {
179c2c66affSColin Finck                             if (aia->rgAccDescr[i].AccessLocation.u.pwszURL)
180c2c66affSColin Finck                             {
181c2c66affSColin Finck                                 lstrcpyW(nextUrl,
182c2c66affSColin Finck                                  aia->rgAccDescr[i].AccessLocation.u.pwszURL);
183c2c66affSColin Finck                                 pUrlArray->rgwszUrl[pUrlArray->cUrl++] =
184c2c66affSColin Finck                                  nextUrl;
185c2c66affSColin Finck                                 nextUrl += (lstrlenW(nextUrl) + 1);
186c2c66affSColin Finck                             }
187c2c66affSColin Finck                         }
188c2c66affSColin Finck                     }
189c2c66affSColin Finck             }
190c2c66affSColin Finck             if (ret)
191c2c66affSColin Finck             {
192c2c66affSColin Finck                 if (pcbUrlInfo)
193c2c66affSColin Finck                 {
194c2c66affSColin Finck                     FIXME("url info: stub\n");
195c2c66affSColin Finck                     if (!pUrlInfo)
196c2c66affSColin Finck                         *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
197c2c66affSColin Finck                     else if (*pcbUrlInfo < sizeof(CRYPT_URL_INFO))
198c2c66affSColin Finck                     {
199c2c66affSColin Finck                         *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
200c2c66affSColin Finck                         SetLastError(ERROR_MORE_DATA);
201c2c66affSColin Finck                         ret = FALSE;
202c2c66affSColin Finck                     }
203c2c66affSColin Finck                     else
204c2c66affSColin Finck                     {
205c2c66affSColin Finck                         *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
206c2c66affSColin Finck                         memset(pUrlInfo, 0, sizeof(CRYPT_URL_INFO));
207c2c66affSColin Finck                     }
208c2c66affSColin Finck                 }
209c2c66affSColin Finck             }
210c2c66affSColin Finck             LocalFree(aia);
211c2c66affSColin Finck         }
212c2c66affSColin Finck     }
213c2c66affSColin Finck     else
214c2c66affSColin Finck         SetLastError(CRYPT_E_NOT_FOUND);
215c2c66affSColin Finck     return ret;
216c2c66affSColin Finck }
217c2c66affSColin Finck 
CRYPT_GetUrlFromCRLDistPointsExt(const CRYPT_DATA_BLOB * value,PCRYPT_URL_ARRAY pUrlArray,DWORD * pcbUrlArray,PCRYPT_URL_INFO pUrlInfo,DWORD * pcbUrlInfo)218c2c66affSColin Finck static BOOL CRYPT_GetUrlFromCRLDistPointsExt(const CRYPT_DATA_BLOB *value,
219c2c66affSColin Finck  PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo,
220c2c66affSColin Finck  DWORD *pcbUrlInfo)
221c2c66affSColin Finck {
222c2c66affSColin Finck     BOOL ret;
223c2c66affSColin Finck     CRL_DIST_POINTS_INFO *info;
224c2c66affSColin Finck     DWORD size;
225c2c66affSColin Finck 
226c2c66affSColin Finck     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CRL_DIST_POINTS,
227c2c66affSColin Finck      value->pbData, value->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
228c2c66affSColin Finck     if (ret)
229c2c66affSColin Finck     {
230c2c66affSColin Finck         DWORD i, cUrl, bytesNeeded = sizeof(CRYPT_URL_ARRAY);
231c2c66affSColin Finck 
232c2c66affSColin Finck         for (i = 0, cUrl = 0; i < info->cDistPoint; i++)
233c2c66affSColin Finck             if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice
234c2c66affSColin Finck              == CRL_DIST_POINT_FULL_NAME)
235c2c66affSColin Finck             {
236c2c66affSColin Finck                 DWORD j;
237c2c66affSColin Finck                 CERT_ALT_NAME_INFO *name =
238c2c66affSColin Finck                  &info->rgDistPoint[i].DistPointName.u.FullName;
239c2c66affSColin Finck 
240c2c66affSColin Finck                 for (j = 0; j < name->cAltEntry; j++)
241c2c66affSColin Finck                     if (name->rgAltEntry[j].dwAltNameChoice ==
242c2c66affSColin Finck                      CERT_ALT_NAME_URL)
243c2c66affSColin Finck                     {
244c2c66affSColin Finck                         if (name->rgAltEntry[j].u.pwszURL)
245c2c66affSColin Finck                         {
246c2c66affSColin Finck                             cUrl++;
247c2c66affSColin Finck                             bytesNeeded += sizeof(LPWSTR) +
248c2c66affSColin Finck                              (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1)
249c2c66affSColin Finck                              * sizeof(WCHAR);
250c2c66affSColin Finck                         }
251c2c66affSColin Finck                     }
252c2c66affSColin Finck             }
253c2c66affSColin Finck         if (!pcbUrlArray)
254c2c66affSColin Finck         {
255c2c66affSColin Finck             SetLastError(E_INVALIDARG);
256c2c66affSColin Finck             ret = FALSE;
257c2c66affSColin Finck         }
258c2c66affSColin Finck         else if (!pUrlArray)
259c2c66affSColin Finck             *pcbUrlArray = bytesNeeded;
260c2c66affSColin Finck         else if (*pcbUrlArray < bytesNeeded)
261c2c66affSColin Finck         {
262c2c66affSColin Finck             SetLastError(ERROR_MORE_DATA);
263c2c66affSColin Finck             *pcbUrlArray = bytesNeeded;
264c2c66affSColin Finck             ret = FALSE;
265c2c66affSColin Finck         }
266c2c66affSColin Finck         else
267c2c66affSColin Finck         {
268c2c66affSColin Finck             LPWSTR nextUrl;
269c2c66affSColin Finck 
270c2c66affSColin Finck             *pcbUrlArray = bytesNeeded;
271c2c66affSColin Finck             pUrlArray->cUrl = 0;
272c2c66affSColin Finck             pUrlArray->rgwszUrl =
273c2c66affSColin Finck              (LPWSTR *)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY));
274c2c66affSColin Finck             nextUrl = (LPWSTR)((BYTE *)pUrlArray + sizeof(CRYPT_URL_ARRAY)
275c2c66affSColin Finck              + cUrl * sizeof(LPWSTR));
276c2c66affSColin Finck             for (i = 0; i < info->cDistPoint; i++)
277c2c66affSColin Finck                 if (info->rgDistPoint[i].DistPointName.dwDistPointNameChoice
278c2c66affSColin Finck                  == CRL_DIST_POINT_FULL_NAME)
279c2c66affSColin Finck                 {
280c2c66affSColin Finck                     DWORD j;
281c2c66affSColin Finck                     CERT_ALT_NAME_INFO *name =
282c2c66affSColin Finck                      &info->rgDistPoint[i].DistPointName.u.FullName;
283c2c66affSColin Finck 
284c2c66affSColin Finck                     for (j = 0; j < name->cAltEntry; j++)
285c2c66affSColin Finck                         if (name->rgAltEntry[j].dwAltNameChoice ==
286c2c66affSColin Finck                          CERT_ALT_NAME_URL)
287c2c66affSColin Finck                         {
288c2c66affSColin Finck                             if (name->rgAltEntry[j].u.pwszURL)
289c2c66affSColin Finck                             {
290c2c66affSColin Finck                                 lstrcpyW(nextUrl,
291c2c66affSColin Finck                                  name->rgAltEntry[j].u.pwszURL);
292c2c66affSColin Finck                                 pUrlArray->rgwszUrl[pUrlArray->cUrl++] =
293c2c66affSColin Finck                                  nextUrl;
294c2c66affSColin Finck                                 nextUrl +=
295c2c66affSColin Finck                                  (lstrlenW(name->rgAltEntry[j].u.pwszURL) + 1);
296c2c66affSColin Finck                             }
297c2c66affSColin Finck                         }
298c2c66affSColin Finck                 }
299c2c66affSColin Finck         }
300c2c66affSColin Finck         if (ret)
301c2c66affSColin Finck         {
302c2c66affSColin Finck             if (pcbUrlInfo)
303c2c66affSColin Finck             {
304c2c66affSColin Finck                 FIXME("url info: stub\n");
305c2c66affSColin Finck                 if (!pUrlInfo)
306c2c66affSColin Finck                     *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
307c2c66affSColin Finck                 else if (*pcbUrlInfo < sizeof(CRYPT_URL_INFO))
308c2c66affSColin Finck                 {
309c2c66affSColin Finck                     *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
310c2c66affSColin Finck                     SetLastError(ERROR_MORE_DATA);
311c2c66affSColin Finck                     ret = FALSE;
312c2c66affSColin Finck                 }
313c2c66affSColin Finck                 else
314c2c66affSColin Finck                 {
315c2c66affSColin Finck                     *pcbUrlInfo = sizeof(CRYPT_URL_INFO);
316c2c66affSColin Finck                     memset(pUrlInfo, 0, sizeof(CRYPT_URL_INFO));
317c2c66affSColin Finck                 }
318c2c66affSColin Finck             }
319c2c66affSColin Finck         }
320c2c66affSColin Finck         LocalFree(info);
321c2c66affSColin Finck     }
322c2c66affSColin Finck     return ret;
323c2c66affSColin Finck }
324c2c66affSColin Finck 
CRYPT_GetUrlFromCertificateCRLDistPoint(LPCSTR pszUrlOid,LPVOID pvPara,DWORD dwFlags,PCRYPT_URL_ARRAY pUrlArray,DWORD * pcbUrlArray,PCRYPT_URL_INFO pUrlInfo,DWORD * pcbUrlInfo,LPVOID pvReserved)325c2c66affSColin Finck static BOOL WINAPI CRYPT_GetUrlFromCertificateCRLDistPoint(LPCSTR pszUrlOid,
326c2c66affSColin Finck  LPVOID pvPara, DWORD dwFlags, PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray,
327c2c66affSColin Finck  PCRYPT_URL_INFO pUrlInfo, DWORD *pcbUrlInfo, LPVOID pvReserved)
328c2c66affSColin Finck {
329c2c66affSColin Finck     PCCERT_CONTEXT cert = pvPara;
330c2c66affSColin Finck     PCERT_EXTENSION ext;
331c2c66affSColin Finck     BOOL ret = FALSE;
332c2c66affSColin Finck 
333c2c66affSColin Finck     /* The only applicable flag is CRYPT_GET_URL_FROM_EXTENSION */
334c2c66affSColin Finck     if (dwFlags && !(dwFlags & CRYPT_GET_URL_FROM_EXTENSION))
335c2c66affSColin Finck     {
336c2c66affSColin Finck         SetLastError(CRYPT_E_NOT_FOUND);
337c2c66affSColin Finck         return FALSE;
338c2c66affSColin Finck     }
339c2c66affSColin Finck     if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS,
340c2c66affSColin Finck      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
341c2c66affSColin Finck         ret = CRYPT_GetUrlFromCRLDistPointsExt(&ext->Value, pUrlArray,
342c2c66affSColin Finck          pcbUrlArray, pUrlInfo, pcbUrlInfo);
343c2c66affSColin Finck     else
344c2c66affSColin Finck         SetLastError(CRYPT_E_NOT_FOUND);
345c2c66affSColin Finck     return ret;
346c2c66affSColin Finck }
347c2c66affSColin Finck 
348c2c66affSColin Finck /***********************************************************************
349c2c66affSColin Finck  *    CryptGetObjectUrl (CRYPTNET.@)
350c2c66affSColin Finck  */
CryptGetObjectUrl(LPCSTR pszUrlOid,LPVOID pvPara,DWORD dwFlags,PCRYPT_URL_ARRAY pUrlArray,DWORD * pcbUrlArray,PCRYPT_URL_INFO pUrlInfo,DWORD * pcbUrlInfo,LPVOID pvReserved)351c2c66affSColin Finck BOOL WINAPI CryptGetObjectUrl(LPCSTR pszUrlOid, LPVOID pvPara, DWORD dwFlags,
352c2c66affSColin Finck  PCRYPT_URL_ARRAY pUrlArray, DWORD *pcbUrlArray, PCRYPT_URL_INFO pUrlInfo,
353c2c66affSColin Finck  DWORD *pcbUrlInfo, LPVOID pvReserved)
354c2c66affSColin Finck {
355c2c66affSColin Finck     UrlDllGetObjectUrlFunc func = NULL;
356c2c66affSColin Finck     HCRYPTOIDFUNCADDR hFunc = NULL;
357c2c66affSColin Finck     BOOL ret = FALSE;
358c2c66affSColin Finck 
359c2c66affSColin Finck     TRACE("(%s, %p, %08x, %p, %p, %p, %p, %p)\n", debugstr_a(pszUrlOid),
360c2c66affSColin Finck      pvPara, dwFlags, pUrlArray, pcbUrlArray, pUrlInfo, pcbUrlInfo, pvReserved);
361c2c66affSColin Finck 
362c2c66affSColin Finck     if (IS_INTOID(pszUrlOid))
363c2c66affSColin Finck     {
364c2c66affSColin Finck         switch (LOWORD(pszUrlOid))
365c2c66affSColin Finck         {
366c2c66affSColin Finck         case LOWORD(URL_OID_CERTIFICATE_ISSUER):
367c2c66affSColin Finck             func = CRYPT_GetUrlFromCertificateIssuer;
368c2c66affSColin Finck             break;
369c2c66affSColin Finck         case LOWORD(URL_OID_CERTIFICATE_CRL_DIST_POINT):
370c2c66affSColin Finck             func = CRYPT_GetUrlFromCertificateCRLDistPoint;
371c2c66affSColin Finck             break;
372c2c66affSColin Finck         default:
373c2c66affSColin Finck             FIXME("unimplemented for %s\n", url_oid_to_str(pszUrlOid));
374c2c66affSColin Finck             SetLastError(ERROR_FILE_NOT_FOUND);
375c2c66affSColin Finck         }
376c2c66affSColin Finck     }
377c2c66affSColin Finck     else
378c2c66affSColin Finck     {
379c2c66affSColin Finck         static HCRYPTOIDFUNCSET set = NULL;
380c2c66affSColin Finck 
381c2c66affSColin Finck         if (!set)
382c2c66affSColin Finck             set = CryptInitOIDFunctionSet(URL_OID_GET_OBJECT_URL_FUNC, 0);
383c2c66affSColin Finck         CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszUrlOid, 0,
384c2c66affSColin Finck          (void **)&func, &hFunc);
385c2c66affSColin Finck     }
386c2c66affSColin Finck     if (func)
387c2c66affSColin Finck         ret = func(pszUrlOid, pvPara, dwFlags, pUrlArray, pcbUrlArray,
388c2c66affSColin Finck          pUrlInfo, pcbUrlInfo, pvReserved);
389c2c66affSColin Finck     if (hFunc)
390c2c66affSColin Finck         CryptFreeOIDFunctionAddress(hFunc, 0);
391c2c66affSColin Finck     return ret;
392c2c66affSColin Finck }
393c2c66affSColin Finck 
394c2c66affSColin Finck /***********************************************************************
395c2c66affSColin Finck  *    CryptRetrieveObjectByUrlA (CRYPTNET.@)
396c2c66affSColin Finck  */
CryptRetrieveObjectByUrlA(LPCSTR pszURL,LPCSTR pszObjectOid,DWORD dwRetrievalFlags,DWORD dwTimeout,LPVOID * ppvObject,HCRYPTASYNC hAsyncRetrieve,PCRYPT_CREDENTIALS pCredentials,LPVOID pvVerify,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)397c2c66affSColin Finck BOOL WINAPI CryptRetrieveObjectByUrlA(LPCSTR pszURL, LPCSTR pszObjectOid,
398c2c66affSColin Finck  DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject,
399c2c66affSColin Finck  HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify,
400c2c66affSColin Finck  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
401c2c66affSColin Finck {
402c2c66affSColin Finck     BOOL ret = FALSE;
403c2c66affSColin Finck     int len;
404c2c66affSColin Finck 
405c2c66affSColin Finck     TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_a(pszURL),
406c2c66affSColin Finck      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject,
407c2c66affSColin Finck      hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo);
408c2c66affSColin Finck 
409c2c66affSColin Finck     if (!pszURL)
410c2c66affSColin Finck     {
411c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
412c2c66affSColin Finck         return FALSE;
413c2c66affSColin Finck     }
414c2c66affSColin Finck     len = MultiByteToWideChar(CP_ACP, 0, pszURL, -1, NULL, 0);
415c2c66affSColin Finck     if (len)
416c2c66affSColin Finck     {
417c2c66affSColin Finck         LPWSTR url = CryptMemAlloc(len * sizeof(WCHAR));
418c2c66affSColin Finck 
419c2c66affSColin Finck         if (url)
420c2c66affSColin Finck         {
421c2c66affSColin Finck             MultiByteToWideChar(CP_ACP, 0, pszURL, -1, url, len);
422c2c66affSColin Finck             ret = CryptRetrieveObjectByUrlW(url, pszObjectOid,
423c2c66affSColin Finck              dwRetrievalFlags, dwTimeout, ppvObject, hAsyncRetrieve,
424c2c66affSColin Finck              pCredentials, pvVerify, pAuxInfo);
425c2c66affSColin Finck             CryptMemFree(url);
426c2c66affSColin Finck         }
427c2c66affSColin Finck         else
428c2c66affSColin Finck             SetLastError(ERROR_OUTOFMEMORY);
429c2c66affSColin Finck     }
430c2c66affSColin Finck     return ret;
431c2c66affSColin Finck }
432c2c66affSColin Finck 
CRYPT_FreeBlob(LPCSTR pszObjectOid,PCRYPT_BLOB_ARRAY pObject,void * pvFreeContext)433c2c66affSColin Finck static void WINAPI CRYPT_FreeBlob(LPCSTR pszObjectOid,
434c2c66affSColin Finck  PCRYPT_BLOB_ARRAY pObject, void *pvFreeContext)
435c2c66affSColin Finck {
436c2c66affSColin Finck     DWORD i;
437c2c66affSColin Finck 
438c2c66affSColin Finck     for (i = 0; i < pObject->cBlob; i++)
439c2c66affSColin Finck         CryptMemFree(pObject->rgBlob[i].pbData);
440c2c66affSColin Finck     CryptMemFree(pObject->rgBlob);
441c2c66affSColin Finck }
442c2c66affSColin Finck 
CRYPT_GetObjectFromFile(HANDLE hFile,PCRYPT_BLOB_ARRAY pObject)443c2c66affSColin Finck static BOOL CRYPT_GetObjectFromFile(HANDLE hFile, PCRYPT_BLOB_ARRAY pObject)
444c2c66affSColin Finck {
445c2c66affSColin Finck     BOOL ret;
446c2c66affSColin Finck     LARGE_INTEGER size;
447c2c66affSColin Finck 
448c2c66affSColin Finck     if ((ret = GetFileSizeEx(hFile, &size)))
449c2c66affSColin Finck     {
450c2c66affSColin Finck         if (size.u.HighPart)
451c2c66affSColin Finck         {
452c2c66affSColin Finck             WARN("file too big\n");
453c2c66affSColin Finck             SetLastError(ERROR_INVALID_DATA);
454c2c66affSColin Finck             ret = FALSE;
455c2c66affSColin Finck         }
456c2c66affSColin Finck         else
457c2c66affSColin Finck         {
458c2c66affSColin Finck             CRYPT_DATA_BLOB blob;
459c2c66affSColin Finck 
460c2c66affSColin Finck             blob.pbData = CryptMemAlloc(size.u.LowPart);
461c2c66affSColin Finck             if (blob.pbData)
462c2c66affSColin Finck             {
463c2c66affSColin Finck                 ret = ReadFile(hFile, blob.pbData, size.u.LowPart, &blob.cbData,
464c2c66affSColin Finck                  NULL);
465c2c66affSColin Finck                 if (ret)
466c2c66affSColin Finck                 {
467c2c66affSColin Finck                     pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB));
468c2c66affSColin Finck                     if (pObject->rgBlob)
469c2c66affSColin Finck                     {
470c2c66affSColin Finck                         pObject->cBlob = 1;
471c2c66affSColin Finck                         memcpy(pObject->rgBlob, &blob, sizeof(CRYPT_DATA_BLOB));
472c2c66affSColin Finck                     }
473c2c66affSColin Finck                     else
474c2c66affSColin Finck                     {
475c2c66affSColin Finck                         SetLastError(ERROR_OUTOFMEMORY);
476c2c66affSColin Finck                         ret = FALSE;
477c2c66affSColin Finck                     }
478c2c66affSColin Finck                 }
479c2c66affSColin Finck                 if (!ret)
480c2c66affSColin Finck                     CryptMemFree(blob.pbData);
481c2c66affSColin Finck             }
482c2c66affSColin Finck             else
483c2c66affSColin Finck             {
484c2c66affSColin Finck                 SetLastError(ERROR_OUTOFMEMORY);
485c2c66affSColin Finck                 ret = FALSE;
486c2c66affSColin Finck             }
487c2c66affSColin Finck         }
488c2c66affSColin Finck     }
489c2c66affSColin Finck     return ret;
490c2c66affSColin Finck }
491c2c66affSColin Finck 
CRYPT_GetObjectFromCache(LPCWSTR pszURL,PCRYPT_BLOB_ARRAY pObject,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)492c2c66affSColin Finck static BOOL CRYPT_GetObjectFromCache(LPCWSTR pszURL, PCRYPT_BLOB_ARRAY pObject,
493c2c66affSColin Finck  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
494c2c66affSColin Finck {
495c2c66affSColin Finck     BOOL ret = FALSE;
496c2c66affSColin Finck     INTERNET_CACHE_ENTRY_INFOW *pCacheInfo = NULL;
497c2c66affSColin Finck     DWORD size = 0;
498c2c66affSColin Finck 
499c2c66affSColin Finck     TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pObject, pAuxInfo);
500c2c66affSColin Finck 
501c2c66affSColin Finck     RetrieveUrlCacheEntryFileW(pszURL, NULL, &size, 0);
502c2c66affSColin Finck     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
503c2c66affSColin Finck         return FALSE;
504c2c66affSColin Finck 
505c2c66affSColin Finck     pCacheInfo = CryptMemAlloc(size);
506c2c66affSColin Finck     if (!pCacheInfo)
507c2c66affSColin Finck     {
508c2c66affSColin Finck         SetLastError(ERROR_OUTOFMEMORY);
509c2c66affSColin Finck         return FALSE;
510c2c66affSColin Finck     }
511c2c66affSColin Finck 
512c2c66affSColin Finck     if ((ret = RetrieveUrlCacheEntryFileW(pszURL, pCacheInfo, &size, 0)))
513c2c66affSColin Finck     {
514c2c66affSColin Finck         FILETIME ft;
515c2c66affSColin Finck 
516c2c66affSColin Finck         GetSystemTimeAsFileTime(&ft);
517c2c66affSColin Finck         if (CompareFileTime(&pCacheInfo->ExpireTime, &ft) >= 0)
518c2c66affSColin Finck         {
519c2c66affSColin Finck             HANDLE hFile = CreateFileW(pCacheInfo->lpszLocalFileName, GENERIC_READ,
520c2c66affSColin Finck              FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
521c2c66affSColin Finck 
522c2c66affSColin Finck             if (hFile != INVALID_HANDLE_VALUE)
523c2c66affSColin Finck             {
524c2c66affSColin Finck                 if ((ret = CRYPT_GetObjectFromFile(hFile, pObject)))
525c2c66affSColin Finck                 {
526c2c66affSColin Finck                     if (pAuxInfo && pAuxInfo->cbSize >=
527c2c66affSColin Finck                      offsetof(CRYPT_RETRIEVE_AUX_INFO,
528c2c66affSColin Finck                      pLastSyncTime) + sizeof(PFILETIME) &&
529c2c66affSColin Finck                      pAuxInfo->pLastSyncTime)
530c2c66affSColin Finck                         memcpy(pAuxInfo->pLastSyncTime,
531c2c66affSColin Finck                          &pCacheInfo->LastSyncTime,
532c2c66affSColin Finck                          sizeof(FILETIME));
533c2c66affSColin Finck                 }
534c2c66affSColin Finck                 CloseHandle(hFile);
535c2c66affSColin Finck             }
536c2c66affSColin Finck             else
537c2c66affSColin Finck             {
538c2c66affSColin Finck                 DeleteUrlCacheEntryW(pszURL);
539c2c66affSColin Finck                 ret = FALSE;
540c2c66affSColin Finck             }
541c2c66affSColin Finck         }
542c2c66affSColin Finck         else
543c2c66affSColin Finck         {
544c2c66affSColin Finck             DeleteUrlCacheEntryW(pszURL);
545c2c66affSColin Finck             ret = FALSE;
546c2c66affSColin Finck         }
547c2c66affSColin Finck         UnlockUrlCacheEntryFileW(pszURL, 0);
548c2c66affSColin Finck     }
549c2c66affSColin Finck     CryptMemFree(pCacheInfo);
550c2c66affSColin Finck     TRACE("returning %d\n", ret);
551c2c66affSColin Finck     return ret;
552c2c66affSColin Finck }
553c2c66affSColin Finck 
554c2c66affSColin Finck /* Parses the URL, and sets components' lpszHostName and lpszUrlPath members
555c2c66affSColin Finck  * to NULL-terminated copies of those portions of the URL (to be freed with
556c2c66affSColin Finck  * CryptMemFree.)
557c2c66affSColin Finck  */
CRYPT_CrackUrl(LPCWSTR pszURL,URL_COMPONENTSW * components)558c2c66affSColin Finck static BOOL CRYPT_CrackUrl(LPCWSTR pszURL, URL_COMPONENTSW *components)
559c2c66affSColin Finck {
560c2c66affSColin Finck     BOOL ret;
561c2c66affSColin Finck 
562c2c66affSColin Finck     TRACE("(%s, %p)\n", debugstr_w(pszURL), components);
563c2c66affSColin Finck 
564c2c66affSColin Finck     memset(components, 0, sizeof(*components));
565c2c66affSColin Finck     components->dwStructSize = sizeof(*components);
566c2c66affSColin Finck     components->lpszHostName = CryptMemAlloc(INTERNET_MAX_HOST_NAME_LENGTH * sizeof(WCHAR));
567c2c66affSColin Finck     components->dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
568c2c66affSColin Finck     if (!components->lpszHostName)
569c2c66affSColin Finck     {
570c2c66affSColin Finck         SetLastError(ERROR_OUTOFMEMORY);
571c2c66affSColin Finck         return FALSE;
572c2c66affSColin Finck     }
573c2c66affSColin Finck     components->lpszUrlPath = CryptMemAlloc(INTERNET_MAX_PATH_LENGTH * sizeof(WCHAR));
574c2c66affSColin Finck     components->dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
575c2c66affSColin Finck     if (!components->lpszUrlPath)
576c2c66affSColin Finck     {
577c2c66affSColin Finck         CryptMemFree(components->lpszHostName);
578c2c66affSColin Finck         SetLastError(ERROR_OUTOFMEMORY);
579c2c66affSColin Finck         return FALSE;
580c2c66affSColin Finck     }
581c2c66affSColin Finck 
582c2c66affSColin Finck     ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, components);
583c2c66affSColin Finck     if (ret)
584c2c66affSColin Finck     {
585c2c66affSColin Finck         switch (components->nScheme)
586c2c66affSColin Finck         {
587c2c66affSColin Finck         case INTERNET_SCHEME_FTP:
588c2c66affSColin Finck             if (!components->nPort)
589c2c66affSColin Finck                 components->nPort = INTERNET_DEFAULT_FTP_PORT;
590c2c66affSColin Finck             break;
591c2c66affSColin Finck         case INTERNET_SCHEME_HTTP:
592c2c66affSColin Finck             if (!components->nPort)
593c2c66affSColin Finck                 components->nPort = INTERNET_DEFAULT_HTTP_PORT;
594c2c66affSColin Finck             break;
595c2c66affSColin Finck         default:
596c2c66affSColin Finck             ; /* do nothing */
597c2c66affSColin Finck         }
598c2c66affSColin Finck     }
599c2c66affSColin Finck     TRACE("returning %d\n", ret);
600c2c66affSColin Finck     return ret;
601c2c66affSColin Finck }
602c2c66affSColin Finck 
603c2c66affSColin Finck struct InetContext
604c2c66affSColin Finck {
605c2c66affSColin Finck     HANDLE event;
606c2c66affSColin Finck     DWORD  timeout;
607c2c66affSColin Finck     DWORD  error;
608c2c66affSColin Finck };
609c2c66affSColin Finck 
CRYPT_MakeInetContext(DWORD dwTimeout)610c2c66affSColin Finck static struct InetContext *CRYPT_MakeInetContext(DWORD dwTimeout)
611c2c66affSColin Finck {
612c2c66affSColin Finck     struct InetContext *context = CryptMemAlloc(sizeof(struct InetContext));
613c2c66affSColin Finck 
614c2c66affSColin Finck     if (context)
615c2c66affSColin Finck     {
616c2c66affSColin Finck         context->event = CreateEventW(NULL, FALSE, FALSE, NULL);
617c2c66affSColin Finck         if (!context->event)
618c2c66affSColin Finck         {
619c2c66affSColin Finck             CryptMemFree(context);
620c2c66affSColin Finck             context = NULL;
621c2c66affSColin Finck         }
622c2c66affSColin Finck         else
623c2c66affSColin Finck         {
624c2c66affSColin Finck             context->timeout = dwTimeout;
625c2c66affSColin Finck             context->error = ERROR_SUCCESS;
626c2c66affSColin Finck         }
627c2c66affSColin Finck     }
628c2c66affSColin Finck     return context;
629c2c66affSColin Finck }
630c2c66affSColin Finck 
CRYPT_DownloadObject(DWORD dwRetrievalFlags,HINTERNET hHttp,struct InetContext * context,PCRYPT_BLOB_ARRAY pObject,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)631c2c66affSColin Finck static BOOL CRYPT_DownloadObject(DWORD dwRetrievalFlags, HINTERNET hHttp,
632c2c66affSColin Finck  struct InetContext *context, PCRYPT_BLOB_ARRAY pObject,
633c2c66affSColin Finck  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
634c2c66affSColin Finck {
635c2c66affSColin Finck     CRYPT_DATA_BLOB object = { 0, NULL };
636c2c66affSColin Finck     DWORD bytesAvailable;
637c2c66affSColin Finck     BOOL ret;
638c2c66affSColin Finck 
639c2c66affSColin Finck     do {
640c2c66affSColin Finck         if ((ret = InternetQueryDataAvailable(hHttp, &bytesAvailable, 0, 0)))
641c2c66affSColin Finck         {
642c2c66affSColin Finck             if (bytesAvailable)
643c2c66affSColin Finck             {
644c2c66affSColin Finck                 if (object.pbData)
645c2c66affSColin Finck                     object.pbData = CryptMemRealloc(object.pbData,
646c2c66affSColin Finck                      object.cbData + bytesAvailable);
647c2c66affSColin Finck                 else
648c2c66affSColin Finck                     object.pbData = CryptMemAlloc(bytesAvailable);
649c2c66affSColin Finck                 if (object.pbData)
650c2c66affSColin Finck                 {
651c2c66affSColin Finck                     INTERNET_BUFFERSA buffer = { sizeof(buffer), 0 };
652c2c66affSColin Finck 
653c2c66affSColin Finck                     buffer.dwBufferLength = bytesAvailable;
654c2c66affSColin Finck                     buffer.lpvBuffer = object.pbData + object.cbData;
655c2c66affSColin Finck                     if (!(ret = InternetReadFileExA(hHttp, &buffer, IRF_NO_WAIT,
656c2c66affSColin Finck                      (DWORD_PTR)context)))
657c2c66affSColin Finck                     {
658c2c66affSColin Finck                         if (GetLastError() == ERROR_IO_PENDING)
659c2c66affSColin Finck                         {
660c2c66affSColin Finck                             if (WaitForSingleObject(context->event,
661c2c66affSColin Finck                              context->timeout) == WAIT_TIMEOUT)
662c2c66affSColin Finck                                 SetLastError(ERROR_TIMEOUT);
663c2c66affSColin Finck                             else if (context->error)
664c2c66affSColin Finck                                 SetLastError(context->error);
665c2c66affSColin Finck                             else
666c2c66affSColin Finck                                 ret = TRUE;
667c2c66affSColin Finck                         }
668c2c66affSColin Finck                     }
669c2c66affSColin Finck                     if (ret)
670c2c66affSColin Finck                         object.cbData += buffer.dwBufferLength;
671c2c66affSColin Finck                 }
672c2c66affSColin Finck                 else
673c2c66affSColin Finck                 {
674c2c66affSColin Finck                     SetLastError(ERROR_OUTOFMEMORY);
675c2c66affSColin Finck                     ret = FALSE;
676c2c66affSColin Finck                 }
677c2c66affSColin Finck             }
678c2c66affSColin Finck         }
679c2c66affSColin Finck         else if (GetLastError() == ERROR_IO_PENDING)
680c2c66affSColin Finck         {
681c2c66affSColin Finck             if (WaitForSingleObject(context->event, context->timeout) ==
682c2c66affSColin Finck              WAIT_TIMEOUT)
683c2c66affSColin Finck                 SetLastError(ERROR_TIMEOUT);
684c2c66affSColin Finck             else
685c2c66affSColin Finck                 ret = TRUE;
686c2c66affSColin Finck         }
687c2c66affSColin Finck     } while (ret && bytesAvailable);
688c2c66affSColin Finck     if (ret)
689c2c66affSColin Finck     {
690c2c66affSColin Finck         pObject->rgBlob = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB));
691c2c66affSColin Finck         if (!pObject->rgBlob)
692c2c66affSColin Finck         {
693c2c66affSColin Finck             CryptMemFree(object.pbData);
694c2c66affSColin Finck             SetLastError(ERROR_OUTOFMEMORY);
695c2c66affSColin Finck             ret = FALSE;
696c2c66affSColin Finck         }
697c2c66affSColin Finck         else
698c2c66affSColin Finck         {
699c2c66affSColin Finck             pObject->rgBlob[0].cbData = object.cbData;
700c2c66affSColin Finck             pObject->rgBlob[0].pbData = object.pbData;
701c2c66affSColin Finck             pObject->cBlob = 1;
702c2c66affSColin Finck         }
703c2c66affSColin Finck     }
704c2c66affSColin Finck     TRACE("returning %d\n", ret);
705c2c66affSColin Finck     return ret;
706c2c66affSColin Finck }
707c2c66affSColin Finck 
708c2c66affSColin Finck /* Finds the object specified by pszURL in the cache.  If it's not found,
709c2c66affSColin Finck  * creates a new cache entry for the object and writes the object to it.
710c2c66affSColin Finck  * Sets the expiration time of the cache entry to expires.
711c2c66affSColin Finck  */
CRYPT_CacheURL(LPCWSTR pszURL,const CRYPT_BLOB_ARRAY * pObject,DWORD dwRetrievalFlags,FILETIME expires)712c2c66affSColin Finck static void CRYPT_CacheURL(LPCWSTR pszURL, const CRYPT_BLOB_ARRAY *pObject,
713c2c66affSColin Finck  DWORD dwRetrievalFlags, FILETIME expires)
714c2c66affSColin Finck {
715c2c66affSColin Finck     WCHAR cacheFileName[MAX_PATH];
716c2c66affSColin Finck     HANDLE hCacheFile;
717c2c66affSColin Finck     DWORD size = 0, entryType;
718c2c66affSColin Finck     FILETIME ft;
719c2c66affSColin Finck 
720c2c66affSColin Finck     GetUrlCacheEntryInfoW(pszURL, NULL, &size);
721c2c66affSColin Finck     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
722c2c66affSColin Finck     {
723c2c66affSColin Finck         INTERNET_CACHE_ENTRY_INFOW *info = CryptMemAlloc(size);
724c2c66affSColin Finck 
725c2c66affSColin Finck         if (!info)
726c2c66affSColin Finck         {
727c2c66affSColin Finck             ERR("out of memory\n");
728c2c66affSColin Finck             return;
729c2c66affSColin Finck         }
730c2c66affSColin Finck 
731c2c66affSColin Finck         if (GetUrlCacheEntryInfoW(pszURL, info, &size))
732c2c66affSColin Finck         {
733c2c66affSColin Finck             lstrcpyW(cacheFileName, info->lpszLocalFileName);
734c2c66affSColin Finck             /* Check if the existing cache entry is up to date.  If it isn't,
735c2c66affSColin Finck              * remove the existing cache entry, and create a new one with the
736c2c66affSColin Finck              * new value.
737c2c66affSColin Finck              */
738c2c66affSColin Finck             GetSystemTimeAsFileTime(&ft);
739c2c66affSColin Finck             if (CompareFileTime(&info->ExpireTime, &ft) < 0)
740c2c66affSColin Finck             {
741c2c66affSColin Finck                 DeleteUrlCacheEntryW(pszURL);
742c2c66affSColin Finck             }
743c2c66affSColin Finck             else
744c2c66affSColin Finck             {
745c2c66affSColin Finck                 info->ExpireTime = expires;
746c2c66affSColin Finck                 SetUrlCacheEntryInfoW(pszURL, info, CACHE_ENTRY_EXPTIME_FC);
747c2c66affSColin Finck                 CryptMemFree(info);
748c2c66affSColin Finck                 return;
749c2c66affSColin Finck             }
750c2c66affSColin Finck         }
751c2c66affSColin Finck         CryptMemFree(info);
752c2c66affSColin Finck     }
753c2c66affSColin Finck 
754c2c66affSColin Finck     if (!CreateUrlCacheEntryW(pszURL, pObject->rgBlob[0].cbData, NULL, cacheFileName, 0))
755c2c66affSColin Finck         return;
756c2c66affSColin Finck 
757c2c66affSColin Finck     hCacheFile = CreateFileW(cacheFileName, GENERIC_WRITE, 0,
758c2c66affSColin Finck             NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
759c2c66affSColin Finck     if(hCacheFile == INVALID_HANDLE_VALUE)
760c2c66affSColin Finck         return;
761c2c66affSColin Finck 
762c2c66affSColin Finck     WriteFile(hCacheFile, pObject->rgBlob[0].pbData,
763c2c66affSColin Finck             pObject->rgBlob[0].cbData, &size, NULL);
764c2c66affSColin Finck     CloseHandle(hCacheFile);
765c2c66affSColin Finck 
766c2c66affSColin Finck     if (!(dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL))
767c2c66affSColin Finck         entryType = NORMAL_CACHE_ENTRY;
768c2c66affSColin Finck     else
769c2c66affSColin Finck         entryType = STICKY_CACHE_ENTRY;
770c2c66affSColin Finck     memset(&ft, 0, sizeof(ft));
771c2c66affSColin Finck     CommitUrlCacheEntryW(pszURL, cacheFileName, expires, ft, entryType,
772c2c66affSColin Finck             NULL, 0, NULL, NULL);
773c2c66affSColin Finck }
774c2c66affSColin Finck 
CRYPT_InetStatusCallback(HINTERNET hInt,DWORD_PTR dwContext,DWORD status,void * statusInfo,DWORD statusInfoLen)775c2c66affSColin Finck static void CALLBACK CRYPT_InetStatusCallback(HINTERNET hInt,
776c2c66affSColin Finck  DWORD_PTR dwContext, DWORD status, void *statusInfo, DWORD statusInfoLen)
777c2c66affSColin Finck {
778c2c66affSColin Finck     struct InetContext *context = (struct InetContext *)dwContext;
779c2c66affSColin Finck     LPINTERNET_ASYNC_RESULT result;
780c2c66affSColin Finck 
781c2c66affSColin Finck     switch (status)
782c2c66affSColin Finck     {
783c2c66affSColin Finck     case INTERNET_STATUS_REQUEST_COMPLETE:
784c2c66affSColin Finck         result = statusInfo;
785c2c66affSColin Finck         context->error = result->dwError;
786c2c66affSColin Finck         SetEvent(context->event);
787c2c66affSColin Finck     }
788c2c66affSColin Finck }
789c2c66affSColin Finck 
CRYPT_Connect(const URL_COMPONENTSW * components,struct InetContext * context,PCRYPT_CREDENTIALS pCredentials,HINTERNET * phInt,HINTERNET * phHost)790c2c66affSColin Finck static BOOL CRYPT_Connect(const URL_COMPONENTSW *components,
791c2c66affSColin Finck  struct InetContext *context, PCRYPT_CREDENTIALS pCredentials,
792c2c66affSColin Finck  HINTERNET *phInt, HINTERNET *phHost)
793c2c66affSColin Finck {
794c2c66affSColin Finck     BOOL ret;
795c2c66affSColin Finck 
796c2c66affSColin Finck     TRACE("(%s:%d, %p, %p, %p, %p)\n", debugstr_w(components->lpszHostName),
797c2c66affSColin Finck      components->nPort, context, pCredentials, phInt, phInt);
798c2c66affSColin Finck 
799c2c66affSColin Finck     *phHost = NULL;
800c2c66affSColin Finck     *phInt = InternetOpenW(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL,
801c2c66affSColin Finck      context ? INTERNET_FLAG_ASYNC : 0);
802c2c66affSColin Finck     if (*phInt)
803c2c66affSColin Finck     {
804c2c66affSColin Finck         DWORD service;
805c2c66affSColin Finck 
806c2c66affSColin Finck         if (context)
807c2c66affSColin Finck             InternetSetStatusCallbackW(*phInt, CRYPT_InetStatusCallback);
808c2c66affSColin Finck         switch (components->nScheme)
809c2c66affSColin Finck         {
810c2c66affSColin Finck         case INTERNET_SCHEME_FTP:
811c2c66affSColin Finck             service = INTERNET_SERVICE_FTP;
812c2c66affSColin Finck             break;
813c2c66affSColin Finck         case INTERNET_SCHEME_HTTP:
814c2c66affSColin Finck             service = INTERNET_SERVICE_HTTP;
815c2c66affSColin Finck             break;
816c2c66affSColin Finck         default:
817c2c66affSColin Finck             service = 0;
818c2c66affSColin Finck         }
819c2c66affSColin Finck         /* FIXME: use pCredentials for username/password */
820c2c66affSColin Finck         *phHost = InternetConnectW(*phInt, components->lpszHostName,
821c2c66affSColin Finck          components->nPort, NULL, NULL, service, 0, (DWORD_PTR)context);
822c2c66affSColin Finck         if (!*phHost)
823c2c66affSColin Finck         {
824c2c66affSColin Finck             InternetCloseHandle(*phInt);
825c2c66affSColin Finck             *phInt = NULL;
826c2c66affSColin Finck             ret = FALSE;
827c2c66affSColin Finck         }
828c2c66affSColin Finck         else
829c2c66affSColin Finck             ret = TRUE;
830c2c66affSColin Finck     }
831c2c66affSColin Finck     else
832c2c66affSColin Finck         ret = FALSE;
833c2c66affSColin Finck     TRACE("returning %d\n", ret);
834c2c66affSColin Finck     return ret;
835c2c66affSColin Finck }
836c2c66affSColin Finck 
FTP_RetrieveEncodedObjectW(LPCWSTR pszURL,LPCSTR pszObjectOid,DWORD dwRetrievalFlags,DWORD dwTimeout,PCRYPT_BLOB_ARRAY pObject,PFN_FREE_ENCODED_OBJECT_FUNC * ppfnFreeObject,void ** ppvFreeContext,HCRYPTASYNC hAsyncRetrieve,PCRYPT_CREDENTIALS pCredentials,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)837c2c66affSColin Finck static BOOL WINAPI FTP_RetrieveEncodedObjectW(LPCWSTR pszURL,
838c2c66affSColin Finck  LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout,
839c2c66affSColin Finck  PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject,
840c2c66affSColin Finck  void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve,
841c2c66affSColin Finck  PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
842c2c66affSColin Finck {
843c2c66affSColin Finck     FIXME("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL),
844c2c66affSColin Finck      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject,
845c2c66affSColin Finck      ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo);
846c2c66affSColin Finck 
847c2c66affSColin Finck     pObject->cBlob = 0;
848c2c66affSColin Finck     pObject->rgBlob = NULL;
849c2c66affSColin Finck     *ppfnFreeObject = CRYPT_FreeBlob;
850c2c66affSColin Finck     *ppvFreeContext = NULL;
851c2c66affSColin Finck     return FALSE;
852c2c66affSColin Finck }
853c2c66affSColin Finck 
854c2c66affSColin Finck static const WCHAR x509cacert[] = { 'a','p','p','l','i','c','a','t','i','o','n',
855c2c66affSColin Finck  '/','x','-','x','5','0','9','-','c','a','-','c','e','r','t',0 };
856c2c66affSColin Finck static const WCHAR x509emailcert[] = { 'a','p','p','l','i','c','a','t','i','o',
857c2c66affSColin Finck  'n','/','x','-','x','5','0','9','-','e','m','a','i','l','-','c','e','r','t',
858c2c66affSColin Finck  0 };
859c2c66affSColin Finck static const WCHAR x509servercert[] = { 'a','p','p','l','i','c','a','t','i','o',
860c2c66affSColin Finck  'n','/','x','-','x','5','0','9','-','s','e','r','v','e','r','-','c','e','r',
861c2c66affSColin Finck  't',0 };
862c2c66affSColin Finck static const WCHAR x509usercert[] = { 'a','p','p','l','i','c','a','t','i','o',
863c2c66affSColin Finck  'n','/','x','-','x','5','0','9','-','u','s','e','r','-','c','e','r','t',0 };
864c2c66affSColin Finck static const WCHAR pkcs7cert[] = { 'a','p','p','l','i','c','a','t','i','o','n',
865c2c66affSColin Finck  '/','x','-','p','k','c','s','7','-','c','e','r','t','i','f','c','a','t','e',
866c2c66affSColin Finck  's',0 };
867c2c66affSColin Finck static const WCHAR pkixCRL[] = { 'a','p','p','l','i','c','a','t','i','o','n',
868c2c66affSColin Finck  '/','p','k','i','x','-','c','r','l',0 };
869c2c66affSColin Finck static const WCHAR pkcs7CRL[] = { 'a','p','p','l','i','c','a','t','i','o','n',
870c2c66affSColin Finck  '/','x','-','p','k','c','s','7','-','c','r','l',0 };
871c2c66affSColin Finck static const WCHAR pkcs7sig[] = { 'a','p','p','l','i','c','a','t','i','o','n',
872c2c66affSColin Finck  '/','x','-','p','k','c','s','7','-','s','i','g','n','a','t','u','r','e',0 };
873c2c66affSColin Finck static const WCHAR pkcs7mime[] = { 'a','p','p','l','i','c','a','t','i','o','n',
874c2c66affSColin Finck  '/','x','-','p','k','c','s','7','-','m','i','m','e',0 };
875c2c66affSColin Finck 
HTTP_RetrieveEncodedObjectW(LPCWSTR pszURL,LPCSTR pszObjectOid,DWORD dwRetrievalFlags,DWORD dwTimeout,PCRYPT_BLOB_ARRAY pObject,PFN_FREE_ENCODED_OBJECT_FUNC * ppfnFreeObject,void ** ppvFreeContext,HCRYPTASYNC hAsyncRetrieve,PCRYPT_CREDENTIALS pCredentials,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)876c2c66affSColin Finck static BOOL WINAPI HTTP_RetrieveEncodedObjectW(LPCWSTR pszURL,
877c2c66affSColin Finck  LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout,
878c2c66affSColin Finck  PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject,
879c2c66affSColin Finck  void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve,
880c2c66affSColin Finck  PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
881c2c66affSColin Finck {
882c2c66affSColin Finck     BOOL ret = FALSE;
883c2c66affSColin Finck 
884c2c66affSColin Finck     TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL),
885c2c66affSColin Finck      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject,
886c2c66affSColin Finck      ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo);
887c2c66affSColin Finck 
888c2c66affSColin Finck     pObject->cBlob = 0;
889c2c66affSColin Finck     pObject->rgBlob = NULL;
890c2c66affSColin Finck     *ppfnFreeObject = CRYPT_FreeBlob;
891c2c66affSColin Finck     *ppvFreeContext = NULL;
892c2c66affSColin Finck 
893c2c66affSColin Finck     if (!(dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL))
894c2c66affSColin Finck         ret = CRYPT_GetObjectFromCache(pszURL, pObject, pAuxInfo);
895c2c66affSColin Finck     if (!ret && (!(dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL) ||
896c2c66affSColin Finck      (dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL)))
897c2c66affSColin Finck     {
898c2c66affSColin Finck         URL_COMPONENTSW components;
899c2c66affSColin Finck 
900c2c66affSColin Finck         if ((ret = CRYPT_CrackUrl(pszURL, &components)))
901c2c66affSColin Finck         {
902c2c66affSColin Finck             HINTERNET hInt, hHost;
903c2c66affSColin Finck             struct InetContext *context = NULL;
904c2c66affSColin Finck 
905c2c66affSColin Finck             if (dwTimeout)
906c2c66affSColin Finck                 context = CRYPT_MakeInetContext(dwTimeout);
907c2c66affSColin Finck             ret = CRYPT_Connect(&components, context, pCredentials, &hInt,
908c2c66affSColin Finck              &hHost);
909c2c66affSColin Finck             if (ret)
910c2c66affSColin Finck             {
911c2c66affSColin Finck                 static LPCWSTR types[] = { x509cacert, x509emailcert,
912c2c66affSColin Finck                  x509servercert, x509usercert, pkcs7cert, pkixCRL, pkcs7CRL,
913c2c66affSColin Finck                  pkcs7sig, pkcs7mime, NULL };
914c2c66affSColin Finck                 HINTERNET hHttp = HttpOpenRequestW(hHost, NULL,
915c2c66affSColin Finck                  components.lpszUrlPath, NULL, NULL, types,
916c2c66affSColin Finck                  INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI,
917c2c66affSColin Finck                  (DWORD_PTR)context);
918c2c66affSColin Finck 
919c2c66affSColin Finck                 if (hHttp)
920c2c66affSColin Finck                 {
921c2c66affSColin Finck                     if (dwTimeout)
922c2c66affSColin Finck                     {
923c2c66affSColin Finck                         InternetSetOptionW(hHttp,
924c2c66affSColin Finck                          INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout,
925c2c66affSColin Finck                          sizeof(dwTimeout));
926c2c66affSColin Finck                         InternetSetOptionW(hHttp, INTERNET_OPTION_SEND_TIMEOUT,
927c2c66affSColin Finck                          &dwTimeout, sizeof(dwTimeout));
928c2c66affSColin Finck                     }
929c2c66affSColin Finck                     ret = HttpSendRequestExW(hHttp, NULL, NULL, 0,
930c2c66affSColin Finck                      (DWORD_PTR)context);
931c2c66affSColin Finck                     if (!ret && GetLastError() == ERROR_IO_PENDING)
932c2c66affSColin Finck                     {
933c2c66affSColin Finck                         if (WaitForSingleObject(context->event,
934c2c66affSColin Finck                          context->timeout) == WAIT_TIMEOUT)
935c2c66affSColin Finck                             SetLastError(ERROR_TIMEOUT);
936c2c66affSColin Finck                         else
937c2c66affSColin Finck                             ret = TRUE;
938c2c66affSColin Finck                     }
939c2c66affSColin Finck                     if (ret &&
940c2c66affSColin Finck                      !(ret = HttpEndRequestW(hHttp, NULL, 0, (DWORD_PTR)context)) &&
941c2c66affSColin Finck                      GetLastError() == ERROR_IO_PENDING)
942c2c66affSColin Finck                     {
943c2c66affSColin Finck                         if (WaitForSingleObject(context->event,
944c2c66affSColin Finck                          context->timeout) == WAIT_TIMEOUT)
945c2c66affSColin Finck                             SetLastError(ERROR_TIMEOUT);
946c2c66affSColin Finck                         else
947c2c66affSColin Finck                             ret = TRUE;
948c2c66affSColin Finck                     }
949c2c66affSColin Finck                     if (ret)
950c2c66affSColin Finck                         ret = CRYPT_DownloadObject(dwRetrievalFlags, hHttp,
951c2c66affSColin Finck                          context, pObject, pAuxInfo);
952c2c66affSColin Finck                     if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT))
953c2c66affSColin Finck                     {
954c2c66affSColin Finck                         SYSTEMTIME st;
955c2c66affSColin Finck                         FILETIME ft;
956c2c66affSColin Finck                         DWORD len = sizeof(st);
957c2c66affSColin Finck 
958c2c66affSColin Finck                         if (HttpQueryInfoW(hHttp, HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME,
959c2c66affSColin Finck                                     &st, &len, NULL) && SystemTimeToFileTime(&st, &ft))
960c2c66affSColin Finck                             CRYPT_CacheURL(pszURL, pObject, dwRetrievalFlags, ft);
961c2c66affSColin Finck                     }
962c2c66affSColin Finck                     InternetCloseHandle(hHttp);
963c2c66affSColin Finck                 }
964c2c66affSColin Finck                 InternetCloseHandle(hHost);
965c2c66affSColin Finck                 InternetCloseHandle(hInt);
966c2c66affSColin Finck             }
967c2c66affSColin Finck             if (context)
968c2c66affSColin Finck             {
969c2c66affSColin Finck                 CloseHandle(context->event);
970c2c66affSColin Finck                 CryptMemFree(context);
971c2c66affSColin Finck             }
972c2c66affSColin Finck             CryptMemFree(components.lpszUrlPath);
973c2c66affSColin Finck             CryptMemFree(components.lpszHostName);
974c2c66affSColin Finck         }
975c2c66affSColin Finck     }
976c2c66affSColin Finck     TRACE("returning %d\n", ret);
977c2c66affSColin Finck     return ret;
978c2c66affSColin Finck }
979c2c66affSColin Finck 
File_RetrieveEncodedObjectW(LPCWSTR pszURL,LPCSTR pszObjectOid,DWORD dwRetrievalFlags,DWORD dwTimeout,PCRYPT_BLOB_ARRAY pObject,PFN_FREE_ENCODED_OBJECT_FUNC * ppfnFreeObject,void ** ppvFreeContext,HCRYPTASYNC hAsyncRetrieve,PCRYPT_CREDENTIALS pCredentials,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)980c2c66affSColin Finck static BOOL WINAPI File_RetrieveEncodedObjectW(LPCWSTR pszURL,
981c2c66affSColin Finck  LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout,
982c2c66affSColin Finck  PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject,
983c2c66affSColin Finck  void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve,
984c2c66affSColin Finck  PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
985c2c66affSColin Finck {
986c2c66affSColin Finck     URL_COMPONENTSW components = { sizeof(components), 0 };
987c2c66affSColin Finck     BOOL ret;
988c2c66affSColin Finck 
989c2c66affSColin Finck     TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL),
990c2c66affSColin Finck      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, pObject,
991c2c66affSColin Finck      ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo);
992c2c66affSColin Finck 
993c2c66affSColin Finck     pObject->cBlob = 0;
994c2c66affSColin Finck     pObject->rgBlob = NULL;
995c2c66affSColin Finck     *ppfnFreeObject = CRYPT_FreeBlob;
996c2c66affSColin Finck     *ppvFreeContext = NULL;
997c2c66affSColin Finck 
998c2c66affSColin Finck     components.lpszUrlPath = CryptMemAlloc(INTERNET_MAX_PATH_LENGTH * sizeof(WCHAR));
999c2c66affSColin Finck     components.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
1000c2c66affSColin Finck     if (!components.lpszUrlPath)
1001c2c66affSColin Finck     {
1002c2c66affSColin Finck         SetLastError(ERROR_OUTOFMEMORY);
1003c2c66affSColin Finck         return FALSE;
1004c2c66affSColin Finck     }
1005c2c66affSColin Finck 
1006c2c66affSColin Finck     ret = InternetCrackUrlW(pszURL, 0, ICU_DECODE, &components);
1007c2c66affSColin Finck     if (ret)
1008c2c66affSColin Finck     {
1009c2c66affSColin Finck         LPWSTR path;
1010c2c66affSColin Finck 
1011c2c66affSColin Finck         /* 3 == lstrlenW(L"c:") + 1 */
1012c2c66affSColin Finck         path = CryptMemAlloc((components.dwUrlPathLength + 3) * sizeof(WCHAR));
1013c2c66affSColin Finck         if (path)
1014c2c66affSColin Finck         {
1015c2c66affSColin Finck             HANDLE hFile;
1016c2c66affSColin Finck 
1017c2c66affSColin Finck             /* Try to create the file directly - Wine handles / in pathnames */
1018c2c66affSColin Finck             lstrcpynW(path, components.lpszUrlPath,
1019c2c66affSColin Finck              components.dwUrlPathLength + 1);
1020c2c66affSColin Finck             hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
1021c2c66affSColin Finck              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1022c2c66affSColin Finck #ifdef __REACTOS__
1023c2c66affSColin Finck             if ((hFile == INVALID_HANDLE_VALUE) && (lstrlenW(components.lpszUrlPath) > 1) && (components.lpszUrlPath[1] != ':'))
1024c2c66affSColin Finck #else
1025c2c66affSColin Finck             if (hFile == INVALID_HANDLE_VALUE)
1026c2c66affSColin Finck #endif
1027c2c66affSColin Finck             {
1028c2c66affSColin Finck                 /* Try again on the current drive */
1029c2c66affSColin Finck                 GetCurrentDirectoryW(components.dwUrlPathLength, path);
1030c2c66affSColin Finck                 if (path[1] == ':')
1031c2c66affSColin Finck                 {
1032c2c66affSColin Finck                     lstrcpynW(path + 2, components.lpszUrlPath,
1033c2c66affSColin Finck                      components.dwUrlPathLength + 1);
1034c2c66affSColin Finck                     hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
1035c2c66affSColin Finck                      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1036c2c66affSColin Finck                 }
1037c2c66affSColin Finck                 if (hFile == INVALID_HANDLE_VALUE)
1038c2c66affSColin Finck                 {
1039c2c66affSColin Finck                     /* Try again on the Windows drive */
1040c2c66affSColin Finck                     GetWindowsDirectoryW(path, components.dwUrlPathLength);
1041c2c66affSColin Finck                     if (path[1] == ':')
1042c2c66affSColin Finck                     {
1043c2c66affSColin Finck                         lstrcpynW(path + 2, components.lpszUrlPath,
1044c2c66affSColin Finck                          components.dwUrlPathLength + 1);
1045c2c66affSColin Finck                         hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
1046c2c66affSColin Finck                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1047c2c66affSColin Finck                     }
1048c2c66affSColin Finck                 }
1049c2c66affSColin Finck             }
1050c2c66affSColin Finck             if (hFile != INVALID_HANDLE_VALUE)
1051c2c66affSColin Finck             {
1052c2c66affSColin Finck                 if ((ret = CRYPT_GetObjectFromFile(hFile, pObject)))
1053c2c66affSColin Finck                 {
1054c2c66affSColin Finck                     if (pAuxInfo && pAuxInfo->cbSize >=
1055c2c66affSColin Finck                      offsetof(CRYPT_RETRIEVE_AUX_INFO,
1056c2c66affSColin Finck                      pLastSyncTime) + sizeof(PFILETIME) &&
1057c2c66affSColin Finck                      pAuxInfo->pLastSyncTime)
1058c2c66affSColin Finck                         GetFileTime(hFile, NULL, NULL,
1059c2c66affSColin Finck                          pAuxInfo->pLastSyncTime);
1060c2c66affSColin Finck                 }
1061c2c66affSColin Finck                 CloseHandle(hFile);
1062c2c66affSColin Finck             }
1063c2c66affSColin Finck             else
1064c2c66affSColin Finck                 ret = FALSE;
1065c2c66affSColin Finck             CryptMemFree(path);
1066c2c66affSColin Finck         }
1067c2c66affSColin Finck         else
1068c2c66affSColin Finck         {
1069c2c66affSColin Finck             SetLastError(ERROR_OUTOFMEMORY);
1070c2c66affSColin Finck             ret = FALSE;
1071c2c66affSColin Finck         }
1072c2c66affSColin Finck     }
1073c2c66affSColin Finck     CryptMemFree(components.lpszUrlPath);
1074c2c66affSColin Finck     return ret;
1075c2c66affSColin Finck }
1076c2c66affSColin Finck 
1077c2c66affSColin Finck typedef BOOL (WINAPI *SchemeDllRetrieveEncodedObjectW)(LPCWSTR pwszUrl,
1078c2c66affSColin Finck  LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout,
1079c2c66affSColin Finck  PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC *ppfnFreeObject,
1080c2c66affSColin Finck  void **ppvFreeContext, HCRYPTASYNC hAsyncRetrieve,
1081c2c66affSColin Finck  PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo);
1082c2c66affSColin Finck 
CRYPT_GetRetrieveFunction(LPCWSTR pszURL,SchemeDllRetrieveEncodedObjectW * pFunc,HCRYPTOIDFUNCADDR * phFunc)1083c2c66affSColin Finck static BOOL CRYPT_GetRetrieveFunction(LPCWSTR pszURL,
1084c2c66affSColin Finck  SchemeDllRetrieveEncodedObjectW *pFunc, HCRYPTOIDFUNCADDR *phFunc)
1085c2c66affSColin Finck {
1086c2c66affSColin Finck     URL_COMPONENTSW components = { sizeof(components), 0 };
1087c2c66affSColin Finck     BOOL ret;
1088c2c66affSColin Finck 
1089c2c66affSColin Finck     TRACE("(%s, %p, %p)\n", debugstr_w(pszURL), pFunc, phFunc);
1090c2c66affSColin Finck 
1091c2c66affSColin Finck     *pFunc = NULL;
1092c2c66affSColin Finck     *phFunc = 0;
1093c2c66affSColin Finck     components.dwSchemeLength = 1;
1094c2c66affSColin Finck     ret = InternetCrackUrlW(pszURL, 0, 0, &components);
1095c2c66affSColin Finck     if (ret)
1096c2c66affSColin Finck     {
1097c2c66affSColin Finck         /* Microsoft always uses CryptInitOIDFunctionSet/
1098c2c66affSColin Finck          * CryptGetOIDFunctionAddress, but there doesn't seem to be a pressing
1099c2c66affSColin Finck          * reason to do so for builtin schemes.
1100c2c66affSColin Finck          */
1101c2c66affSColin Finck         switch (components.nScheme)
1102c2c66affSColin Finck         {
1103c2c66affSColin Finck         case INTERNET_SCHEME_FTP:
1104c2c66affSColin Finck             *pFunc = FTP_RetrieveEncodedObjectW;
1105c2c66affSColin Finck             break;
1106c2c66affSColin Finck         case INTERNET_SCHEME_HTTP:
1107c2c66affSColin Finck             *pFunc = HTTP_RetrieveEncodedObjectW;
1108c2c66affSColin Finck             break;
1109c2c66affSColin Finck         case INTERNET_SCHEME_FILE:
1110c2c66affSColin Finck             *pFunc = File_RetrieveEncodedObjectW;
1111c2c66affSColin Finck             break;
1112c2c66affSColin Finck         default:
1113c2c66affSColin Finck         {
1114c2c66affSColin Finck             int len = WideCharToMultiByte(CP_ACP, 0, components.lpszScheme,
1115c2c66affSColin Finck              components.dwSchemeLength, NULL, 0, NULL, NULL);
1116c2c66affSColin Finck 
1117c2c66affSColin Finck             if (len)
1118c2c66affSColin Finck             {
1119c2c66affSColin Finck                 LPSTR scheme = CryptMemAlloc(len);
1120c2c66affSColin Finck 
1121c2c66affSColin Finck                 if (scheme)
1122c2c66affSColin Finck                 {
1123c2c66affSColin Finck                     static HCRYPTOIDFUNCSET set = NULL;
1124c2c66affSColin Finck 
1125c2c66affSColin Finck                     if (!set)
1126c2c66affSColin Finck                         set = CryptInitOIDFunctionSet(
1127c2c66affSColin Finck                          SCHEME_OID_RETRIEVE_ENCODED_OBJECTW_FUNC, 0);
1128c2c66affSColin Finck                     WideCharToMultiByte(CP_ACP, 0, components.lpszScheme,
1129c2c66affSColin Finck                      components.dwSchemeLength, scheme, len, NULL, NULL);
1130c2c66affSColin Finck                     ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING,
1131c2c66affSColin Finck                      scheme, 0, (void **)pFunc, phFunc);
1132c2c66affSColin Finck                     CryptMemFree(scheme);
1133c2c66affSColin Finck                 }
1134c2c66affSColin Finck                 else
1135c2c66affSColin Finck                 {
1136c2c66affSColin Finck                     SetLastError(ERROR_OUTOFMEMORY);
1137c2c66affSColin Finck                     ret = FALSE;
1138c2c66affSColin Finck                 }
1139c2c66affSColin Finck             }
1140c2c66affSColin Finck             else
1141c2c66affSColin Finck                 ret = FALSE;
1142c2c66affSColin Finck         }
1143c2c66affSColin Finck         }
1144c2c66affSColin Finck     }
1145c2c66affSColin Finck     TRACE("returning %d\n", ret);
1146c2c66affSColin Finck     return ret;
1147c2c66affSColin Finck }
1148c2c66affSColin Finck 
CRYPT_CreateBlob(LPCSTR pszObjectOid,DWORD dwRetrievalFlags,const CRYPT_BLOB_ARRAY * pObject,void ** ppvContext)1149c2c66affSColin Finck static BOOL WINAPI CRYPT_CreateBlob(LPCSTR pszObjectOid,
1150c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext)
1151c2c66affSColin Finck {
1152c2c66affSColin Finck     DWORD size, i;
1153c2c66affSColin Finck     CRYPT_BLOB_ARRAY *context;
1154c2c66affSColin Finck     BOOL ret = FALSE;
1155c2c66affSColin Finck 
1156c2c66affSColin Finck     size = sizeof(CRYPT_BLOB_ARRAY) + pObject->cBlob * sizeof(CRYPT_DATA_BLOB);
1157c2c66affSColin Finck     for (i = 0; i < pObject->cBlob; i++)
1158c2c66affSColin Finck         size += pObject->rgBlob[i].cbData;
1159c2c66affSColin Finck     context = CryptMemAlloc(size);
1160c2c66affSColin Finck     if (context)
1161c2c66affSColin Finck     {
1162c2c66affSColin Finck         LPBYTE nextData;
1163c2c66affSColin Finck 
1164c2c66affSColin Finck         context->cBlob = 0;
1165c2c66affSColin Finck         context->rgBlob =
1166c2c66affSColin Finck          (CRYPT_DATA_BLOB *)((LPBYTE)context + sizeof(CRYPT_BLOB_ARRAY));
1167c2c66affSColin Finck         nextData =
1168c2c66affSColin Finck          (LPBYTE)context->rgBlob + pObject->cBlob * sizeof(CRYPT_DATA_BLOB);
1169c2c66affSColin Finck         for (i = 0; i < pObject->cBlob; i++)
1170c2c66affSColin Finck         {
1171c2c66affSColin Finck             memcpy(nextData, pObject->rgBlob[i].pbData,
1172c2c66affSColin Finck              pObject->rgBlob[i].cbData);
1173c2c66affSColin Finck             context->rgBlob[i].pbData = nextData;
1174c2c66affSColin Finck             context->rgBlob[i].cbData = pObject->rgBlob[i].cbData;
1175c2c66affSColin Finck             nextData += pObject->rgBlob[i].cbData;
1176c2c66affSColin Finck             context->cBlob++;
1177c2c66affSColin Finck         }
1178c2c66affSColin Finck         *ppvContext = context;
1179c2c66affSColin Finck         ret = TRUE;
1180c2c66affSColin Finck     }
1181c2c66affSColin Finck     return ret;
1182c2c66affSColin Finck }
1183c2c66affSColin Finck 
1184c2c66affSColin Finck typedef BOOL (WINAPI *AddContextToStore)(HCERTSTORE hCertStore,
1185c2c66affSColin Finck  const void *pContext, DWORD dwAddDisposition, const void **ppStoreContext);
1186c2c66affSColin Finck 
decode_base64_blob(const CRYPT_DATA_BLOB * in,CRYPT_DATA_BLOB * out)1187c2c66affSColin Finck static BOOL decode_base64_blob( const CRYPT_DATA_BLOB *in, CRYPT_DATA_BLOB *out )
1188c2c66affSColin Finck {
1189c2c66affSColin Finck     BOOL ret;
1190c2c66affSColin Finck     DWORD len = in->cbData;
1191c2c66affSColin Finck 
1192c2c66affSColin Finck     while (len && !in->pbData[len - 1]) len--;
1193c2c66affSColin Finck     if (!CryptStringToBinaryA( (char *)in->pbData, len, CRYPT_STRING_BASE64_ANY,
1194c2c66affSColin Finck                                NULL, &out->cbData, NULL, NULL )) return FALSE;
1195c2c66affSColin Finck 
1196c2c66affSColin Finck     if (!(out->pbData = CryptMemAlloc( out->cbData ))) return FALSE;
1197c2c66affSColin Finck     ret = CryptStringToBinaryA( (char *)in->pbData, len, CRYPT_STRING_BASE64_ANY,
1198c2c66affSColin Finck                                 out->pbData, &out->cbData, NULL, NULL );
1199c2c66affSColin Finck     if (!ret) CryptMemFree( out->pbData );
1200c2c66affSColin Finck     return ret;
1201c2c66affSColin Finck }
1202c2c66affSColin Finck 
CRYPT_CreateContext(const CRYPT_BLOB_ARRAY * pObject,DWORD dwExpectedContentTypeFlags,AddContextToStore addFunc,void ** ppvContext)1203c2c66affSColin Finck static BOOL CRYPT_CreateContext(const CRYPT_BLOB_ARRAY *pObject,
1204c2c66affSColin Finck  DWORD dwExpectedContentTypeFlags, AddContextToStore addFunc, void **ppvContext)
1205c2c66affSColin Finck {
1206c2c66affSColin Finck     BOOL ret = TRUE;
1207c2c66affSColin Finck     CRYPT_DATA_BLOB blob;
1208c2c66affSColin Finck 
1209c2c66affSColin Finck     if (!pObject->cBlob)
1210c2c66affSColin Finck     {
1211c2c66affSColin Finck         SetLastError(ERROR_INVALID_DATA);
1212c2c66affSColin Finck         *ppvContext = NULL;
1213c2c66affSColin Finck         ret = FALSE;
1214c2c66affSColin Finck     }
1215c2c66affSColin Finck     else if (pObject->cBlob == 1)
1216c2c66affSColin Finck     {
1217c2c66affSColin Finck         if (decode_base64_blob(&pObject->rgBlob[0], &blob))
1218c2c66affSColin Finck         {
1219c2c66affSColin Finck             ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
1220c2c66affSColin Finck              dwExpectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_BINARY, 0,
1221c2c66affSColin Finck              NULL, NULL, NULL, NULL, NULL, (const void **)ppvContext);
1222c2c66affSColin Finck             CryptMemFree(blob.pbData);
1223c2c66affSColin Finck         }
1224c2c66affSColin Finck         else
1225c2c66affSColin Finck         {
1226c2c66affSColin Finck             ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pObject->rgBlob[0],
1227c2c66affSColin Finck              dwExpectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_BINARY, 0,
1228c2c66affSColin Finck              NULL, NULL, NULL, NULL, NULL, (const void **)ppvContext);
1229c2c66affSColin Finck         }
1230c2c66affSColin Finck         if (!ret)
1231c2c66affSColin Finck         {
1232c2c66affSColin Finck             SetLastError(CRYPT_E_NO_MATCH);
1233c2c66affSColin Finck             ret = FALSE;
1234c2c66affSColin Finck         }
1235c2c66affSColin Finck     }
1236c2c66affSColin Finck     else
1237c2c66affSColin Finck     {
1238c2c66affSColin Finck         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1239c2c66affSColin Finck          CERT_STORE_CREATE_NEW_FLAG, NULL);
1240c2c66affSColin Finck 
1241c2c66affSColin Finck         if (store)
1242c2c66affSColin Finck         {
1243c2c66affSColin Finck             DWORD i;
1244c2c66affSColin Finck             const void *context;
1245c2c66affSColin Finck 
1246c2c66affSColin Finck             for (i = 0; i < pObject->cBlob; i++)
1247c2c66affSColin Finck             {
1248c2c66affSColin Finck                 if (decode_base64_blob(&pObject->rgBlob[i], &blob))
1249c2c66affSColin Finck                 {
1250c2c66affSColin Finck                     ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
1251c2c66affSColin Finck                      dwExpectedContentTypeFlags, CERT_QUERY_FORMAT_FLAG_BINARY,
1252c2c66affSColin Finck                      0, NULL, NULL, NULL, NULL, NULL, &context);
1253c2c66affSColin Finck                     CryptMemFree(blob.pbData);
1254c2c66affSColin Finck                 }
1255c2c66affSColin Finck                 else
1256c2c66affSColin Finck                 {
1257c2c66affSColin Finck                     ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
1258c2c66affSColin Finck                      &pObject->rgBlob[i], dwExpectedContentTypeFlags,
1259c2c66affSColin Finck                      CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, NULL,
1260c2c66affSColin Finck                      NULL, &context);
1261c2c66affSColin Finck                 }
1262c2c66affSColin Finck                 if (ret)
1263c2c66affSColin Finck                 {
1264c2c66affSColin Finck                     if (!addFunc(store, context, CERT_STORE_ADD_ALWAYS, NULL))
1265c2c66affSColin Finck                         ret = FALSE;
1266c2c66affSColin Finck                 }
1267c2c66affSColin Finck                 else
1268c2c66affSColin Finck                 {
1269c2c66affSColin Finck                     SetLastError(CRYPT_E_NO_MATCH);
1270c2c66affSColin Finck                     ret = FALSE;
1271c2c66affSColin Finck                 }
1272c2c66affSColin Finck             }
1273c2c66affSColin Finck         }
1274c2c66affSColin Finck         else
1275c2c66affSColin Finck             ret = FALSE;
1276c2c66affSColin Finck         *ppvContext = store;
1277c2c66affSColin Finck     }
1278c2c66affSColin Finck     return ret;
1279c2c66affSColin Finck }
1280c2c66affSColin Finck 
CRYPT_CreateCert(LPCSTR pszObjectOid,DWORD dwRetrievalFlags,const CRYPT_BLOB_ARRAY * pObject,void ** ppvContext)1281c2c66affSColin Finck static BOOL WINAPI CRYPT_CreateCert(LPCSTR pszObjectOid,
1282c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext)
1283c2c66affSColin Finck {
1284c2c66affSColin Finck     return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CERT,
1285c2c66affSColin Finck      (AddContextToStore)CertAddCertificateContextToStore, ppvContext);
1286c2c66affSColin Finck }
1287c2c66affSColin Finck 
CRYPT_CreateCRL(LPCSTR pszObjectOid,DWORD dwRetrievalFlags,const CRYPT_BLOB_ARRAY * pObject,void ** ppvContext)1288c2c66affSColin Finck static BOOL WINAPI CRYPT_CreateCRL(LPCSTR pszObjectOid,
1289c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext)
1290c2c66affSColin Finck {
1291c2c66affSColin Finck     return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CRL,
1292c2c66affSColin Finck      (AddContextToStore)CertAddCRLContextToStore, ppvContext);
1293c2c66affSColin Finck }
1294c2c66affSColin Finck 
CRYPT_CreateCTL(LPCSTR pszObjectOid,DWORD dwRetrievalFlags,const CRYPT_BLOB_ARRAY * pObject,void ** ppvContext)1295c2c66affSColin Finck static BOOL WINAPI CRYPT_CreateCTL(LPCSTR pszObjectOid,
1296c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext)
1297c2c66affSColin Finck {
1298c2c66affSColin Finck     return CRYPT_CreateContext(pObject, CERT_QUERY_CONTENT_FLAG_CTL,
1299c2c66affSColin Finck      (AddContextToStore)CertAddCTLContextToStore, ppvContext);
1300c2c66affSColin Finck }
1301c2c66affSColin Finck 
CRYPT_CreatePKCS7(LPCSTR pszObjectOid,DWORD dwRetrievalFlags,const CRYPT_BLOB_ARRAY * pObject,void ** ppvContext)1302c2c66affSColin Finck static BOOL WINAPI CRYPT_CreatePKCS7(LPCSTR pszObjectOid,
1303c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext)
1304c2c66affSColin Finck {
1305c2c66affSColin Finck     BOOL ret;
1306c2c66affSColin Finck 
1307c2c66affSColin Finck     if (!pObject->cBlob)
1308c2c66affSColin Finck     {
1309c2c66affSColin Finck         SetLastError(ERROR_INVALID_DATA);
1310c2c66affSColin Finck         *ppvContext = NULL;
1311c2c66affSColin Finck         ret = FALSE;
1312c2c66affSColin Finck     }
1313c2c66affSColin Finck     else if (pObject->cBlob == 1)
1314c2c66affSColin Finck         ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pObject->rgBlob[0],
1315c2c66affSColin Finck          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
1316c2c66affSColin Finck          CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED, CERT_QUERY_FORMAT_FLAG_BINARY,
1317c2c66affSColin Finck          0, NULL, NULL, NULL, ppvContext, NULL, NULL);
1318c2c66affSColin Finck     else
1319c2c66affSColin Finck     {
1320c2c66affSColin Finck         FIXME("multiple messages unimplemented\n");
1321c2c66affSColin Finck         ret = FALSE;
1322c2c66affSColin Finck     }
1323c2c66affSColin Finck     return ret;
1324c2c66affSColin Finck }
1325c2c66affSColin Finck 
CRYPT_CreateAny(LPCSTR pszObjectOid,DWORD dwRetrievalFlags,const CRYPT_BLOB_ARRAY * pObject,void ** ppvContext)1326c2c66affSColin Finck static BOOL WINAPI CRYPT_CreateAny(LPCSTR pszObjectOid,
1327c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext)
1328c2c66affSColin Finck {
1329c2c66affSColin Finck     BOOL ret;
1330c2c66affSColin Finck 
1331c2c66affSColin Finck     if (!pObject->cBlob)
1332c2c66affSColin Finck     {
1333c2c66affSColin Finck         SetLastError(ERROR_INVALID_DATA);
1334c2c66affSColin Finck         *ppvContext = NULL;
1335c2c66affSColin Finck         ret = FALSE;
1336c2c66affSColin Finck     }
1337c2c66affSColin Finck     else
1338c2c66affSColin Finck     {
1339c2c66affSColin Finck         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1340c2c66affSColin Finck          CERT_STORE_CREATE_NEW_FLAG, NULL);
1341c2c66affSColin Finck 
1342c2c66affSColin Finck         if (store)
1343c2c66affSColin Finck         {
1344c2c66affSColin Finck             HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
1345c2c66affSColin Finck              CERT_STORE_CREATE_NEW_FLAG, NULL);
1346c2c66affSColin Finck 
1347c2c66affSColin Finck             if (memStore)
1348c2c66affSColin Finck             {
1349c2c66affSColin Finck                 CertAddStoreToCollection(store, memStore,
1350c2c66affSColin Finck                  CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1351c2c66affSColin Finck                 CertCloseStore(memStore, 0);
1352c2c66affSColin Finck             }
1353c2c66affSColin Finck             else
1354c2c66affSColin Finck             {
1355c2c66affSColin Finck                 CertCloseStore(store, 0);
1356c2c66affSColin Finck                 store = NULL;
1357c2c66affSColin Finck             }
1358c2c66affSColin Finck         }
1359c2c66affSColin Finck         if (store)
1360c2c66affSColin Finck         {
1361c2c66affSColin Finck             DWORD i;
1362c2c66affSColin Finck 
1363c2c66affSColin Finck             ret = TRUE;
1364c2c66affSColin Finck             for (i = 0; i < pObject->cBlob; i++)
1365c2c66affSColin Finck             {
1366c2c66affSColin Finck                 DWORD contentType, expectedContentTypes =
1367c2c66affSColin Finck                  CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
1368c2c66affSColin Finck                  CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED |
1369c2c66affSColin Finck                  CERT_QUERY_CONTENT_FLAG_CERT |
1370c2c66affSColin Finck                  CERT_QUERY_CONTENT_FLAG_CRL |
1371c2c66affSColin Finck                  CERT_QUERY_CONTENT_FLAG_CTL;
1372c2c66affSColin Finck                 HCERTSTORE contextStore;
1373c2c66affSColin Finck                 const void *context;
1374c2c66affSColin Finck 
1375c2c66affSColin Finck                 if (CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
1376c2c66affSColin Finck                  &pObject->rgBlob[i], expectedContentTypes,
1377c2c66affSColin Finck                  CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, &contentType, NULL,
1378c2c66affSColin Finck                  &contextStore, NULL, &context))
1379c2c66affSColin Finck                 {
1380c2c66affSColin Finck                     switch (contentType)
1381c2c66affSColin Finck                     {
1382c2c66affSColin Finck                     case CERT_QUERY_CONTENT_CERT:
1383c2c66affSColin Finck                         if (!CertAddCertificateContextToStore(store,
1384c2c66affSColin Finck                          context, CERT_STORE_ADD_ALWAYS, NULL))
1385c2c66affSColin Finck                             ret = FALSE;
1386c2c66affSColin Finck                         CertFreeCertificateContext(context);
1387c2c66affSColin Finck                         break;
1388c2c66affSColin Finck                     case CERT_QUERY_CONTENT_CRL:
1389c2c66affSColin Finck                         if (!CertAddCRLContextToStore(store,
1390c2c66affSColin Finck                          context, CERT_STORE_ADD_ALWAYS, NULL))
1391c2c66affSColin Finck                              ret = FALSE;
1392c2c66affSColin Finck                         CertFreeCRLContext(context);
1393c2c66affSColin Finck                         break;
1394c2c66affSColin Finck                     case CERT_QUERY_CONTENT_CTL:
1395c2c66affSColin Finck                         if (!CertAddCTLContextToStore(store,
1396c2c66affSColin Finck                          context, CERT_STORE_ADD_ALWAYS, NULL))
1397c2c66affSColin Finck                              ret = FALSE;
1398c2c66affSColin Finck                         CertFreeCTLContext(context);
1399c2c66affSColin Finck                         break;
1400c2c66affSColin Finck                     default:
1401c2c66affSColin Finck                         CertAddStoreToCollection(store, contextStore, 0, 0);
1402c2c66affSColin Finck                     }
1403c2c66affSColin Finck                     CertCloseStore(contextStore, 0);
1404c2c66affSColin Finck                 }
1405c2c66affSColin Finck                 else
1406c2c66affSColin Finck                     ret = FALSE;
1407c2c66affSColin Finck             }
1408c2c66affSColin Finck         }
1409c2c66affSColin Finck         else
1410c2c66affSColin Finck             ret = FALSE;
1411c2c66affSColin Finck         *ppvContext = store;
1412c2c66affSColin Finck     }
1413c2c66affSColin Finck     return ret;
1414c2c66affSColin Finck }
1415c2c66affSColin Finck 
1416c2c66affSColin Finck typedef BOOL (WINAPI *ContextDllCreateObjectContext)(LPCSTR pszObjectOid,
1417c2c66affSColin Finck  DWORD dwRetrievalFlags, const CRYPT_BLOB_ARRAY *pObject, void **ppvContext);
1418c2c66affSColin Finck 
CRYPT_GetCreateFunction(LPCSTR pszObjectOid,ContextDllCreateObjectContext * pFunc,HCRYPTOIDFUNCADDR * phFunc)1419c2c66affSColin Finck static BOOL CRYPT_GetCreateFunction(LPCSTR pszObjectOid,
1420c2c66affSColin Finck  ContextDllCreateObjectContext *pFunc, HCRYPTOIDFUNCADDR *phFunc)
1421c2c66affSColin Finck {
1422c2c66affSColin Finck     BOOL ret = TRUE;
1423c2c66affSColin Finck 
1424c2c66affSColin Finck     TRACE("(%s, %p, %p)\n", debugstr_a(pszObjectOid), pFunc, phFunc);
1425c2c66affSColin Finck 
1426c2c66affSColin Finck     *pFunc = NULL;
1427c2c66affSColin Finck     *phFunc = 0;
1428c2c66affSColin Finck     if (IS_INTOID(pszObjectOid))
1429c2c66affSColin Finck     {
1430c2c66affSColin Finck         switch (LOWORD(pszObjectOid))
1431c2c66affSColin Finck         {
1432c2c66affSColin Finck         case 0:
1433c2c66affSColin Finck             *pFunc = CRYPT_CreateBlob;
1434c2c66affSColin Finck             break;
1435c2c66affSColin Finck         case LOWORD(CONTEXT_OID_CERTIFICATE):
1436c2c66affSColin Finck             *pFunc = CRYPT_CreateCert;
1437c2c66affSColin Finck             break;
1438c2c66affSColin Finck         case LOWORD(CONTEXT_OID_CRL):
1439c2c66affSColin Finck             *pFunc = CRYPT_CreateCRL;
1440c2c66affSColin Finck             break;
1441c2c66affSColin Finck         case LOWORD(CONTEXT_OID_CTL):
1442c2c66affSColin Finck             *pFunc = CRYPT_CreateCTL;
1443c2c66affSColin Finck             break;
1444c2c66affSColin Finck         case LOWORD(CONTEXT_OID_PKCS7):
1445c2c66affSColin Finck             *pFunc = CRYPT_CreatePKCS7;
1446c2c66affSColin Finck             break;
1447c2c66affSColin Finck         case LOWORD(CONTEXT_OID_CAPI2_ANY):
1448c2c66affSColin Finck             *pFunc = CRYPT_CreateAny;
1449c2c66affSColin Finck             break;
1450c2c66affSColin Finck         }
1451c2c66affSColin Finck     }
1452c2c66affSColin Finck     if (!*pFunc)
1453c2c66affSColin Finck     {
1454c2c66affSColin Finck         static HCRYPTOIDFUNCSET set = NULL;
1455c2c66affSColin Finck 
1456c2c66affSColin Finck         if (!set)
1457c2c66affSColin Finck             set = CryptInitOIDFunctionSet(
1458c2c66affSColin Finck              CONTEXT_OID_CREATE_OBJECT_CONTEXT_FUNC, 0);
1459c2c66affSColin Finck         ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, pszObjectOid,
1460c2c66affSColin Finck          0, (void **)pFunc, phFunc);
1461c2c66affSColin Finck     }
1462c2c66affSColin Finck     TRACE("returning %d\n", ret);
1463c2c66affSColin Finck     return ret;
1464c2c66affSColin Finck }
1465c2c66affSColin Finck 
CRYPT_GetExpiration(const void * object,const char * pszObjectOid,FILETIME * expiration)1466c2c66affSColin Finck static BOOL CRYPT_GetExpiration(const void *object, const char *pszObjectOid, FILETIME *expiration)
1467c2c66affSColin Finck {
1468c2c66affSColin Finck     if (!IS_INTOID(pszObjectOid))
1469c2c66affSColin Finck         return FALSE;
1470c2c66affSColin Finck 
1471c2c66affSColin Finck     switch (LOWORD(pszObjectOid)) {
1472c2c66affSColin Finck     case LOWORD(CONTEXT_OID_CERTIFICATE):
1473c2c66affSColin Finck         *expiration = ((const CERT_CONTEXT*)object)->pCertInfo->NotAfter;
1474c2c66affSColin Finck         return TRUE;
1475c2c66affSColin Finck     case LOWORD(CONTEXT_OID_CRL):
1476c2c66affSColin Finck         *expiration = ((const CRL_CONTEXT*)object)->pCrlInfo->NextUpdate;
1477c2c66affSColin Finck         return TRUE;
1478c2c66affSColin Finck     case LOWORD(CONTEXT_OID_CTL):
1479c2c66affSColin Finck         *expiration = ((const CTL_CONTEXT*)object)->pCtlInfo->NextUpdate;
1480c2c66affSColin Finck         return TRUE;
1481c2c66affSColin Finck     }
1482c2c66affSColin Finck 
1483c2c66affSColin Finck     return FALSE;
1484c2c66affSColin Finck }
1485c2c66affSColin Finck 
1486c2c66affSColin Finck /***********************************************************************
1487c2c66affSColin Finck  *    CryptRetrieveObjectByUrlW (CRYPTNET.@)
1488c2c66affSColin Finck  */
CryptRetrieveObjectByUrlW(LPCWSTR pszURL,LPCSTR pszObjectOid,DWORD dwRetrievalFlags,DWORD dwTimeout,LPVOID * ppvObject,HCRYPTASYNC hAsyncRetrieve,PCRYPT_CREDENTIALS pCredentials,LPVOID pvVerify,PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)1489c2c66affSColin Finck BOOL WINAPI CryptRetrieveObjectByUrlW(LPCWSTR pszURL, LPCSTR pszObjectOid,
1490c2c66affSColin Finck  DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID *ppvObject,
1491c2c66affSColin Finck  HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify,
1492c2c66affSColin Finck  PCRYPT_RETRIEVE_AUX_INFO pAuxInfo)
1493c2c66affSColin Finck {
1494c2c66affSColin Finck     BOOL ret;
1495c2c66affSColin Finck     SchemeDllRetrieveEncodedObjectW retrieve;
1496c2c66affSColin Finck     ContextDllCreateObjectContext create;
1497c2c66affSColin Finck     HCRYPTOIDFUNCADDR hRetrieve = 0, hCreate = 0;
1498c2c66affSColin Finck 
1499c2c66affSColin Finck     TRACE("(%s, %s, %08x, %d, %p, %p, %p, %p, %p)\n", debugstr_w(pszURL),
1500c2c66affSColin Finck      debugstr_a(pszObjectOid), dwRetrievalFlags, dwTimeout, ppvObject,
1501c2c66affSColin Finck      hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo);
1502c2c66affSColin Finck 
1503c2c66affSColin Finck     if (!pszURL)
1504c2c66affSColin Finck     {
1505c2c66affSColin Finck         SetLastError(ERROR_INVALID_PARAMETER);
1506c2c66affSColin Finck         return FALSE;
1507c2c66affSColin Finck     }
1508c2c66affSColin Finck     ret = CRYPT_GetRetrieveFunction(pszURL, &retrieve, &hRetrieve);
1509c2c66affSColin Finck     if (ret)
1510c2c66affSColin Finck         ret = CRYPT_GetCreateFunction(pszObjectOid, &create, &hCreate);
1511c2c66affSColin Finck     if (ret)
1512c2c66affSColin Finck     {
1513c2c66affSColin Finck         CRYPT_BLOB_ARRAY object = { 0, NULL };
1514c2c66affSColin Finck         PFN_FREE_ENCODED_OBJECT_FUNC freeObject;
1515c2c66affSColin Finck         void *freeContext;
1516c2c66affSColin Finck         FILETIME expires;
1517c2c66affSColin Finck 
1518c2c66affSColin Finck         ret = retrieve(pszURL, pszObjectOid, dwRetrievalFlags, dwTimeout,
1519c2c66affSColin Finck          &object, &freeObject, &freeContext, hAsyncRetrieve, pCredentials,
1520c2c66affSColin Finck          pAuxInfo);
1521c2c66affSColin Finck         if (ret)
1522c2c66affSColin Finck         {
1523c2c66affSColin Finck             ret = create(pszObjectOid, dwRetrievalFlags, &object, ppvObject);
1524c2c66affSColin Finck             if (ret && !(dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT) &&
1525c2c66affSColin Finck                 CRYPT_GetExpiration(*ppvObject, pszObjectOid, &expires))
1526c2c66affSColin Finck             {
1527c2c66affSColin Finck                 CRYPT_CacheURL(pszURL, &object, dwRetrievalFlags, expires);
1528c2c66affSColin Finck             }
1529c2c66affSColin Finck             freeObject(pszObjectOid, &object, freeContext);
1530c2c66affSColin Finck         }
1531c2c66affSColin Finck     }
1532c2c66affSColin Finck     if (hCreate)
1533c2c66affSColin Finck         CryptFreeOIDFunctionAddress(hCreate, 0);
1534c2c66affSColin Finck     if (hRetrieve)
1535c2c66affSColin Finck         CryptFreeOIDFunctionAddress(hRetrieve, 0);
1536c2c66affSColin Finck     TRACE("returning %d\n", ret);
1537c2c66affSColin Finck     return ret;
1538c2c66affSColin Finck }
1539c2c66affSColin Finck 
verify_cert_revocation_with_crl_online(PCCERT_CONTEXT cert,PCCRL_CONTEXT crl,DWORD index,FILETIME * pTime,PCERT_REVOCATION_STATUS pRevStatus)1540c2c66affSColin Finck static DWORD verify_cert_revocation_with_crl_online(PCCERT_CONTEXT cert,
1541c2c66affSColin Finck  PCCRL_CONTEXT crl, DWORD index, FILETIME *pTime,
1542c2c66affSColin Finck  PCERT_REVOCATION_STATUS pRevStatus)
1543c2c66affSColin Finck {
1544c2c66affSColin Finck     DWORD error;
1545c2c66affSColin Finck     PCRL_ENTRY entry = NULL;
1546c2c66affSColin Finck 
1547c2c66affSColin Finck     CertFindCertificateInCRL(cert, crl, 0, NULL, &entry);
1548c2c66affSColin Finck     if (entry)
1549c2c66affSColin Finck     {
1550c2c66affSColin Finck         error = CRYPT_E_REVOKED;
1551c2c66affSColin Finck         pRevStatus->dwIndex = index;
1552c2c66affSColin Finck     }
1553c2c66affSColin Finck     else
1554c2c66affSColin Finck     {
1555c2c66affSColin Finck         /* Since the CRL was retrieved for the cert being checked, then it's
1556c2c66affSColin Finck          * guaranteed to be fresh, and the cert is not revoked.
1557c2c66affSColin Finck          */
1558c2c66affSColin Finck         error = ERROR_SUCCESS;
1559c2c66affSColin Finck     }
1560c2c66affSColin Finck     return error;
1561c2c66affSColin Finck }
1562c2c66affSColin Finck 
verify_cert_revocation_from_dist_points_ext(const CRYPT_DATA_BLOB * value,PCCERT_CONTEXT cert,DWORD index,FILETIME * pTime,DWORD dwFlags,const CERT_REVOCATION_PARA * pRevPara,PCERT_REVOCATION_STATUS pRevStatus)1563c2c66affSColin Finck static DWORD verify_cert_revocation_from_dist_points_ext(
1564c2c66affSColin Finck  const CRYPT_DATA_BLOB *value, PCCERT_CONTEXT cert, DWORD index,
1565c2c66affSColin Finck  FILETIME *pTime, DWORD dwFlags, const CERT_REVOCATION_PARA *pRevPara,
1566c2c66affSColin Finck  PCERT_REVOCATION_STATUS pRevStatus)
1567c2c66affSColin Finck {
1568c2c66affSColin Finck     DWORD error = ERROR_SUCCESS, cbUrlArray;
1569c2c66affSColin Finck 
1570c2c66affSColin Finck     if (CRYPT_GetUrlFromCRLDistPointsExt(value, NULL, &cbUrlArray, NULL, NULL))
1571c2c66affSColin Finck     {
1572c2c66affSColin Finck         CRYPT_URL_ARRAY *urlArray = CryptMemAlloc(cbUrlArray);
1573c2c66affSColin Finck 
1574c2c66affSColin Finck         if (urlArray)
1575c2c66affSColin Finck         {
1576c2c66affSColin Finck             DWORD j, retrievalFlags = 0, startTime, endTime, timeout;
1577c2c66affSColin Finck             BOOL ret;
1578c2c66affSColin Finck 
1579c2c66affSColin Finck             ret = CRYPT_GetUrlFromCRLDistPointsExt(value, urlArray,
1580c2c66affSColin Finck              &cbUrlArray, NULL, NULL);
1581c2c66affSColin Finck             if (dwFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION)
1582c2c66affSColin Finck                 retrievalFlags |= CRYPT_CACHE_ONLY_RETRIEVAL;
1583c2c66affSColin Finck             if (dwFlags & CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG &&
1584c2c66affSColin Finck              pRevPara && pRevPara->cbSize >= offsetof(CERT_REVOCATION_PARA,
1585c2c66affSColin Finck              dwUrlRetrievalTimeout) + sizeof(DWORD))
1586c2c66affSColin Finck             {
1587c2c66affSColin Finck                 startTime = GetTickCount();
1588c2c66affSColin Finck                 endTime = startTime + pRevPara->dwUrlRetrievalTimeout;
1589c2c66affSColin Finck                 timeout = pRevPara->dwUrlRetrievalTimeout;
1590c2c66affSColin Finck             }
1591c2c66affSColin Finck             else
1592c2c66affSColin Finck                 endTime = timeout = 0;
1593c2c66affSColin Finck             if (!ret)
1594c2c66affSColin Finck                 error = GetLastError();
1595c2c66affSColin Finck             /* continue looping if one was offline; break if revoked or timed out */
1596c2c66affSColin Finck             for (j = 0; (!error || error == CRYPT_E_REVOCATION_OFFLINE) && j < urlArray->cUrl; j++)
1597c2c66affSColin Finck             {
1598c2c66affSColin Finck                 PCCRL_CONTEXT crl;
1599c2c66affSColin Finck 
1600c2c66affSColin Finck                 ret = CryptRetrieveObjectByUrlW(urlArray->rgwszUrl[j],
1601c2c66affSColin Finck                  CONTEXT_OID_CRL, retrievalFlags, timeout, (void **)&crl,
1602c2c66affSColin Finck                  NULL, NULL, NULL, NULL);
1603c2c66affSColin Finck                 if (ret)
1604c2c66affSColin Finck                 {
1605c2c66affSColin Finck                     error = verify_cert_revocation_with_crl_online(cert, crl,
1606c2c66affSColin Finck                      index, pTime, pRevStatus);
1607c2c66affSColin Finck                     if (!error && timeout)
1608c2c66affSColin Finck                     {
1609c2c66affSColin Finck                         DWORD time = GetTickCount();
1610c2c66affSColin Finck 
1611c2c66affSColin Finck                         if ((int)(endTime - time) <= 0)
1612c2c66affSColin Finck                         {
1613c2c66affSColin Finck                             error = ERROR_TIMEOUT;
1614c2c66affSColin Finck                             pRevStatus->dwIndex = index;
1615c2c66affSColin Finck                         }
1616c2c66affSColin Finck                         else
1617c2c66affSColin Finck                             timeout = endTime - time;
1618c2c66affSColin Finck                     }
1619c2c66affSColin Finck                     CertFreeCRLContext(crl);
1620c2c66affSColin Finck                 }
1621c2c66affSColin Finck                 else
1622c2c66affSColin Finck                     error = CRYPT_E_REVOCATION_OFFLINE;
1623c2c66affSColin Finck             }
1624c2c66affSColin Finck             CryptMemFree(urlArray);
1625c2c66affSColin Finck         }
1626c2c66affSColin Finck         else
1627c2c66affSColin Finck         {
1628c2c66affSColin Finck             error = ERROR_OUTOFMEMORY;
1629c2c66affSColin Finck             pRevStatus->dwIndex = index;
1630c2c66affSColin Finck         }
1631c2c66affSColin Finck     }
1632c2c66affSColin Finck     else
1633c2c66affSColin Finck     {
1634c2c66affSColin Finck         error = GetLastError();
1635c2c66affSColin Finck         pRevStatus->dwIndex = index;
1636c2c66affSColin Finck     }
1637c2c66affSColin Finck     return error;
1638c2c66affSColin Finck }
1639c2c66affSColin Finck 
verify_cert_revocation_from_aia_ext(const CRYPT_DATA_BLOB * value,PCCERT_CONTEXT cert,DWORD index,FILETIME * pTime,DWORD dwFlags,PCERT_REVOCATION_PARA pRevPara,PCERT_REVOCATION_STATUS pRevStatus)1640c2c66affSColin Finck static DWORD verify_cert_revocation_from_aia_ext(
1641c2c66affSColin Finck  const CRYPT_DATA_BLOB *value, PCCERT_CONTEXT cert, DWORD index,
1642c2c66affSColin Finck  FILETIME *pTime, DWORD dwFlags, PCERT_REVOCATION_PARA pRevPara,
1643c2c66affSColin Finck  PCERT_REVOCATION_STATUS pRevStatus)
1644c2c66affSColin Finck {
1645c2c66affSColin Finck     BOOL ret;
1646c2c66affSColin Finck     DWORD error, size;
1647c2c66affSColin Finck     CERT_AUTHORITY_INFO_ACCESS *aia;
1648c2c66affSColin Finck 
1649c2c66affSColin Finck     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_AUTHORITY_INFO_ACCESS,
1650c2c66affSColin Finck      value->pbData, value->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &aia, &size);
1651c2c66affSColin Finck     if (ret)
1652c2c66affSColin Finck     {
1653c2c66affSColin Finck         DWORD i;
1654c2c66affSColin Finck 
1655c2c66affSColin Finck         for (i = 0; i < aia->cAccDescr; i++)
1656c2c66affSColin Finck             if (!strcmp(aia->rgAccDescr[i].pszAccessMethod,
1657c2c66affSColin Finck              szOID_PKIX_OCSP))
1658c2c66affSColin Finck             {
1659c2c66affSColin Finck                 if (aia->rgAccDescr[i].AccessLocation.dwAltNameChoice ==
1660c2c66affSColin Finck                  CERT_ALT_NAME_URL)
1661c2c66affSColin Finck                     FIXME("OCSP URL = %s\n",
1662c2c66affSColin Finck                      debugstr_w(aia->rgAccDescr[i].AccessLocation.u.pwszURL));
1663c2c66affSColin Finck                 else
1664c2c66affSColin Finck                     FIXME("unsupported AccessLocation type %d\n",
1665c2c66affSColin Finck                      aia->rgAccDescr[i].AccessLocation.dwAltNameChoice);
1666c2c66affSColin Finck             }
1667c2c66affSColin Finck         LocalFree(aia);
1668c2c66affSColin Finck         /* FIXME: lie and pretend OCSP validated the cert */
1669c2c66affSColin Finck         error = ERROR_SUCCESS;
1670c2c66affSColin Finck     }
1671c2c66affSColin Finck     else
1672c2c66affSColin Finck         error = GetLastError();
1673c2c66affSColin Finck     return error;
1674c2c66affSColin Finck }
1675c2c66affSColin Finck 
verify_cert_revocation_with_crl_offline(PCCERT_CONTEXT cert,PCCRL_CONTEXT crl,DWORD index,FILETIME * pTime,PCERT_REVOCATION_STATUS pRevStatus)1676c2c66affSColin Finck static DWORD verify_cert_revocation_with_crl_offline(PCCERT_CONTEXT cert,
1677c2c66affSColin Finck  PCCRL_CONTEXT crl, DWORD index, FILETIME *pTime,
1678c2c66affSColin Finck  PCERT_REVOCATION_STATUS pRevStatus)
1679c2c66affSColin Finck {
1680c2c66affSColin Finck     DWORD error;
1681c2c66affSColin Finck     LONG valid;
1682c2c66affSColin Finck 
1683c2c66affSColin Finck     valid = CompareFileTime(pTime, &crl->pCrlInfo->ThisUpdate);
1684c2c66affSColin Finck     if (valid <= 0)
1685c2c66affSColin Finck     {
1686c2c66affSColin Finck         /* If this CRL is not older than the time being verified, there's no
1687c2c66affSColin Finck          * way to know whether the certificate was revoked.
1688c2c66affSColin Finck          */
1689c2c66affSColin Finck         TRACE("CRL not old enough\n");
1690c2c66affSColin Finck         error = CRYPT_E_REVOCATION_OFFLINE;
1691c2c66affSColin Finck     }
1692c2c66affSColin Finck     else
1693c2c66affSColin Finck     {
1694c2c66affSColin Finck         PCRL_ENTRY entry = NULL;
1695c2c66affSColin Finck 
1696c2c66affSColin Finck         CertFindCertificateInCRL(cert, crl, 0, NULL, &entry);
1697c2c66affSColin Finck         if (entry)
1698c2c66affSColin Finck         {
1699c2c66affSColin Finck             error = CRYPT_E_REVOKED;
1700c2c66affSColin Finck             pRevStatus->dwIndex = index;
1701c2c66affSColin Finck         }
1702c2c66affSColin Finck         else
1703c2c66affSColin Finck         {
1704c2c66affSColin Finck             /* Since the CRL was not retrieved for the cert being checked,
1705c2c66affSColin Finck              * there's no guarantee it's fresh, so the cert *might* be okay,
1706c2c66affSColin Finck              * but it's safer not to guess.
1707c2c66affSColin Finck              */
1708c2c66affSColin Finck             TRACE("certificate not found\n");
1709c2c66affSColin Finck             error = CRYPT_E_REVOCATION_OFFLINE;
1710c2c66affSColin Finck         }
1711c2c66affSColin Finck     }
1712c2c66affSColin Finck     return error;
1713c2c66affSColin Finck }
1714c2c66affSColin Finck 
verify_cert_revocation(PCCERT_CONTEXT cert,DWORD index,FILETIME * pTime,DWORD dwFlags,PCERT_REVOCATION_PARA pRevPara,PCERT_REVOCATION_STATUS pRevStatus)1715c2c66affSColin Finck static DWORD verify_cert_revocation(PCCERT_CONTEXT cert, DWORD index,
1716c2c66affSColin Finck  FILETIME *pTime, DWORD dwFlags, PCERT_REVOCATION_PARA pRevPara,
1717c2c66affSColin Finck  PCERT_REVOCATION_STATUS pRevStatus)
1718c2c66affSColin Finck {
1719c2c66affSColin Finck     DWORD error = ERROR_SUCCESS;
1720c2c66affSColin Finck     PCERT_EXTENSION ext;
1721c2c66affSColin Finck 
1722c2c66affSColin Finck     if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS,
1723c2c66affSColin Finck      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
1724c2c66affSColin Finck         error = verify_cert_revocation_from_dist_points_ext(&ext->Value, cert,
1725c2c66affSColin Finck          index, pTime, dwFlags, pRevPara, pRevStatus);
1726c2c66affSColin Finck     else if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS,
1727c2c66affSColin Finck      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
1728c2c66affSColin Finck         error = verify_cert_revocation_from_aia_ext(&ext->Value, cert,
1729c2c66affSColin Finck          index, pTime, dwFlags, pRevPara, pRevStatus);
1730c2c66affSColin Finck     else
1731c2c66affSColin Finck     {
1732c2c66affSColin Finck         if (pRevPara && pRevPara->hCrlStore && pRevPara->pIssuerCert)
1733c2c66affSColin Finck         {
1734c2c66affSColin Finck             PCCRL_CONTEXT crl = NULL;
1735c2c66affSColin Finck             BOOL canSignCRLs;
1736c2c66affSColin Finck 
1737c2c66affSColin Finck             /* If the caller told us about the issuer, make sure the issuer
1738c2c66affSColin Finck              * can sign CRLs before looking for one.
1739c2c66affSColin Finck              */
1740c2c66affSColin Finck             if ((ext = CertFindExtension(szOID_KEY_USAGE,
1741c2c66affSColin Finck              pRevPara->pIssuerCert->pCertInfo->cExtension,
1742c2c66affSColin Finck              pRevPara->pIssuerCert->pCertInfo->rgExtension)))
1743c2c66affSColin Finck             {
1744c2c66affSColin Finck                 CRYPT_BIT_BLOB usage;
1745c2c66affSColin Finck                 DWORD size = sizeof(usage);
1746c2c66affSColin Finck 
1747c2c66affSColin Finck                 if (!CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS,
1748c2c66affSColin Finck                  ext->Value.pbData, ext->Value.cbData,
1749c2c66affSColin Finck                  CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
1750c2c66affSColin Finck                     canSignCRLs = FALSE;
1751c2c66affSColin Finck                 else if (usage.cbData > 2)
1752c2c66affSColin Finck                 {
1753c2c66affSColin Finck                     /* The key usage extension only defines 9 bits => no more
1754c2c66affSColin Finck                      * than 2 bytes are needed to encode all known usages.
1755c2c66affSColin Finck                      */
1756c2c66affSColin Finck                     canSignCRLs = FALSE;
1757c2c66affSColin Finck                 }
1758c2c66affSColin Finck                 else
1759c2c66affSColin Finck                 {
1760c2c66affSColin Finck                     BYTE usageBits = usage.pbData[usage.cbData - 1];
1761c2c66affSColin Finck 
1762c2c66affSColin Finck                     canSignCRLs = usageBits & CERT_CRL_SIGN_KEY_USAGE;
1763c2c66affSColin Finck                 }
1764c2c66affSColin Finck             }
1765c2c66affSColin Finck             else
1766c2c66affSColin Finck                 canSignCRLs = TRUE;
1767c2c66affSColin Finck             if (canSignCRLs)
1768c2c66affSColin Finck             {
1769c2c66affSColin Finck                 /* If the caller was helpful enough to tell us where to find a
1770c2c66affSColin Finck                  * CRL for the cert, look for one and check it.
1771c2c66affSColin Finck                  */
1772c2c66affSColin Finck                 crl = CertFindCRLInStore(pRevPara->hCrlStore,
1773c2c66affSColin Finck                  cert->dwCertEncodingType,
1774c2c66affSColin Finck                  CRL_FIND_ISSUED_BY_SIGNATURE_FLAG |
1775c2c66affSColin Finck                  CRL_FIND_ISSUED_BY_AKI_FLAG,
1776c2c66affSColin Finck                  CRL_FIND_ISSUED_BY, pRevPara->pIssuerCert, NULL);
1777c2c66affSColin Finck             }
1778c2c66affSColin Finck             if (crl)
1779c2c66affSColin Finck             {
1780c2c66affSColin Finck                 error = verify_cert_revocation_with_crl_offline(cert, crl,
1781c2c66affSColin Finck                  index, pTime, pRevStatus);
1782c2c66affSColin Finck                 CertFreeCRLContext(crl);
1783c2c66affSColin Finck             }
1784c2c66affSColin Finck             else
1785c2c66affSColin Finck             {
1786c2c66affSColin Finck                 TRACE("no CRL found\n");
1787c2c66affSColin Finck                 error = CRYPT_E_NO_REVOCATION_CHECK;
1788c2c66affSColin Finck                 pRevStatus->dwIndex = index;
1789c2c66affSColin Finck             }
1790c2c66affSColin Finck         }
1791c2c66affSColin Finck         else
1792c2c66affSColin Finck         {
1793c2c66affSColin Finck             if (!pRevPara)
1794c2c66affSColin Finck                 WARN("no CERT_REVOCATION_PARA\n");
1795c2c66affSColin Finck             else if (!pRevPara->hCrlStore)
1796c2c66affSColin Finck                 WARN("no dist points/aia extension and no CRL store\n");
1797c2c66affSColin Finck             else if (!pRevPara->pIssuerCert)
1798c2c66affSColin Finck                 WARN("no dist points/aia extension and no issuer\n");
1799c2c66affSColin Finck             error = CRYPT_E_NO_REVOCATION_CHECK;
1800c2c66affSColin Finck             pRevStatus->dwIndex = index;
1801c2c66affSColin Finck         }
1802c2c66affSColin Finck     }
1803c2c66affSColin Finck     return error;
1804c2c66affSColin Finck }
1805c2c66affSColin Finck 
1806c2c66affSColin Finck typedef struct _CERT_REVOCATION_PARA_NO_EXTRA_FIELDS {
1807c2c66affSColin Finck     DWORD                     cbSize;
1808c2c66affSColin Finck     PCCERT_CONTEXT            pIssuerCert;
1809c2c66affSColin Finck     DWORD                     cCertStore;
1810c2c66affSColin Finck     HCERTSTORE               *rgCertStore;
1811c2c66affSColin Finck     HCERTSTORE                hCrlStore;
1812c2c66affSColin Finck     LPFILETIME                pftTimeToUse;
1813c2c66affSColin Finck } CERT_REVOCATION_PARA_NO_EXTRA_FIELDS;
1814c2c66affSColin Finck 
1815c2c66affSColin Finck typedef struct _OLD_CERT_REVOCATION_STATUS {
1816c2c66affSColin Finck     DWORD cbSize;
1817c2c66affSColin Finck     DWORD dwIndex;
1818c2c66affSColin Finck     DWORD dwError;
1819c2c66affSColin Finck     DWORD dwReason;
1820c2c66affSColin Finck } OLD_CERT_REVOCATION_STATUS;
1821c2c66affSColin Finck 
1822c2c66affSColin Finck /***********************************************************************
1823c2c66affSColin Finck  *    CertDllVerifyRevocation (CRYPTNET.@)
1824c2c66affSColin Finck  */
CertDllVerifyRevocation(DWORD dwEncodingType,DWORD dwRevType,DWORD cContext,PVOID rgpvContext[],DWORD dwFlags,PCERT_REVOCATION_PARA pRevPara,PCERT_REVOCATION_STATUS pRevStatus)1825c2c66affSColin Finck BOOL WINAPI CertDllVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1826c2c66affSColin Finck  DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1827c2c66affSColin Finck  PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1828c2c66affSColin Finck {
1829c2c66affSColin Finck     DWORD error = 0, i;
1830c2c66affSColin Finck     FILETIME now;
1831c2c66affSColin Finck     LPFILETIME pTime = NULL;
1832c2c66affSColin Finck 
1833c2c66affSColin Finck     TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1834c2c66affSColin Finck      cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1835c2c66affSColin Finck 
1836c2c66affSColin Finck     if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1837c2c66affSColin Finck      pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1838c2c66affSColin Finck     {
1839c2c66affSColin Finck         SetLastError(E_INVALIDARG);
1840c2c66affSColin Finck         return FALSE;
1841c2c66affSColin Finck     }
1842c2c66affSColin Finck     if (!cContext)
1843c2c66affSColin Finck     {
1844c2c66affSColin Finck         SetLastError(E_INVALIDARG);
1845c2c66affSColin Finck         return FALSE;
1846c2c66affSColin Finck     }
1847c2c66affSColin Finck     if (pRevPara && pRevPara->cbSize >=
1848c2c66affSColin Finck      sizeof(CERT_REVOCATION_PARA_NO_EXTRA_FIELDS))
1849c2c66affSColin Finck         pTime = pRevPara->pftTimeToUse;
1850c2c66affSColin Finck     if (!pTime)
1851c2c66affSColin Finck     {
1852c2c66affSColin Finck         GetSystemTimeAsFileTime(&now);
1853c2c66affSColin Finck         pTime = &now;
1854c2c66affSColin Finck     }
1855c2c66affSColin Finck     memset(&pRevStatus->dwIndex, 0, pRevStatus->cbSize - sizeof(DWORD));
1856c2c66affSColin Finck     if (dwRevType != CERT_CONTEXT_REVOCATION_TYPE)
1857c2c66affSColin Finck         error = CRYPT_E_NO_REVOCATION_CHECK;
1858c2c66affSColin Finck     else
1859c2c66affSColin Finck     {
1860c2c66affSColin Finck         for (i = 0; !error && i < cContext; i++)
1861c2c66affSColin Finck             error = verify_cert_revocation(rgpvContext[i], i, pTime, dwFlags,
1862c2c66affSColin Finck              pRevPara, pRevStatus);
1863c2c66affSColin Finck     }
1864c2c66affSColin Finck     if (error)
1865c2c66affSColin Finck     {
1866c2c66affSColin Finck         SetLastError(error);
1867c2c66affSColin Finck         pRevStatus->dwError = error;
1868c2c66affSColin Finck     }
1869c2c66affSColin Finck     TRACE("returning %d (%08x)\n", !error, error);
1870c2c66affSColin Finck     return !error;
1871c2c66affSColin Finck }
1872