2 * wintrust softpub functions tests
4 * Copyright 2007,2010 Juan Lang
5 * Copyright 2010 Andrey Turkin
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/test.h"
35 /* Just in case we're being built with borked headers, redefine function
36 * pointers to have the correct calling convention.
38 typedef void *(WINAPI *SAFE_MEM_ALLOC)(DWORD);
39 typedef void (WINAPI *SAFE_MEM_FREE)(void *);
40 typedef BOOL (WINAPI *SAFE_ADD_STORE)(CRYPT_PROVIDER_DATA *,
42 typedef BOOL (WINAPI *SAFE_ADD_SGNR)(CRYPT_PROVIDER_DATA *,
43 BOOL, DWORD, struct _CRYPT_PROVIDER_SGNR *);
44 typedef BOOL (WINAPI *SAFE_ADD_CERT)(CRYPT_PROVIDER_DATA *,
45 DWORD, BOOL, DWORD, PCCERT_CONTEXT);
46 typedef BOOL (WINAPI *SAFE_ADD_PRIVDATA)(CRYPT_PROVIDER_DATA *,
47 CRYPT_PROVIDER_PRIVDATA *);
48 typedef HRESULT (WINAPI *SAFE_PROVIDER_INIT_CALL)(CRYPT_PROVIDER_DATA *);
49 typedef HRESULT (WINAPI *SAFE_PROVIDER_OBJTRUST_CALL)(CRYPT_PROVIDER_DATA *);
50 typedef HRESULT (WINAPI *SAFE_PROVIDER_SIGTRUST_CALL)(CRYPT_PROVIDER_DATA *);
51 typedef HRESULT (WINAPI *SAFE_PROVIDER_CERTTRUST_CALL)(CRYPT_PROVIDER_DATA *);
52 typedef HRESULT (WINAPI *SAFE_PROVIDER_FINALPOLICY_CALL)(CRYPT_PROVIDER_DATA *);
53 typedef HRESULT (WINAPI *SAFE_PROVIDER_TESTFINALPOLICY_CALL)(
54 CRYPT_PROVIDER_DATA *);
55 typedef HRESULT (WINAPI *SAFE_PROVIDER_CLEANUP_CALL)(CRYPT_PROVIDER_DATA *);
56 typedef BOOL (WINAPI *SAFE_PROVIDER_CERTCHKPOLICY_CALL)(
57 CRYPT_PROVIDER_DATA *, DWORD, BOOL, DWORD);
59 typedef struct _SAFE_PROVIDER_FUNCTIONS
62 SAFE_MEM_ALLOC pfnAlloc;
63 SAFE_MEM_FREE pfnFree;
64 SAFE_ADD_STORE pfnAddStore2Chain;
65 SAFE_ADD_SGNR pfnAddSgnr2Chain;
66 SAFE_ADD_CERT pfnAddCert2Chain;
67 SAFE_ADD_PRIVDATA pfnAddPrivData2Chain;
68 SAFE_PROVIDER_INIT_CALL pfnInitialize;
69 SAFE_PROVIDER_OBJTRUST_CALL pfnObjectTrust;
70 SAFE_PROVIDER_SIGTRUST_CALL pfnSignatureTrust;
71 SAFE_PROVIDER_CERTTRUST_CALL pfnCertificateTrust;
72 SAFE_PROVIDER_FINALPOLICY_CALL pfnFinalPolicy;
73 SAFE_PROVIDER_CERTCHKPOLICY_CALL pfnCertCheckPolicy;
74 SAFE_PROVIDER_TESTFINALPOLICY_CALL pfnTestFinalPolicy;
75 struct _CRYPT_PROVUI_FUNCS *psUIpfns;
76 SAFE_PROVIDER_CLEANUP_CALL pfnCleanupPolicy;
77 } SAFE_PROVIDER_FUNCTIONS;
79 static BOOL (WINAPI * pWTHelperGetKnownUsages)(DWORD action, PCCRYPT_OID_INFO **usages);
80 static BOOL (WINAPI * CryptSIPCreateIndirectData_p)(SIP_SUBJECTINFO *, DWORD *, SIP_INDIRECT_DATA *);
81 static VOID (WINAPI * CertFreeCertificateChain_p)(PCCERT_CHAIN_CONTEXT);
83 static void InitFunctionPtrs(void)
85 HMODULE hWintrust = GetModuleHandleA("wintrust.dll");
86 HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll");
88 #define WINTRUST_GET_PROC(func) \
89 p ## func = (void*)GetProcAddress(hWintrust, #func); \
91 trace("GetProcAddress(%s) failed\n", #func); \
94 WINTRUST_GET_PROC(WTHelperGetKnownUsages)
96 #undef WINTRUST_GET_PROC
98 #define CRYPT32_GET_PROC(func) \
99 func ## _p = (void*)GetProcAddress(hCrypt32, #func); \
101 trace("GetProcAddress(%s) failed\n", #func); \
104 CRYPT32_GET_PROC(CryptSIPCreateIndirectData)
105 CRYPT32_GET_PROC(CertFreeCertificateChain)
107 #undef CRYPT32_GET_PROC
110 static const BYTE v1CertWithPubKey[] = {
111 0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,
112 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
113 0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
114 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
115 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,
116 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
117 0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
118 0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
119 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,
120 0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,
123 static void test_utils(SAFE_PROVIDER_FUNCTIONS *funcs)
125 CRYPT_PROVIDER_DATA data = { 0 };
127 CRYPT_PROVIDER_SGNR sgnr = { 0 };
131 ret = funcs->pfnAddStore2Chain(NULL, NULL);
132 ret = funcs->pfnAddStore2Chain(&data, NULL);
134 store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0,
135 CERT_STORE_CREATE_NEW_FLAG, NULL);
138 ret = funcs->pfnAddStore2Chain(&data, store);
139 ok(ret, "pfnAddStore2Chain failed: %08x\n", GetLastError());
140 ok(data.chStores == 1, "Expected 1 store, got %d\n", data.chStores);
141 ok(data.pahStores != NULL, "Expected pahStores to be allocated\n");
144 ok(data.pahStores[0] == store, "Unexpected store\n");
145 CertCloseStore(data.pahStores[0], 0);
146 funcs->pfnFree(data.pahStores);
147 data.pahStores = NULL;
149 CertCloseStore(store, 0);
154 skip("CertOpenStore failed: %08x\n", GetLastError());
157 ret = funcs->pfnAddSgnr2Chain(NULL, FALSE, 0, NULL);
158 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, NULL);
160 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
161 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
162 ok(data.csSigners == 1, "Expected 1 signer, got %d\n", data.csSigners);
163 ok(data.pasSigners != NULL, "Expected pasSigners to be allocated\n");
168 ok(!memcmp(&data.pasSigners[0], &sgnr, sizeof(sgnr)),
169 "Unexpected data in signer\n");
170 /* Adds into the location specified by the index */
171 sgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);
172 sgnr.sftVerifyAsOf.dwLowDateTime = 0xdeadbeef;
173 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 1, &sgnr);
174 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
175 ok(data.csSigners == 2, "Expected 2 signers, got %d\n", data.csSigners);
176 ok(!memcmp(&data.pasSigners[1], &sgnr, sizeof(sgnr)),
177 "Unexpected data in signer\n");
178 /* This also adds, but the data aren't copied */
179 sgnr.cbStruct = sizeof(DWORD);
180 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
181 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
182 ok(data.csSigners == 3, "Expected 3 signers, got %d\n", data.csSigners);
183 ok(data.pasSigners[0].cbStruct == 0, "Unexpected data size %d\n",
184 data.pasSigners[0].cbStruct);
185 ok(data.pasSigners[0].sftVerifyAsOf.dwLowDateTime == 0,
186 "Unexpected verify time %d\n",
187 data.pasSigners[0].sftVerifyAsOf.dwLowDateTime);
188 /* But too large a thing isn't added */
189 sgnr.cbStruct = sizeof(sgnr) + sizeof(DWORD);
190 SetLastError(0xdeadbeef);
191 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
192 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
193 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
196 ret = funcs->pfnAddCert2Chain(NULL, 0, FALSE, 0, NULL);
197 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, NULL);
199 cert = CertCreateCertificateContext(X509_ASN_ENCODING, v1CertWithPubKey,
200 sizeof(v1CertWithPubKey));
203 /* Notes on behavior that are hard to test:
204 * 1. If pasSigners is invalid, pfnAddCert2Chain crashes
205 * 2. An invalid signer index isn't checked.
207 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
208 ok(ret, "pfnAddCert2Chain failed: %08x\n", GetLastError());
209 ok(data.pasSigners[0].csCertChain == 1, "Expected 1 cert, got %d\n",
210 data.pasSigners[0].csCertChain);
211 ok(data.pasSigners[0].pasCertChain != NULL,
212 "Expected pasCertChain to be allocated\n");
213 if (data.pasSigners[0].pasCertChain)
215 ok(data.pasSigners[0].pasCertChain[0].pCert == cert,
216 "Unexpected cert\n");
217 CertFreeCertificateContext(
218 data.pasSigners[0].pasCertChain[0].pCert);
220 CertFreeCertificateContext(cert);
223 skip("CertCreateCertificateContext failed: %08x\n", GetLastError());
227 static void testInitialize(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
230 CRYPT_PROVIDER_DATA data = { 0 };
231 WINTRUST_DATA wintrust_data = { 0 };
233 if (!funcs->pfnInitialize)
235 skip("missing pfnInitialize\n");
240 ret = funcs->pfnInitialize(NULL);
242 memset(&data, 0, sizeof(data));
243 ret = funcs->pfnInitialize(&data);
244 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
245 data.padwTrustStepErrors =
246 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
247 /* Without wintrust data set, crashes when padwTrustStepErrors is set */
248 data.pWintrustData = &wintrust_data;
249 if (data.padwTrustStepErrors)
251 /* Apparently, cdwTrustStepErrors does not need to be set. */
252 ret = funcs->pfnInitialize(&data);
253 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
254 data.cdwTrustStepErrors = 1;
255 ret = funcs->pfnInitialize(&data);
256 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
257 memset(data.padwTrustStepErrors, 0xba,
258 TRUSTERROR_MAX_STEPS * sizeof(DWORD));
259 ret = funcs->pfnInitialize(&data);
260 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
261 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT] = 0;
262 ret = funcs->pfnInitialize(&data);
263 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
264 funcs->pfnFree(data.padwTrustStepErrors);
268 static void getNotepadPath(WCHAR *notepadPathW, DWORD size)
270 static const CHAR notepad[] = "\\notepad.exe";
271 CHAR notepadPath[MAX_PATH];
273 /* Workaround missing W-functions for win9x */
274 GetWindowsDirectoryA(notepadPath, MAX_PATH);
275 lstrcatA(notepadPath, notepad);
276 MultiByteToWideChar(0, 0, notepadPath, -1, notepadPathW, size);
279 /* Creates a test file and returns a handle to it. The file's path is returned
280 * in temp_file, which must be at least MAX_PATH characters in length.
282 static HANDLE create_temp_file(WCHAR *temp_file)
284 HANDLE file = INVALID_HANDLE_VALUE;
285 WCHAR temp_path[MAX_PATH];
287 if (GetTempPathW(sizeof(temp_path) / sizeof(temp_path[0]), temp_path))
289 static const WCHAR img[] = { 'i','m','g',0 };
291 if (GetTempFileNameW(temp_path, img, 0, temp_file))
292 file = CreateFileW(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
293 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
298 static void testObjTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
301 CRYPT_PROVIDER_DATA data = { 0 };
302 WINTRUST_DATA wintrust_data = { 0 };
303 WINTRUST_CERT_INFO certInfo = { sizeof(WINTRUST_CERT_INFO), 0 };
304 WINTRUST_FILE_INFO fileInfo = { sizeof(WINTRUST_FILE_INFO), 0 };
306 if (!funcs->pfnObjectTrust)
308 skip("missing pfnObjectTrust\n");
313 ret = funcs->pfnObjectTrust(NULL);
315 data.pWintrustData = &wintrust_data;
316 data.padwTrustStepErrors =
317 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
318 if (data.padwTrustStepErrors)
320 WCHAR pathW[MAX_PATH];
321 PROVDATA_SIP provDataSIP = { 0 };
322 static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
323 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
324 static GUID bogusGuid = { 0xdeadbeef, 0xbaad, 0xf00d, { 0x00,0x00,0x00,
325 0x00,0x00,0x00,0x00,0x00 } };
327 ret = funcs->pfnObjectTrust(&data);
328 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
329 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
330 ERROR_INVALID_PARAMETER,
331 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
332 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
333 U(wintrust_data).pCert = &certInfo;
334 wintrust_data.dwUnionChoice = WTD_CHOICE_CERT;
335 ret = funcs->pfnObjectTrust(&data);
336 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
337 certInfo.psCertContext = (PCERT_CONTEXT)CertCreateCertificateContext(
338 X509_ASN_ENCODING, v1CertWithPubKey, sizeof(v1CertWithPubKey));
339 ret = funcs->pfnObjectTrust(&data);
340 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
341 CertFreeCertificateContext(certInfo.psCertContext);
342 certInfo.psCertContext = NULL;
343 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
344 U(wintrust_data).pFile = NULL;
345 ret = funcs->pfnObjectTrust(&data);
346 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
347 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
348 ERROR_INVALID_PARAMETER,
349 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
350 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
351 U(wintrust_data).pFile = &fileInfo;
353 ret = funcs->pfnObjectTrust(&data);
355 /* Create and test with an empty file */
356 fileInfo.hFile = create_temp_file(pathW);
357 /* pfnObjectTrust now crashes unless both pPDSip and psPfns are set */
358 U(data).pPDSip = &provDataSIP;
359 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
360 ret = funcs->pfnObjectTrust(&data);
361 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
362 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
363 TRUST_E_SUBJECT_FORM_UNKNOWN,
364 "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
365 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
366 CloseHandle(fileInfo.hFile);
367 fileInfo.hFile = NULL;
368 fileInfo.pcwszFilePath = pathW;
369 ret = funcs->pfnObjectTrust(&data);
370 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
371 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
372 TRUST_E_SUBJECT_FORM_UNKNOWN,
373 "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
374 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
376 /* Test again with a file we expect to exist, and to contain no
379 getNotepadPath(pathW, MAX_PATH);
380 ret = funcs->pfnObjectTrust(&data);
381 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
382 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
383 TRUST_E_NOSIGNATURE ||
384 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
385 TRUST_E_SUBJECT_FORM_UNKNOWN,
386 "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
387 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
388 if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
391 ok(!memcmp(&provDataSIP.gSubject, &unknown, sizeof(unknown)),
392 "Unexpected subject GUID\n");
393 ok(provDataSIP.pSip != NULL, "Expected a SIP\n");
394 ok(provDataSIP.psSipSubjectInfo != NULL,
395 "Expected a subject info\n");
397 /* Specifying the GUID results in that GUID being the subject GUID */
398 fileInfo.pgKnownSubject = &bogusGuid;
399 ret = funcs->pfnObjectTrust(&data);
400 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
401 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
402 TRUST_E_NOSIGNATURE ||
403 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
404 TRUST_E_SUBJECT_FORM_UNKNOWN ||
405 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
406 TRUST_E_PROVIDER_UNKNOWN,
407 "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN or TRUST_E_PROVIDER_UNKNOWN, got %08x\n",
408 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
409 if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
412 ok(!memcmp(&provDataSIP.gSubject, &bogusGuid, sizeof(bogusGuid)),
413 "unexpected subject GUID\n");
415 /* Specifying a bogus GUID pointer crashes */
418 fileInfo.pgKnownSubject = (GUID *)0xdeadbeef;
419 ret = funcs->pfnObjectTrust(&data);
420 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
422 funcs->pfnFree(data.padwTrustStepErrors);
426 static const BYTE selfSignedCert[] = {
427 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
428 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49,
429 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d,
430 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
431 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30,
432 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30,
433 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31,
434 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
435 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e,
436 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
437 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
438 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4,
439 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b,
440 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0,
441 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96,
442 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79,
443 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
444 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41,
445 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66,
446 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a,
447 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7,
448 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f,
449 0xa8, 0x76, 0x57, 0x92, 0x36 };
451 static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
453 CRYPT_PROVIDER_DATA data = { 0 };
454 CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
457 if (!CertFreeCertificateChain_p)
459 win_skip("CertFreeCertificateChain not found\n");
463 data.padwTrustStepErrors =
464 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
465 if (!data.padwTrustStepErrors)
467 skip("pfnAlloc failed\n");
470 ret = funcs->pfnCertificateTrust(&data);
471 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
472 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] ==
473 TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n",
474 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
475 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
480 /* An empty signer "succeeds," even though there's no cert */
481 ret = funcs->pfnCertificateTrust(&data);
482 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
483 cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert,
484 sizeof(selfSignedCert));
487 WINTRUST_DATA wintrust_data = { 0 };
489 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
490 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
492 /* If pWintrustData isn't set, crashes attempting to access
493 * pWintrustData->fdwRevocationChecks
495 data.pWintrustData = &wintrust_data;
496 /* If psPfns isn't set, crashes attempting to access
497 * psPfns->pfnCertCheckPolicy
499 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
500 ret = funcs->pfnCertificateTrust(&data);
501 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
502 ok(data.csSigners == 1, "Unexpected number of signers %d\n",
504 ok(data.pasSigners[0].pChainContext != NULL,
505 "Expected a certificate chain\n");
506 ok(data.pasSigners[0].csCertChain == 1,
507 "Unexpected number of chain elements %d\n",
508 data.pasSigners[0].csCertChain);
509 /* pasSigners and pasSigners[0].pasCertChain are guaranteed to be
510 * initialized, see tests for pfnAddSgnr2Chain and pfnAddCert2Chain
512 ok(!data.pasSigners[0].pasCertChain[0].fTrustedRoot,
513 "Didn't expect cert to be trusted\n");
514 ok(data.pasSigners[0].pasCertChain[0].fSelfSigned,
515 "Expected cert to be self-signed\n");
516 ok(data.pasSigners[0].pasCertChain[0].dwConfidence ==
517 (CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST),
518 "Expected CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST, got %08x\n",
519 data.pasSigners[0].pasCertChain[0].dwConfidence);
520 CertFreeCertificateContext(
521 data.pasSigners[0].pasCertChain[0].pCert);
522 CertFreeCertificateChain_p(data.pasSigners[0].pChainContext);
523 CertFreeCertificateContext(cert);
526 funcs->pfnFree(data.padwTrustStepErrors);
529 static void test_provider_funcs(void)
531 static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
532 SAFE_PROVIDER_FUNCTIONS funcs = { sizeof(SAFE_PROVIDER_FUNCTIONS), 0 };
535 ret = WintrustLoadFunctionPointers(&generic_verify_v2,
536 (CRYPT_PROVIDER_FUNCTIONS *)&funcs);
538 skip("WintrustLoadFunctionPointers failed\n");
542 testInitialize(&funcs, &generic_verify_v2);
543 testObjTrust(&funcs, &generic_verify_v2);
544 testCertTrust(&funcs, &generic_verify_v2);
548 /* minimal PE file image */
549 #define VA_START 0x400000
550 #define FILE_PE_START 0x50
551 #define NUM_SECTIONS 3
552 #define FILE_TEXT 0x200
553 #define RVA_TEXT 0x1000
554 #define RVA_BSS 0x2000
555 #define FILE_IDATA 0x400
556 #define RVA_IDATA 0x3000
557 #define FILE_TOTAL 0x600
558 #define RVA_TOTAL 0x4000
559 #include <pshpack1.h>
561 IMAGE_IMPORT_DESCRIPTOR descriptors[2];
562 IMAGE_THUNK_DATA32 original_thunks[2];
563 IMAGE_THUNK_DATA32 thunks[2];
564 struct __IMPORT_BY_NAME {
570 #define EXIT_PROCESS (VA_START+RVA_IDATA+FIELD_OFFSET(struct Imports, thunks[0]))
572 static struct _PeImage {
573 IMAGE_DOS_HEADER dos_header;
574 char __alignment1[FILE_PE_START - sizeof(IMAGE_DOS_HEADER)];
575 IMAGE_NT_HEADERS32 nt_headers;
576 IMAGE_SECTION_HEADER sections[NUM_SECTIONS];
577 char __alignment2[FILE_TEXT - FILE_PE_START - sizeof(IMAGE_NT_HEADERS32) -
578 NUM_SECTIONS * sizeof(IMAGE_SECTION_HEADER)];
579 unsigned char text_section[FILE_IDATA-FILE_TEXT];
580 struct Imports idata_section;
581 char __alignment3[FILE_TOTAL-FILE_IDATA-sizeof(struct Imports)];
584 {IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, 0, 0, {}, FILE_PE_START},
585 /* alignment before PE header */
589 /* basic headers - 3 sections, no symbols, EXE file */
590 {IMAGE_FILE_MACHINE_I386, NUM_SECTIONS, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32),
591 IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE},
592 /* optional header */
593 {IMAGE_NT_OPTIONAL_HDR32_MAGIC, 4, 0, FILE_IDATA-FILE_TEXT,
594 FILE_TOTAL-FILE_IDATA + FILE_IDATA-FILE_TEXT, 0x400,
595 RVA_TEXT, RVA_TEXT, RVA_BSS, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 4, 0, 0,
596 RVA_TOTAL, FILE_TEXT, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0,
597 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10,
599 {RVA_IDATA, sizeof(struct Imports)}
605 {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT, FILE_TEXT,
606 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ},
607 {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0,
608 IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE},
609 {".idata", {sizeof(struct Imports)}, RVA_IDATA, FILE_TOTAL-FILE_IDATA, FILE_IDATA, 0,
610 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}
612 /* alignment before first section */
616 0x31, 0xC0, /* xor eax, eax */
617 0xFF, 0x25, EXIT_PROCESS&0xFF, (EXIT_PROCESS>>8)&0xFF, (EXIT_PROCESS>>16)&0xFF,
618 (EXIT_PROCESS>>24)&0xFF, /* jmp ExitProcess */
624 {{RVA_IDATA + FIELD_OFFSET(struct Imports, original_thunks)}, 0, 0,
625 RVA_IDATA + FIELD_OFFSET(struct Imports, dllname),
626 RVA_IDATA + FIELD_OFFSET(struct Imports, thunks)
630 {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
631 {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
635 /* final alignment */
640 static void test_sip_create_indirect_data(void)
642 static GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
643 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
644 static char oid_sha1[] = szOID_OIWSEC_sha1;
646 SIP_SUBJECTINFO subjinfo = { 0 };
647 WCHAR temp_file[MAX_PATH];
651 if (!CryptSIPCreateIndirectData_p)
653 skip("Missing CryptSIPCreateIndirectData\n");
656 SetLastError(0xdeadbeef);
657 ret = CryptSIPCreateIndirectData_p(NULL, NULL, NULL);
658 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
659 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
660 SetLastError(0xdeadbeef);
661 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
662 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
663 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
664 subjinfo.cbSize = sizeof(subjinfo);
665 SetLastError(0xdeadbeef);
666 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
667 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
668 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
669 file = create_temp_file(temp_file);
670 if (file == INVALID_HANDLE_VALUE)
672 skip("couldn't create temp file\n");
675 WriteFile(file, &bin, sizeof(bin), &count, NULL);
676 FlushFileBuffers(file);
678 subjinfo.hFile = file;
679 SetLastError(0xdeadbeef);
680 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
681 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
682 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
683 subjinfo.pgSubjectType = &unknown;
684 SetLastError(0xdeadbeef);
685 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
686 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
687 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
689 SetLastError(0xdeadbeef);
690 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
692 ok(!ret && (GetLastError() == NTE_BAD_ALGID ||
693 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */),
694 "expected NTE_BAD_ALGID or ERROR_INVALID_PARAMETER, got %08x\n",
696 ok(count == 0xdeadbeef, "expected count to be unmodified, got %d\n", count);
697 subjinfo.DigestAlgorithm.pszObjId = oid_sha1;
699 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
701 ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
702 ok(count, "expected a positive count\n");
705 SIP_INDIRECT_DATA *indirect = HeapAlloc(GetProcessHeap(), 0, count);
708 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, indirect);
709 ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
710 /* If the count is larger than needed, it's unmodified */
711 ok(count == 256, "unexpected count %d\n", count);
712 ok(!strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID),
713 "unexpected data oid %s\n",
714 indirect->Data.pszObjId);
715 ok(!strcmp(indirect->DigestAlgorithm.pszObjId, oid_sha1),
716 "unexpected digest algorithm oid %s\n",
717 indirect->DigestAlgorithm.pszObjId);
718 ok(indirect->Digest.cbData == 20, "unexpected hash size %d\n",
719 indirect->Digest.cbData);
720 if (indirect->Digest.cbData == 20)
722 const BYTE hash[20] = {
723 0x8a,0xd5,0x45,0x53,0x3d,0x67,0xdf,0x2f,0x78,0xe0,
724 0x55,0x0a,0xe0,0xd9,0x7a,0x28,0x3e,0xbf,0x45,0x2b };
726 ok(!memcmp(indirect->Digest.pbData, hash, 20),
727 "unexpected value\n");
730 HeapFree(GetProcessHeap(), 0, indirect);
733 DeleteFileW(temp_file);
736 static void test_wintrust(void)
738 static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
740 WINTRUST_FILE_INFO file;
743 WCHAR pathW[MAX_PATH];
745 memset(&wtd, 0, sizeof(wtd));
746 wtd.cbStruct = sizeof(wtd);
747 wtd.dwUIChoice = WTD_UI_NONE;
748 wtd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
749 wtd.dwUnionChoice = WTD_CHOICE_FILE;
750 U(wtd).pFile = &file;
751 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
752 memset(&file, 0, sizeof(file));
753 file.cbStruct = sizeof(file);
754 file.pcwszFilePath = pathW;
755 /* Test with an empty file */
756 file.hFile = create_temp_file(pathW);
757 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
758 ok(r == TRUST_E_SUBJECT_FORM_UNKNOWN,
759 "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n", r);
760 CloseHandle(file.hFile);
763 /* Test with a known file path, which we expect not have a signature */
764 getNotepadPath(pathW, MAX_PATH);
765 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
766 ok(r == TRUST_E_NOSIGNATURE || r == CRYPT_E_FILE_ERROR,
767 "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", r);
768 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
769 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
770 ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
771 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
772 hr = WinVerifyTrustEx(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
773 ok(hr == TRUST_E_NOSIGNATURE || hr == CRYPT_E_FILE_ERROR,
774 "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", hr);
775 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
776 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
777 ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
780 static void test_get_known_usages(void)
783 PCCRYPT_OID_INFO *usages;
785 if (!pWTHelperGetKnownUsages)
787 skip("missing WTHelperGetKnownUsages\n");
790 SetLastError(0xdeadbeef);
791 ret = pWTHelperGetKnownUsages(0, NULL);
792 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
793 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
794 SetLastError(0xdeadbeef);
795 ret = pWTHelperGetKnownUsages(1, NULL);
796 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
797 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
798 SetLastError(0xdeadbeef);
799 ret = pWTHelperGetKnownUsages(0, &usages);
800 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
801 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
802 /* A value of 1 for the first parameter seems to imply the value is
805 SetLastError(0xdeadbeef);
807 ret = pWTHelperGetKnownUsages(1, &usages);
808 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
809 ok(usages != NULL, "expected a pointer\n");
812 PCCRYPT_OID_INFO *ptr;
814 /* The returned usages are an array of PCCRYPT_OID_INFOs, terminated with a
817 for (ptr = usages; *ptr; ptr++)
819 ok((*ptr)->cbSize == sizeof(CRYPT_OID_INFO) ||
820 (*ptr)->cbSize == (sizeof(CRYPT_OID_INFO) + 2 * sizeof(LPCWSTR)), /* Vista */
821 "unexpected size %d\n", (*ptr)->cbSize);
822 /* Each returned usage is in the CRYPT_ENHKEY_USAGE_OID_GROUP_ID group */
823 ok((*ptr)->dwGroupId == CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
824 "expected group CRYPT_ENHKEY_USAGE_OID_GROUP_ID, got %d\n",
828 /* A value of 2 for the second parameter seems to imply the value is freed
830 SetLastError(0xdeadbeef);
831 ret = pWTHelperGetKnownUsages(2, &usages);
832 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
833 ok(usages == NULL, "expected pointer to be cleared\n");
834 SetLastError(0xdeadbeef);
836 ret = pWTHelperGetKnownUsages(2, &usages);
837 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
838 SetLastError(0xdeadbeef);
839 ret = pWTHelperGetKnownUsages(2, NULL);
840 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
841 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
847 test_provider_funcs();
848 test_sip_create_indirect_data();
850 test_get_known_usages();