ole32/tests: Do not compare returned by DeleteFile value with TRUE.
[wine] / dlls / crypt32 / tests / cert.c
1 /*
2  * crypt32 cert functions tests
3  *
4  * Copyright 2005-2006 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winreg.h>
27 #include <winerror.h>
28 #include <wincrypt.h>
29
30 #include "wine/test.h"
31
32 static BOOL (WINAPI * pCryptVerifyCertificateSignatureEx)
33                         (HCRYPTPROV, DWORD, DWORD, void *, DWORD, void *, DWORD, void *);
34
35 #define CRYPT_GET_PROC(func)                                       \
36     p ## func = (void *)GetProcAddress(hCrypt32, #func);           \
37     if(!p ## func)                                                 \
38         trace("GetProcAddress(hCrypt32, \"%s\") failed\n", #func); \
39
40 static void init_function_pointers(void)
41 {
42     HMODULE hCrypt32;
43
44     pCryptVerifyCertificateSignatureEx = NULL;
45
46     hCrypt32 = GetModuleHandleA("crypt32.dll");
47     assert(hCrypt32);
48
49     CRYPT_GET_PROC(CryptVerifyCertificateSignatureEx);
50 }
51
52 static void testCryptHashCert(void)
53 {
54     static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b,
55      0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
56      0x09 };
57     static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee,
58      0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8,
59      0xa2 };
60     static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:";
61     BOOL ret;
62     BYTE hash[20];
63     DWORD hashLen = sizeof(hash);
64
65     /* NULL buffer and nonzero length crashes
66     ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen);
67        empty hash length also crashes
68     ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL);
69      */
70     /* Test empty hash */
71     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL,
72      &hashLen);
73     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
74     ok(hashLen == sizeof(hash),
75      "Got unexpected size of hash %ld, expected %d\n", hashLen, sizeof(hash));
76     /* Test with empty buffer */
77     ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen);
78     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
79     ok(!memcmp(hash, emptyHash, sizeof(emptyHash)),
80      "Unexpected hash of nothing\n");
81     /* Test a known value */
82     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash,
83      &hashLen);
84     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
85     ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n");
86 }
87
88 static const char cspName[] = "WineCryptTemp";
89
90 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
91  const BYTE *sig, size_t sigLen)
92 {
93     HCRYPTHASH hash;
94     BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
95
96     ok(ret, "CryptCreateHash failed: %08lx\n", GetLastError());
97     if (ret)
98     {
99         BYTE mySig[64];
100         DWORD mySigSize = sizeof(mySig);
101
102         ret = CryptHashData(hash, toSign, toSignLen, 0);
103         ok(ret, "CryptHashData failed: %08lx\n", GetLastError());
104         /* use the A variant so the test can run on Win9x */
105         ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
106         ok(ret, "CryptSignHash failed: %08lx\n", GetLastError());
107         if (ret)
108         {
109             ok(mySigSize == sigLen, "Expected sig length %d, got %ld\n",
110              sigLen, mySigSize);
111             ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
112         }
113         CryptDestroyHash(hash);
114     }
115 }
116
117 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
118  * using the algorithm with OID sigOID.  The CSP is assumed to be empty, and a
119  * keyset named AT_SIGNATURE will be added to it.  The signing key will be
120  * stored in *key, and the signature will be stored in sig.  sigLen should be
121  * at least 64 bytes.
122  */
123 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
124  LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
125 {
126     BOOL ret;
127     DWORD size = 0;
128     CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
129
130     /* These all crash
131     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
132     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
133     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
134      NULL, NULL, NULL, &size);
135      */
136     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
137      &algoID, NULL, NULL, &size);
138     ok(!ret && GetLastError() == NTE_BAD_ALGID, 
139      "Expected NTE_BAD_ALGID, got %08lx\n", GetLastError());
140     algoID.pszObjId = (LPSTR)sigOID;
141     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
142      &algoID, NULL, NULL, &size);
143     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
144      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
145     ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
146      toBeSigned->cbData, &algoID, NULL, NULL, &size);
147     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
148      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
149
150     /* No keys exist in the new CSP yet.. */
151     ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
152      toBeSigned->cbData, &algoID, NULL, NULL, &size);
153     ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
154      NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08lx\n",
155      GetLastError());
156     ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
157     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
158     if (ret)
159     {
160         ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
161          toBeSigned->cbData, &algoID, NULL, NULL, &size);
162         ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
163         ok(size <= *sigLen, "Expected size <= %ld, got %ld\n", *sigLen, size);
164         if (ret)
165         {
166             ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
167              toBeSigned->cbData, &algoID, NULL, sig, &size);
168             ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
169             if (ret)
170             {
171                 *sigLen = size;
172                 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
173                  size);
174             }
175         }
176     }
177 }
178
179 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
180  LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
181 {
182     CERT_SIGNED_CONTENT_INFO info;
183     LPBYTE cert = NULL;
184     DWORD size = 0;
185     BOOL ret;
186
187     if(pCryptVerifyCertificateSignatureEx) {
188         ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
189         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
190          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
191          GetLastError());
192         ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
193         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
194          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
195         GetLastError());
196         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
197          NULL, 0, NULL);
198         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
199          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
200          GetLastError());
201         /* This crashes
202         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
203          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
204          */
205     }
206     info.ToBeSigned.cbData = toBeSigned->cbData;
207     info.ToBeSigned.pbData = toBeSigned->pbData;
208     info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
209     info.SignatureAlgorithm.Parameters.cbData = 0;
210     info.Signature.cbData = sigLen;
211     info.Signature.pbData = (BYTE *)sig;
212     info.Signature.cUnusedBits = 0;
213     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
214      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
215     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
216     if (cert)
217     {
218         CRYPT_DATA_BLOB certBlob = { 0, NULL };
219         PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
220
221         if(pCryptVerifyCertificateSignatureEx) {
222             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
223              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
224             ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
225              "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
226             certBlob.cbData = 1;
227             certBlob.pbData = (void *)0xdeadbeef;
228             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
229              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
230             ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
231              "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
232             certBlob.cbData = size;
233             certBlob.pbData = cert;
234             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
235              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
236             ok(!ret && GetLastError() ==
237              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
238              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
239              GetLastError());
240             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
241              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
242              CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
243             ok(!ret && GetLastError() ==
244              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
245              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
246              GetLastError());
247             /* This crashes
248             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
249              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
250              CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
251              */
252         }
253         CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
254          (LPSTR)sigOID, 0, NULL, NULL, &size);
255         pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
256         if (pubKeyInfo)
257         {
258             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
259              X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
260             ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
261             if (ret && pCryptVerifyCertificateSignatureEx)
262             {
263                 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
264                  CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
265                  CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
266                 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
267                  GetLastError());
268             }
269             HeapFree(GetProcessHeap(), 0, pubKeyInfo);
270         }
271         LocalFree(cert);
272     }
273 }
274
275 static const BYTE emptyCert[] = { 0x30, 0x00 };
276
277 static void testCertSigs(void)
278 {
279     HCRYPTPROV csp;
280     CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
281     BOOL ret;
282     HCRYPTKEY key;
283     BYTE sig[64];
284     DWORD sigSize = sizeof(sig);
285
286     /* Just in case a previous run failed, delete this thing */
287     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
288      CRYPT_DELETEKEYSET);
289     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
290      CRYPT_NEWKEYSET);
291     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
292
293     testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
294     testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
295
296     CryptDestroyKey(key);
297     CryptReleaseContext(csp, 0);
298     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
299      CRYPT_DELETEKEYSET);
300 }
301
302 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
303  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
304  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
305  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
306  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
307  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
308  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
309  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
310  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
311  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
312
313 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
314  szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
315
316 static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30,
317  0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
318  0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00,
319  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
320  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
321  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31,
322  0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61,
323  0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00,
324  0x03, 0x01, 0x00, 0xa3, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d,
325  0x25, 0x01, 0x01, 0xff, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01,
326  0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
327  0x03, 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
328
329 static void testKeyUsage(void)
330 {
331     BOOL ret;
332     PCCERT_CONTEXT context;
333     DWORD size;
334
335     /* Test base cases */
336     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, NULL);
337     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
338      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
339     size = 1;
340     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
341     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
342      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
343     size = 0;
344     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
345     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
346      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
347     /* These crash
348     ret = CertSetEnhancedKeyUsage(NULL, NULL);
349     usage.cUsageIdentifier = 0;
350     ret = CertSetEnhancedKeyUsage(NULL, &usage);
351      */
352     /* Test with a cert with no enhanced key usage extension */
353     context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
354      sizeof(bigCert));
355     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
356      GetLastError());
357     if (context)
358     {
359         static const char oid[] = "1.2.3.4";
360         BYTE buf[sizeof(CERT_ENHKEY_USAGE) + 2 * (sizeof(LPSTR) + sizeof(oid))];
361         PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
362
363         ret = CertGetEnhancedKeyUsage(context, 0, NULL, NULL);
364         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
365          "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
366         size = 1;
367         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &size);
368         if (ret)
369         {
370             /* Windows 2000, ME, or later: even though it succeeded, we expect
371              * CRYPT_E_NOT_FOUND, which indicates there is no enhanced key
372              * usage set for this cert (which implies it's valid for all uses.)
373              */
374             ok(GetLastError() == CRYPT_E_NOT_FOUND,
375              "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
376             ok(size == sizeof(CERT_ENHKEY_USAGE), "Expected size %d, got %ld\n",
377              sizeof(CERT_ENHKEY_USAGE), size);
378             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
379             ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
380             ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
381              pUsage->cUsageIdentifier);
382         }
383         else
384         {
385             /* Windows NT, 95, or 98: it fails, and the last error is
386              * CRYPT_E_NOT_FOUND.
387              */
388             ok(GetLastError() == CRYPT_E_NOT_FOUND,
389              "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
390         }
391         /* I can add a usage identifier when no key usage has been set */
392         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
393         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
394          GetLastError());
395         size = sizeof(buf);
396         ret = CertGetEnhancedKeyUsage(context,
397          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
398         ok(ret && GetLastError() == 0,
399          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
400         ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
401          pUsage->cUsageIdentifier);
402         if (pUsage->cUsageIdentifier)
403             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
404              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
405         /* Now set an empty key usage */
406         pUsage->cUsageIdentifier = 0;
407         ret = CertSetEnhancedKeyUsage(context, pUsage);
408         ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
409         /* Shouldn't find it in the cert */
410         size = sizeof(buf);
411         ret = CertGetEnhancedKeyUsage(context,
412          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
413         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
414          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
415         /* Should find it as an extended property */
416         ret = CertGetEnhancedKeyUsage(context,
417          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
418         ok(ret && GetLastError() == 0,
419          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
420         ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
421          pUsage->cUsageIdentifier);
422         /* Should find it as either */
423         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
424         ok(ret && GetLastError() == 0,
425          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
426         ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
427          pUsage->cUsageIdentifier);
428         /* Add a usage identifier */
429         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
430         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
431          GetLastError());
432         size = sizeof(buf);
433         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
434         ok(ret && GetLastError() == 0,
435          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
436         ok(pUsage->cUsageIdentifier == 1, "Expected 1 identifier, got %ld\n",
437          pUsage->cUsageIdentifier);
438         if (pUsage->cUsageIdentifier)
439             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
440              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
441         /* Yep, I can re-add the same usage identifier */
442         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
443         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
444          GetLastError());
445         size = sizeof(buf);
446         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
447         ok(ret && GetLastError() == 0,
448          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
449         ok(pUsage->cUsageIdentifier == 2, "Expected 2 identifiers, got %ld\n",
450          pUsage->cUsageIdentifier);
451         if (pUsage->cUsageIdentifier)
452             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
453              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
454         if (pUsage->cUsageIdentifier >= 2)
455             ok(!strcmp(pUsage->rgpszUsageIdentifier[1], oid),
456              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[1]);
457         /* Now set a NULL extended property--this deletes the property. */
458         ret = CertSetEnhancedKeyUsage(context, NULL);
459         ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
460         SetLastError(0xbaadcafe);
461         size = sizeof(buf);
462         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
463         ok(GetLastError() == CRYPT_E_NOT_FOUND,
464          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
465
466         CertFreeCertificateContext(context);
467     }
468     /* Now test with a cert with an enhanced key usage extension */
469     context = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage,
470      sizeof(certWithUsage));
471     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
472      GetLastError());
473     if (context)
474     {
475         LPBYTE buf = NULL;
476         DWORD bufSize = 0, i;
477
478         /* The size may depend on what flags are used to query it, so I
479          * realloc the buffer for each test.
480          */
481         ret = CertGetEnhancedKeyUsage(context,
482          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
483         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
484         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
485         if (buf)
486         {
487             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
488
489             /* Should find it in the cert */
490             size = bufSize;
491             ret = CertGetEnhancedKeyUsage(context,
492              CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
493             ok(ret && GetLastError() == 0,
494              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
495             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
496              pUsage->cUsageIdentifier);
497             for (i = 0; i < pUsage->cUsageIdentifier; i++)
498                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
499                  "Expected %s, got %s\n", keyUsages[i],
500                  pUsage->rgpszUsageIdentifier[i]);
501             HeapFree(GetProcessHeap(), 0, buf);
502         }
503         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
504         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
505         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
506         if (buf)
507         {
508             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
509
510             /* Should find it as either */
511             size = bufSize;
512             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
513             /* In Windows, GetLastError returns CRYPT_E_NOT_FOUND not found
514              * here, even though the return is successful and the usage id
515              * count is positive.  I don't enforce that here.
516              */
517             ok(ret,
518              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
519             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
520              pUsage->cUsageIdentifier);
521             for (i = 0; i < pUsage->cUsageIdentifier; i++)
522                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
523                  "Expected %s, got %s\n", keyUsages[i],
524                  pUsage->rgpszUsageIdentifier[i]);
525             HeapFree(GetProcessHeap(), 0, buf);
526         }
527         /* Shouldn't find it as an extended property */
528         ret = CertGetEnhancedKeyUsage(context,
529          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size);
530         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
531          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
532         /* Adding a usage identifier overrides the cert's usage!? */
533         ret = CertAddEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
534         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
535          GetLastError());
536         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
537         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
538         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
539         if (buf)
540         {
541             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
542
543             /* Should find it as either */
544             size = bufSize;
545             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
546             ok(ret,
547              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
548             ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
549              pUsage->cUsageIdentifier);
550             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA),
551              "Expected %s, got %s\n", szOID_RSA_RSA,
552              pUsage->rgpszUsageIdentifier[0]);
553             HeapFree(GetProcessHeap(), 0, buf);
554         }
555         /* But querying the cert directly returns its usage */
556         ret = CertGetEnhancedKeyUsage(context,
557          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
558         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
559         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
560         if (buf)
561         {
562             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
563
564             size = bufSize;
565             ret = CertGetEnhancedKeyUsage(context,
566              CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
567             ok(ret,
568              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
569             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
570              pUsage->cUsageIdentifier);
571             for (i = 0; i < pUsage->cUsageIdentifier; i++)
572                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
573                  "Expected %s, got %s\n", keyUsages[i],
574                  pUsage->rgpszUsageIdentifier[i]);
575             HeapFree(GetProcessHeap(), 0, buf);
576         }
577         /* And removing the only usage identifier in the extended property
578          * results in the cert's key usage being found.
579          */
580         ret = CertRemoveEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
581         ok(ret, "CertRemoveEnhancedKeyUsage failed: %08lx\n", GetLastError());
582         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
583         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
584         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
585         if (buf)
586         {
587             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
588
589             /* Should find it as either */
590             size = bufSize;
591             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
592             ok(ret,
593              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
594             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
595              pUsage->cUsageIdentifier);
596             for (i = 0; i < pUsage->cUsageIdentifier; i++)
597                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
598                  "Expected %s, got %s\n", keyUsages[i],
599                  pUsage->rgpszUsageIdentifier[i]);
600             HeapFree(GetProcessHeap(), 0, buf);
601         }
602
603         CertFreeCertificateContext(context);
604     }
605 }
606
607 START_TEST(cert)
608 {
609     init_function_pointers();
610     testCryptHashCert();
611     testCertSigs();
612     testKeyUsage();
613 }