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 static void testObjTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
282 CRYPT_PROVIDER_DATA data = { 0 };
283 WINTRUST_DATA wintrust_data = { 0 };
284 WINTRUST_CERT_INFO certInfo = { sizeof(WINTRUST_CERT_INFO), 0 };
285 WINTRUST_FILE_INFO fileInfo = { sizeof(WINTRUST_FILE_INFO), 0 };
287 if (!funcs->pfnObjectTrust)
289 skip("missing pfnObjectTrust\n");
294 ret = funcs->pfnObjectTrust(NULL);
296 data.pWintrustData = &wintrust_data;
297 data.padwTrustStepErrors =
298 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
299 if (data.padwTrustStepErrors)
301 WCHAR notepadPathW[MAX_PATH];
302 PROVDATA_SIP provDataSIP = { 0 };
303 static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
304 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
305 static GUID bogusGuid = { 0xdeadbeef, 0xbaad, 0xf00d, { 0x00,0x00,0x00,
306 0x00,0x00,0x00,0x00,0x00 } };
308 ret = funcs->pfnObjectTrust(&data);
309 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
310 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
311 ERROR_INVALID_PARAMETER,
312 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
313 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
314 U(wintrust_data).pCert = &certInfo;
315 wintrust_data.dwUnionChoice = WTD_CHOICE_CERT;
316 ret = funcs->pfnObjectTrust(&data);
317 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
318 certInfo.psCertContext = (PCERT_CONTEXT)CertCreateCertificateContext(
319 X509_ASN_ENCODING, v1CertWithPubKey, sizeof(v1CertWithPubKey));
320 ret = funcs->pfnObjectTrust(&data);
321 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
322 CertFreeCertificateContext(certInfo.psCertContext);
323 certInfo.psCertContext = NULL;
324 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
325 U(wintrust_data).pFile = NULL;
326 ret = funcs->pfnObjectTrust(&data);
327 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
328 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
329 ERROR_INVALID_PARAMETER,
330 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
331 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
332 U(wintrust_data).pFile = &fileInfo;
334 ret = funcs->pfnObjectTrust(&data);
336 getNotepadPath(notepadPathW, MAX_PATH);
337 fileInfo.pcwszFilePath = notepadPathW;
338 /* pfnObjectTrust now crashes unless both pPDSip and psPfns are set */
339 U(data).pPDSip = &provDataSIP;
340 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
341 ret = funcs->pfnObjectTrust(&data);
342 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
343 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
344 TRUST_E_NOSIGNATURE ||
345 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
346 TRUST_E_SUBJECT_FORM_UNKNOWN,
347 "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
348 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
349 if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
352 ok(!memcmp(&provDataSIP.gSubject, &unknown, sizeof(unknown)),
353 "Unexpected subject GUID\n");
354 ok(provDataSIP.pSip != NULL, "Expected a SIP\n");
355 ok(provDataSIP.psSipSubjectInfo != NULL,
356 "Expected a subject info\n");
358 /* Specifying the GUID results in that GUID being the subject GUID */
359 fileInfo.pgKnownSubject = &bogusGuid;
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_NOSIGNATURE ||
364 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
365 TRUST_E_SUBJECT_FORM_UNKNOWN ||
366 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
367 TRUST_E_PROVIDER_UNKNOWN,
368 "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN or TRUST_E_PROVIDER_UNKNOWN, got %08x\n",
369 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
370 if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
373 ok(!memcmp(&provDataSIP.gSubject, &bogusGuid, sizeof(bogusGuid)),
374 "unexpected subject GUID\n");
376 /* Specifying a bogus GUID pointer crashes */
379 fileInfo.pgKnownSubject = (GUID *)0xdeadbeef;
380 ret = funcs->pfnObjectTrust(&data);
381 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
383 funcs->pfnFree(data.padwTrustStepErrors);
387 static const BYTE selfSignedCert[] = {
388 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
389 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49,
390 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d,
391 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
392 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30,
393 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30,
394 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31,
395 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
396 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e,
397 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
398 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
399 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4,
400 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b,
401 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0,
402 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96,
403 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79,
404 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
405 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41,
406 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66,
407 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a,
408 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7,
409 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f,
410 0xa8, 0x76, 0x57, 0x92, 0x36 };
412 static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
414 CRYPT_PROVIDER_DATA data = { 0 };
415 CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
418 if (!CertFreeCertificateChain_p)
420 win_skip("CertFreeCertificateChain not found\n");
424 data.padwTrustStepErrors =
425 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
426 if (!data.padwTrustStepErrors)
428 skip("pfnAlloc failed\n");
431 ret = funcs->pfnCertificateTrust(&data);
432 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
433 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] ==
434 TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n",
435 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
436 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
441 /* An empty signer "succeeds," even though there's no cert */
442 ret = funcs->pfnCertificateTrust(&data);
443 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
444 cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert,
445 sizeof(selfSignedCert));
448 WINTRUST_DATA wintrust_data = { 0 };
450 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
451 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
453 /* If pWintrustData isn't set, crashes attempting to access
454 * pWintrustData->fdwRevocationChecks
456 data.pWintrustData = &wintrust_data;
457 /* If psPfns isn't set, crashes attempting to access
458 * psPfns->pfnCertCheckPolicy
460 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
461 ret = funcs->pfnCertificateTrust(&data);
462 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
463 ok(data.csSigners == 1, "Unexpected number of signers %d\n",
465 ok(data.pasSigners[0].pChainContext != NULL,
466 "Expected a certificate chain\n");
467 ok(data.pasSigners[0].csCertChain == 1,
468 "Unexpected number of chain elements %d\n",
469 data.pasSigners[0].csCertChain);
470 /* pasSigners and pasSigners[0].pasCertChain are guaranteed to be
471 * initialized, see tests for pfnAddSgnr2Chain and pfnAddCert2Chain
473 ok(!data.pasSigners[0].pasCertChain[0].fTrustedRoot,
474 "Didn't expect cert to be trusted\n");
475 ok(data.pasSigners[0].pasCertChain[0].fSelfSigned,
476 "Expected cert to be self-signed\n");
477 ok(data.pasSigners[0].pasCertChain[0].dwConfidence ==
478 (CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST),
479 "Expected CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST, got %08x\n",
480 data.pasSigners[0].pasCertChain[0].dwConfidence);
481 CertFreeCertificateContext(
482 data.pasSigners[0].pasCertChain[0].pCert);
483 CertFreeCertificateChain_p(data.pasSigners[0].pChainContext);
484 CertFreeCertificateContext(cert);
487 funcs->pfnFree(data.padwTrustStepErrors);
490 static void test_provider_funcs(void)
492 static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
493 SAFE_PROVIDER_FUNCTIONS funcs = { sizeof(SAFE_PROVIDER_FUNCTIONS), 0 };
496 ret = WintrustLoadFunctionPointers(&generic_verify_v2,
497 (CRYPT_PROVIDER_FUNCTIONS *)&funcs);
499 skip("WintrustLoadFunctionPointers failed\n");
503 testInitialize(&funcs, &generic_verify_v2);
504 testObjTrust(&funcs, &generic_verify_v2);
505 testCertTrust(&funcs, &generic_verify_v2);
509 /* minimal PE file image */
510 #define VA_START 0x400000
511 #define FILE_PE_START 0x50
512 #define NUM_SECTIONS 3
513 #define FILE_TEXT 0x200
514 #define RVA_TEXT 0x1000
515 #define RVA_BSS 0x2000
516 #define FILE_IDATA 0x400
517 #define RVA_IDATA 0x3000
518 #define FILE_TOTAL 0x600
519 #define RVA_TOTAL 0x4000
520 #include <pshpack1.h>
522 IMAGE_IMPORT_DESCRIPTOR descriptors[2];
523 IMAGE_THUNK_DATA32 original_thunks[2];
524 IMAGE_THUNK_DATA32 thunks[2];
525 struct __IMPORT_BY_NAME {
531 #define EXIT_PROCESS (VA_START+RVA_IDATA+FIELD_OFFSET(struct Imports, thunks[0]))
533 static struct _PeImage {
534 IMAGE_DOS_HEADER dos_header;
535 char __alignment1[FILE_PE_START - sizeof(IMAGE_DOS_HEADER)];
536 IMAGE_NT_HEADERS32 nt_headers;
537 IMAGE_SECTION_HEADER sections[NUM_SECTIONS];
538 char __alignment2[FILE_TEXT - FILE_PE_START - sizeof(IMAGE_NT_HEADERS32) -
539 NUM_SECTIONS * sizeof(IMAGE_SECTION_HEADER)];
540 unsigned char text_section[FILE_IDATA-FILE_TEXT];
541 struct Imports idata_section;
542 char __alignment3[FILE_TOTAL-FILE_IDATA-sizeof(struct Imports)];
545 {IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, 0, 0, {}, FILE_PE_START},
546 /* alignment before PE header */
550 /* basic headers - 3 sections, no symbols, EXE file */
551 {IMAGE_FILE_MACHINE_I386, NUM_SECTIONS, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32),
552 IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE},
553 /* optional header */
554 {IMAGE_NT_OPTIONAL_HDR32_MAGIC, 4, 0, FILE_IDATA-FILE_TEXT,
555 FILE_TOTAL-FILE_IDATA + FILE_IDATA-FILE_TEXT, 0x400,
556 RVA_TEXT, RVA_TEXT, RVA_BSS, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 4, 0, 0,
557 RVA_TOTAL, FILE_TEXT, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0,
558 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10,
560 {RVA_IDATA, sizeof(struct Imports)}
566 {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT, FILE_TEXT,
567 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ},
568 {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0,
569 IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE},
570 {".idata", {sizeof(struct Imports)}, RVA_IDATA, FILE_TOTAL-FILE_IDATA, FILE_IDATA, 0,
571 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}
573 /* alignment before first section */
577 0x31, 0xC0, /* xor eax, eax */
578 0xFF, 0x25, EXIT_PROCESS&0xFF, (EXIT_PROCESS>>8)&0xFF, (EXIT_PROCESS>>16)&0xFF,
579 (EXIT_PROCESS>>24)&0xFF, /* jmp ExitProcess */
585 {{RVA_IDATA + FIELD_OFFSET(struct Imports, original_thunks)}, 0, 0,
586 RVA_IDATA + FIELD_OFFSET(struct Imports, dllname),
587 RVA_IDATA + FIELD_OFFSET(struct Imports, thunks)
591 {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
592 {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
596 /* final alignment */
601 /* Creates a test file and returns a handle to it. The file's path is returned
602 * in temp_file, which must be at least MAX_PATH characters in length.
604 static HANDLE create_temp_file(char *temp_file)
606 HANDLE file = INVALID_HANDLE_VALUE;
607 char temp_path[MAX_PATH];
609 if (GetTempPathA(sizeof(temp_path), temp_path))
611 if (GetTempFileNameA(temp_path, "img", 0, temp_file))
612 file = CreateFileA(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
613 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
618 static void test_sip_create_indirect_data(void)
620 static GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
621 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
622 static char oid_sha1[] = szOID_OIWSEC_sha1;
624 SIP_SUBJECTINFO subjinfo = { 0 };
625 char temp_file[MAX_PATH];
629 if (!CryptSIPCreateIndirectData_p)
631 skip("Missing CryptSIPCreateIndirectData\n");
634 SetLastError(0xdeadbeef);
635 ret = CryptSIPCreateIndirectData_p(NULL, NULL, NULL);
636 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
637 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
638 SetLastError(0xdeadbeef);
639 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
640 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
641 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
642 subjinfo.cbSize = sizeof(subjinfo);
643 SetLastError(0xdeadbeef);
644 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
645 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
646 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
647 file = create_temp_file(temp_file);
648 if (file == INVALID_HANDLE_VALUE)
650 skip("couldn't create temp file\n");
653 WriteFile(file, &bin, sizeof(bin), &count, NULL);
654 FlushFileBuffers(file);
656 subjinfo.hFile = file;
657 SetLastError(0xdeadbeef);
658 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
659 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
660 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
661 subjinfo.pgSubjectType = &unknown;
662 SetLastError(0xdeadbeef);
663 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
664 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
665 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
667 SetLastError(0xdeadbeef);
668 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
670 ok(!ret && (GetLastError() == NTE_BAD_ALGID ||
671 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */),
672 "expected NTE_BAD_ALGID or ERROR_INVALID_PARAMETER, got %08x\n",
674 ok(count == 0xdeadbeef, "expected count to be unmodified, got %d\n", count);
675 subjinfo.DigestAlgorithm.pszObjId = oid_sha1;
677 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
679 ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
680 ok(count, "expected a positive count\n");
683 SIP_INDIRECT_DATA *indirect = HeapAlloc(GetProcessHeap(), 0, count);
686 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, indirect);
687 ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
688 /* If the count is larger than needed, it's unmodified */
689 ok(count == 256, "unexpected count %d\n", count);
690 ok(!strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID),
691 "unexpected data oid %s\n",
692 indirect->Data.pszObjId);
693 ok(!strcmp(indirect->DigestAlgorithm.pszObjId, oid_sha1),
694 "unexpected digest algorithm oid %s\n",
695 indirect->DigestAlgorithm.pszObjId);
696 ok(indirect->Digest.cbData == 20, "unexpected hash size %d\n",
697 indirect->Digest.cbData);
698 if (indirect->Digest.cbData == 20)
700 const BYTE hash[20] = {
701 0x8a,0xd5,0x45,0x53,0x3d,0x67,0xdf,0x2f,0x78,0xe0,
702 0x55,0x0a,0xe0,0xd9,0x7a,0x28,0x3e,0xbf,0x45,0x2b };
704 ok(!memcmp(indirect->Digest.pbData, hash, 20),
705 "unexpected value\n");
708 HeapFree(GetProcessHeap(), 0, indirect);
711 DeleteFileA(temp_file);
714 static void test_wintrust(void)
716 static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
718 WINTRUST_FILE_INFO file;
721 WCHAR notepadPathW[MAX_PATH];
723 memset(&wtd, 0, sizeof(wtd));
724 wtd.cbStruct = sizeof(wtd);
725 wtd.dwUIChoice = WTD_UI_NONE;
726 wtd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
727 wtd.dwUnionChoice = WTD_CHOICE_FILE;
728 U(wtd).pFile = &file;
729 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
730 memset(&file, 0, sizeof(file));
731 file.cbStruct = sizeof(file);
732 getNotepadPath(notepadPathW, MAX_PATH);
733 file.pcwszFilePath = notepadPathW;
734 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
735 ok(r == TRUST_E_NOSIGNATURE || r == CRYPT_E_FILE_ERROR,
736 "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", r);
737 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
738 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
739 ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
740 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
741 hr = WinVerifyTrustEx(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
742 ok(hr == TRUST_E_NOSIGNATURE || hr == CRYPT_E_FILE_ERROR,
743 "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", hr);
744 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
745 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
746 ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
749 static void test_get_known_usages(void)
752 PCCRYPT_OID_INFO *usages;
754 if (!pWTHelperGetKnownUsages)
756 skip("missing WTHelperGetKnownUsages\n");
759 SetLastError(0xdeadbeef);
760 ret = pWTHelperGetKnownUsages(0, NULL);
761 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
762 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
763 SetLastError(0xdeadbeef);
764 ret = pWTHelperGetKnownUsages(1, NULL);
765 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
766 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
767 SetLastError(0xdeadbeef);
768 ret = pWTHelperGetKnownUsages(0, &usages);
769 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
770 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
771 /* A value of 1 for the first parameter seems to imply the value is
774 SetLastError(0xdeadbeef);
776 ret = pWTHelperGetKnownUsages(1, &usages);
777 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
778 ok(usages != NULL, "expected a pointer\n");
781 PCCRYPT_OID_INFO *ptr;
783 /* The returned usages are an array of PCCRYPT_OID_INFOs, terminated with a
786 for (ptr = usages; *ptr; ptr++)
788 ok((*ptr)->cbSize == sizeof(CRYPT_OID_INFO) ||
789 (*ptr)->cbSize == (sizeof(CRYPT_OID_INFO) + 2 * sizeof(LPCWSTR)), /* Vista */
790 "unexpected size %d\n", (*ptr)->cbSize);
791 /* Each returned usage is in the CRYPT_ENHKEY_USAGE_OID_GROUP_ID group */
792 ok((*ptr)->dwGroupId == CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
793 "expected group CRYPT_ENHKEY_USAGE_OID_GROUP_ID, got %d\n",
797 /* A value of 2 for the second parameter seems to imply the value is freed
799 SetLastError(0xdeadbeef);
800 ret = pWTHelperGetKnownUsages(2, &usages);
801 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
802 ok(usages == NULL, "expected pointer to be cleared\n");
803 SetLastError(0xdeadbeef);
805 ret = pWTHelperGetKnownUsages(2, &usages);
806 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
807 SetLastError(0xdeadbeef);
808 ret = pWTHelperGetKnownUsages(2, NULL);
809 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
810 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
816 test_provider_funcs();
817 test_sip_create_indirect_data();
819 test_get_known_usages();