Release 1.5.29.
[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
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(CP_ACP, 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     file = create_temp_file(temp_file);
671     if (file == INVALID_HANDLE_VALUE)
672     {
673         skip("couldn't create temp file\n");
674         return;
675     }
676     WriteFile(file, &bin, sizeof(bin), &count, NULL);
677     FlushFileBuffers(file);
678
679     subjinfo.hFile = file;
680     SetLastError(0xdeadbeef);
681     ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
682     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
683        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
684     subjinfo.pgSubjectType = &unknown;
685     SetLastError(0xdeadbeef);
686     ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL);
687     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
688        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
689     count = 0xdeadbeef;
690     SetLastError(0xdeadbeef);
691     ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
692     todo_wine
693     ok(!ret && (GetLastError() == NTE_BAD_ALGID ||
694                 GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */),
695        "expected NTE_BAD_ALGID or ERROR_INVALID_PARAMETER, got %08x\n",
696        GetLastError());
697     ok(count == 0xdeadbeef, "expected count to be unmodified, got %d\n", count);
698     subjinfo.DigestAlgorithm.pszObjId = oid_sha1;
699     count = 0xdeadbeef;
700     ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL);
701     todo_wine
702     ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
703     ok(count, "expected a positive count\n");
704     if (ret)
705     {
706         SIP_INDIRECT_DATA *indirect = HeapAlloc(GetProcessHeap(), 0, count);
707
708         count = 256;
709         ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, indirect);
710         ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError());
711         /* If the count is larger than needed, it's unmodified */
712         ok(count == 256, "unexpected count %d\n", count);
713         ok(!strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID),
714            "unexpected data oid %s\n",
715            indirect->Data.pszObjId);
716         ok(!strcmp(indirect->DigestAlgorithm.pszObjId, oid_sha1),
717            "unexpected digest algorithm oid %s\n",
718            indirect->DigestAlgorithm.pszObjId);
719         ok(indirect->Digest.cbData == 20, "unexpected hash size %d\n",
720            indirect->Digest.cbData);
721         if (indirect->Digest.cbData == 20)
722         {
723             const BYTE hash[20] = {
724                 0x8a,0xd5,0x45,0x53,0x3d,0x67,0xdf,0x2f,0x78,0xe0,
725                 0x55,0x0a,0xe0,0xd9,0x7a,0x28,0x3e,0xbf,0x45,0x2b };
726
727             ok(!memcmp(indirect->Digest.pbData, hash, 20),
728                "unexpected value\n");
729         }
730
731         HeapFree(GetProcessHeap(), 0, indirect);
732     }
733     CloseHandle(file);
734     DeleteFileW(temp_file);
735 }
736
737 static void test_wintrust(void)
738 {
739     static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
740     WINTRUST_DATA wtd;
741     WINTRUST_FILE_INFO file;
742     LONG r;
743     HRESULT hr;
744     WCHAR pathW[MAX_PATH];
745
746     memset(&wtd, 0, sizeof(wtd));
747     wtd.cbStruct = sizeof(wtd);
748     wtd.dwUIChoice = WTD_UI_NONE;
749     wtd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
750     wtd.dwUnionChoice = WTD_CHOICE_FILE;
751     U(wtd).pFile = &file;
752     wtd.dwStateAction = WTD_STATEACTION_VERIFY;
753     memset(&file, 0, sizeof(file));
754     file.cbStruct = sizeof(file);
755     file.pcwszFilePath = pathW;
756     /* Test with an empty file */
757     file.hFile = create_temp_file(pathW);
758     r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
759     ok(r == TRUST_E_SUBJECT_FORM_UNKNOWN,
760      "expected TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n", r);
761     CloseHandle(file.hFile);
762     DeleteFileW(pathW);
763     file.hFile = NULL;
764     /* Test with a known file path, which we expect not have a signature */
765     getNotepadPath(pathW, MAX_PATH);
766     r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
767     ok(r == TRUST_E_NOSIGNATURE || r == CRYPT_E_FILE_ERROR,
768      "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", r);
769     wtd.dwStateAction = WTD_STATEACTION_CLOSE;
770     r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
771     ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
772     wtd.dwStateAction = WTD_STATEACTION_VERIFY;
773     hr = WinVerifyTrustEx(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
774     ok(hr == TRUST_E_NOSIGNATURE || hr == CRYPT_E_FILE_ERROR,
775      "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", hr);
776     wtd.dwStateAction = WTD_STATEACTION_CLOSE;
777     r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd);
778     ok(r == S_OK, "WinVerifyTrust failed: %08x\n", r);
779 }
780
781 static void test_get_known_usages(void)
782 {
783     BOOL ret;
784     PCCRYPT_OID_INFO *usages;
785
786     if (!pWTHelperGetKnownUsages)
787     {
788         skip("missing WTHelperGetKnownUsages\n");
789         return;
790     }
791     SetLastError(0xdeadbeef);
792     ret = pWTHelperGetKnownUsages(0, NULL);
793     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
794      "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
795     SetLastError(0xdeadbeef);
796     ret = pWTHelperGetKnownUsages(1, NULL);
797     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
798      "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
799     SetLastError(0xdeadbeef);
800     ret = pWTHelperGetKnownUsages(0, &usages);
801     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
802      "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
803     /* A value of 1 for the first parameter seems to imply the value is
804      * allocated
805      */
806     SetLastError(0xdeadbeef);
807     usages = NULL;
808     ret = pWTHelperGetKnownUsages(1, &usages);
809     ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
810     ok(usages != NULL, "expected a pointer\n");
811     if (ret && usages)
812     {
813         PCCRYPT_OID_INFO *ptr;
814
815         /* The returned usages are an array of PCCRYPT_OID_INFOs, terminated with a
816          * NULL pointer.
817          */
818         for (ptr = usages; *ptr; ptr++)
819         {
820             ok((*ptr)->cbSize == sizeof(CRYPT_OID_INFO) ||
821              (*ptr)->cbSize == (sizeof(CRYPT_OID_INFO) + 2 * sizeof(LPCWSTR)), /* Vista */
822              "unexpected size %d\n", (*ptr)->cbSize);
823             /* Each returned usage is in the CRYPT_ENHKEY_USAGE_OID_GROUP_ID group */
824             ok((*ptr)->dwGroupId == CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
825              "expected group CRYPT_ENHKEY_USAGE_OID_GROUP_ID, got %d\n",
826              (*ptr)->dwGroupId);
827         }
828     }
829     /* A value of 2 for the second parameter seems to imply the value is freed
830      */
831     SetLastError(0xdeadbeef);
832     ret = pWTHelperGetKnownUsages(2, &usages);
833     ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
834     ok(usages == NULL, "expected pointer to be cleared\n");
835     SetLastError(0xdeadbeef);
836     usages = NULL;
837     ret = pWTHelperGetKnownUsages(2, &usages);
838     ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError());
839     SetLastError(0xdeadbeef);
840     ret = pWTHelperGetKnownUsages(2, NULL);
841     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
842      "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
843 }
844
845 START_TEST(softpub)
846 {
847     InitFunctionPtrs();
848     test_provider_funcs();
849     test_sip_create_indirect_data();
850     test_wintrust();
851     test_get_known_usages();
852 }