secur32: Basic implementation of schannel AcquireCredentialsHandle/FreeCredentialsHandle.
[wine] / dlls / cryptnet / tests / cryptnet.c
1 /*
2  * Unit test suite for cryptnet.dll
3  *
4  * Copyright 2007 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21 #include <stdio.h>
22 #define NONAMELESSUNION
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winerror.h>
26 #include <wincrypt.h>
27 #include "wine/test.h"
28
29 static const BYTE bigCert[] = {
30 0x30,0x78,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x14,0x31,0x12,0x30,0x10,
31 0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
32 0x67,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,
33 0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
34 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,
35 0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x30,
36 0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,
37 0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,
38 0x01,0x01};
39 static const BYTE certWithIssuingDistPoint[] = {
40 0x30,0x81,0x99,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,
41 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x14,0x31,0x12,
42 0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,
43 0x61,0x6e,0x67,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
44 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
45 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x14,0x31,0x12,0x30,0x10,
46 0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
47 0x67,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x27,0x30,0x25,0x30,
48 0x23,0x06,0x03,0x55,0x1d,0x1c,0x01,0x01,0xff,0x04,0x19,0x30,0x17,0xa0,0x15,
49 0xa0,0x13,0x86,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,
50 0x68,0x71,0x2e,0x6f,0x72,0x67, };
51 static const BYTE certWithCRLDistPoint[] = {
52 0x30,0x81,0x9b,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,
53 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x14,0x31,0x12,
54 0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,
55 0x61,0x6e,0x67,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
56 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
57 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x14,0x31,0x12,0x30,0x10,
58 0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
59 0x67,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x29,0x30,0x27,0x30,
60 0x25,0x06,0x03,0x55,0x1d,0x1f,0x01,0x01,0xff,0x04,0x1b,0x30,0x19,0x30,0x17,
61 0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,
62 0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67, };
63
64 static void compareUrlArray(const CRYPT_URL_ARRAY *expected,
65  const CRYPT_URL_ARRAY *got)
66 {
67     ok(expected->cUrl == got->cUrl, "Expected %d URLs, got %d\n",
68      expected->cUrl, got->cUrl);
69     if (expected->cUrl == got->cUrl)
70     {
71         DWORD i;
72
73         for (i = 0; i < got->cUrl; i++)
74             ok(!lstrcmpiW(expected->rgwszUrl[i], got->rgwszUrl[i]),
75              "%d: unexpected URL\n", i);
76     }
77 }
78
79 static WCHAR url[] =
80  { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
81
82 static void test_getObjectUrl(void)
83 {
84     BOOL ret;
85     DWORD urlArraySize = 0, infoSize = 0;
86     PCCERT_CONTEXT cert;
87
88     SetLastError(0xdeadbeef);
89     ret = CryptGetObjectUrl(NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
90     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
91      "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
92     /* Crash
93     ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, NULL,
94      NULL, NULL, NULL);
95     ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, NULL,
96      NULL, &infoSize, NULL);
97     ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL,
98      &urlArraySize, NULL, &infoSize, NULL);
99      */
100     /* A cert with no CRL dist point extension fails.. */
101     cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
102      sizeof(bigCert));
103     SetLastError(0xdeadbeef);
104     ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, NULL,
105      NULL, NULL, NULL, NULL);
106     ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
107      "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
108     CertFreeCertificateContext(cert);
109
110     cert = CertCreateCertificateContext(X509_ASN_ENCODING,
111      certWithIssuingDistPoint, sizeof(certWithIssuingDistPoint));
112     if (cert)
113     {
114         /* This cert has no AIA extension, so expect this to fail */
115         SetLastError(0xdeadbeef);
116         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0,
117          NULL, NULL, NULL, NULL, NULL);
118         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
119          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
120         SetLastError(0xdeadbeef);
121         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert,
122          CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL);
123         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
124          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
125         SetLastError(0xdeadbeef);
126         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert,
127          CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL);
128         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
129          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
130         /* It does have an issuing dist point extension, but that's not what
131          * this is looking for (it wants a CRL dist points extension)
132          */
133         SetLastError(0xdeadbeef);
134         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
135          (void *)cert, 0, NULL, NULL, NULL, NULL, NULL);
136         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
137          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
138         SetLastError(0xdeadbeef);
139         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
140          (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL,
141          NULL);
142         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
143          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
144         SetLastError(0xdeadbeef);
145         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
146          (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL,
147          NULL);
148         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
149          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
150         CertFreeCertificateContext(cert);
151     }
152     cert = CertCreateCertificateContext(X509_ASN_ENCODING,
153      certWithCRLDistPoint, sizeof(certWithCRLDistPoint));
154     if (cert)
155     {
156         PCRYPT_URL_ARRAY urlArray;
157
158         /* This cert has no AIA extension, so expect this to fail */
159         SetLastError(0xdeadbeef);
160         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0,
161          NULL, NULL, NULL, NULL, NULL);
162         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
163          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
164         SetLastError(0xdeadbeef);
165         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert,
166          CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL);
167         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
168          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
169         SetLastError(0xdeadbeef);
170         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert,
171          CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL);
172         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
173          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
174         /* It does have a CRL dist points extension */
175         SetLastError(0xdeadbeef);
176         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
177          (void *)cert, 0, NULL, NULL, NULL, NULL, NULL);
178         ok(!ret && GetLastError() == E_INVALIDARG,
179          "Expected E_INVALIDARG, got %08x\n", GetLastError());
180         SetLastError(0xdeadbeef);
181         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
182          (void *)cert, 0, NULL, NULL, NULL, &infoSize, NULL);
183         ok(!ret && GetLastError() == E_INVALIDARG,
184          "Expected E_INVALIDARG, got %08x\n", GetLastError());
185         /* Can get it without specifying the location: */
186         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
187          (void *)cert, 0, NULL, &urlArraySize, NULL, NULL, NULL);
188         ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError());
189         urlArray = HeapAlloc(GetProcessHeap(), 0, urlArraySize);
190         if (urlArray)
191         {
192             ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
193              (void *)cert, 0, urlArray, &urlArraySize, NULL, NULL, NULL);
194             ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError());
195             if (ret)
196             {
197                 LPWSTR pUrl = url;
198                 CRYPT_URL_ARRAY expectedUrl = { 1, &pUrl };
199
200                 compareUrlArray(&expectedUrl, urlArray);
201             }
202             HeapFree(GetProcessHeap(), 0, urlArray);
203         }
204         /* or by specifying it's an extension: */
205         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
206          (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, &urlArraySize, NULL,
207          NULL, NULL);
208         ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError());
209         urlArray = HeapAlloc(GetProcessHeap(), 0, urlArraySize);
210         if (urlArray)
211         {
212             ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
213              (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, urlArray,
214              &urlArraySize, NULL, NULL, NULL);
215             ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError());
216             if (ret)
217             {
218                 LPWSTR pUrl = url;
219                 CRYPT_URL_ARRAY expectedUrl = { 1, &pUrl };
220
221                 compareUrlArray(&expectedUrl, urlArray);
222             }
223             HeapFree(GetProcessHeap(), 0, urlArray);
224         }
225         /* but it isn't contained in a property: */
226         SetLastError(0xdeadbeef);
227         ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT,
228          (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, &urlArraySize, NULL,
229          NULL, NULL);
230         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
231          "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
232         CertFreeCertificateContext(cert);
233     }
234 }
235
236 static void make_tmp_file(LPSTR path)
237 {
238     static char curr[MAX_PATH] = { 0 };
239     char temp[MAX_PATH];
240     DWORD dwNumberOfBytesWritten;
241     HANDLE hf;
242
243     if (!*curr)
244         GetCurrentDirectoryA(MAX_PATH, curr);
245     GetTempFileNameA(curr, "net", 0, temp);
246     lstrcpyA(path, temp);
247     hf = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
248      FILE_ATTRIBUTE_NORMAL, NULL);
249     WriteFile(hf, certWithCRLDistPoint, sizeof(certWithCRLDistPoint),
250      &dwNumberOfBytesWritten, NULL);
251     CloseHandle(hf);
252 }
253
254 static void test_retrieveObjectByUrl(void)
255 {
256     BOOL ret;
257     char tmpfile[MAX_PATH * 2], *ptr, url[MAX_PATH + 8];
258     CRYPT_BLOB_ARRAY *pBlobArray;
259     PCCERT_CONTEXT cert;
260     PCCRL_CONTEXT crl;
261     HCERTSTORE store;
262     CRYPT_RETRIEVE_AUX_INFO aux = { 0 };
263     FILETIME ft = { 0 };
264
265     SetLastError(0xdeadbeef);
266     ret = CryptRetrieveObjectByUrlA(NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL);
267     ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER ||
268                 GetLastError() == E_INVALIDARG),
269        "got 0x%x/%u (expected ERROR_INVALID_PARAMETER or E_INVALIDARG)\n",
270        GetLastError(), GetLastError());
271
272     make_tmp_file(tmpfile);
273     ptr = strchr(tmpfile, ':');
274     if (ptr)
275         ptr += 2; /* skip colon and first slash */
276     else
277         ptr = tmpfile;
278     snprintf(url, sizeof(url), "file:///%s", ptr);
279     do {
280         ptr = strchr(url, '\\');
281         if (ptr)
282             *ptr = '/';
283     } while (ptr);
284
285     pBlobArray = (CRYPT_BLOB_ARRAY *)0xdeadbeef;
286     ret = CryptRetrieveObjectByUrlA(url, NULL, 0, 0, (void **)&pBlobArray,
287      NULL, NULL, NULL, NULL);
288     ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError());
289     ok(pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef,
290      "Expected a valid pointer\n");
291     if (pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef)
292     {
293         ok(pBlobArray->cBlob == 1, "Expected 1 blob, got %d\n",
294          pBlobArray->cBlob);
295         ok(pBlobArray->rgBlob[0].cbData == sizeof(certWithCRLDistPoint),
296          "Unexpected size %d\n", pBlobArray->rgBlob[0].cbData);
297         CryptMemFree(pBlobArray);
298     }
299     cert = (PCCERT_CONTEXT)0xdeadbeef;
300     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0,
301      (void **)&cert, NULL, NULL, NULL, NULL);
302     ok(cert && cert != (PCCERT_CONTEXT)0xdeadbeef, "Expected a cert\n");
303     if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef)
304         CertFreeCertificateContext(cert);
305     crl = (PCCRL_CONTEXT)0xdeadbeef;
306     SetLastError(0xdeadbeef);
307     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CRL, 0, 0, (void **)&crl,
308      NULL, NULL, NULL, NULL);
309     /* vista: ERROR_NOT_SUPPORTED, w2k3,XP, newer w2k: CRYPT_E_NO_MATCH,
310        95: OSS_DATA_ERROR */
311     ok(!ret && (GetLastError() == ERROR_NOT_SUPPORTED ||
312                 GetLastError() == CRYPT_E_NO_MATCH ||
313                 GetLastError() == CRYPT_E_ASN1_BADTAG ||
314                 GetLastError() == OSS_DATA_ERROR),
315        "got 0x%x/%u (expected CRYPT_E_NO_MATCH or CRYPT_E_ASN1_BADTAG or "
316        "OSS_DATA_ERROR)\n", GetLastError(), GetLastError());
317
318     /* only newer versions of cryptnet do the cleanup */
319     if(!ret && GetLastError() != CRYPT_E_ASN1_BADTAG &&
320                GetLastError() != OSS_DATA_ERROR) {
321         ok(crl == NULL, "Expected CRL to be NULL\n");
322     }
323
324     if (crl && crl != (PCCRL_CONTEXT)0xdeadbeef)
325         CertFreeCRLContext(crl);
326     store = (HCERTSTORE)0xdeadbeef;
327     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CAPI2_ANY, 0, 0,
328      (void **)&store, NULL, NULL, NULL, NULL);
329     ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError());
330     if (store && store != (HCERTSTORE)0xdeadbeef)
331     {
332         DWORD certs = 0;
333
334         cert = NULL;
335         do {
336             cert = CertEnumCertificatesInStore(store, cert);
337             if (cert)
338                 certs++;
339         } while (cert);
340         ok(certs == 1, "Expected 1 cert, got %d\n", certs);
341         CertCloseStore(store, 0);
342     }
343     /* Are file URLs cached? */
344     cert = (PCCERT_CONTEXT)0xdeadbeef;
345     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE,
346      CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL);
347     ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError());
348     if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef)
349         CertFreeCertificateContext(cert);
350
351     cert = (PCCERT_CONTEXT)0xdeadbeef;
352     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0,
353      (void **)&cert, NULL, NULL, NULL, &aux);
354     /* w2k: success, 9x: fail with E_INVALIDARG */
355     ok(ret || (GetLastError() == E_INVALIDARG),
356        "got %u with 0x%x/%u (expected '!=0' or '0' with E_INVALIDARG)\n",
357        ret, GetLastError(), GetLastError());
358     if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef)
359         CertFreeCertificateContext(cert);
360
361     cert = (PCCERT_CONTEXT)0xdeadbeef;
362     aux.cbSize = sizeof(aux);
363     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0,
364      (void **)&cert, NULL, NULL, NULL, &aux);
365     /* w2k: success, 9x: fail with E_INVALIDARG */
366     ok(ret || (GetLastError() == E_INVALIDARG),
367        "got %u with 0x%x/%u (expected '!=0' or '0' with E_INVALIDARG)\n",
368        ret, GetLastError(), GetLastError());
369     if (!ret) {
370         /* no more tests useful */
371         DeleteFileA(tmpfile);
372         skip("no usable CertificateContext\n");
373         return;
374     }
375
376     aux.pLastSyncTime = &ft;
377     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0,
378      (void **)&cert, NULL, NULL, NULL, &aux);
379     ok(ft.dwLowDateTime || ft.dwHighDateTime,
380      "Expected last sync time to be set\n");
381     DeleteFileA(tmpfile);
382     /* Okay, after being deleted, are file URLs still cached? */
383     SetLastError(0xdeadbeef);
384     ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE,
385      CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL);
386     ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND ||
387      GetLastError() == ERROR_PATH_NOT_FOUND),
388      "Expected ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND, got %d\n",
389      GetLastError());
390 }
391
392 START_TEST(cryptnet)
393 {
394     test_getObjectUrl();
395     test_retrieveObjectByUrl();
396 }