dinput: Fix printing NULL strings.
[wine] / dlls / wintrust / tests / 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 #include <assert.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winerror.h>
27 #include <wintrust.h>
28 #include <softpub.h>
29 #include <mssip.h>
30 #include <winuser.h>
31 #include "winnls.h"
32
33 #include "wine/test.h"
34
35 /* Just in case we're being built with borked headers, redefine function
36  * pointers to have the correct calling convention.
37  */
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 *,
41  HCERTSTORE);
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);
58
59 typedef struct _SAFE_PROVIDER_FUNCTIONS
60 {
61     DWORD                              cbStruct;
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;
78
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);
82
83 static void InitFunctionPtrs(void)
84 {
85     HMODULE hWintrust = GetModuleHandleA("wintrust.dll");
86     HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll");
87
88 #define WINTRUST_GET_PROC(func) \
89     p ## func = (void*)GetProcAddress(hWintrust, #func); \
90     if(!p ## func) { \
91       trace("GetProcAddress(%s) failed\n", #func); \
92     }
93
94     WINTRUST_GET_PROC(WTHelperGetKnownUsages)
95
96 #undef WINTRUST_GET_PROC
97
98 #define CRYPT32_GET_PROC(func) \
99     func ## _p = (void*)GetProcAddress(hCrypt32, #func); \
100     if(!func ## _p) { \
101       trace("GetProcAddress(%s) failed\n", #func); \
102     }
103
104     CRYPT32_GET_PROC(CryptSIPCreateIndirectData)
105     CRYPT32_GET_PROC(CertFreeCertificateChain)
106
107 #undef CRYPT32_GET_PROC
108 }
109
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,
121 0x01,0x01 };
122
123 static void test_utils(SAFE_PROVIDER_FUNCTIONS *funcs)
124 {
125     CRYPT_PROVIDER_DATA data = { 0 };
126     HCERTSTORE store;
127     CRYPT_PROVIDER_SGNR sgnr = { 0 };
128     BOOL ret;
129
130     /* Crash
131     ret = funcs->pfnAddStore2Chain(NULL, NULL);
132     ret = funcs->pfnAddStore2Chain(&data, NULL);
133      */
134     store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0,
135      CERT_STORE_CREATE_NEW_FLAG, NULL);
136     if (store)
137     {
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");
142         if (data.pahStores)
143         {
144             ok(data.pahStores[0] == store, "Unexpected store\n");
145             CertCloseStore(data.pahStores[0], 0);
146             funcs->pfnFree(data.pahStores);
147             data.pahStores = NULL;
148             data.chStores = 0;
149             CertCloseStore(store, 0);
150             store = NULL;
151         }
152     }
153     else
154         skip("CertOpenStore failed: %08x\n", GetLastError());
155
156     /* Crash
157     ret = funcs->pfnAddSgnr2Chain(NULL, FALSE, 0, NULL);
158     ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, NULL);
159      */
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");
164     if (data.pasSigners)
165     {
166         PCCERT_CONTEXT cert;
167
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());
194
195         /* Crash
196         ret = funcs->pfnAddCert2Chain(NULL, 0, FALSE, 0, NULL);
197         ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, NULL);
198          */
199         cert = CertCreateCertificateContext(X509_ASN_ENCODING, v1CertWithPubKey,
200          sizeof(v1CertWithPubKey));
201         if (cert)
202         {
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.
206              */
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)
214             {
215                 ok(data.pasSigners[0].pasCertChain[0].pCert == cert,
216                  "Unexpected cert\n");
217                 CertFreeCertificateContext(
218                  data.pasSigners[0].pasCertChain[0].pCert);
219             }
220             CertFreeCertificateContext(cert);
221         }
222         else
223             skip("CertCreateCertificateContext failed: %08x\n", GetLastError());
224     }
225 }
226
227 static void testInitialize(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
228 {
229     HRESULT ret;
230     CRYPT_PROVIDER_DATA data = { 0 };
231     WINTRUST_DATA wintrust_data = { 0 };
232
233     if (!funcs->pfnInitialize)
234     {
235         skip("missing pfnInitialize\n");
236         return;
237     }
238
239     /* Crashes
240     ret = funcs->pfnInitialize(NULL);
241      */
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)
250     {
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);
265     }
266 }
267
268 static void getNotepadPath(WCHAR *notepadPathW, DWORD size)
269 {
270     static const CHAR notepad[] = "\\notepad.exe";
271     CHAR notepadPath[MAX_PATH];
272
273     /* Workaround missing W-functions for win9x */
274     GetWindowsDirectoryA(notepadPath, MAX_PATH);
275     lstrcatA(notepadPath, notepad);
276     MultiByteToWideChar(0, 0, notepadPath, -1, notepadPathW, size);
277 }
278
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.
281  */
282 static HANDLE create_temp_file(WCHAR *temp_file)
283 {
284     HANDLE file = INVALID_HANDLE_VALUE;
285     WCHAR temp_path[MAX_PATH];
286
287     if (GetTempPathW(sizeof(temp_path) / sizeof(temp_path[0]), temp_path))
288     {
289         static const WCHAR img[] = { 'i','m','g',0 };
290
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);
294     }
295     return file;
296 }
297
298 static void testObjTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
299 {
300     HRESULT ret;
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 };
305
306     if (!funcs->pfnObjectTrust)
307     {
308         skip("missing pfnObjectTrust\n");
309         return;
310     }
311
312     /* Crashes
313     ret = funcs->pfnObjectTrust(NULL);
314      */
315     data.pWintrustData = &wintrust_data;
316     data.padwTrustStepErrors =
317      funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
318     if (data.padwTrustStepErrors)
319     {
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 } };
326
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;
352         /* Crashes
353         ret = funcs->pfnObjectTrust(&data);
354          */
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]);
375         DeleteFileW(pathW);
376         /* Test again with a file we expect to exist, and to contain no
377          * signature.
378          */
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] ==
389          TRUST_E_NOSIGNATURE)
390         {
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");
396         }
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] ==
410          TRUST_E_NOSIGNATURE)
411         {
412             ok(!memcmp(&provDataSIP.gSubject, &bogusGuid, sizeof(bogusGuid)),
413              "unexpected subject GUID\n");
414         }
415         /* Specifying a bogus GUID pointer crashes */
416         if (0)
417         {
418             fileInfo.pgKnownSubject = (GUID *)0xdeadbeef;
419             ret = funcs->pfnObjectTrust(&data);
420             ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
421         }
422         funcs->pfnFree(data.padwTrustStepErrors);
423     }
424 }
425
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 };
450
451 static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
452 {
453     CRYPT_PROVIDER_DATA data = { 0 };
454     CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
455     HRESULT ret;
456
457     if (!CertFreeCertificateChain_p)
458     {
459         win_skip("CertFreeCertificateChain not found\n");
460         return;
461     }
462
463     data.padwTrustStepErrors =
464      funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
465     if (!data.padwTrustStepErrors)
466     {
467         skip("pfnAlloc failed\n");
468         return;
469     }
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);
476     if (ret)
477     {
478         PCCERT_CONTEXT cert;
479
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));
485         if (cert)
486         {
487             WINTRUST_DATA wintrust_data = { 0 };
488
489             ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
490             ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
491
492             /* If pWintrustData isn't set, crashes attempting to access
493              * pWintrustData->fdwRevocationChecks
494              */
495             data.pWintrustData = &wintrust_data;
496             /* If psPfns isn't set, crashes attempting to access
497              * psPfns->pfnCertCheckPolicy
498              */
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",
503              data.csSigners);
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
511              */
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);
524         }
525     }
526     funcs->pfnFree(data.padwTrustStepErrors);
527 }
528
529 static void test_provider_funcs(void)
530 {
531     static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
532     SAFE_PROVIDER_FUNCTIONS funcs = { sizeof(SAFE_PROVIDER_FUNCTIONS), 0 };
533     BOOL ret;
534
535     ret = WintrustLoadFunctionPointers(&generic_verify_v2,
536      (CRYPT_PROVIDER_FUNCTIONS *)&funcs);
537     if (!ret)
538         skip("WintrustLoadFunctionPointers failed\n");
539     else
540     {
541         test_utils(&funcs);
542         testInitialize(&funcs, &generic_verify_v2);
543         testObjTrust(&funcs, &generic_verify_v2);
544         testCertTrust(&funcs, &generic_verify_v2);
545     }
546 }
547
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>
560 struct Imports {
561     IMAGE_IMPORT_DESCRIPTOR descriptors[2];
562     IMAGE_THUNK_DATA32 original_thunks[2];
563     IMAGE_THUNK_DATA32 thunks[2];
564     struct __IMPORT_BY_NAME {
565         WORD hint;
566         char funcname[0x20];
567     } ibn;
568     char dllname[0x10];
569 };
570 #define EXIT_PROCESS (VA_START+RVA_IDATA+FIELD_OFFSET(struct Imports, thunks[0]))
571
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)];
582 } bin = {
583     /* dos header */
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 */
586     {},
587     /* nt headers */
588     {IMAGE_NT_SIGNATURE,
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,
598             {{0, 0},
599              {RVA_IDATA, sizeof(struct Imports)}
600             }
601         }
602     },
603     /* sections */
604     {
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}
611     },
612     /* alignment before first section */
613     {},
614     /* .text section */
615     {
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 */
619         0
620     },
621     /* .idata section */
622     {
623         {
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)
627             },
628             {{0}, 0, 0, 0, 0}
629         },
630         {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
631         {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}},
632         {0,"ExitProcess"},
633         "KERNEL32.DLL"
634     },
635     /* final alignment */
636     {}
637 };
638 #include <poppack.h>
639
640 static void test_sip_create_indirect_data(void)
641 {
642     static GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
643      0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
644     static char oid_sha1[] = szOID_OIWSEC_sha1;
645     BOOL ret;
646     SIP_SUBJECTINFO subjinfo = { 0 };
647     WCHAR temp_file[MAX_PATH];
648     HANDLE file;
649     DWORD count;
650
651     if (!CryptSIPCreateIndirectData_p)
652     {
653         skip("Missing CryptSIPCreateIndirectData\n");
654         return;
655     }
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)
671     {
672         skip("couldn't create temp file\n");
673         return;
674     }
675     WriteFile(file, &bin, sizeof(bin), &count, NULL);
676     FlushFileBuffers(file);
677
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());
688     count = 0xdeadbeef;
689     SetLastError(0xdeadbeef);
690     ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
691     todo_wine
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",
695        GetLastError());
696     ok(count == 0xdeadbeef, "expected count to be unmodified, got %d\n", count);
697     subjinfo.DigestAlgorithm.pszObjId = oid_sha1;
698     count = 0xdeadbeef;
699     ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
700     todo_wine
701     ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
702     ok(count, "expected a positive count\n");
703     if (ret)
704     {
705         SIP_INDIRECT_DATA *indirect = HeapAlloc(GetProcessHeap(), 0, count);
706
707         count = 256;
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)
721         {
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 };
725
726             ok(!memcmp(indirect->Digest.pbData, hash, 20),
727                "unexpected value\n");
728         }
729
730         HeapFree(GetProcessHeap(), 0, indirect);
731     }
732     CloseHandle(file);
733     DeleteFileW(temp_file);
734 }
735
736 static void test_wintrust(void)
737 {
738     static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
739     WINTRUST_DATA wtd;
740     WINTRUST_FILE_INFO file;
741     LONG r;
742     HRESULT hr;
743     WCHAR pathW[MAX_PATH];
744
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);
761     DeleteFileW(pathW);
762     file.hFile = NULL;
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);
778 }
779
780 static void test_get_known_usages(void)
781 {
782     BOOL ret;
783     PCCRYPT_OID_INFO *usages;
784
785     if (!pWTHelperGetKnownUsages)
786     {
787         skip("missing WTHelperGetKnownUsages\n");
788         return;
789     }
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
803      * allocated
804      */
805     SetLastError(0xdeadbeef);
806     usages = NULL;
807     ret = pWTHelperGetKnownUsages(1, &usages);
808     ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
809     ok(usages != NULL, "expected a pointer\n");
810     if (ret && usages)
811     {
812         PCCRYPT_OID_INFO *ptr;
813
814         /* The returned usages are an array of PCCRYPT_OID_INFOs, terminated with a
815          * NULL pointer.
816          */
817         for (ptr = usages; *ptr; ptr++)
818         {
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",
825              (*ptr)->dwGroupId);
826         }
827     }
828     /* A value of 2 for the second parameter seems to imply the value is freed
829      */
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);
835     usages = NULL;
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());
842 }
843
844 START_TEST(softpub)
845 {
846     InitFunctionPtrs();
847     test_provider_funcs();
848     test_sip_create_indirect_data();
849     test_wintrust();
850     test_get_known_usages();
851 }