make_dlls: Recursively ignore .ok files in all tests directories.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 const BYTE subjectName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
53  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
54  0x6e, 0x67, 0x00 };
55 static const BYTE serialNum[] = { 1 };
56 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
57  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
58  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
59  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
60  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
61  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
62  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
63  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
64  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
65  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
66 static const BYTE bigCertHash[] = { 0x6e, 0x30, 0x90, 0x71, 0x5f, 0xd9, 0x23,
67  0x56, 0xeb, 0xae, 0x25, 0x40, 0xe6, 0x22, 0xda, 0x19, 0x26, 0x02, 0xa6, 0x08 };
68
69 static const BYTE bigCertWithDifferentSubject[] = { 0x30, 0x7a, 0x02, 0x01, 0x02,
70  0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
71  0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67,
72  0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31,
73  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
74  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15,
75  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c,
76  0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06,
77  0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
78  0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
79  0x01, 0x01 };
80 static const BYTE bigCertWithDifferentIssuer[] = { 0x30, 0x7a, 0x02, 0x01,
81  0x01, 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
82  0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e,
83  0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
84  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30,
85  0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
86  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
87  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02,
88  0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03,
89  0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff,
90  0x02, 0x01, 0x01 };
91
92 static const BYTE subjectName2[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
93  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61,
94  0x6e, 0x67, 0x00 };
95 static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
96  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
97  0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
98  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
99  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
100  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
101  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20,
102  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
103  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
104  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
105 static const BYTE bigCert2WithDifferentSerial[] = { 0x30, 0x7a, 0x02, 0x01,
106  0x02, 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
107  0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e,
108  0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
109  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30,
110  0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
111  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41,
112  0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02,
113  0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03,
114  0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff,
115  0x02, 0x01, 0x01 };
116 static const BYTE bigCert2Hash[] = { 0x4a, 0x7f, 0x32, 0x1f, 0xcf, 0x3b, 0xc0,
117  0x87, 0x48, 0x2b, 0xa1, 0x86, 0x54, 0x18, 0xe4, 0x3a, 0x0e, 0x53, 0x7e, 0x2b };
118
119 static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30,
120  0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
121  0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00,
122  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
123  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
124  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31,
125  0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61,
126  0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00,
127  0x03, 0x01, 0x00, 0xa3, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d,
128  0x25, 0x01, 0x01, 0xff, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01,
129  0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
130  0x03, 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
131
132 static void testAddCert(void)
133 {
134     HCERTSTORE store;
135
136     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
137      CERT_STORE_CREATE_NEW_FLAG, NULL);
138     ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
139     if (store != NULL)
140     {
141         HCERTSTORE collection;
142         PCCERT_CONTEXT context;
143         BOOL ret;
144
145         /* Weird--bad add disposition leads to an access violation in Windows.
146          */
147         ret = CertAddEncodedCertificateToStore(0, X509_ASN_ENCODING, bigCert,
148          sizeof(bigCert), 0, NULL);
149         ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
150          "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
151         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
152          bigCert, sizeof(bigCert), 0, NULL);
153         ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
154          "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
155
156         /* Weird--can add a cert to the NULL store (does this have special
157          * meaning?)
158          */
159         context = NULL;
160         ret = CertAddEncodedCertificateToStore(0, X509_ASN_ENCODING, bigCert,
161          sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
162         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
163          GetLastError());
164         if (context)
165             CertFreeCertificateContext(context);
166
167         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
168          bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
169         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
170          GetLastError());
171         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
172          bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL);
173         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
174          GetLastError());
175         /* This has the same name as bigCert, so finding isn't done by name */
176         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
177          certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, &context);
178         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
179          GetLastError());
180         ok(context != NULL, "Expected a context\n");
181         if (context)
182         {
183             CRYPT_DATA_BLOB hash = { sizeof(bigCert2Hash),
184              (LPBYTE)bigCert2Hash };
185
186             /* Duplicate (AddRef) the context so we can still use it after
187              * deleting it from the store.
188              */
189             CertDuplicateCertificateContext(context);
190             CertDeleteCertificateFromStore(context);
191             /* Set the same hash as bigCert2, and try to readd it */
192             ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID,
193              0, &hash);
194             ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
195              GetLastError());
196             ret = CertAddCertificateContextToStore(store, context,
197              CERT_STORE_ADD_NEW, NULL);
198             /* The failure is a bit odd (CRYPT_E_ASN1_BADTAG), so just check
199              * that it fails.
200              */
201             ok(!ret, "Expected failure\n");
202             CertFreeCertificateContext(context);
203         }
204         context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2,
205          sizeof(bigCert2));
206         ok(context != NULL, "Expected a context\n");
207         if (context)
208         {
209             /* Try to readd bigCert2 to the store */
210             ret = CertAddCertificateContextToStore(store, context,
211              CERT_STORE_ADD_NEW, NULL);
212             ok(!ret && GetLastError() == CRYPT_E_EXISTS,
213              "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
214             CertFreeCertificateContext(context);
215         }
216
217         /* Adding a cert with the same issuer name and serial number (but
218          * different subject) as an existing cert succeeds.
219          */
220         context = NULL;
221         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
222          bigCert2WithDifferentSerial, sizeof(bigCert2WithDifferentSerial),
223          CERT_STORE_ADD_NEW, &context);
224         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
225          GetLastError());
226         if (context)
227             CertDeleteCertificateFromStore(context);
228
229         /* Adding a cert with the same subject name and serial number (but
230          * different issuer) as an existing cert succeeds.
231          */
232         context = NULL;
233         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
234          bigCertWithDifferentSubject, sizeof(bigCertWithDifferentSubject),
235          CERT_STORE_ADD_NEW, &context);
236         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
237          GetLastError());
238         if (context)
239             CertDeleteCertificateFromStore(context);
240
241         /* Adding a cert with the same issuer name and serial number (but
242          * different otherwise) as an existing cert succeeds.
243          */
244         context = NULL;
245         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
246          bigCertWithDifferentIssuer, sizeof(bigCertWithDifferentIssuer),
247          CERT_STORE_ADD_NEW, &context);
248         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
249          GetLastError());
250         if (context)
251             CertDeleteCertificateFromStore(context);
252
253         collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
254          CERT_STORE_CREATE_NEW_FLAG, NULL);
255         ok(collection != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
256         if (collection)
257         {
258             /* Add store to the collection, but disable updates */
259             CertAddStoreToCollection(collection, store, 0, 0);
260
261             context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2,
262              sizeof(bigCert2));
263             ok(context != NULL, "Expected a context\n");
264             if (context)
265             {
266                 /* Try to readd bigCert2 to the collection */
267                 ret = CertAddCertificateContextToStore(collection, context,
268                  CERT_STORE_ADD_NEW, NULL);
269                 ok(!ret && GetLastError() == CRYPT_E_EXISTS,
270                  "Expected CRYPT_E_EXISTS, got %08lx\n", GetLastError());
271                 /* Replacing an existing certificate context is allowed, even
272                  * though updates to the collection aren't..
273                  */
274                 ret = CertAddCertificateContextToStore(collection, context,
275                  CERT_STORE_ADD_REPLACE_EXISTING, NULL);
276                 ok(ret, "CertAddCertificateContextToStore failed: %08lx\n",
277                  GetLastError());
278                 /* but adding a new certificate isn't allowed. */
279                 ret = CertAddCertificateContextToStore(collection, context,
280                  CERT_STORE_ADD_ALWAYS, NULL);
281                 ok(!ret && GetLastError() == E_ACCESSDENIED,
282                  "Expected E_ACCESSDENIED, got %08lx\n", GetLastError());
283                 CertFreeCertificateContext(context);
284             }
285
286             CertCloseStore(collection, 0);
287         }
288
289         CertCloseStore(store, 0);
290     }
291 }
292
293 static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID,
294  PCCERT_CONTEXT context, DWORD propID)
295 {
296     BYTE hash[20] = { 0 }, hashProperty[20];
297     BOOL ret;
298     DWORD size;
299
300     memset(hash, 0, sizeof(hash));
301     memset(hashProperty, 0, sizeof(hashProperty));
302     size = sizeof(hash);
303     ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size);
304     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
305     ret = CertGetCertificateContextProperty(context, propID, hashProperty,
306      &size);
307     ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
308      GetLastError());
309     ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %ld\n",
310      propID);
311 }
312
313 static void testCertProperties(void)
314 {
315     PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
316      bigCert, sizeof(bigCert));
317
318     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
319      GetLastError());
320     if (context)
321     {
322         DWORD propID, numProps, access, size;
323         BOOL ret;
324         BYTE hash[20] = { 0 }, hashProperty[20];
325         CRYPT_DATA_BLOB blob;
326
327         /* This crashes
328         propID = CertEnumCertificateContextProperties(NULL, 0);
329          */
330
331         propID = 0;
332         numProps = 0;
333         do {
334             propID = CertEnumCertificateContextProperties(context, propID);
335             if (propID)
336                 numProps++;
337         } while (propID != 0);
338         ok(numProps == 0, "Expected 0 properties, got %ld\n", numProps);
339
340         /* Tests with a NULL cert context.  Prop ID 0 fails.. */
341         ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
342         ok(!ret && GetLastError() == E_INVALIDARG,
343          "Expected E_INVALIDARG, got %08lx\n", GetLastError());
344         /* while this just crashes.
345         ret = CertSetCertificateContextProperty(NULL,
346          CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
347          */
348
349         ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
350         ok(!ret && GetLastError() == E_INVALIDARG,
351          "Expected E_INVALIDARG, got %08lx\n", GetLastError());
352         /* Can't set the cert property directly, this crashes.
353         ret = CertSetCertificateContextProperty(context,
354          CERT_CERT_PROP_ID, 0, bigCert2);
355          */
356
357         /* These all crash.
358         ret = CertGetCertificateContextProperty(context,
359          CERT_ACCESS_STATE_PROP_ID, 0, NULL);
360         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, 
361          NULL, NULL);
362         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, 
363          hashProperty, NULL);
364          */
365         /* A missing prop */
366         size = 0;
367         ret = CertGetCertificateContextProperty(context,
368          CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
369         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
370          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
371         /* And, an implicit property */
372         size = sizeof(access);
373         ret = CertGetCertificateContextProperty(context,
374          CERT_ACCESS_STATE_PROP_ID, &access, &size);
375         ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
376          GetLastError());
377         ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
378          "Didn't expect a persisted cert\n");
379         /* Trying to set this "read only" property crashes.
380         access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
381         ret = CertSetCertificateContextProperty(context,
382          CERT_ACCESS_STATE_PROP_ID, 0, &access);
383          */
384
385         /* Can I set the hash to an invalid hash? */
386         blob.pbData = hash;
387         blob.cbData = sizeof(hash);
388         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
389          &blob);
390         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
391          GetLastError());
392         size = sizeof(hashProperty);
393         ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
394          hashProperty, &size);
395         ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
396         /* Delete the (bogus) hash, and get the real one */
397         ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
398          NULL);
399         ok(ret, "CertSetCertificateContextProperty failed: %08lx\n",
400          GetLastError());
401         checkHash(bigCert, sizeof(bigCert), CALG_SHA1, context,
402          CERT_HASH_PROP_ID);
403
404         /* Now that the hash property is set, we should get one property when
405          * enumerating.
406          */
407         propID = 0;
408         numProps = 0;
409         do {
410             propID = CertEnumCertificateContextProperties(context, propID);
411             if (propID)
412                 numProps++;
413         } while (propID != 0);
414         ok(numProps == 1, "Expected 1 properties, got %ld\n", numProps);
415
416         /* Check a few other implicit properties */
417         checkHash(bigCert, sizeof(bigCert), CALG_MD5, context,
418          CERT_MD5_HASH_PROP_ID);
419         checkHash(
420          context->pCertInfo->Subject.pbData,
421          context->pCertInfo->Subject.cbData,
422          CALG_MD5, context, CERT_SUBJECT_NAME_MD5_HASH_PROP_ID);
423         checkHash(
424          context->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
425          context->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
426          CALG_MD5, context, CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID);
427
428         /* Odd: this doesn't fail on other certificates, so there must be
429          * something weird about this cert that causes it to fail.
430          */
431         size = 0;
432         ret = CertGetCertificateContextProperty(context,
433          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
434         todo_wine ok(!ret && GetLastError() == ERROR_INVALID_DATA,
435          "Expected ERROR_INVALID_DATA, got %08lx\n", GetLastError());
436
437         CertFreeCertificateContext(context);
438     }
439 }
440
441 static void testDupCert(void)
442 {
443     HCERTSTORE store;
444
445     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
446      CERT_STORE_CREATE_NEW_FLAG, NULL);
447     ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
448     if (store != NULL)
449     {
450         PCCERT_CONTEXT context, dupContext;
451         BOOL ret;
452
453         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
454          bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
455         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
456          GetLastError());
457         ok(context != NULL, "Expected a valid cert context\n");
458         if (context)
459         {
460             ok(context->cbCertEncoded == sizeof(bigCert),
461              "Wrong cert size %ld\n", context->cbCertEncoded);
462             ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
463              "Unexpected encoded cert in context\n");
464             ok(context->hCertStore == store, "Unexpected store\n");
465
466             dupContext = CertDuplicateCertificateContext(context);
467             ok(dupContext != NULL, "Expected valid duplicate\n");
468             /* Not only is it a duplicate, it's identical: the address is the
469              * same.
470              */
471             ok(dupContext == context, "Expected identical context addresses\n");
472             CertFreeCertificateContext(dupContext);
473             CertFreeCertificateContext(context);
474         }
475         CertCloseStore(store, 0);
476     }
477 }
478
479 static void testFindCert(void)
480 {
481     HCERTSTORE store;
482
483     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
484      CERT_STORE_CREATE_NEW_FLAG, NULL);
485     ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
486     if (store)
487     {
488         PCCERT_CONTEXT context = NULL;
489         BOOL ret;
490         CERT_INFO certInfo = { 0 };
491         CRYPT_HASH_BLOB blob;
492
493         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
494          bigCert, sizeof(bigCert), CERT_STORE_ADD_NEW, NULL);
495         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
496          GetLastError());
497         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
498          bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL);
499         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
500          GetLastError());
501         /* This has the same name as bigCert */
502         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
503          certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL);
504         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
505          GetLastError());
506
507         /* Crashes
508         context = CertFindCertificateInStore(NULL, 0, 0, 0, NULL, NULL);
509          */
510
511         /* Check first cert's there, by issuer */
512         certInfo.Subject.pbData = (LPBYTE)subjectName;
513         certInfo.Subject.cbData = sizeof(subjectName);
514         certInfo.SerialNumber.pbData = (LPBYTE)serialNum;
515         certInfo.SerialNumber.cbData = sizeof(serialNum);
516         context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
517          CERT_FIND_ISSUER_NAME, &certInfo.Subject, NULL);
518         ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n",
519          GetLastError());
520         if (context)
521         {
522             context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
523              CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
524             ok(context != NULL, "Expected more than one cert\n");
525             if (context)
526             {
527                 context = CertFindCertificateInStore(store, X509_ASN_ENCODING,
528                  0, CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
529                 ok(context == NULL, "Expected precisely two certs\n");
530             }
531         }
532
533         /* Check second cert's there as well, by subject name */
534         certInfo.Subject.pbData = (LPBYTE)subjectName2;
535         certInfo.Subject.cbData = sizeof(subjectName2);
536         context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
537          CERT_FIND_SUBJECT_NAME, &certInfo.Subject, NULL);
538         ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n",
539          GetLastError());
540         if (context)
541         {
542             context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
543              CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
544             ok(context == NULL, "Expected one cert only\n");
545         }
546
547         /* Strange but true: searching for the subject cert requires you to set
548          * the issuer, not the subject
549          */
550         context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
551          CERT_FIND_SUBJECT_CERT, &certInfo.Subject, NULL);
552         ok(context == NULL, "Expected no certificate\n");
553         certInfo.Subject.pbData = NULL;
554         certInfo.Subject.cbData = 0;
555         certInfo.Issuer.pbData = (LPBYTE)subjectName2;
556         certInfo.Issuer.cbData = sizeof(subjectName2);
557         context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
558          CERT_FIND_SUBJECT_CERT, &certInfo, NULL);
559         ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n",
560          GetLastError());
561         if (context)
562         {
563             context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
564              CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
565             ok(context == NULL, "Expected one cert only\n");
566         }
567
568         /* The nice thing about hashes, they're unique */
569         blob.pbData = (LPBYTE)bigCertHash;
570         blob.cbData = sizeof(bigCertHash);
571         context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
572          CERT_FIND_SHA1_HASH, &blob, NULL);
573         ok(context != NULL, "CertFindCertificateInStore failed: %08lx\n",
574          GetLastError());
575         if (context)
576         {
577             context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
578              CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
579             ok(context == NULL, "Expected one cert only\n");
580         }
581
582         CertCloseStore(store, 0);
583     }
584 }
585
586 static void testGetSubjectCert(void)
587 {
588     HCERTSTORE store;
589
590     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
591      CERT_STORE_CREATE_NEW_FLAG, NULL);
592     ok(store != NULL, "CertOpenStore failed: %ld\n", GetLastError());
593     if (store != NULL)
594     {
595         PCCERT_CONTEXT context1, context2;
596         CERT_INFO info = { 0 };
597         BOOL ret;
598
599         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
600          bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
601         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
602          GetLastError());
603         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
604          bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, &context1);
605         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
606          GetLastError());
607         ok(context1 != NULL, "Expected a context\n");
608         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
609          certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL);
610         ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
611          GetLastError());
612
613         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
614          NULL);
615         ok(!context2 && GetLastError() == E_INVALIDARG,
616          "Expected E_INVALIDARG, got %08lx\n", GetLastError());
617         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
618          &info);
619         ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND,
620          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
621         info.SerialNumber.cbData = sizeof(serialNum);
622         info.SerialNumber.pbData = (LPBYTE)serialNum;
623         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
624          &info);
625         ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND,
626          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
627         info.Issuer.cbData = sizeof(subjectName2);
628         info.Issuer.pbData = (LPBYTE)subjectName2;
629         context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
630          &info);
631         ok(context2 != NULL,
632          "CertGetSubjectCertificateFromStore failed: %08lx\n", GetLastError());
633         /* Not only should this find a context, but it should be the same
634          * (same address) as context1.
635          */
636         ok(context1 == context2, "Expected identical context addresses\n");
637         CertFreeCertificateContext(context2);
638
639         CertFreeCertificateContext(context1);
640         CertCloseStore(store, 0);
641     }
642 }
643
644 /* This expires in 1970 or so */
645 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
646  0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
647  0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
648  0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
649  0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
650  0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
651  0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
652  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
653  0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
654  0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
655  0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
656  0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
657  0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
658  0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
659  0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
660  0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
661  0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
662  0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
663  0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
664  0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
665  0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
666  0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
667  0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
668  0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
669  0x49, 0xe5, 0xf9, 0x65, 0xf3 };
670
671 /* This expires in 2036 or so */
672 static const BYTE childOfExpired[] = { 0x30, 0x81, 0xcc, 0x30, 0x78, 0xa0,
673  0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
674  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d,
675  0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63,
676  0x40, 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e,
677  0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x35, 0x30, 0x35,
678  0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x35,
679  0x30, 0x35, 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x30, 0x15, 0x31, 0x13,
680  0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e,
681  0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03,
682  0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
683  0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x20, 0x3b, 0xdb, 0x4d, 0x67, 0x50,
684  0xec, 0x73, 0x9d, 0xf9, 0x85, 0x5d, 0x18, 0xe9, 0xb4, 0x98, 0xe3, 0x31, 0xb7,
685  0x03, 0x0b, 0xc0, 0x39, 0x93, 0x56, 0x81, 0x0a, 0xfc, 0x78, 0xa8, 0x29, 0x42,
686  0x5f, 0x69, 0xfb, 0xbc, 0x5b, 0xf2, 0xa6, 0x2a, 0xbe, 0x91, 0x2c, 0xfc, 0x89,
687  0x69, 0x15, 0x18, 0x58, 0xe5, 0x02, 0x75, 0xf7, 0x2a, 0xb6, 0xa9, 0xfb, 0x47,
688  0x6a, 0x6e, 0x0a, 0x9b, 0xe9, 0xdc };
689
690 static void testGetIssuerCert(void)
691 {
692     BOOL ret;
693     PCCERT_CONTEXT parent, child;
694     DWORD flags = 0xffffffff;
695     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
696      CERT_STORE_CREATE_NEW_FLAG, NULL);
697
698     ok(store != NULL, "CertOpenStore failed: %08lx\n", GetLastError());
699
700     ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
701      expiredCert, sizeof(expiredCert), CERT_STORE_ADD_ALWAYS, NULL);
702     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
703      GetLastError());
704
705     ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
706      childOfExpired, sizeof(childOfExpired), CERT_STORE_ADD_ALWAYS, &child);
707     ok(ret, "CertAddEncodedCertificateToStore failed: %08lx\n",
708      GetLastError());
709
710     /* These crash:
711     parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, NULL);
712     parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, NULL);
713      */
714     parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, &flags);
715     ok(!parent && GetLastError() == E_INVALIDARG,
716      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
717     parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, &flags);
718     ok(!parent && GetLastError() == E_INVALIDARG,
719      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
720     parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
721     ok(!parent && GetLastError() == E_INVALIDARG,
722      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
723     /* Confusing: the caller cannot set either of the
724      * CERT_STORE_NO_*_FLAGs, as these are not checks,
725      * they're results:
726      */
727     flags = CERT_STORE_NO_CRL_FLAG | CERT_STORE_NO_ISSUER_FLAG;
728     parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
729     ok(!parent && GetLastError() == E_INVALIDARG,
730      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
731     /* Perform no checks */
732     flags = 0;
733     parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
734     ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08lx\n",
735      GetLastError());
736     if (parent)
737         CertFreeCertificateContext(parent);
738     /* Check revocation and signature only */
739     flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
740     parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
741     ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08lx\n",
742      GetLastError());
743     /* Confusing: CERT_STORE_REVOCATION_FLAG succeeds when there is no CRL by
744      * setting CERT_STORE_NO_CRL_FLAG.
745      */
746     ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG),
747      "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08lx\n",
748      flags);
749     if (parent)
750         CertFreeCertificateContext(parent);
751     /* Now check just the time */
752     flags = CERT_STORE_TIME_VALIDITY_FLAG;
753     parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
754     ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08lx\n",
755      GetLastError());
756     /* Oops: the child is not expired, so the time validity check actually
757      * succeeds, even though the signing cert is expired.
758      */
759     ok(!flags, "Expected check to succeed, got %08lx\n", flags);
760     if (parent)
761         CertFreeCertificateContext(parent);
762
763     CertFreeCertificateContext(child);
764     CertCloseStore(store, 0);
765 }
766
767 static void testCryptHashCert(void)
768 {
769     static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b,
770      0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
771      0x09 };
772     static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee,
773      0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8,
774      0xa2 };
775     static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:";
776     BOOL ret;
777     BYTE hash[20];
778     DWORD hashLen = sizeof(hash);
779
780     /* NULL buffer and nonzero length crashes
781     ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen);
782        empty hash length also crashes
783     ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL);
784      */
785     /* Test empty hash */
786     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL,
787      &hashLen);
788     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
789     ok(hashLen == sizeof(hash), "Got unexpected size of hash %ld\n", hashLen);
790     /* Test with empty buffer */
791     ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen);
792     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
793     ok(!memcmp(hash, emptyHash, sizeof(emptyHash)),
794      "Unexpected hash of nothing\n");
795     /* Test a known value */
796     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash,
797      &hashLen);
798     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
799     ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n");
800 }
801
802 static const WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e',
803  'm','p',0 };
804
805 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
806  const BYTE *sig, unsigned int sigLen)
807 {
808     HCRYPTHASH hash;
809     BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
810
811     ok(ret, "CryptCreateHash failed: %08lx\n", GetLastError());
812     if (ret)
813     {
814         BYTE mySig[64];
815         DWORD mySigSize = sizeof(mySig);
816
817         ret = CryptHashData(hash, toSign, toSignLen, 0);
818         ok(ret, "CryptHashData failed: %08lx\n", GetLastError());
819         /* use the A variant so the test can run on Win9x */
820         ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
821         ok(ret, "CryptSignHash failed: %08lx\n", GetLastError());
822         if (ret)
823         {
824             ok(mySigSize == sigLen, "Expected sig length %d, got %ld\n",
825              sigLen, mySigSize);
826             ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
827         }
828         CryptDestroyHash(hash);
829     }
830 }
831
832 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
833  * using the algorithm with OID sigOID.  The CSP is assumed to be empty, and a
834  * keyset named AT_SIGNATURE will be added to it.  The signing key will be
835  * stored in *key, and the signature will be stored in sig.  sigLen should be
836  * at least 64 bytes.
837  */
838 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
839  LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
840 {
841     BOOL ret;
842     DWORD size = 0;
843     CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
844
845     /* These all crash
846     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
847     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
848     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
849      NULL, NULL, NULL, &size);
850      */
851     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
852      &algoID, NULL, NULL, &size);
853     ok(!ret && GetLastError() == NTE_BAD_ALGID, 
854      "Expected NTE_BAD_ALGID, got %08lx\n", GetLastError());
855     algoID.pszObjId = (LPSTR)sigOID;
856     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
857      &algoID, NULL, NULL, &size);
858     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
859      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
860     ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
861      toBeSigned->cbData, &algoID, NULL, NULL, &size);
862     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
863      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
864
865     /* No keys exist in the new CSP yet.. */
866     ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
867      toBeSigned->cbData, &algoID, NULL, NULL, &size);
868     ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
869      NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08lx\n",
870      GetLastError());
871     ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
872     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
873     if (ret)
874     {
875         ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
876          toBeSigned->cbData, &algoID, NULL, NULL, &size);
877         ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
878         ok(size <= *sigLen, "Expected size <= %ld, got %ld\n", *sigLen, size);
879         if (ret)
880         {
881             ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
882              toBeSigned->cbData, &algoID, NULL, sig, &size);
883             ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
884             if (ret)
885             {
886                 *sigLen = size;
887                 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
888                  size);
889             }
890         }
891     }
892 }
893
894 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
895  LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
896 {
897     CERT_SIGNED_CONTENT_INFO info;
898     LPBYTE cert = NULL;
899     DWORD size = 0;
900     BOOL ret;
901
902     if(pCryptVerifyCertificateSignatureEx) {
903         ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
904         ok(!ret && GetLastError() == E_INVALIDARG,
905          "Expected E_INVALIDARG, got %08lx\n", GetLastError());
906         ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
907         ok(!ret && GetLastError() == E_INVALIDARG,
908          "Expected E_INVALIDARG, got %08lx\n", GetLastError());
909         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
910          NULL, 0, NULL);
911         ok(!ret && GetLastError() == E_INVALIDARG,
912          "Expected E_INVALIDARG, got %08lx\n", GetLastError());
913         /* This crashes
914         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
915          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
916          */
917     }
918     info.ToBeSigned.cbData = toBeSigned->cbData;
919     info.ToBeSigned.pbData = toBeSigned->pbData;
920     info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
921     info.SignatureAlgorithm.Parameters.cbData = 0;
922     info.Signature.cbData = sigLen;
923     info.Signature.pbData = (BYTE *)sig;
924     info.Signature.cUnusedBits = 0;
925     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
926      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
927     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
928     if (cert)
929     {
930         CRYPT_DATA_BLOB certBlob = { 0, NULL };
931         PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
932
933         if(pCryptVerifyCertificateSignatureEx) {
934             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
935              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
936             ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
937              "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
938             certBlob.cbData = 1;
939             certBlob.pbData = (void *)0xdeadbeef;
940             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
941              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
942             ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
943              "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
944             certBlob.cbData = size;
945             certBlob.pbData = cert;
946             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
947              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
948             ok(!ret && GetLastError() == E_INVALIDARG,
949              "Expected E_INVALIDARG, got %08lx\n", GetLastError());
950             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
951              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
952              CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
953             ok(!ret && GetLastError() == E_INVALIDARG,
954              "Expected E_INVALIDARG, got %08lx\n", GetLastError());
955             /* This crashes
956             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
957              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
958              CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
959              */
960         }
961         CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
962          (LPSTR)sigOID, 0, NULL, NULL, &size);
963         pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
964         if (pubKeyInfo)
965         {
966             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
967              X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
968             ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
969             if (ret && pCryptVerifyCertificateSignatureEx)
970             {
971                 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
972                  CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
973                  CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
974                 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
975                  GetLastError());
976             }
977             HeapFree(GetProcessHeap(), 0, pubKeyInfo);
978         }
979         LocalFree(cert);
980     }
981 }
982
983 static const BYTE emptyCert[] = { 0x30, 0x00 };
984
985 static void testCertSigs(void)
986 {
987     HCRYPTPROV csp;
988     CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
989     BOOL ret;
990     HCRYPTKEY key;
991     BYTE sig[64];
992     DWORD sigSize = sizeof(sig);
993
994     /* Just in case a previous run failed, delete this thing */
995     CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
996      CRYPT_DELETEKEYSET);
997     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
998      CRYPT_NEWKEYSET);
999     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
1000
1001     testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
1002     testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
1003
1004     CryptDestroyKey(key);
1005     CryptReleaseContext(csp, 0);
1006     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1007      CRYPT_DELETEKEYSET);
1008 }
1009
1010 static void testCreateSelfSignCert(void)
1011 {
1012     PCCERT_CONTEXT context;
1013     CERT_NAME_BLOB name = { sizeof(subjectName), (LPBYTE)subjectName };
1014     HCRYPTPROV csp;
1015     BOOL ret;
1016     HCRYPTKEY key;
1017
1018     /* This crashes:
1019     context = CertCreateSelfSignCertificate(0, NULL, 0, NULL, NULL, NULL, NULL,
1020      NULL);
1021      * Calling this with no first parameter creates a new key container, which
1022      * lasts beyond the test, so I don't test that.  Nb: the generated key
1023      * name is a GUID.
1024     context = CertCreateSelfSignCertificate(0, &name, 0, NULL, NULL, NULL, NULL,
1025      NULL);
1026      */
1027
1028     /* Acquire a CSP */
1029     CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1030      CRYPT_DELETEKEYSET);
1031     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1032      CRYPT_NEWKEYSET);
1033     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
1034
1035     context = CertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL,
1036      NULL, NULL);
1037     ok(!context && GetLastError() == NTE_NO_KEY,
1038      "Expected NTE_NO_KEY, got %08lx\n", GetLastError());
1039     ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
1040     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
1041     if (ret)
1042     {
1043         context = CertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL,
1044          NULL, NULL);
1045         ok(context != NULL, "CertCreateSelfSignCertificate failed: %08lx\n",
1046          GetLastError());
1047         if (context)
1048         {
1049             DWORD size = 0;
1050             PCRYPT_KEY_PROV_INFO info;
1051
1052             /* The context must have a key provider info property */
1053             ret = CertGetCertificateContextProperty(context,
1054              CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
1055             ok(ret && size, "Expected non-zero key provider info\n");
1056             if (size)
1057             {
1058                 info = HeapAlloc(GetProcessHeap(), 0, size);
1059                 if (info)
1060                 {
1061                     ret = CertGetCertificateContextProperty(context,
1062                      CERT_KEY_PROV_INFO_PROP_ID, info, &size);
1063                     ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
1064                      GetLastError());
1065                     if (ret)
1066                     {
1067                         /* Sanity-check the key provider */
1068                         ok(!lstrcmpW(info->pwszContainerName, cspNameW),
1069                          "Unexpected key container\n");
1070                         ok(!lstrcmpW(info->pwszProvName, MS_DEF_PROV_W),
1071                          "Unexpected provider\n");
1072                         ok(info->dwKeySpec == AT_SIGNATURE,
1073                          "Expected AT_SIGNATURE, got %ld\n", info->dwKeySpec);
1074                     }
1075                     HeapFree(GetProcessHeap(), 0, info);
1076                 }
1077             }
1078
1079             CertFreeCertificateContext(context);
1080         }
1081
1082         CryptDestroyKey(key);
1083     }
1084
1085     CryptReleaseContext(csp, 0);
1086     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1087      CRYPT_DELETEKEYSET);
1088 }
1089
1090 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
1091  szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
1092
1093 static void testKeyUsage(void)
1094 {
1095     BOOL ret;
1096     PCCERT_CONTEXT context;
1097     DWORD size;
1098
1099     /* Test base cases */
1100     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, NULL);
1101     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1102      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1103     size = 1;
1104     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
1105     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1106      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1107     size = 0;
1108     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
1109     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1110      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1111     /* These crash
1112     ret = CertSetEnhancedKeyUsage(NULL, NULL);
1113     usage.cUsageIdentifier = 0;
1114     ret = CertSetEnhancedKeyUsage(NULL, &usage);
1115      */
1116     /* Test with a cert with no enhanced key usage extension */
1117     context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
1118      sizeof(bigCert));
1119     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1120      GetLastError());
1121     if (context)
1122     {
1123         static const char oid[] = "1.2.3.4";
1124         BYTE buf[sizeof(CERT_ENHKEY_USAGE) + 2 * (sizeof(LPSTR) + sizeof(oid))];
1125         PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1126
1127         ret = CertGetEnhancedKeyUsage(context, 0, NULL, NULL);
1128         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1129          "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
1130         size = 1;
1131         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &size);
1132         if (ret)
1133         {
1134             /* Windows 2000, ME, or later: even though it succeeded, we expect
1135              * CRYPT_E_NOT_FOUND, which indicates there is no enhanced key
1136              * usage set for this cert (which implies it's valid for all uses.)
1137              */
1138             ok(GetLastError() == CRYPT_E_NOT_FOUND,
1139              "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1140             ok(size == sizeof(CERT_ENHKEY_USAGE), "Wrong size %ld\n", size);
1141             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1142             ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1143             ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
1144              pUsage->cUsageIdentifier);
1145         }
1146         else
1147         {
1148             /* Windows NT, 95, or 98: it fails, and the last error is
1149              * CRYPT_E_NOT_FOUND.
1150              */
1151             ok(GetLastError() == CRYPT_E_NOT_FOUND,
1152              "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1153         }
1154         /* I can add a usage identifier when no key usage has been set */
1155         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
1156         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
1157          GetLastError());
1158         size = sizeof(buf);
1159         ret = CertGetEnhancedKeyUsage(context,
1160          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1161         ok(ret && GetLastError() == 0,
1162          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1163         ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
1164          pUsage->cUsageIdentifier);
1165         if (pUsage->cUsageIdentifier)
1166             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
1167              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
1168         /* Now set an empty key usage */
1169         pUsage->cUsageIdentifier = 0;
1170         ret = CertSetEnhancedKeyUsage(context, pUsage);
1171         ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1172         /* Shouldn't find it in the cert */
1173         size = sizeof(buf);
1174         ret = CertGetEnhancedKeyUsage(context,
1175          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1176         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1177          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1178         /* Should find it as an extended property */
1179         ret = CertGetEnhancedKeyUsage(context,
1180          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1181         ok(ret && GetLastError() == 0,
1182          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1183         ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
1184          pUsage->cUsageIdentifier);
1185         /* Should find it as either */
1186         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1187         ok(ret && GetLastError() == 0,
1188          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1189         ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
1190          pUsage->cUsageIdentifier);
1191         /* Add a usage identifier */
1192         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
1193         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
1194          GetLastError());
1195         size = sizeof(buf);
1196         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1197         ok(ret && GetLastError() == 0,
1198          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1199         ok(pUsage->cUsageIdentifier == 1, "Expected 1 identifier, got %ld\n",
1200          pUsage->cUsageIdentifier);
1201         if (pUsage->cUsageIdentifier)
1202             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
1203              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
1204         /* Yep, I can re-add the same usage identifier */
1205         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
1206         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
1207          GetLastError());
1208         size = sizeof(buf);
1209         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1210         ok(ret && GetLastError() == 0,
1211          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1212         ok(pUsage->cUsageIdentifier == 2, "Expected 2 identifiers, got %ld\n",
1213          pUsage->cUsageIdentifier);
1214         if (pUsage->cUsageIdentifier)
1215             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
1216              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
1217         if (pUsage->cUsageIdentifier >= 2)
1218             ok(!strcmp(pUsage->rgpszUsageIdentifier[1], oid),
1219              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[1]);
1220         /* Now set a NULL extended property--this deletes the property. */
1221         ret = CertSetEnhancedKeyUsage(context, NULL);
1222         ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1223         SetLastError(0xbaadcafe);
1224         size = sizeof(buf);
1225         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1226         ok(GetLastError() == CRYPT_E_NOT_FOUND,
1227          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1228
1229         CertFreeCertificateContext(context);
1230     }
1231     /* Now test with a cert with an enhanced key usage extension */
1232     context = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage,
1233      sizeof(certWithUsage));
1234     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
1235      GetLastError());
1236     if (context)
1237     {
1238         LPBYTE buf = NULL;
1239         DWORD bufSize = 0, i;
1240
1241         /* The size may depend on what flags are used to query it, so I
1242          * realloc the buffer for each test.
1243          */
1244         ret = CertGetEnhancedKeyUsage(context,
1245          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
1246         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1247         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1248         if (buf)
1249         {
1250             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1251
1252             /* Should find it in the cert */
1253             size = bufSize;
1254             ret = CertGetEnhancedKeyUsage(context,
1255              CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1256             ok(ret && GetLastError() == 0,
1257              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1258             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
1259              pUsage->cUsageIdentifier);
1260             for (i = 0; i < pUsage->cUsageIdentifier; i++)
1261                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1262                  "Expected %s, got %s\n", keyUsages[i],
1263                  pUsage->rgpszUsageIdentifier[i]);
1264             HeapFree(GetProcessHeap(), 0, buf);
1265         }
1266         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
1267         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1268         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1269         if (buf)
1270         {
1271             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1272
1273             /* Should find it as either */
1274             size = bufSize;
1275             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1276             /* In Windows, GetLastError returns CRYPT_E_NOT_FOUND not found
1277              * here, even though the return is successful and the usage id
1278              * count is positive.  I don't enforce that here.
1279              */
1280             ok(ret,
1281              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1282             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
1283              pUsage->cUsageIdentifier);
1284             for (i = 0; i < pUsage->cUsageIdentifier; i++)
1285                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1286                  "Expected %s, got %s\n", keyUsages[i],
1287                  pUsage->rgpszUsageIdentifier[i]);
1288             HeapFree(GetProcessHeap(), 0, buf);
1289         }
1290         /* Shouldn't find it as an extended property */
1291         ret = CertGetEnhancedKeyUsage(context,
1292          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size);
1293         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1294          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
1295         /* Adding a usage identifier overrides the cert's usage!? */
1296         ret = CertAddEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
1297         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
1298          GetLastError());
1299         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
1300         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1301         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1302         if (buf)
1303         {
1304             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1305
1306             /* Should find it as either */
1307             size = bufSize;
1308             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1309             ok(ret,
1310              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1311             ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
1312              pUsage->cUsageIdentifier);
1313             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA),
1314              "Expected %s, got %s\n", szOID_RSA_RSA,
1315              pUsage->rgpszUsageIdentifier[0]);
1316             HeapFree(GetProcessHeap(), 0, buf);
1317         }
1318         /* But querying the cert directly returns its usage */
1319         ret = CertGetEnhancedKeyUsage(context,
1320          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
1321         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1322         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1323         if (buf)
1324         {
1325             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1326
1327             size = bufSize;
1328             ret = CertGetEnhancedKeyUsage(context,
1329              CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1330             ok(ret,
1331              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1332             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
1333              pUsage->cUsageIdentifier);
1334             for (i = 0; i < pUsage->cUsageIdentifier; i++)
1335                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1336                  "Expected %s, got %s\n", keyUsages[i],
1337                  pUsage->rgpszUsageIdentifier[i]);
1338             HeapFree(GetProcessHeap(), 0, buf);
1339         }
1340         /* And removing the only usage identifier in the extended property
1341          * results in the cert's key usage being found.
1342          */
1343         ret = CertRemoveEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
1344         ok(ret, "CertRemoveEnhancedKeyUsage failed: %08lx\n", GetLastError());
1345         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
1346         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1347         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1348         if (buf)
1349         {
1350             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1351
1352             /* Should find it as either */
1353             size = bufSize;
1354             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1355             ok(ret,
1356              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
1357             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
1358              pUsage->cUsageIdentifier);
1359             for (i = 0; i < pUsage->cUsageIdentifier; i++)
1360                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1361                  "Expected %s, got %s\n", keyUsages[i],
1362                  pUsage->rgpszUsageIdentifier[i]);
1363             HeapFree(GetProcessHeap(), 0, buf);
1364         }
1365
1366         CertFreeCertificateContext(context);
1367     }
1368 }
1369
1370 static void testCompareCertName(void)
1371 {
1372     static const BYTE bogus[] = { 1, 2, 3, 4 };
1373     static const BYTE bogusPrime[] = { 0, 1, 2, 3, 4 };
1374     static const BYTE emptyPrime[] = { 0x30, 0x00, 0x01 };
1375     BOOL ret;
1376     CERT_NAME_BLOB blob1, blob2;
1377
1378     /* crashes
1379     ret = CertCompareCertificateName(0, NULL, NULL);
1380      */
1381     /* An empty name checks against itself.. */
1382     blob1.pbData = (LPBYTE)emptyCert;
1383     blob1.cbData = sizeof(emptyCert);
1384     ret = CertCompareCertificateName(0, &blob1, &blob1);
1385     ok(ret, "CertCompareCertificateName failed: %08lx\n", GetLastError());
1386     /* It doesn't have to be a valid encoded name.. */
1387     blob1.pbData = (LPBYTE)bogus;
1388     blob1.cbData = sizeof(bogus);
1389     ret = CertCompareCertificateName(0, &blob1, &blob1);
1390     ok(ret, "CertCompareCertificateName failed: %08lx\n", GetLastError());
1391     /* Leading zeroes matter.. */
1392     blob2.pbData = (LPBYTE)bogusPrime;
1393     blob2.cbData = sizeof(bogusPrime);
1394     ret = CertCompareCertificateName(0, &blob1, &blob2);
1395     ok(!ret, "Expected failure\n");
1396     /* As do trailing extra bytes. */
1397     blob2.pbData = (LPBYTE)emptyPrime;
1398     blob2.cbData = sizeof(emptyPrime);
1399     ret = CertCompareCertificateName(0, &blob1, &blob2);
1400     ok(!ret, "Expected failure\n");
1401 }
1402
1403 static const BYTE int1[] = { 0x88, 0xff, 0xff, 0xff };
1404 static const BYTE int2[] = { 0x88, 0xff };
1405 static const BYTE int3[] = { 0x23, 0xff };
1406 static const BYTE int4[] = { 0x7f, 0x00 };
1407 static const BYTE int5[] = { 0x7f };
1408 static const BYTE int6[] = { 0x80, 0x00, 0x00, 0x00 };
1409 static const BYTE int7[] = { 0x80, 0x00 };
1410
1411 struct IntBlobTest
1412 {
1413     CRYPT_INTEGER_BLOB blob1;
1414     CRYPT_INTEGER_BLOB blob2;
1415     BOOL areEqual;
1416 } intBlobs[] = {
1417  { { sizeof(int1), (LPBYTE)int1 }, { sizeof(int2), (LPBYTE)int2 }, TRUE },
1418  { { sizeof(int3), (LPBYTE)int3 }, { sizeof(int3), (LPBYTE)int3 }, TRUE },
1419  { { sizeof(int4), (LPBYTE)int4 }, { sizeof(int5), (LPBYTE)int5 }, TRUE },
1420  { { sizeof(int6), (LPBYTE)int6 }, { sizeof(int7), (LPBYTE)int7 }, TRUE },
1421  { { sizeof(int1), (LPBYTE)int1 }, { sizeof(int7), (LPBYTE)int7 }, FALSE },
1422 };
1423
1424 static void testCompareIntegerBlob(void)
1425 {
1426     DWORD i;
1427     BOOL ret;
1428
1429     for (i = 0; i < sizeof(intBlobs) / sizeof(intBlobs[0]); i++)
1430     {
1431         ret = CertCompareIntegerBlob(&intBlobs[i].blob1, &intBlobs[i].blob2);
1432         ok(ret == intBlobs[i].areEqual,
1433          "%ld: expected blobs %s compare\n", i, intBlobs[i].areEqual ?
1434          "to" : "not to");
1435     }
1436 }
1437
1438 static void testComparePublicKeyInfo(void)
1439 {
1440     BOOL ret;
1441     CERT_PUBLIC_KEY_INFO info1 = { { 0 } }, info2 = { { 0 } };
1442     static CHAR oid_rsa_rsa[]     = szOID_RSA_RSA;
1443     static CHAR oid_rsa_sha1rsa[] = szOID_RSA_SHA1RSA;
1444     static CHAR oid_x957_dsa[]    = szOID_X957_DSA;
1445     static const BYTE bits1[] = { 1, 0 };
1446     static const BYTE bits2[] = { 0 };
1447     static const BYTE bits3[] = { 1 };
1448
1449     /* crashes
1450     ret = CertComparePublicKeyInfo(0, NULL, NULL);
1451      */
1452     /* Empty public keys compare */
1453     ret = CertComparePublicKeyInfo(0, &info1, &info2);
1454     ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
1455     /* Different OIDs appear to compare */
1456     info1.Algorithm.pszObjId = oid_rsa_rsa;
1457     info2.Algorithm.pszObjId = oid_rsa_sha1rsa;
1458     ret = CertComparePublicKeyInfo(0, &info1, &info2);
1459     ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
1460     info2.Algorithm.pszObjId = oid_x957_dsa;
1461     ret = CertComparePublicKeyInfo(0, &info1, &info2);
1462     ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
1463     info1.PublicKey.cbData = sizeof(bits1);
1464     info1.PublicKey.pbData = (LPBYTE)bits1;
1465     info1.PublicKey.cUnusedBits = 0;
1466     info2.PublicKey.cbData = sizeof(bits1);
1467     info2.PublicKey.pbData = (LPBYTE)bits1;
1468     info2.PublicKey.cUnusedBits = 0;
1469     ret = CertComparePublicKeyInfo(0, &info1, &info2);
1470     ok(ret, "CertComparePublicKeyInfo failed: %08lx\n", GetLastError());
1471     /* Even though they compare in their used bits, these do not compare */
1472     info1.PublicKey.cbData = sizeof(bits2);
1473     info1.PublicKey.pbData = (LPBYTE)bits2;
1474     info1.PublicKey.cUnusedBits = 0;
1475     info2.PublicKey.cbData = sizeof(bits3);
1476     info2.PublicKey.pbData = (LPBYTE)bits3;
1477     info2.PublicKey.cUnusedBits = 1;
1478     ret = CertComparePublicKeyInfo(0, &info1, &info2);
1479     /* Simple (non-comparing) case */
1480     ok(!ret, "Expected keys not to compare\n");
1481     info2.PublicKey.cbData = sizeof(bits1);
1482     info2.PublicKey.pbData = (LPBYTE)bits1;
1483     info2.PublicKey.cUnusedBits = 0;
1484     ret = CertComparePublicKeyInfo(0, &info1, &info2);
1485     ok(!ret, "Expected keys not to compare\n");
1486 }
1487
1488 void testCompareCert(void)
1489 {
1490     CERT_INFO info1 = { 0 }, info2 = { 0 };
1491     BOOL ret;
1492
1493     /* Crashes
1494     ret = CertCompareCertificate(X509_ASN_ENCODING, NULL, NULL);
1495      */
1496
1497     /* Certs with the same issuer and serial number are equal, even if they
1498      * differ in other respects (like subject).
1499      */
1500     info1.SerialNumber.pbData = (LPBYTE)serialNum;
1501     info1.SerialNumber.cbData = sizeof(serialNum);
1502     info1.Issuer.pbData = (LPBYTE)subjectName;
1503     info1.Issuer.cbData = sizeof(subjectName);
1504     info1.Subject.pbData = (LPBYTE)subjectName2;
1505     info1.Subject.cbData = sizeof(subjectName2);
1506     info2.SerialNumber.pbData = (LPBYTE)serialNum;
1507     info2.SerialNumber.cbData = sizeof(serialNum);
1508     info2.Issuer.pbData = (LPBYTE)subjectName;
1509     info2.Issuer.cbData = sizeof(subjectName);
1510     info2.Subject.pbData = (LPBYTE)subjectName;
1511     info2.Subject.cbData = sizeof(subjectName);
1512     ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2);
1513     ok(ret, "Expected certs to be equal\n");
1514
1515     info2.Issuer.pbData = (LPBYTE)subjectName2;
1516     info2.Issuer.cbData = sizeof(subjectName2);
1517     ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2);
1518     ok(!ret, "Expected certs not to be equal\n");
1519 }
1520
1521 static void testVerifySubjectCert(void)
1522 {
1523     BOOL ret;
1524     DWORD flags;
1525     PCCERT_CONTEXT context1, context2;
1526
1527     /* Crashes
1528     ret = CertVerifySubjectCertificateContext(NULL, NULL, NULL);
1529      */
1530     flags = 0;
1531     ret = CertVerifySubjectCertificateContext(NULL, NULL, &flags);
1532     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1533      GetLastError());
1534     flags = CERT_STORE_NO_CRL_FLAG;
1535     ret = CertVerifySubjectCertificateContext(NULL, NULL, &flags);
1536     ok(!ret && GetLastError() == E_INVALIDARG,
1537      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1538
1539     flags = 0;
1540     context1 = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
1541      sizeof(bigCert));
1542     ret = CertVerifySubjectCertificateContext(NULL, context1, &flags);
1543     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1544      GetLastError());
1545     ret = CertVerifySubjectCertificateContext(context1, NULL, &flags);
1546     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1547      GetLastError());
1548     ret = CertVerifySubjectCertificateContext(context1, context1, &flags);
1549     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1550      GetLastError());
1551
1552     context2 = CertCreateCertificateContext(X509_ASN_ENCODING,
1553      bigCertWithDifferentSubject, sizeof(bigCertWithDifferentSubject));
1554     SetLastError(0xdeadbeef);
1555     ret = CertVerifySubjectCertificateContext(context1, context2, &flags);
1556     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1557      GetLastError());
1558     flags = CERT_STORE_REVOCATION_FLAG;
1559     ret = CertVerifySubjectCertificateContext(context1, context2, &flags);
1560     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1561      GetLastError());
1562     ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG),
1563      "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08lx\n",
1564      flags);
1565     flags = CERT_STORE_SIGNATURE_FLAG;
1566     ret = CertVerifySubjectCertificateContext(context1, context2, &flags);
1567     ok(ret, "CertVerifySubjectCertificateContext failed; %08lx\n",
1568      GetLastError());
1569     ok(flags == CERT_STORE_SIGNATURE_FLAG,
1570      "Expected CERT_STORE_SIGNATURE_FLAG, got %08lx\n", flags);
1571     CertFreeCertificateContext(context2);
1572
1573     CertFreeCertificateContext(context1);
1574 }
1575
1576 START_TEST(cert)
1577 {
1578     init_function_pointers();
1579
1580     testAddCert();
1581     testCertProperties();
1582     testDupCert();
1583     testFindCert();
1584     testGetSubjectCert();
1585     testGetIssuerCert();
1586
1587     testCryptHashCert();
1588     testCertSigs();
1589     testCreateSelfSignCert();
1590     testKeyUsage();
1591     testCompareCertName();
1592     testCompareIntegerBlob();
1593     testComparePublicKeyInfo();
1594     testCompareCert();
1595     testVerifySubjectCert();
1596 }