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