[WINTRUST_WINETEST]
[reactos.git] / rostests / winetests / wintrust / softpub.c
1 /*
2 * wintrust softpub functions tests
3 *
4 * Copyright 2007,2010 Juan Lang
5 * Copyright 2010 Andrey Turkin
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <stdio.h>
23 #include <stdarg.h>
24
25 #include <windef.h>
26 #include <winbase.h>
27 #include <winerror.h>
28 #include <wintrust.h>
29 #include <softpub.h>
30 #include <mssip.h>
31 #include <winuser.h>
32 #include "winnls.h"
33
34 #include "wine/test.h"
35
36 /* Just in case we're being built with borked headers, redefine function
37 * pointers to have the correct calling convention.
38 */
39 typedef void *(WINAPI *SAFE_MEM_ALLOC)(DWORD);
40 typedef void (WINAPI *SAFE_MEM_FREE)(void *);
41 typedef BOOL (WINAPI *SAFE_ADD_STORE)(CRYPT_PROVIDER_DATA *,
42 HCERTSTORE);
43 typedef BOOL (WINAPI *SAFE_ADD_SGNR)(CRYPT_PROVIDER_DATA *,
44 BOOL, DWORD, struct _CRYPT_PROVIDER_SGNR *);
45 typedef BOOL (WINAPI *SAFE_ADD_CERT)(CRYPT_PROVIDER_DATA *,
46 DWORD, BOOL, DWORD, PCCERT_CONTEXT);
47 typedef BOOL (WINAPI *SAFE_ADD_PRIVDATA)(CRYPT_PROVIDER_DATA *,
48 CRYPT_PROVIDER_PRIVDATA *);
49 typedef HRESULT (WINAPI *SAFE_PROVIDER_INIT_CALL)(CRYPT_PROVIDER_DATA *);
50 typedef HRESULT (WINAPI *SAFE_PROVIDER_OBJTRUST_CALL)(CRYPT_PROVIDER_DATA *);
51 typedef HRESULT (WINAPI *SAFE_PROVIDER_SIGTRUST_CALL)(CRYPT_PROVIDER_DATA *);
52 typedef HRESULT (WINAPI *SAFE_PROVIDER_CERTTRUST_CALL)(CRYPT_PROVIDER_DATA *);
53 typedef HRESULT (WINAPI *SAFE_PROVIDER_FINALPOLICY_CALL)(CRYPT_PROVIDER_DATA *);
54 typedef HRESULT (WINAPI *SAFE_PROVIDER_TESTFINALPOLICY_CALL)(
55 CRYPT_PROVIDER_DATA *);
56 typedef HRESULT (WINAPI *SAFE_PROVIDER_CLEANUP_CALL)(CRYPT_PROVIDER_DATA *);
57 typedef BOOL (WINAPI *SAFE_PROVIDER_CERTCHKPOLICY_CALL)(
58 CRYPT_PROVIDER_DATA *, DWORD, BOOL, DWORD);
59
60 typedef struct _SAFE_PROVIDER_FUNCTIONS
61 {
62 DWORD cbStruct;
63 SAFE_MEM_ALLOC pfnAlloc;
64 SAFE_MEM_FREE pfnFree;
65 SAFE_ADD_STORE pfnAddStore2Chain;
66 SAFE_ADD_SGNR pfnAddSgnr2Chain;
67 SAFE_ADD_CERT pfnAddCert2Chain;
68 SAFE_ADD_PRIVDATA pfnAddPrivData2Chain;
69 SAFE_PROVIDER_INIT_CALL pfnInitialize;
70 SAFE_PROVIDER_OBJTRUST_CALL pfnObjectTrust;
71 SAFE_PROVIDER_SIGTRUST_CALL pfnSignatureTrust;
72 SAFE_PROVIDER_CERTTRUST_CALL pfnCertificateTrust;
73 SAFE_PROVIDER_FINALPOLICY_CALL pfnFinalPolicy;
74 SAFE_PROVIDER_CERTCHKPOLICY_CALL pfnCertCheckPolicy;
75 SAFE_PROVIDER_TESTFINALPOLICY_CALL pfnTestFinalPolicy;
76 struct _CRYPT_PROVUI_FUNCS *psUIpfns;
77 SAFE_PROVIDER_CLEANUP_CALL pfnCleanupPolicy;
78 } SAFE_PROVIDER_FUNCTIONS;
79
80 static BOOL (WINAPI * pWTHelperGetKnownUsages)(DWORD action, PCCRYPT_OID_INFO **usages);
81 static BOOL (WINAPI * CryptSIPCreateIndirectData_p)(SIP_SUBJECTINFO *, DWORD *, SIP_INDIRECT_DATA *);
82 static VOID (WINAPI * CertFreeCertificateChain_p)(PCCERT_CHAIN_CONTEXT);
83
84 static void InitFunctionPtrs(void)
85 {
86 HMODULE hWintrust = GetModuleHandleA("wintrust.dll");
87 HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll");
88
89 #define WINTRUST_GET_PROC(func) \
90 p ## func = (void*)GetProcAddress(hWintrust, #func); \
91 if(!p ## func) { \
92 trace("GetProcAddress(%s) failed\n", #func); \
93 }
94
95 WINTRUST_GET_PROC(WTHelperGetKnownUsages)
96
97 #undef WINTRUST_GET_PROC
98
99 #define CRYPT32_GET_PROC(func) \
100 func ## _p = (void*)GetProcAddress(hCrypt32, #func); \
101 if(!func ## _p) { \
102 trace("GetProcAddress(%s) failed\n", #func); \
103 }
104
105 CRYPT32_GET_PROC(CryptSIPCreateIndirectData)
106 CRYPT32_GET_PROC(CertFreeCertificateChain)
107
108 #undef CRYPT32_GET_PROC
109 }
110
111 static const BYTE v1CertWithPubKey[] = {
112 0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,
113 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
114 0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
115 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
116 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,
117 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
118 0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
119 0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
120 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,
121 0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,
122 0x01,0x01 };
123
124 static void test_utils(SAFE_PROVIDER_FUNCTIONS *funcs)
125 {
126 CRYPT_PROVIDER_DATA data = { 0 };
127 HCERTSTORE store;
128 CRYPT_PROVIDER_SGNR sgnr = { 0 };
129 BOOL ret;
130
131 /* Crash
132 ret = funcs->pfnAddStore2Chain(NULL, NULL);
133 ret = funcs->pfnAddStore2Chain(&data, NULL);
134 */
135 store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0,
136 CERT_STORE_CREATE_NEW_FLAG, NULL);
137 if (store)
138 {
139 ret = funcs->pfnAddStore2Chain(&data, store);
140 ok(ret, "pfnAddStore2Chain failed: %08x\n", GetLastError());
141 ok(data.chStores == 1, "Expected 1 store, got %d\n", data.chStores);
142 ok(data.pahStores != NULL, "Expected pahStores to be allocated\n");
143 if (data.pahStores)
144 {
145 ok(data.pahStores[0] == store, "Unexpected store\n");
146 CertCloseStore(data.pahStores[0], 0);
147 funcs->pfnFree(data.pahStores);
148 data.pahStores = NULL;
149 data.chStores = 0;
150 CertCloseStore(store, 0);
151 store = NULL;
152 }
153 }
154 else
155 skip("CertOpenStore failed: %08x\n", GetLastError());
156
157 /* Crash
158 ret = funcs->pfnAddSgnr2Chain(NULL, FALSE, 0, NULL);
159 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, NULL);
160 */
161 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
162 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
163 ok(data.csSigners == 1, "Expected 1 signer, got %d\n", data.csSigners);
164 ok(data.pasSigners != NULL, "Expected pasSigners to be allocated\n");
165 if (data.pasSigners)
166 {
167 PCCERT_CONTEXT cert;
168
169 ok(!memcmp(&data.pasSigners[0], &sgnr, sizeof(sgnr)),
170 "Unexpected data in signer\n");
171 /* Adds into the location specified by the index */
172 sgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);
173 sgnr.sftVerifyAsOf.dwLowDateTime = 0xdeadbeef;
174 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 1, &sgnr);
175 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
176 ok(data.csSigners == 2, "Expected 2 signers, got %d\n", data.csSigners);
177 ok(!memcmp(&data.pasSigners[1], &sgnr, sizeof(sgnr)),
178 "Unexpected data in signer\n");
179 /* This also adds, but the data aren't copied */
180 sgnr.cbStruct = sizeof(DWORD);
181 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
182 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
183 ok(data.csSigners == 3, "Expected 3 signers, got %d\n", data.csSigners);
184 ok(data.pasSigners[0].cbStruct == 0, "Unexpected data size %d\n",
185 data.pasSigners[0].cbStruct);
186 ok(data.pasSigners[0].sftVerifyAsOf.dwLowDateTime == 0,
187 "Unexpected verify time %d\n",
188 data.pasSigners[0].sftVerifyAsOf.dwLowDateTime);
189 /* But too large a thing isn't added */
190 sgnr.cbStruct = sizeof(sgnr) + sizeof(DWORD);
191 SetLastError(0xdeadbeef);
192 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
193 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
194 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
195
196 /* Crash
197 ret = funcs->pfnAddCert2Chain(NULL, 0, FALSE, 0, NULL);
198 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, NULL);
199 */
200 cert = CertCreateCertificateContext(X509_ASN_ENCODING, v1CertWithPubKey,
201 sizeof(v1CertWithPubKey));
202 if (cert)
203 {
204 /* Notes on behavior that are hard to test:
205 * 1. If pasSigners is invalid, pfnAddCert2Chain crashes
206 * 2. An invalid signer index isn't checked.
207 */
208 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
209 ok(ret, "pfnAddCert2Chain failed: %08x\n", GetLastError());
210 ok(data.pasSigners[0].csCertChain == 1, "Expected 1 cert, got %d\n",
211 data.pasSigners[0].csCertChain);
212 ok(data.pasSigners[0].pasCertChain != NULL,
213 "Expected pasCertChain to be allocated\n");
214 if (data.pasSigners[0].pasCertChain)
215 {
216 ok(data.pasSigners[0].pasCertChain[0].pCert == cert,
217 "Unexpected cert\n");
218 CertFreeCertificateContext(
219 data.pasSigners[0].pasCertChain[0].pCert);
220 }
221 CertFreeCertificateContext(cert);
222 }
223 else
224 skip("CertCreateCertificateContext failed: %08x\n", GetLastError());
225 }
226 }
227
228 static void testInitialize(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
229 {
230 HRESULT ret;
231 CRYPT_PROVIDER_DATA data = { 0 };
232 WINTRUST_DATA wintrust_data = { 0 };
233
234 if (!funcs->pfnInitialize)
235 {
236 skip("missing pfnInitialize\n");
237 return;
238 }
239
240 /* Crashes
241 ret = funcs->pfnInitialize(NULL);
242 */
243 memset(&data, 0, sizeof(data));
244 ret = funcs->pfnInitialize(&data);
245 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
246 data.padwTrustStepErrors =
247 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
248 /* Without wintrust data set, crashes when padwTrustStepErrors is set */
249 data.pWintrustData = &wintrust_data;
250 if (data.padwTrustStepErrors)
251 {
252 /* Apparently, cdwTrustStepErrors does not need to be set. */
253 ret = funcs->pfnInitialize(&data);
254 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
255 data.cdwTrustStepErrors = 1;
256 ret = funcs->pfnInitialize(&data);
257 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
258 memset(data.padwTrustStepErrors, 0xba,
259 TRUSTERROR_MAX_STEPS * sizeof(DWORD));
260 ret = funcs->pfnInitialize(&data);
261 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
262 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT] = 0;
263 ret = funcs->pfnInitialize(&data);
264 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
265 funcs->pfnFree(data.padwTrustStepErrors);
266 }
267 }
268
269 static void getNotepadPath(WCHAR *notepadPathW, DWORD size)
270 {
271 static const CHAR notepad[] = "\\notepad.exe";
272 CHAR notepadPath[MAX_PATH];
273
274 /* Workaround missing W-functions for win9x */
275 GetWindowsDirectoryA(notepadPath, MAX_PATH);
276 lstrcatA(notepadPath, notepad);
277 MultiByteToWideChar(0, 0, notepadPath, -1, notepadPathW, size);
278 }
279
280 /* Creates a test file and returns a handle to it. The file's path is returned
281 * in temp_file, which must be at least MAX_PATH characters in length.
282 */
283 static HANDLE create_temp_file(WCHAR *temp_file)
284 {
285 HANDLE file = INVALID_HANDLE_VALUE;
286 WCHAR temp_path[MAX_PATH];
287
288 if (GetTempPathW(sizeof(temp_path) / sizeof(temp_path[0]), temp_path))
289 {
290 static const WCHAR img[] = { 'i','m','g',0 };
291
292 if (GetTempFileNameW(temp_path, img, 0, temp_file))
293 file = CreateFileW(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
294 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
295 }
296 return file;
297 }
298
299 static void testObjTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
300 {
301 HRESULT ret;
302 CRYPT_PROVIDER_DATA data = { 0 };
303 WINTRUST_DATA wintrust_data = { 0 };
304 WINTRUST_CERT_INFO certInfo = { sizeof(WINTRUST_CERT_INFO), 0 };
305 WINTRUST_FILE_INFO fileInfo = { sizeof(WINTRUST_FILE_INFO), 0 };
306
307 if (!funcs->pfnObjectTrust)
308 {
309 skip("missing pfnObjectTrust\n");
310 return;
311 }
312
313 /* Crashes
314 ret = funcs->pfnObjectTrust(NULL);
315 */
316 data.pWintrustData = &wintrust_data;
317 data.padwTrustStepErrors =
318 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
319 if (data.padwTrustStepErrors)
320 {
321 WCHAR pathW[MAX_PATH];
322 PROVDATA_SIP provDataSIP = { 0 };
323 static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
324 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
325 static GUID bogusGuid = { 0xdeadbeef, 0xbaad, 0xf00d, { 0x00,0x00,0x00,
326 0x00,0x00,0x00,0x00,0x00 } };
327
328 ret = funcs->pfnObjectTrust(&data);
329 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
330 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
331 ERROR_INVALID_PARAMETER,
332 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
333 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
334 U(wintrust_data).pCert = &certInfo;
335 wintrust_data.dwUnionChoice = WTD_CHOICE_CERT;
336 ret = funcs->pfnObjectTrust(&data);
337 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
338 certInfo.psCertContext = (PCERT_CONTEXT)CertCreateCertificateContext(
339 X509_ASN_ENCODING, v1CertWithPubKey, sizeof(v1CertWithPubKey));
340 ret = funcs->pfnObjectTrust(&data);
341 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
342 CertFreeCertificateContext(certInfo.psCertContext);
343 certInfo.psCertContext = NULL;
344 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
345 U(wintrust_data).pFile = NULL;
346 ret = funcs->pfnObjectTrust(&data);
347 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
348 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
349 ERROR_INVALID_PARAMETER,
350 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
351 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
352 U(wintrust_data).pFile = &fileInfo;
353 /* Crashes
354 ret = funcs->pfnObjectTrust(&data);
355 */
356 /* Create and test with an empty file */
357 fileInfo.hFile = create_temp_file(pathW);
358 /* pfnObjectTrust now crashes unless both pPDSip and psPfns are set */
359 U(data).pPDSip = &provDataSIP;
360 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
361 ret = funcs->pfnObjectTrust(&data);
362 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
363 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
364 TRUST_E_SUBJECT_FORM_UNKNOWN,
365 "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
366 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
367 CloseHandle(fileInfo.hFile);
368 fileInfo.hFile = NULL;
369 fileInfo.pcwszFilePath = pathW;
370 ret = funcs->pfnObjectTrust(&data);
371 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
372 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
373 TRUST_E_SUBJECT_FORM_UNKNOWN,
374 "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
375 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
376 DeleteFileW(pathW);
377 /* Test again with a file we expect to exist, and to contain no
378 * signature.
379 */
380 getNotepadPath(pathW, MAX_PATH);
381 ret = funcs->pfnObjectTrust(&data);
382 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
383 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
384 TRUST_E_NOSIGNATURE ||
385 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
386 TRUST_E_SUBJECT_FORM_UNKNOWN,
387 "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n",
388 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
389 if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
390 TRUST_E_NOSIGNATURE)
391 {
392 ok(!memcmp(&provDataSIP.gSubject, &unknown, sizeof(unknown)),
393 "Unexpected subject GUID\n");
394 ok(provDataSIP.pSip != NULL, "Expected a SIP\n");
395 ok(provDataSIP.psSipSubjectInfo != NULL,
396 "Expected a subject info\n");
397 }
398 /* Specifying the GUID results in that GUID being the subject GUID */
399 fileInfo.pgKnownSubject = &bogusGuid;
400 ret = funcs->pfnObjectTrust(&data);
401 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
402 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
403 TRUST_E_NOSIGNATURE ||
404 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
405 TRUST_E_SUBJECT_FORM_UNKNOWN ||
406 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
407 TRUST_E_PROVIDER_UNKNOWN,
408 "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN or TRUST_E_PROVIDER_UNKNOWN, got %08x\n",
409 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
410 if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
411 TRUST_E_NOSIGNATURE)
412 {
413 ok(!memcmp(&provDataSIP.gSubject, &bogusGuid, sizeof(bogusGuid)),
414 "unexpected subject GUID\n");
415 }
416 /* Specifying a bogus GUID pointer crashes */
417 if (0)
418 {
419 fileInfo.pgKnownSubject = (GUID *)0xdeadbeef;
420 ret = funcs->pfnObjectTrust(&data);
421 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
422 }
423 funcs->pfnFree(data.padwTrustStepErrors);
424 }
425 }
426
427 static const BYTE selfSignedCert[] = {
428 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
429 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49,
430 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d,
431 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
432 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30,
433 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30,
434 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31,
435 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
436 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e,
437 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
438 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
439 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4,
440 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b,
441 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0,
442 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96,
443 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79,
444 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
445 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41,
446 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66,
447 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a,
448 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7,
449 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f,
450 0xa8, 0x76, 0x57, 0x92, 0x36 };
451
452 static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
453 {
454 CRYPT_PROVIDER_DATA data = { 0 };
455 CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
456 HRESULT ret;
457
458 if (!CertFreeCertificateChain_p)
459 {
460 win_skip("CertFreeCertificateChain not found\n");
461 return;
462 }
463
464 data.padwTrustStepErrors =
465 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
466 if (!data.padwTrustStepErrors)
467 {
468 skip("pfnAlloc failed\n");
469 return;
470 }
471 ret = funcs->pfnCertificateTrust(&data);
472 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
473 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] ==
474 TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n",
475 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
476 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
477 if (ret)
478 {
479 PCCERT_CONTEXT cert;
480
481 /* An empty signer "succeeds," even though there's no cert */
482 ret = funcs->pfnCertificateTrust(&data);
483 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
484 cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert,
485 sizeof(selfSignedCert));
486 if (cert)
487 {
488 WINTRUST_DATA wintrust_data = { 0 };
489
490 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
491 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
492
493 /* If pWintrustData isn't set, crashes attempting to access
494 * pWintrustData->fdwRevocationChecks
495 */
496 data.pWintrustData = &wintrust_data;
497 /* If psPfns isn't set, crashes attempting to access
498 * psPfns->pfnCertCheckPolicy
499 */
500 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
501 ret = funcs->pfnCertificateTrust(&data);
502 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
503 ok(data.csSigners == 1, "Unexpected number of signers %d\n",
504 data.csSigners);
505 ok(data.pasSigners[0].pChainContext != NULL,
506 "Expected a certificate chain\n");
507 ok(data.pasSigners[0].csCertChain == 1,
508 "Unexpected number of chain elements %d\n",
509 data.pasSigners[0].csCertChain);
510 /* pasSigners and pasSigners[0].pasCertChain are guaranteed to be
511 * initialized, see tests for pfnAddSgnr2Chain and pfnAddCert2Chain
512 */
513 ok(!data.pasSigners[0].pasCertChain[0].fTrustedRoot,
514 "Didn't expect cert to be trusted\n");
515 ok(data.pasSigners[0].pasCertChain[0].fSelfSigned,
516 "Expected cert to be self-signed\n");
517 ok(data.pasSigners[0].pasCertChain[0].dwConfidence ==
518 (CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST),
519 "Expected CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST, got %08x\n",
520 data.pasSigners[0].pasCertChain[0].dwConfidence);
521 CertFreeCertificateContext(
522 data.pasSigners[0].pasCertChain[0].pCert);
523 CertFreeCertificateChain_p(data.pasSigners[0].pChainContext);
524 CertFreeCertificateContext(cert);
525 }
526 }
527 funcs->pfnFree(data.padwTrustStepErrors);
528 }
529
530 static void test_provider_funcs(void)
531 {
532 static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
533 SAFE_PROVIDER_FUNCTIONS funcs = { sizeof(SAFE_PROVIDER_FUNCTIONS), 0 };
534 BOOL ret;
535
536 ret = WintrustLoadFunctionPointers(&generic_verify_v2,
537 (CRYPT_PROVIDER_FUNCTIONS *)&funcs);
538 if (!ret)
539 skip("WintrustLoadFunctionPointers failed\n");
540 else
541 {
542 test_utils(&funcs);
543 testInitialize(&funcs, &generic_verify_v2);
544 testObjTrust(&funcs, &generic_verify_v2);
545 testCertTrust(&funcs, &generic_verify_v2);
546 }
547 }
548
549 /* minimal PE file image */
550 #define VA_START 0x400000
551 #define FILE_PE_START 0x50
552 #define NUM_SECTIONS 3
553 #define FILE_TEXT 0x200
554 #define RVA_TEXT 0x1000
555 #define RVA_BSS 0x2000
556 #define FILE_IDATA 0x400
557 #define RVA_IDATA 0x3000
558 #define FILE_TOTAL 0x600
559 #define RVA_TOTAL 0x4000
560 #include <pshpack1.h>
561 struct Imports {
562 IMAGE_IMPORT_DESCRIPTOR descriptors[2];
563 IMAGE_THUNK_DATA32 original_thunks[2];
564 IMAGE_THUNK_DATA32 thunks[2];
565 struct __IMPORT_BY_NAME {
566 WORD hint;
567 char funcname[0x20];
568 } ibn;
569 char dllname[0x10];
570 };
571 #define EXIT_PROCESS (VA_START+RVA_IDATA+FIELD_OFFSET(struct Imports, thunks))
572
573 static struct _PeImage {
574 IMAGE_DOS_HEADER dos_header;
575 char __alignment1[FILE_PE_START - sizeof(IMAGE_DOS_HEADER)];
576 IMAGE_NT_HEADERS32 nt_headers;
577 IMAGE_SECTION_HEADER sections[NUM_SECTIONS];
578 char __alignment2[FILE_TEXT - FILE_PE_START - sizeof(IMAGE_NT_HEADERS32) -
579 NUM_SECTIONS * sizeof(IMAGE_SECTION_HEADER)];
580 unsigned char text_section[FILE_IDATA-FILE_TEXT];
581 struct Imports idata_section;
582 char __alignment3[FILE_TOTAL-FILE_IDATA-sizeof(struct Imports)];
583 } bin = {
584 /* dos header */
585 {IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, 0, {0}, FILE_PE_START},
586 /* alignment before PE header */
587 {0},
588 /* nt headers */
589 {IMAGE_NT_SIGNATURE,
590 /* basic headers - 3 sections, no symbols, EXE file */
591 {IMAGE_FILE_MACHINE_I386, NUM_SECTIONS, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32),
592 IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE},
593 /* optional header */
594 {IMAGE_NT_OPTIONAL_HDR32_MAGIC, 4, 0, FILE_IDATA-FILE_TEXT,
595 FILE_TOTAL-FILE_IDATA + FILE_IDATA-FILE_TEXT, 0x400,
596 RVA_TEXT, RVA_TEXT, RVA_BSS, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 4, 0, 0,
597 RVA_TOTAL, FILE_TEXT, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0,
598 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10,
599 {{0, 0},
600 {RVA_IDATA, sizeof(struct Imports)}
601 }
602 }
603 },
604 /* sections */
605 {
606 {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT, FILE_TEXT,
607 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ},
608 {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0,
609 IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE},
610 {".idata", {sizeof(struct Imports)}, RVA_IDATA, FILE_TOTAL-FILE_IDATA, FILE_IDATA, 0,
611 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}
612 },
613 /* alignment before first section */
614 {0},
615 /* .text section */
616 {
617 0x31, 0xC0, /* xor eax, eax */
618 0xFF, 0x25, EXIT_PROCESS&0xFF, (EXIT_PROCESS>>8)&0xFF, (EXIT_PROCESS>>16)&0xFF,
619 (EXIT_PROCESS>>24)&0xFF, /* jmp ExitProcess */
620 0
621 },
622 /* .idata section */
623 {
624 {
625 {{RVA_IDATA + FIELD_OFFSET(struct Imports, original_thunks)}, 0, 0,
626 RVA_IDATA + FIELD_OFFSET(struct Imports, dllname),
627 RVA_IDATA + FIELD_OFFSET(struct Imports, thunks)
628 },
629 {{0}, 0, 0, 0, 0}
630 },
631 {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
632 {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
633 {0,"ExitProcess"},
634 "KERNEL32.DLL"
635 },
636 /* final alignment */
637 {0}
638 };
639 #include <poppack.h>
640
641 static void test_sip_create_indirect_data(void)
642 {
643 static GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
644 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
645 static char oid_sha1[] = szOID_OIWSEC_sha1;
646 BOOL ret;
647 SIP_SUBJECTINFO subjinfo = { 0 };
648 WCHAR temp_file[MAX_PATH];
649 HANDLE file;
650 DWORD count;
651
652 if (!CryptSIPCreateIndirectData_p)
653 {
654 skip("Missing CryptSIPCreateIndirectData\n");
655 return;
656 }
657 SetLastError(0xdeadbeef);
658 ret = CryptSIPCreateIndirectData_p(NULL, NULL, NULL);
659 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
660 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
661 SetLastError(0xdeadbeef);
662 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
663 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
664 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
665 subjinfo.cbSize = sizeof(subjinfo);
666 SetLastError(0xdeadbeef);
667 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
668 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
669 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
670
671 file = create_temp_file(temp_file);
672 if (file == INVALID_HANDLE_VALUE)
673 {
674 skip("couldn't create temp file\n");
675 return;
676 }
677 WriteFile(file, &bin, sizeof(bin), &count, NULL);
678 FlushFileBuffers(file);
679
680 subjinfo.hFile = file;
681 SetLastError(0xdeadbeef);
682 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
683 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
684 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
685 subjinfo.pgSubjectType = &unknown;
686 SetLastError(0xdeadbeef);
687 ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
688 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
689 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
690 count = 0xdeadbeef;
691 SetLastError(0xdeadbeef);
692 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
693 todo_wine
694 ok(!ret && (GetLastError() == NTE_BAD_ALGID ||
695 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */),
696 "expected NTE_BAD_ALGID or ERROR_INVALID_PARAMETER, got %08x\n",
697 GetLastError());
698 ok(count == 0xdeadbeef, "expected count to be unmodified, got %d\n", count);
699 subjinfo.DigestAlgorithm.pszObjId = oid_sha1;
700 count = 0xdeadbeef;
701 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
702 todo_wine
703 ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
704 ok(count, "expected a positive count\n");
705 if (ret)
706 {
707 SIP_INDIRECT_DATA *indirect = HeapAlloc(GetProcessHeap(), 0, count);
708
709 count = 256;
710 ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, indirect);
711 ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
712 /* If the count is larger than needed, it's unmodified */
713 ok(count == 256, "unexpected count %d\n", count);
714 ok(!strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID),
715 "unexpected data oid %s\n",
716 indirect->Data.pszObjId);
717 ok(!strcmp(indirect->DigestAlgorithm.pszObjId, oid_sha1),
718 "unexpected digest algorithm oid %s\n",
719 indirect->DigestAlgorithm.pszObjId);
720 ok(indirect->Digest.cbData == 20, "unexpected hash size %d\n",
721 indirect->Digest.cbData);
722 if (indirect->Digest.cbData == 20)
723 {
724 const BYTE hash[20] = {
725 0x8a,0xd5,0x45,0x53,0x3d,0x67,0xdf,0x2f,0x78,0xe0,
726 0x55,0x0a,0xe0,0xd9,0x7a,0x28,0x3e,0xbf,0x45,0x2b };
727
728 ok(!memcmp(indirect->Digest.pbData, hash, 20),
729 "unexpected value\n");
730 }
731
732 HeapFree(GetProcessHeap(), 0, indirect);
733 }
734 CloseHandle(file);
735 DeleteFileW(temp_file);
736 }
737
738 static void test_wintrust(void)
739 {
740 static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
741 WINTRUST_DATA wtd;
742 WINTRUST_FILE_INFO file;
743 LONG r;
744 HRESULT hr;
745 WCHAR pathW[MAX_PATH];
746
747 memset(&wtd, 0, sizeof(wtd));
748 wtd.cbStruct = sizeof(wtd);
749 wtd.dwUIChoice = WTD_UI_NONE;
750 wtd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
751 wtd.dwUnionChoice = WTD_CHOICE_FILE;
752 U(wtd).pFile = &file;
753 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
754 memset(&file, 0, sizeof(file));
755 file.cbStruct = sizeof(file);
756 file.pcwszFilePath = pathW;
757 /* Test with an empty file */
758 file.hFile = create_temp_file(pathW);
759 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
760 ok(r == TRUST_E_SUBJECT_FORM_UNKNOWN,
761 "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n", r);
762 CloseHandle(file.hFile);
763 DeleteFileW(pathW);
764 file.hFile = NULL;
765 /* Test with a known file path, which we expect not have a signature */
766 getNotepadPath(pathW, MAX_PATH);
767 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
768 ok(r == TRUST_E_NOSIGNATURE || r == CRYPT_E_FILE_ERROR,
769 "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", r);
770 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
771 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
772 ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
773 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
774 hr = WinVerifyTrustEx(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
775 ok(hr == TRUST_E_NOSIGNATURE || hr == CRYPT_E_FILE_ERROR,
776 "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", hr);
777 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
778 r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
779 ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
780 }
781
782 static void test_get_known_usages(void)
783 {
784 BOOL ret;
785 PCCRYPT_OID_INFO *usages;
786
787 if (!pWTHelperGetKnownUsages)
788 {
789 skip("missing WTHelperGetKnownUsages\n");
790 return;
791 }
792 SetLastError(0xdeadbeef);
793 ret = pWTHelperGetKnownUsages(0, NULL);
794 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
795 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
796 SetLastError(0xdeadbeef);
797 ret = pWTHelperGetKnownUsages(1, NULL);
798 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
799 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
800 SetLastError(0xdeadbeef);
801 ret = pWTHelperGetKnownUsages(0, &usages);
802 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
803 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
804 /* A value of 1 for the first parameter seems to imply the value is
805 * allocated
806 */
807 SetLastError(0xdeadbeef);
808 usages = NULL;
809 ret = pWTHelperGetKnownUsages(1, &usages);
810 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
811 ok(usages != NULL, "expected a pointer\n");
812 if (ret && usages)
813 {
814 PCCRYPT_OID_INFO *ptr;
815
816 /* The returned usages are an array of PCCRYPT_OID_INFOs, terminated with a
817 * NULL pointer.
818 */
819 for (ptr = usages; *ptr; ptr++)
820 {
821 ok((*ptr)->cbSize == sizeof(CRYPT_OID_INFO) ||
822 (*ptr)->cbSize == (sizeof(CRYPT_OID_INFO) + 2 * sizeof(LPCWSTR)), /* Vista */
823 "unexpected size %d\n", (*ptr)->cbSize);
824 /* Each returned usage is in the CRYPT_ENHKEY_USAGE_OID_GROUP_ID group */
825 ok((*ptr)->dwGroupId == CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
826 "expected group CRYPT_ENHKEY_USAGE_OID_GROUP_ID, got %d\n",
827 (*ptr)->dwGroupId);
828 }
829 }
830 /* A value of 2 for the second parameter seems to imply the value is freed
831 */
832 SetLastError(0xdeadbeef);
833 ret = pWTHelperGetKnownUsages(2, &usages);
834 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
835 ok(usages == NULL, "expected pointer to be cleared\n");
836 SetLastError(0xdeadbeef);
837 usages = NULL;
838 ret = pWTHelperGetKnownUsages(2, &usages);
839 ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
840 SetLastError(0xdeadbeef);
841 ret = pWTHelperGetKnownUsages(2, NULL);
842 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
843 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
844 }
845
846 START_TEST(softpub)
847 {
848 InitFunctionPtrs();
849 test_provider_funcs();
850 test_sip_create_indirect_data();
851 test_wintrust();
852 test_get_known_usages();
853 }