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