2 * crypt32 cert functions tests
4 * Copyright 2005-2006 Juan Lang
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.
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.
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
30 #include "wine/test.h"
32 static BOOL (WINAPI * pCryptVerifyCertificateSignatureEx)
33 (HCRYPTPROV, DWORD, DWORD, void *, DWORD, void *, DWORD, void *);
35 #define CRYPT_GET_PROC(func) \
36 p ## func = (void *)GetProcAddress(hCrypt32, #func); \
38 trace("GetProcAddress(hCrypt32, \"%s\") failed\n", #func); \
40 static void init_function_pointers(void)
44 pCryptVerifyCertificateSignatureEx = NULL;
46 hCrypt32 = GetModuleHandleA("crypt32.dll");
49 CRYPT_GET_PROC(CryptVerifyCertificateSignatureEx);
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,
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 };
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,
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,
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,
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,
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 };
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 };
132 static void testAddCert(void)
135 HCERTSTORE collection;
136 PCCERT_CONTEXT context;
139 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
140 CERT_STORE_CREATE_NEW_FLAG, NULL);
141 ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError());
145 /* Weird--bad add disposition leads to an access violation in Windows.
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 %08x\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 %08x\n", GetLastError());
156 /* Weird--can add a cert to the NULL store (does this have special
160 ret = CertAddEncodedCertificateToStore(0, X509_ASN_ENCODING, bigCert,
161 sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
162 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
165 CertFreeCertificateContext(context);
167 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
168 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
169 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
171 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
172 bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL);
173 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
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: %08x\n",
180 ok(context != NULL, "Expected a context\n");
183 CRYPT_DATA_BLOB hash = { sizeof(bigCert2Hash),
184 (LPBYTE)bigCert2Hash };
186 /* Duplicate (AddRef) the context so we can still use it after
187 * deleting it from the store.
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,
194 ok(ret, "CertSetCertificateContextProperty failed: %08x\n",
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
201 ok(!ret, "Expected failure\n");
202 CertFreeCertificateContext(context);
204 context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2,
206 ok(context != NULL, "Expected a context\n");
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 %08x\n", GetLastError());
214 CertFreeCertificateContext(context);
217 /* Adding a cert with the same issuer name and serial number (but
218 * different subject) as an existing cert succeeds.
221 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
222 bigCert2WithDifferentSerial, sizeof(bigCert2WithDifferentSerial),
223 CERT_STORE_ADD_NEW, &context);
224 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
227 CertDeleteCertificateFromStore(context);
229 /* Adding a cert with the same subject name and serial number (but
230 * different issuer) as an existing cert succeeds.
233 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
234 bigCertWithDifferentSubject, sizeof(bigCertWithDifferentSubject),
235 CERT_STORE_ADD_NEW, &context);
236 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
239 CertDeleteCertificateFromStore(context);
241 /* Adding a cert with the same issuer name and serial number (but
242 * different otherwise) as an existing cert succeeds.
245 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
246 bigCertWithDifferentIssuer, sizeof(bigCertWithDifferentIssuer),
247 CERT_STORE_ADD_NEW, &context);
248 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
251 CertDeleteCertificateFromStore(context);
253 collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
254 CERT_STORE_CREATE_NEW_FLAG, NULL);
255 ok(collection != NULL, "CertOpenStore failed: %08x\n", GetLastError());
258 /* Add store to the collection, but disable updates */
259 CertAddStoreToCollection(collection, store, 0, 0);
261 context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2,
263 ok(context != NULL, "Expected a context\n");
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 %08x\n", GetLastError());
271 /* Replacing an existing certificate context is allowed, even
272 * though updates to the collection aren't..
274 ret = CertAddCertificateContextToStore(collection, context,
275 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
276 ok(ret, "CertAddCertificateContextToStore failed: %08x\n",
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 %08x\n", GetLastError());
283 CertFreeCertificateContext(context);
286 CertCloseStore(collection, 0);
289 CertCloseStore(store, 0);
292 static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID,
293 PCCERT_CONTEXT context, DWORD propID)
295 BYTE hash[20] = { 0 }, hashProperty[20];
299 memset(hash, 0, sizeof(hash));
300 memset(hashProperty, 0, sizeof(hashProperty));
302 ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size);
303 ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError());
304 ret = CertGetCertificateContextProperty(context, propID, hashProperty,
306 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
308 ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %d\n",
312 static const WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e',
315 static void testCertProperties(void)
317 PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING,
318 bigCert, sizeof(bigCert));
319 DWORD propID, numProps, access, size;
321 BYTE hash[20] = { 0 }, hashProperty[20];
322 CRYPT_DATA_BLOB blob;
323 CERT_KEY_CONTEXT keyContext;
326 ok(context != NULL, "CertCreateCertificateContext failed: %08x\n",
332 propID = CertEnumCertificateContextProperties(NULL, 0);
338 propID = CertEnumCertificateContextProperties(context, propID);
341 } while (propID != 0);
342 ok(numProps == 0, "Expected 0 properties, got %d\n", numProps);
344 /* Tests with a NULL cert context. Prop ID 0 fails.. */
345 ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL);
346 ok(!ret && GetLastError() == E_INVALIDARG,
347 "Expected E_INVALIDARG, got %08x\n", GetLastError());
348 /* while this just crashes.
349 ret = CertSetCertificateContextProperty(NULL,
350 CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
353 ret = CertSetCertificateContextProperty(context, 0, 0, NULL);
354 ok(!ret && GetLastError() == E_INVALIDARG,
355 "Expected E_INVALIDARG, got %08x\n", GetLastError());
356 /* Can't set the cert property directly, this crashes.
357 ret = CertSetCertificateContextProperty(context,
358 CERT_CERT_PROP_ID, 0, bigCert2);
362 ret = CertGetCertificateContextProperty(context,
363 CERT_ACCESS_STATE_PROP_ID, 0, NULL);
364 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
366 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
371 ret = CertGetCertificateContextProperty(context,
372 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
373 ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
374 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
375 /* And, an implicit property */
376 size = sizeof(access);
377 ret = CertGetCertificateContextProperty(context,
378 CERT_ACCESS_STATE_PROP_ID, &access, &size);
379 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
381 ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG),
382 "Didn't expect a persisted cert\n");
383 /* Trying to set this "read only" property crashes.
384 access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
385 ret = CertSetCertificateContextProperty(context,
386 CERT_ACCESS_STATE_PROP_ID, 0, &access);
389 /* Can I set the hash to an invalid hash? */
391 blob.cbData = sizeof(hash);
392 ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
394 ok(ret, "CertSetCertificateContextProperty failed: %08x\n",
396 size = sizeof(hashProperty);
397 ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID,
398 hashProperty, &size);
399 ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n");
400 /* Delete the (bogus) hash, and get the real one */
401 ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0,
403 ok(ret, "CertSetCertificateContextProperty failed: %08x\n",
405 checkHash(bigCert, sizeof(bigCert), CALG_SHA1, context,
408 /* Now that the hash property is set, we should get one property when
414 propID = CertEnumCertificateContextProperties(context, propID);
417 } while (propID != 0);
418 ok(numProps == 1, "Expected 1 properties, got %d\n", numProps);
420 /* Check a few other implicit properties */
421 checkHash(bigCert, sizeof(bigCert), CALG_MD5, context,
422 CERT_MD5_HASH_PROP_ID);
424 context->pCertInfo->Subject.pbData,
425 context->pCertInfo->Subject.cbData,
426 CALG_MD5, context, CERT_SUBJECT_NAME_MD5_HASH_PROP_ID);
428 context->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
429 context->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
430 CALG_MD5, context, CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID);
432 /* Test key identifiers and handles and such */
434 ret = CertGetCertificateContextProperty(context,
435 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
436 ok(!ret && GetLastError() == ERROR_INVALID_DATA,
437 "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
438 size = sizeof(CERT_KEY_CONTEXT);
439 ret = CertGetCertificateContextProperty(context,
440 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
441 ok(!ret && GetLastError() == ERROR_INVALID_DATA,
442 "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
443 ret = CertGetCertificateContextProperty(context,
444 CERT_KEY_IDENTIFIER_PROP_ID, &keyContext, &size);
445 ok(!ret && GetLastError() == ERROR_INVALID_DATA,
446 "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError());
447 /* Key context with an invalid size */
448 keyContext.cbSize = 0;
449 ret = CertSetCertificateContextProperty(context,
450 CERT_KEY_IDENTIFIER_PROP_ID, 0, &keyContext);
451 ok(ret, "CertSetCertificateContextProperty failed: %08x\n",
453 size = sizeof(keyContext);
454 ret = CertGetCertificateContextProperty(context,
455 CERT_KEY_IDENTIFIER_PROP_ID, &keyContext, &size);
456 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
458 keyContext.cbSize = sizeof(keyContext);
459 keyContext.hCryptProv = 0;
460 keyContext.dwKeySpec = AT_SIGNATURE;
462 ret = CertSetCertificateContextProperty(context,
463 CERT_KEY_IDENTIFIER_PROP_ID, 0, &keyContext);
464 ret = CertSetCertificateContextProperty(context,
465 CERT_KEY_IDENTIFIER_PROP_ID, CERT_STORE_NO_CRYPT_RELEASE_FLAG,
468 ret = CryptAcquireContextW(&csp, cspNameW,
469 MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET);
470 ok(ret, "CryptAcquireContextW failed: %08x\n", GetLastError());
471 keyContext.hCryptProv = csp;
472 ret = CertSetCertificateContextProperty(context,
473 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext);
474 ok(ret, "CertSetCertificateContextProperty failed: %08x\n",
476 /* Now that that's set, the key prov handle property is also gettable.
478 size = sizeof(DWORD);
479 ret = CertGetCertificateContextProperty(context,
480 CERT_KEY_PROV_HANDLE_PROP_ID, &keyContext.hCryptProv, &size);
481 ok(ret, "Expected to get the CERT_KEY_PROV_HANDLE_PROP_ID, got %08x\n",
483 /* Remove the key prov handle property.. */
484 ret = CertSetCertificateContextProperty(context,
485 CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
486 ok(ret, "CertSetCertificateContextProperty failed: %08x\n",
488 /* and the key context's CSP is set to NULL. */
489 size = sizeof(keyContext);
490 ret = CertGetCertificateContextProperty(context,
491 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
492 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
494 ok(keyContext.hCryptProv == 0, "Expected no hCryptProv\n");
496 CryptReleaseContext(csp, 0);
498 CertFreeCertificateContext(context);
501 static void testDupCert(void)
504 PCCERT_CONTEXT context, dupContext;
507 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
508 CERT_STORE_CREATE_NEW_FLAG, NULL);
509 ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError());
513 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
514 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context);
515 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
517 ok(context != NULL, "Expected a valid cert context\n");
520 ok(context->cbCertEncoded == sizeof(bigCert),
521 "Wrong cert size %d\n", context->cbCertEncoded);
522 ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)),
523 "Unexpected encoded cert in context\n");
524 ok(context->hCertStore == store, "Unexpected store\n");
526 dupContext = CertDuplicateCertificateContext(context);
527 ok(dupContext != NULL, "Expected valid duplicate\n");
528 /* Not only is it a duplicate, it's identical: the address is the
531 ok(dupContext == context, "Expected identical context addresses\n");
532 CertFreeCertificateContext(dupContext);
533 CertFreeCertificateContext(context);
535 CertCloseStore(store, 0);
538 static void testFindCert(void)
541 PCCERT_CONTEXT context = NULL;
543 CERT_INFO certInfo = { 0 };
544 CRYPT_HASH_BLOB blob;
546 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
547 CERT_STORE_CREATE_NEW_FLAG, NULL);
548 ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError());
552 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
553 bigCert, sizeof(bigCert), CERT_STORE_ADD_NEW, NULL);
554 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
556 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
557 bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL);
558 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
560 /* This has the same name as bigCert */
561 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
562 certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL);
563 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
567 context = CertFindCertificateInStore(NULL, 0, 0, 0, NULL, NULL);
570 /* Check first cert's there, by issuer */
571 certInfo.Subject.pbData = (LPBYTE)subjectName;
572 certInfo.Subject.cbData = sizeof(subjectName);
573 certInfo.SerialNumber.pbData = (LPBYTE)serialNum;
574 certInfo.SerialNumber.cbData = sizeof(serialNum);
575 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
576 CERT_FIND_ISSUER_NAME, &certInfo.Subject, NULL);
577 ok(context != NULL, "CertFindCertificateInStore failed: %08x\n",
581 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
582 CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
583 ok(context != NULL, "Expected more than one cert\n");
586 context = CertFindCertificateInStore(store, X509_ASN_ENCODING,
587 0, CERT_FIND_ISSUER_NAME, &certInfo.Subject, context);
588 ok(context == NULL, "Expected precisely two certs\n");
592 /* Check second cert's there as well, by subject name */
593 certInfo.Subject.pbData = (LPBYTE)subjectName2;
594 certInfo.Subject.cbData = sizeof(subjectName2);
595 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
596 CERT_FIND_SUBJECT_NAME, &certInfo.Subject, NULL);
597 ok(context != NULL, "CertFindCertificateInStore failed: %08x\n",
601 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
602 CERT_FIND_SUBJECT_NAME, &certInfo.Subject, context);
603 ok(context == NULL, "Expected one cert only\n");
606 /* Strange but true: searching for the subject cert requires you to set
607 * the issuer, not the subject
609 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
610 CERT_FIND_SUBJECT_CERT, &certInfo.Subject, NULL);
611 ok(context == NULL, "Expected no certificate\n");
612 certInfo.Subject.pbData = NULL;
613 certInfo.Subject.cbData = 0;
614 certInfo.Issuer.pbData = (LPBYTE)subjectName2;
615 certInfo.Issuer.cbData = sizeof(subjectName2);
616 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
617 CERT_FIND_SUBJECT_CERT, &certInfo, NULL);
618 ok(context != NULL, "CertFindCertificateInStore failed: %08x\n",
622 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
623 CERT_FIND_SUBJECT_CERT, &certInfo.Subject, context);
624 ok(context == NULL, "Expected one cert only\n");
627 /* The nice thing about hashes, they're unique */
628 blob.pbData = (LPBYTE)bigCertHash;
629 blob.cbData = sizeof(bigCertHash);
630 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
631 CERT_FIND_SHA1_HASH, &blob, NULL);
632 ok(context != NULL, "CertFindCertificateInStore failed: %08x\n",
636 context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0,
637 CERT_FIND_SHA1_HASH, &certInfo.Subject, context);
638 ok(context == NULL, "Expected one cert only\n");
641 CertCloseStore(store, 0);
644 static void testGetSubjectCert(void)
647 PCCERT_CONTEXT context1, context2;
648 CERT_INFO info = { 0 };
651 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
652 CERT_STORE_CREATE_NEW_FLAG, NULL);
653 ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError());
657 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
658 bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL);
659 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
661 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
662 bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, &context1);
663 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
665 ok(context1 != NULL, "Expected a context\n");
666 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
667 certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL);
668 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
671 context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
673 ok(!context2 && GetLastError() == E_INVALIDARG,
674 "Expected E_INVALIDARG, got %08x\n", GetLastError());
675 context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
677 ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND,
678 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
679 info.SerialNumber.cbData = sizeof(serialNum);
680 info.SerialNumber.pbData = (LPBYTE)serialNum;
681 context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
683 ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND,
684 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
685 info.Issuer.cbData = sizeof(subjectName2);
686 info.Issuer.pbData = (LPBYTE)subjectName2;
687 context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING,
690 "CertGetSubjectCertificateFromStore failed: %08x\n", GetLastError());
691 /* Not only should this find a context, but it should be the same
692 * (same address) as context1.
694 ok(context1 == context2, "Expected identical context addresses\n");
695 CertFreeCertificateContext(context2);
697 CertFreeCertificateContext(context1);
698 CertCloseStore(store, 0);
701 /* This expires in 1970 or so */
702 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
703 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
704 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
705 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
706 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
707 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
708 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
709 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
710 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
711 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
712 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
713 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
714 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
715 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
716 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
717 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
718 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
719 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
720 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
721 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
722 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
723 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
724 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
725 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
726 0x49, 0xe5, 0xf9, 0x65, 0xf3 };
728 /* This expires in 2036 or so */
729 static const BYTE childOfExpired[] = { 0x30, 0x81, 0xcc, 0x30, 0x78, 0xa0,
730 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
731 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d,
732 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63,
733 0x40, 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e,
734 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x35, 0x30, 0x35,
735 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x35,
736 0x30, 0x35, 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x30, 0x15, 0x31, 0x13,
737 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e,
738 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03,
739 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
740 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x20, 0x3b, 0xdb, 0x4d, 0x67, 0x50,
741 0xec, 0x73, 0x9d, 0xf9, 0x85, 0x5d, 0x18, 0xe9, 0xb4, 0x98, 0xe3, 0x31, 0xb7,
742 0x03, 0x0b, 0xc0, 0x39, 0x93, 0x56, 0x81, 0x0a, 0xfc, 0x78, 0xa8, 0x29, 0x42,
743 0x5f, 0x69, 0xfb, 0xbc, 0x5b, 0xf2, 0xa6, 0x2a, 0xbe, 0x91, 0x2c, 0xfc, 0x89,
744 0x69, 0x15, 0x18, 0x58, 0xe5, 0x02, 0x75, 0xf7, 0x2a, 0xb6, 0xa9, 0xfb, 0x47,
745 0x6a, 0x6e, 0x0a, 0x9b, 0xe9, 0xdc };
747 static void testGetIssuerCert(void)
750 PCCERT_CONTEXT parent, child;
751 DWORD flags = 0xffffffff;
752 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
753 CERT_STORE_CREATE_NEW_FLAG, NULL);
755 ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError());
757 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
758 expiredCert, sizeof(expiredCert), CERT_STORE_ADD_ALWAYS, NULL);
759 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
762 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
763 childOfExpired, sizeof(childOfExpired), CERT_STORE_ADD_ALWAYS, &child);
764 ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n",
768 parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, NULL);
769 parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, NULL);
771 parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, &flags);
772 ok(!parent && GetLastError() == E_INVALIDARG,
773 "Expected E_INVALIDARG, got %08x\n", GetLastError());
774 parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, &flags);
775 ok(!parent && GetLastError() == E_INVALIDARG,
776 "Expected E_INVALIDARG, got %08x\n", GetLastError());
777 parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
778 ok(!parent && GetLastError() == E_INVALIDARG,
779 "Expected E_INVALIDARG, got %08x\n", GetLastError());
780 /* Confusing: the caller cannot set either of the
781 * CERT_STORE_NO_*_FLAGs, as these are not checks,
784 flags = CERT_STORE_NO_CRL_FLAG | CERT_STORE_NO_ISSUER_FLAG;
785 parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
786 ok(!parent && GetLastError() == E_INVALIDARG,
787 "Expected E_INVALIDARG, got %08x\n", GetLastError());
788 /* Perform no checks */
790 parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
791 ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08x\n",
794 CertFreeCertificateContext(parent);
795 /* Check revocation and signature only */
796 flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG;
797 parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
798 ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08x\n",
800 /* Confusing: CERT_STORE_REVOCATION_FLAG succeeds when there is no CRL by
801 * setting CERT_STORE_NO_CRL_FLAG.
803 ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG),
804 "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08x\n",
807 CertFreeCertificateContext(parent);
808 /* Now check just the time */
809 flags = CERT_STORE_TIME_VALIDITY_FLAG;
810 parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags);
811 ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08x\n",
813 /* Oops: the child is not expired, so the time validity check actually
814 * succeeds, even though the signing cert is expired.
816 ok(!flags, "Expected check to succeed, got %08x\n", flags);
818 CertFreeCertificateContext(parent);
820 CertFreeCertificateContext(child);
821 CertCloseStore(store, 0);
824 static void testCryptHashCert(void)
826 static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b,
827 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
829 static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee,
830 0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8,
832 static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:";
835 DWORD hashLen = sizeof(hash);
837 /* NULL buffer and nonzero length crashes
838 ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen);
839 empty hash length also crashes
840 ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL);
842 /* Test empty hash */
843 ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL,
845 ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError());
846 ok(hashLen == sizeof(hash), "Got unexpected size of hash %d\n", hashLen);
847 /* Test with empty buffer */
848 ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen);
849 ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError());
850 ok(!memcmp(hash, emptyHash, sizeof(emptyHash)),
851 "Unexpected hash of nothing\n");
852 /* Test a known value */
853 ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash,
855 ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError());
856 ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n");
859 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
860 const BYTE *sig, unsigned int sigLen)
863 BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
865 ok(ret, "CryptCreateHash failed: %08x\n", GetLastError());
869 DWORD mySigSize = sizeof(mySig);
871 ret = CryptHashData(hash, toSign, toSignLen, 0);
872 ok(ret, "CryptHashData failed: %08x\n", GetLastError());
873 /* use the A variant so the test can run on Win9x */
874 ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
875 ok(ret, "CryptSignHash failed: %08x\n", GetLastError());
878 ok(mySigSize == sigLen, "Expected sig length %d, got %d\n",
880 ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
882 CryptDestroyHash(hash);
886 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
887 * using the algorithm with OID sigOID. The CSP is assumed to be empty, and a
888 * keyset named AT_SIGNATURE will be added to it. The signing key will be
889 * stored in *key, and the signature will be stored in sig. sigLen should be
892 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
893 LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
897 CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
900 ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
901 ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
902 ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
903 NULL, NULL, NULL, &size);
905 ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
906 &algoID, NULL, NULL, &size);
907 ok(!ret && GetLastError() == NTE_BAD_ALGID,
908 "Expected NTE_BAD_ALGID, got %08x\n", GetLastError());
909 algoID.pszObjId = (LPSTR)sigOID;
910 ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
911 &algoID, NULL, NULL, &size);
912 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
913 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
914 ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
915 toBeSigned->cbData, &algoID, NULL, NULL, &size);
916 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
917 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
919 /* No keys exist in the new CSP yet.. */
920 ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
921 toBeSigned->cbData, &algoID, NULL, NULL, &size);
922 ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
923 NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08x\n",
925 ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
926 ok(ret, "CryptGenKey failed: %08x\n", GetLastError());
929 ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
930 toBeSigned->cbData, &algoID, NULL, NULL, &size);
931 ok(ret, "CryptSignCertificate failed: %08x\n", GetLastError());
932 ok(size <= *sigLen, "Expected size <= %d, got %d\n", *sigLen, size);
935 ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
936 toBeSigned->cbData, &algoID, NULL, sig, &size);
937 ok(ret, "CryptSignCertificate failed: %08x\n", GetLastError());
941 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
948 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
949 LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
951 CERT_SIGNED_CONTENT_INFO info;
956 if(pCryptVerifyCertificateSignatureEx) {
957 ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
958 ok(!ret && GetLastError() == E_INVALIDARG,
959 "Expected E_INVALIDARG, got %08x\n", GetLastError());
960 ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
961 ok(!ret && GetLastError() == E_INVALIDARG,
962 "Expected E_INVALIDARG, got %08x\n", GetLastError());
963 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
965 ok(!ret && GetLastError() == E_INVALIDARG,
966 "Expected E_INVALIDARG, got %08x\n", GetLastError());
968 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
969 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
972 info.ToBeSigned.cbData = toBeSigned->cbData;
973 info.ToBeSigned.pbData = toBeSigned->pbData;
974 info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
975 info.SignatureAlgorithm.Parameters.cbData = 0;
976 info.Signature.cbData = sigLen;
977 info.Signature.pbData = (BYTE *)sig;
978 info.Signature.cUnusedBits = 0;
979 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
980 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
981 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
984 CRYPT_DATA_BLOB certBlob = { 0, NULL };
985 PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
987 if(pCryptVerifyCertificateSignatureEx) {
988 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
989 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
990 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
991 "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError());
993 certBlob.pbData = (void *)0xdeadbeef;
994 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
995 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
996 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
997 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
998 certBlob.cbData = size;
999 certBlob.pbData = cert;
1000 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1001 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
1002 ok(!ret && GetLastError() == E_INVALIDARG,
1003 "Expected E_INVALIDARG, got %08x\n", GetLastError());
1004 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1005 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1006 CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
1007 ok(!ret && GetLastError() == E_INVALIDARG,
1008 "Expected E_INVALIDARG, got %08x\n", GetLastError());
1010 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1011 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1012 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
1015 CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
1016 (LPSTR)sigOID, 0, NULL, NULL, &size);
1017 pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
1020 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
1021 X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
1022 ok(ret, "CryptExportKey failed: %08x\n", GetLastError());
1023 if (ret && pCryptVerifyCertificateSignatureEx)
1025 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
1026 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
1027 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
1028 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08x\n",
1031 HeapFree(GetProcessHeap(), 0, pubKeyInfo);
1037 static const BYTE emptyCert[] = { 0x30, 0x00 };
1039 static void testCertSigs(void)
1042 CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
1046 DWORD sigSize = sizeof(sig);
1048 /* Just in case a previous run failed, delete this thing */
1049 CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1050 CRYPT_DELETEKEYSET);
1051 ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1053 ok(ret, "CryptAcquireContext failed: %08x\n", GetLastError());
1055 testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
1056 testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
1058 CryptDestroyKey(key);
1059 CryptReleaseContext(csp, 0);
1060 ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1061 CRYPT_DELETEKEYSET);
1064 static const BYTE md5SignedEmptyCert[] = {
1065 0x30,0x56,0x30,0x33,0x02,0x00,0x30,0x02,0x06,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,
1066 0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,
1067 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x07,
1068 0x30,0x02,0x06,0x00,0x03,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,
1069 0x0d,0x02,0x05,0x05,0x00,0x03,0x11,0x00,0xfb,0x0f,0x66,0x82,0x66,0xd9,0xe5,0xf8,
1070 0xd8,0xa2,0x55,0x2b,0xe1,0xa5,0xd9,0x04 };
1071 static const BYTE md5SignedEmptyCertNoNull[] = {
1072 0x30,0x54,0x30,0x33,0x02,0x00,0x30,0x02,0x06,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,
1073 0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,
1074 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x07,
1075 0x30,0x02,0x06,0x00,0x03,0x01,0x00,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,
1076 0x0d,0x02,0x05,0x03,0x11,0x00,0x04,0xd9,0xa5,0xe1,0x2b,0x55,0xa2,0xd8,0xf8,0xe5,
1077 0xd9,0x66,0x82,0x66,0x0f,0xfb };
1079 static void testSignAndEncodeCert(void)
1081 static char oid_rsa_md5rsa[] = szOID_RSA_MD5RSA;
1082 static char oid_rsa_md5[] = szOID_RSA_MD5;
1085 CRYPT_ALGORITHM_IDENTIFIER algID = { 0 };
1086 CERT_INFO info = { 0 };
1089 ret = CryptSignAndEncodeCertificate(0, 0, 0, NULL, NULL, NULL, NULL, NULL,
1091 ret = CryptSignAndEncodeCertificate(0, 0, 0, NULL, NULL, NULL, NULL, NULL,
1094 ret = CryptSignAndEncodeCertificate(0, 0, 0, NULL, NULL, &algID, NULL, NULL,
1096 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1097 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
1098 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, NULL, NULL,
1099 &algID, NULL, NULL, &size);
1100 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1101 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
1102 ret = CryptSignAndEncodeCertificate(0, 0, 0, X509_CERT_TO_BE_SIGNED, NULL,
1103 &algID, NULL, NULL, &size);
1104 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1105 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
1106 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING,
1107 X509_CERT_TO_BE_SIGNED, NULL, &algID, NULL, NULL, &size);
1108 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1109 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
1111 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING,
1112 X509_CERT_TO_BE_SIGNED, &info, NULL, NULL, NULL, &size);
1114 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING,
1115 X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, NULL, &size);
1116 ok(!ret && GetLastError() == NTE_BAD_ALGID,
1117 "Expected NTE_BAD_ALGID, got %08x\n", GetLastError());
1118 algID.pszObjId = oid_rsa_md5rsa;
1119 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING,
1120 X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, NULL, &size);
1121 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1122 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1123 algID.pszObjId = oid_rsa_md5;
1124 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING,
1125 X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, NULL, &size);
1126 ok(ret, "CryptSignAndEncodeCertificate failed: %08x\n", GetLastError());
1129 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size);
1133 ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING,
1134 X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, buf, &size);
1135 ok(ret, "CryptSignAndEncodeCertificate failed: %08x\n",
1137 /* Tricky: because the NULL parameters may either be omitted or
1138 * included as an asn.1-encoded NULL (0x05,0x00), two different
1139 * values are allowed.
1141 ok(size == sizeof(md5SignedEmptyCert) ||
1142 size == sizeof(md5SignedEmptyCertNoNull), "Unexpected size %d\n",
1144 if (size == sizeof(md5SignedEmptyCert))
1145 ok(!memcmp(buf, md5SignedEmptyCert, size),
1146 "Unexpected value\n");
1147 else if (size == sizeof(md5SignedEmptyCertNoNull))
1148 ok(!memcmp(buf, md5SignedEmptyCertNoNull, size),
1149 "Unexpected value\n");
1150 HeapFree(GetProcessHeap(), 0, buf);
1155 static void testCreateSelfSignCert(void)
1157 PCCERT_CONTEXT context;
1158 CERT_NAME_BLOB name = { sizeof(subjectName), (LPBYTE)subjectName };
1164 context = CertCreateSelfSignCertificate(0, NULL, 0, NULL, NULL, NULL, NULL,
1166 * Calling this with no first parameter creates a new key container, which
1167 * lasts beyond the test, so I don't test that. Nb: the generated key
1169 context = CertCreateSelfSignCertificate(0, &name, 0, NULL, NULL, NULL, NULL,
1174 CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1175 CRYPT_DELETEKEYSET);
1176 ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1178 ok(ret, "CryptAcquireContext failed: %08x\n", GetLastError());
1180 context = CertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL,
1182 ok(!context && GetLastError() == NTE_NO_KEY,
1183 "Expected NTE_NO_KEY, got %08x\n", GetLastError());
1184 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
1185 ok(ret, "CryptGenKey failed: %08x\n", GetLastError());
1188 context = CertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL,
1190 ok(context != NULL, "CertCreateSelfSignCertificate failed: %08x\n",
1195 PCRYPT_KEY_PROV_INFO info;
1197 /* The context must have a key provider info property */
1198 ret = CertGetCertificateContextProperty(context,
1199 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
1200 ok(ret && size, "Expected non-zero key provider info\n");
1203 info = HeapAlloc(GetProcessHeap(), 0, size);
1206 ret = CertGetCertificateContextProperty(context,
1207 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
1208 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
1212 /* Sanity-check the key provider */
1213 ok(!lstrcmpW(info->pwszContainerName, cspNameW),
1214 "Unexpected key container\n");
1215 ok(!lstrcmpW(info->pwszProvName, MS_DEF_PROV_W),
1216 "Unexpected provider\n");
1217 ok(info->dwKeySpec == AT_SIGNATURE,
1218 "Expected AT_SIGNATURE, got %d\n", info->dwKeySpec);
1220 HeapFree(GetProcessHeap(), 0, info);
1224 CertFreeCertificateContext(context);
1227 CryptDestroyKey(key);
1230 CryptReleaseContext(csp, 0);
1231 ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1232 CRYPT_DELETEKEYSET);
1235 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
1236 szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
1238 static void testKeyUsage(void)
1241 PCCERT_CONTEXT context;
1244 /* Test base cases */
1245 ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, NULL);
1246 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1247 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1249 ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
1250 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1251 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1253 ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
1254 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1255 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1257 ret = CertSetEnhancedKeyUsage(NULL, NULL);
1258 usage.cUsageIdentifier = 0;
1259 ret = CertSetEnhancedKeyUsage(NULL, &usage);
1261 /* Test with a cert with no enhanced key usage extension */
1262 context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
1264 ok(context != NULL, "CertCreateCertificateContext failed: %08x\n",
1268 static const char oid[] = "1.2.3.4";
1269 BYTE buf[sizeof(CERT_ENHKEY_USAGE) + 2 * (sizeof(LPSTR) + sizeof(oid))];
1270 PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1272 ret = CertGetEnhancedKeyUsage(context, 0, NULL, NULL);
1273 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1274 "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
1276 ret = CertGetEnhancedKeyUsage(context, 0, NULL, &size);
1279 /* Windows 2000, ME, or later: even though it succeeded, we expect
1280 * CRYPT_E_NOT_FOUND, which indicates there is no enhanced key
1281 * usage set for this cert (which implies it's valid for all uses.)
1283 ok(GetLastError() == CRYPT_E_NOT_FOUND,
1284 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
1285 ok(size == sizeof(CERT_ENHKEY_USAGE), "Wrong size %d\n", size);
1286 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1287 ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1288 ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %d\n",
1289 pUsage->cUsageIdentifier);
1293 /* Windows NT, 95, or 98: it fails, and the last error is
1294 * CRYPT_E_NOT_FOUND.
1296 ok(GetLastError() == CRYPT_E_NOT_FOUND,
1297 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
1299 /* I can add a usage identifier when no key usage has been set */
1300 ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
1301 ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n",
1304 ret = CertGetEnhancedKeyUsage(context,
1305 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1306 ok(ret && GetLastError() == 0,
1307 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1308 ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %d\n",
1309 pUsage->cUsageIdentifier);
1310 if (pUsage->cUsageIdentifier)
1311 ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
1312 "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
1313 /* Now set an empty key usage */
1314 pUsage->cUsageIdentifier = 0;
1315 ret = CertSetEnhancedKeyUsage(context, pUsage);
1316 ok(ret, "CertSetEnhancedKeyUsage failed: %08x\n", GetLastError());
1317 /* Shouldn't find it in the cert */
1319 ret = CertGetEnhancedKeyUsage(context,
1320 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1321 ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1322 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
1323 /* Should find it as an extended property */
1324 ret = CertGetEnhancedKeyUsage(context,
1325 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1326 ok(ret && GetLastError() == 0,
1327 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1328 ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %d\n",
1329 pUsage->cUsageIdentifier);
1330 /* Should find it as either */
1331 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1332 ok(ret && GetLastError() == 0,
1333 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1334 ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %d\n",
1335 pUsage->cUsageIdentifier);
1336 /* Add a usage identifier */
1337 ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
1338 ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n",
1341 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1342 ok(ret && GetLastError() == 0,
1343 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1344 ok(pUsage->cUsageIdentifier == 1, "Expected 1 identifier, got %d\n",
1345 pUsage->cUsageIdentifier);
1346 if (pUsage->cUsageIdentifier)
1347 ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
1348 "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
1349 /* Yep, I can re-add the same usage identifier */
1350 ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
1351 ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n",
1354 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1355 ok(ret && GetLastError() == 0,
1356 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1357 ok(pUsage->cUsageIdentifier == 2, "Expected 2 identifiers, got %d\n",
1358 pUsage->cUsageIdentifier);
1359 if (pUsage->cUsageIdentifier)
1360 ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
1361 "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
1362 if (pUsage->cUsageIdentifier >= 2)
1363 ok(!strcmp(pUsage->rgpszUsageIdentifier[1], oid),
1364 "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[1]);
1365 /* Now set a NULL extended property--this deletes the property. */
1366 ret = CertSetEnhancedKeyUsage(context, NULL);
1367 ok(ret, "CertSetEnhancedKeyUsage failed: %08x\n", GetLastError());
1368 SetLastError(0xbaadcafe);
1370 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1371 ok(GetLastError() == CRYPT_E_NOT_FOUND,
1372 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
1374 CertFreeCertificateContext(context);
1376 /* Now test with a cert with an enhanced key usage extension */
1377 context = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage,
1378 sizeof(certWithUsage));
1379 ok(context != NULL, "CertCreateCertificateContext failed: %08x\n",
1384 DWORD bufSize = 0, i;
1386 /* The size may depend on what flags are used to query it, so I
1387 * realloc the buffer for each test.
1389 ret = CertGetEnhancedKeyUsage(context,
1390 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
1391 ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1392 buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1395 PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1397 /* Should find it in the cert */
1399 ret = CertGetEnhancedKeyUsage(context,
1400 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1401 ok(ret && GetLastError() == 0,
1402 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1403 ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n",
1404 pUsage->cUsageIdentifier);
1405 for (i = 0; i < pUsage->cUsageIdentifier; i++)
1406 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1407 "Expected %s, got %s\n", keyUsages[i],
1408 pUsage->rgpszUsageIdentifier[i]);
1409 HeapFree(GetProcessHeap(), 0, buf);
1411 ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
1412 ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1413 buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1416 PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1418 /* Should find it as either */
1420 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1421 /* In Windows, GetLastError returns CRYPT_E_NOT_FOUND not found
1422 * here, even though the return is successful and the usage id
1423 * count is positive. I don't enforce that here.
1426 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1427 ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n",
1428 pUsage->cUsageIdentifier);
1429 for (i = 0; i < pUsage->cUsageIdentifier; i++)
1430 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1431 "Expected %s, got %s\n", keyUsages[i],
1432 pUsage->rgpszUsageIdentifier[i]);
1433 HeapFree(GetProcessHeap(), 0, buf);
1435 /* Shouldn't find it as an extended property */
1436 ret = CertGetEnhancedKeyUsage(context,
1437 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size);
1438 ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
1439 "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError());
1440 /* Adding a usage identifier overrides the cert's usage!? */
1441 ret = CertAddEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
1442 ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n",
1444 ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
1445 ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1446 buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1449 PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1451 /* Should find it as either */
1453 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1455 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1456 ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %d\n",
1457 pUsage->cUsageIdentifier);
1458 ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA),
1459 "Expected %s, got %s\n", szOID_RSA_RSA,
1460 pUsage->rgpszUsageIdentifier[0]);
1461 HeapFree(GetProcessHeap(), 0, buf);
1463 /* But querying the cert directly returns its usage */
1464 ret = CertGetEnhancedKeyUsage(context,
1465 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
1466 ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1467 buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1470 PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1473 ret = CertGetEnhancedKeyUsage(context,
1474 CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1476 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1477 ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n",
1478 pUsage->cUsageIdentifier);
1479 for (i = 0; i < pUsage->cUsageIdentifier; i++)
1480 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1481 "Expected %s, got %s\n", keyUsages[i],
1482 pUsage->rgpszUsageIdentifier[i]);
1483 HeapFree(GetProcessHeap(), 0, buf);
1485 /* And removing the only usage identifier in the extended property
1486 * results in the cert's key usage being found.
1488 ret = CertRemoveEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
1489 ok(ret, "CertRemoveEnhancedKeyUsage failed: %08x\n", GetLastError());
1490 ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
1491 ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1492 buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
1495 PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
1497 /* Should find it as either */
1499 ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
1501 "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError());
1502 ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n",
1503 pUsage->cUsageIdentifier);
1504 for (i = 0; i < pUsage->cUsageIdentifier; i++)
1505 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
1506 "Expected %s, got %s\n", keyUsages[i],
1507 pUsage->rgpszUsageIdentifier[i]);
1508 HeapFree(GetProcessHeap(), 0, buf);
1511 CertFreeCertificateContext(context);
1515 static void testCompareCertName(void)
1517 static const BYTE bogus[] = { 1, 2, 3, 4 };
1518 static const BYTE bogusPrime[] = { 0, 1, 2, 3, 4 };
1519 static const BYTE emptyPrime[] = { 0x30, 0x00, 0x01 };
1521 CERT_NAME_BLOB blob1, blob2;
1524 ret = CertCompareCertificateName(0, NULL, NULL);
1526 /* An empty name checks against itself.. */
1527 blob1.pbData = (LPBYTE)emptyCert;
1528 blob1.cbData = sizeof(emptyCert);
1529 ret = CertCompareCertificateName(0, &blob1, &blob1);
1530 ok(ret, "CertCompareCertificateName failed: %08x\n", GetLastError());
1531 /* It doesn't have to be a valid encoded name.. */
1532 blob1.pbData = (LPBYTE)bogus;
1533 blob1.cbData = sizeof(bogus);
1534 ret = CertCompareCertificateName(0, &blob1, &blob1);
1535 ok(ret, "CertCompareCertificateName failed: %08x\n", GetLastError());
1536 /* Leading zeroes matter.. */
1537 blob2.pbData = (LPBYTE)bogusPrime;
1538 blob2.cbData = sizeof(bogusPrime);
1539 ret = CertCompareCertificateName(0, &blob1, &blob2);
1540 ok(!ret, "Expected failure\n");
1541 /* As do trailing extra bytes. */
1542 blob2.pbData = (LPBYTE)emptyPrime;
1543 blob2.cbData = sizeof(emptyPrime);
1544 ret = CertCompareCertificateName(0, &blob1, &blob2);
1545 ok(!ret, "Expected failure\n");
1548 static const BYTE int1[] = { 0x88, 0xff, 0xff, 0xff };
1549 static const BYTE int2[] = { 0x88, 0xff };
1550 static const BYTE int3[] = { 0x23, 0xff };
1551 static const BYTE int4[] = { 0x7f, 0x00 };
1552 static const BYTE int5[] = { 0x7f };
1553 static const BYTE int6[] = { 0x80, 0x00, 0x00, 0x00 };
1554 static const BYTE int7[] = { 0x80, 0x00 };
1558 CRYPT_INTEGER_BLOB blob1;
1559 CRYPT_INTEGER_BLOB blob2;
1562 { { sizeof(int1), (LPBYTE)int1 }, { sizeof(int2), (LPBYTE)int2 }, TRUE },
1563 { { sizeof(int3), (LPBYTE)int3 }, { sizeof(int3), (LPBYTE)int3 }, TRUE },
1564 { { sizeof(int4), (LPBYTE)int4 }, { sizeof(int5), (LPBYTE)int5 }, TRUE },
1565 { { sizeof(int6), (LPBYTE)int6 }, { sizeof(int7), (LPBYTE)int7 }, TRUE },
1566 { { sizeof(int1), (LPBYTE)int1 }, { sizeof(int7), (LPBYTE)int7 }, FALSE },
1569 static void testCompareIntegerBlob(void)
1574 for (i = 0; i < sizeof(intBlobs) / sizeof(intBlobs[0]); i++)
1576 ret = CertCompareIntegerBlob(&intBlobs[i].blob1, &intBlobs[i].blob2);
1577 ok(ret == intBlobs[i].areEqual,
1578 "%d: expected blobs %s compare\n", i, intBlobs[i].areEqual ?
1583 static void testComparePublicKeyInfo(void)
1586 CERT_PUBLIC_KEY_INFO info1 = { { 0 } }, info2 = { { 0 } };
1587 static CHAR oid_rsa_rsa[] = szOID_RSA_RSA;
1588 static CHAR oid_rsa_sha1rsa[] = szOID_RSA_SHA1RSA;
1589 static CHAR oid_x957_dsa[] = szOID_X957_DSA;
1590 static const BYTE bits1[] = { 1, 0 };
1591 static const BYTE bits2[] = { 0 };
1592 static const BYTE bits3[] = { 1 };
1595 ret = CertComparePublicKeyInfo(0, NULL, NULL);
1597 /* Empty public keys compare */
1598 ret = CertComparePublicKeyInfo(0, &info1, &info2);
1599 ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError());
1600 /* Different OIDs appear to compare */
1601 info1.Algorithm.pszObjId = oid_rsa_rsa;
1602 info2.Algorithm.pszObjId = oid_rsa_sha1rsa;
1603 ret = CertComparePublicKeyInfo(0, &info1, &info2);
1604 ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError());
1605 info2.Algorithm.pszObjId = oid_x957_dsa;
1606 ret = CertComparePublicKeyInfo(0, &info1, &info2);
1607 ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError());
1608 info1.PublicKey.cbData = sizeof(bits1);
1609 info1.PublicKey.pbData = (LPBYTE)bits1;
1610 info1.PublicKey.cUnusedBits = 0;
1611 info2.PublicKey.cbData = sizeof(bits1);
1612 info2.PublicKey.pbData = (LPBYTE)bits1;
1613 info2.PublicKey.cUnusedBits = 0;
1614 ret = CertComparePublicKeyInfo(0, &info1, &info2);
1615 ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError());
1616 /* Even though they compare in their used bits, these do not compare */
1617 info1.PublicKey.cbData = sizeof(bits2);
1618 info1.PublicKey.pbData = (LPBYTE)bits2;
1619 info1.PublicKey.cUnusedBits = 0;
1620 info2.PublicKey.cbData = sizeof(bits3);
1621 info2.PublicKey.pbData = (LPBYTE)bits3;
1622 info2.PublicKey.cUnusedBits = 1;
1623 ret = CertComparePublicKeyInfo(0, &info1, &info2);
1624 /* Simple (non-comparing) case */
1625 ok(!ret, "Expected keys not to compare\n");
1626 info2.PublicKey.cbData = sizeof(bits1);
1627 info2.PublicKey.pbData = (LPBYTE)bits1;
1628 info2.PublicKey.cUnusedBits = 0;
1629 ret = CertComparePublicKeyInfo(0, &info1, &info2);
1630 ok(!ret, "Expected keys not to compare\n");
1633 static void testHashPublicKeyInfo(void)
1636 CERT_PUBLIC_KEY_INFO info = { { 0 } };
1640 ret = CryptHashPublicKeyInfo(0, 0, 0, 0, NULL, NULL, NULL);
1641 ret = CryptHashPublicKeyInfo(0, 0, 0, 0, &info, NULL, NULL);
1643 ret = CryptHashPublicKeyInfo(0, 0, 0, 0, NULL, NULL, &len);
1644 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1645 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
1646 ret = CryptHashPublicKeyInfo(0, 0, 0, X509_ASN_ENCODING, NULL, NULL, &len);
1647 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1648 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
1649 ret = CryptHashPublicKeyInfo(0, 0, 0, X509_ASN_ENCODING, &info, NULL, &len);
1650 ok(ret, "CryptHashPublicKeyInfo failed: %08x\n", GetLastError());
1651 ok(len == 16, "Expected hash size 16, got %d\n", len);
1654 static const BYTE emptyHash[] = { 0xb8,0x51,0x3a,0x31,0x0e,0x9f,0x40,
1655 0x36,0x9c,0x92,0x45,0x1b,0x9d,0xc8,0xf9,0xf6 };
1658 ret = CryptHashPublicKeyInfo(0, 0, 0, X509_ASN_ENCODING, &info, buf,
1660 ok(ret, "CryptHashPublicKeyInfo failed: %08x\n", GetLastError());
1661 ok(!memcmp(buf, emptyHash, len), "Unexpected hash\n");
1665 void testCompareCert(void)
1667 CERT_INFO info1 = { 0 }, info2 = { 0 };
1671 ret = CertCompareCertificate(X509_ASN_ENCODING, NULL, NULL);
1674 /* Certs with the same issuer and serial number are equal, even if they
1675 * differ in other respects (like subject).
1677 info1.SerialNumber.pbData = (LPBYTE)serialNum;
1678 info1.SerialNumber.cbData = sizeof(serialNum);
1679 info1.Issuer.pbData = (LPBYTE)subjectName;
1680 info1.Issuer.cbData = sizeof(subjectName);
1681 info1.Subject.pbData = (LPBYTE)subjectName2;
1682 info1.Subject.cbData = sizeof(subjectName2);
1683 info2.SerialNumber.pbData = (LPBYTE)serialNum;
1684 info2.SerialNumber.cbData = sizeof(serialNum);
1685 info2.Issuer.pbData = (LPBYTE)subjectName;
1686 info2.Issuer.cbData = sizeof(subjectName);
1687 info2.Subject.pbData = (LPBYTE)subjectName;
1688 info2.Subject.cbData = sizeof(subjectName);
1689 ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2);
1690 ok(ret, "Expected certs to be equal\n");
1692 info2.Issuer.pbData = (LPBYTE)subjectName2;
1693 info2.Issuer.cbData = sizeof(subjectName2);
1694 ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2);
1695 ok(!ret, "Expected certs not to be equal\n");
1698 static void testVerifySubjectCert(void)
1702 PCCERT_CONTEXT context1, context2;
1705 ret = CertVerifySubjectCertificateContext(NULL, NULL, NULL);
1708 ret = CertVerifySubjectCertificateContext(NULL, NULL, &flags);
1709 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1711 flags = CERT_STORE_NO_CRL_FLAG;
1712 ret = CertVerifySubjectCertificateContext(NULL, NULL, &flags);
1713 ok(!ret && GetLastError() == E_INVALIDARG,
1714 "Expected E_INVALIDARG, got %08x\n", GetLastError());
1717 context1 = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
1719 ret = CertVerifySubjectCertificateContext(NULL, context1, &flags);
1720 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1722 ret = CertVerifySubjectCertificateContext(context1, NULL, &flags);
1723 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1725 ret = CertVerifySubjectCertificateContext(context1, context1, &flags);
1726 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1729 context2 = CertCreateCertificateContext(X509_ASN_ENCODING,
1730 bigCertWithDifferentSubject, sizeof(bigCertWithDifferentSubject));
1731 SetLastError(0xdeadbeef);
1732 ret = CertVerifySubjectCertificateContext(context1, context2, &flags);
1733 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1735 flags = CERT_STORE_REVOCATION_FLAG;
1736 ret = CertVerifySubjectCertificateContext(context1, context2, &flags);
1737 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1739 ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG),
1740 "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08x\n",
1742 flags = CERT_STORE_SIGNATURE_FLAG;
1743 ret = CertVerifySubjectCertificateContext(context1, context2, &flags);
1744 ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n",
1746 ok(flags == CERT_STORE_SIGNATURE_FLAG,
1747 "Expected CERT_STORE_SIGNATURE_FLAG, got %08x\n", flags);
1748 CertFreeCertificateContext(context2);
1750 CertFreeCertificateContext(context1);
1753 static const BYTE privKey[] = {
1754 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00,
1755 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10,
1756 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd,
1757 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde,
1758 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68,
1759 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27,
1760 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b,
1761 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4,
1762 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77,
1763 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca,
1764 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06,
1765 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72,
1766 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e,
1767 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf,
1768 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b,
1769 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd,
1770 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8,
1771 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67,
1772 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40,
1773 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e,
1774 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d,
1775 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda,
1776 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78,
1777 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 };
1779 static const BYTE selfSignedCert[] = {
1780 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
1781 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49,
1782 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d,
1783 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
1784 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30,
1785 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30,
1786 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31,
1787 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
1788 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e,
1789 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
1790 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
1791 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4,
1792 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b,
1793 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0,
1794 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96,
1795 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79,
1796 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
1797 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41,
1798 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66,
1799 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a,
1800 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7,
1801 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f,
1802 0xa8, 0x76, 0x57, 0x92, 0x36 };
1804 static const BYTE exportedPublicKeyBlob[] = {
1805 0x06,0x02,0x00,0x00,0x00,0xa4,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x02,0x00,0x00,
1806 0x01,0x00,0x01,0x00,0x79,0x10,0x1c,0xd0,0x6b,0x10,0x18,0x30,0x94,0x61,0xdc,0x0e,
1807 0xcb,0x96,0x4e,0x21,0x3f,0x79,0xcd,0xa9,0x17,0x62,0xbc,0xbb,0x61,0x4c,0xe0,0x75,
1808 0x38,0x6c,0xf3,0xde,0x60,0x86,0x03,0x97,0x65,0xeb,0x1e,0x6b,0xdb,0x53,0x85,0xad,
1809 0x68,0x21,0xf1,0x5d,0xe7,0x1f,0xe6,0x53,0xb4,0xbb,0x59,0x3e,0x14,0x27,0xb1,0x83,
1810 0xa7,0x3a,0x54,0xe2 };
1812 static const BYTE asnEncodedPublicKey[] = {
1813 0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a,0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,
1814 0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1,0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb,
1815 0x65,0x97,0x03,0x86,0x60,0xde,0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62,
1816 0x17,0xa9,0xcd,0x79,0x3f,0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10,
1817 0x6b,0xd0,0x1c,0x10,0x79,0x02,0x03,0x01,0x00,0x01 };
1819 static void testAcquireCertPrivateKey(void)
1822 PCCERT_CONTEXT cert;
1824 DWORD size, keySpec;
1826 CRYPT_KEY_PROV_INFO keyProvInfo;
1829 keyProvInfo.pwszContainerName = (LPWSTR)cspNameW;
1830 keyProvInfo.pwszProvName = (LPWSTR)MS_DEF_PROV_W;
1831 keyProvInfo.dwProvType = PROV_RSA_FULL;
1832 keyProvInfo.dwFlags = 0;
1833 keyProvInfo.cProvParam = 0;
1834 keyProvInfo.rgProvParam = NULL;
1835 keyProvInfo.dwKeySpec = AT_SIGNATURE;
1837 CryptAcquireContextW(NULL, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1838 CRYPT_DELETEKEYSET);
1840 cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert,
1841 sizeof(selfSignedCert));
1844 ret = CryptAcquireCertificatePrivateKey(NULL, 0, NULL, NULL, NULL, NULL);
1845 ret = CryptAcquireCertificatePrivateKey(NULL, 0, NULL, NULL, NULL,
1847 ret = CryptAcquireCertificatePrivateKey(NULL, 0, NULL, NULL, &keySpec,
1849 ret = CryptAcquireCertificatePrivateKey(NULL, 0, NULL, &csp, NULL, NULL);
1850 ret = CryptAcquireCertificatePrivateKey(NULL, 0, NULL, &csp, &keySpec,
1852 ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, NULL, NULL, NULL);
1855 /* Missing private key */
1856 ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &csp, NULL, NULL);
1857 ok(!ret && GetLastError() == CRYPT_E_NO_KEY_PROPERTY,
1858 "Expected CRYPT_E_NO_KEY_PROPERTY, got %08x\n", GetLastError());
1859 ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &csp, &keySpec,
1861 ok(!ret && GetLastError() == CRYPT_E_NO_KEY_PROPERTY,
1862 "Expected CRYPT_E_NO_KEY_PROPERTY, got %08x\n", GetLastError());
1863 CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0,
1865 ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &csp, &keySpec,
1867 ok(!ret && GetLastError() == CRYPT_E_NO_KEY_PROPERTY,
1868 "Expected CRYPT_E_NO_KEY_PROPERTY, got %08x\n", GetLastError());
1870 CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1872 ret = CryptImportKey(csp, (LPBYTE)privKey, sizeof(privKey), 0, 0, &key);
1873 ok(ret, "CryptImportKey failed: %08x\n", GetLastError());
1878 CERT_KEY_CONTEXT keyContext;
1880 /* Don't cache provider */
1881 ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &certCSP,
1882 &keySpec, &callerFree);
1883 ok(ret, "CryptAcquireCertificatePrivateKey failed: %08x\n",
1885 ok(callerFree, "Expected callerFree to be TRUE\n");
1886 CryptReleaseContext(certCSP, 0);
1887 ret = CryptAcquireCertificatePrivateKey(cert, 0, NULL, &certCSP,
1889 ok(ret, "CryptAcquireCertificatePrivateKey failed: %08x\n",
1891 CryptReleaseContext(certCSP, 0);
1893 /* Use the key prov info's caching (there shouldn't be any) */
1894 ret = CryptAcquireCertificatePrivateKey(cert,
1895 CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, NULL, &certCSP, &keySpec,
1897 ok(ret, "CryptAcquireCertificatePrivateKey failed: %08x\n",
1899 ok(callerFree, "Expected callerFree to be TRUE\n");
1900 CryptReleaseContext(certCSP, 0);
1902 /* Cache it (and check that it's cached) */
1903 ret = CryptAcquireCertificatePrivateKey(cert,
1904 CRYPT_ACQUIRE_CACHE_FLAG, NULL, &certCSP, &keySpec, &callerFree);
1905 ok(ret, "CryptAcquireCertificatePrivateKey failed: %08x\n",
1907 ok(!callerFree, "Expected callerFree to be FALSE\n");
1908 size = sizeof(keyContext);
1909 ret = CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
1910 &keyContext, &size);
1911 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
1914 /* Remove the cached provider */
1915 CryptReleaseContext(keyContext.hCryptProv, 0);
1916 CertSetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID, 0,
1918 /* Allow caching via the key prov info */
1919 keyProvInfo.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
1920 CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0,
1922 /* Now use the key prov info's caching */
1923 ret = CryptAcquireCertificatePrivateKey(cert,
1924 CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, NULL, &certCSP, &keySpec,
1926 ok(ret, "CryptAcquireCertificatePrivateKey failed: %08x\n",
1928 ok(!callerFree, "Expected callerFree to be FALSE\n");
1929 size = sizeof(keyContext);
1930 ret = CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
1931 &keyContext, &size);
1932 ok(ret, "CertGetCertificateContextProperty failed: %08x\n",
1935 CryptDestroyKey(key);
1938 /* Some sanity-checking on public key exporting */
1939 ret = CryptImportPublicKeyInfo(csp, X509_ASN_ENCODING,
1940 &cert->pCertInfo->SubjectPublicKeyInfo, &key);
1941 ok(ret, "CryptImportPublicKeyInfo failed: %08x\n", GetLastError());
1944 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &size);
1945 ok(ret, "CryptExportKey failed: %08x\n", GetLastError());
1948 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size), encodedKey;
1950 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, buf, &size);
1951 ok(ret, "CryptExportKey failed: %08x\n", GetLastError());
1952 ok(size == sizeof(exportedPublicKeyBlob), "Unexpected size %d\n",
1954 ok(!memcmp(buf, exportedPublicKeyBlob, size), "Unexpected value\n");
1955 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
1956 buf, CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedKey, &size);
1957 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
1960 ok(size == sizeof(asnEncodedPublicKey), "Unexpected size %d\n",
1962 ok(!memcmp(encodedKey, asnEncodedPublicKey, size),
1963 "Unexpected value\n");
1964 LocalFree(encodedKey);
1966 HeapFree(GetProcessHeap(), 0, buf);
1968 CryptDestroyKey(key);
1970 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
1971 NULL, 0, NULL, NULL, &size);
1972 ok(ret, "CryptExportPublicKeyInfoEx failed: %08x\n", GetLastError());
1975 PCERT_PUBLIC_KEY_INFO info = HeapAlloc(GetProcessHeap(), 0, size);
1977 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
1978 NULL, 0, NULL, info, &size);
1979 ok(ret, "CryptExportPublicKeyInfoEx failed: %08x\n", GetLastError());
1982 ok(info->PublicKey.cbData == sizeof(asnEncodedPublicKey),
1983 "Unexpected size %d\n", info->PublicKey.cbData);
1984 ok(!memcmp(info->PublicKey.pbData, asnEncodedPublicKey,
1985 info->PublicKey.cbData), "Unexpected value\n");
1987 HeapFree(GetProcessHeap(), 0, info);
1990 CryptReleaseContext(csp, 0);
1991 CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
1992 CRYPT_DELETEKEYSET);
1994 CertFreeCertificateContext(cert);
1997 static void testGetPublicKeyLength(void)
1999 static char oid_rsa_rsa[] = szOID_RSA_RSA;
2000 static char oid_rsa_dh[] = szOID_RSA_DH;
2001 static char bogusOID[] = "1.2.3";
2003 CERT_PUBLIC_KEY_INFO info = { { 0 } };
2004 BYTE bogusKey[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
2005 BYTE key[] = { 0x30,0x0f,0x02,0x08,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
2006 0x02,0x03,0x01,0x00,0x01 };
2009 ret = CertGetPublicKeyLength(0, NULL);
2011 /* With an empty public key info */
2012 SetLastError(0xdeadbeef);
2013 ret = CertGetPublicKeyLength(0, &info);
2014 ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
2015 "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n",
2016 ret, GetLastError());
2017 SetLastError(0xdeadbeef);
2018 ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
2019 ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_EOD,
2020 "Expected length 0 and CRYPT_E_ASN1_EOD, got length %d, %08x\n",
2021 ret, GetLastError());
2022 /* With a nearly-empty public key info */
2023 info.Algorithm.pszObjId = oid_rsa_rsa;
2024 SetLastError(0xdeadbeef);
2025 ret = CertGetPublicKeyLength(0, &info);
2026 ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
2027 "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n",
2028 ret, GetLastError());
2029 SetLastError(0xdeadbeef);
2030 ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
2031 ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_EOD,
2032 "Expected length 0 and CRYPT_E_ASN1_EOD, got length %d, %08x\n",
2033 ret, GetLastError());
2034 /* With a bogus key */
2035 info.PublicKey.cbData = sizeof(bogusKey);
2036 info.PublicKey.pbData = bogusKey;
2037 SetLastError(0xdeadbeef);
2038 ret = CertGetPublicKeyLength(0, &info);
2039 ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
2040 "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n",
2041 ret, GetLastError());
2042 SetLastError(0xdeadbeef);
2043 ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
2044 ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_BADTAG,
2045 "Expected length 0 and CRYPT_E_ASN1_BADTAGTAG, got length %d, %08x\n",
2046 ret, GetLastError());
2047 /* With a believable RSA key but a bogus OID */
2048 info.Algorithm.pszObjId = bogusOID;
2049 info.PublicKey.cbData = sizeof(key);
2050 info.PublicKey.pbData = key;
2051 SetLastError(0xdeadbeef);
2052 ret = CertGetPublicKeyLength(0, &info);
2053 ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND,
2054 "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n",
2055 ret, GetLastError());
2056 SetLastError(0xdeadbeef);
2057 ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
2058 ok(ret == 56, "Expected length 56, got %d\n", ret);
2059 /* An RSA key with the DH OID */
2060 info.Algorithm.pszObjId = oid_rsa_dh;
2061 SetLastError(0xdeadbeef);
2062 ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
2063 ok(ret == 0 && GetLastError() == CRYPT_E_ASN1_BADTAG,
2064 "Expected length 0 and CRYPT_E_ASN1_BADTAG, got length %d, %08x\n",
2065 ret, GetLastError());
2066 /* With the RSA OID */
2067 info.Algorithm.pszObjId = oid_rsa_rsa;
2068 SetLastError(0xdeadbeef);
2069 ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info);
2070 ok(ret == 56, "Expected length 56, got %d\n", ret);
2075 init_function_pointers();
2078 testCertProperties();
2081 testGetSubjectCert();
2082 testGetIssuerCert();
2084 testCryptHashCert();
2086 testSignAndEncodeCert();
2087 testCreateSelfSignCert();
2089 testCompareCertName();
2090 testCompareIntegerBlob();
2091 testComparePublicKeyInfo();
2092 testHashPublicKeyInfo();
2094 testVerifySubjectCert();
2095 testAcquireCertPrivateKey();
2096 testGetPublicKeyLength();