jscript: Added '|=' expression implementation.
[wine] / dlls / wintrust / tests / crypt.c
1 /* Unit test suite for wintrust crypt functions
2  *
3  * Copyright 2007 Paul Vriens
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #include "windows.h"
25 #include "mscat.h"
26
27 #include "wine/test.h"
28
29 static char selfname[MAX_PATH];
30
31 static CHAR CURR_DIR[MAX_PATH];
32
33 static BOOL (WINAPI * pCryptCATAdminAcquireContext)(HCATADMIN*, const GUID*, DWORD);
34 static BOOL (WINAPI * pCryptCATAdminReleaseContext)(HCATADMIN, DWORD);
35 static BOOL (WINAPI * pCryptCATAdminCalcHashFromFileHandle)(HANDLE hFile, DWORD*, BYTE*, DWORD);
36
37 static void InitFunctionPtrs(void)
38 {
39     HMODULE hWintrust = GetModuleHandleA("wintrust.dll");
40
41 #define WINTRUST_GET_PROC(func) \
42     p ## func = (void*)GetProcAddress(hWintrust, #func); \
43     if(!p ## func) { \
44       trace("GetProcAddress(%s) failed\n", #func); \
45     }
46
47     WINTRUST_GET_PROC(CryptCATAdminAcquireContext)
48     WINTRUST_GET_PROC(CryptCATAdminReleaseContext)
49     WINTRUST_GET_PROC(CryptCATAdminCalcHashFromFileHandle)
50
51 #undef WINTRUST_GET_PROC
52 }
53
54 static void test_context(void)
55 {
56     BOOL ret;
57     HCATADMIN hca;
58     static GUID dummy   = { 0xdeadbeef, 0xdead, 0xbeef, { 0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef }};
59     static GUID unknown = { 0xC689AABA, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; /* WINTRUST.DLL */
60     CHAR windir[MAX_PATH], catroot[MAX_PATH], catroot2[MAX_PATH], dummydir[MAX_PATH];
61     DWORD attrs;
62
63     if (!pCryptCATAdminAcquireContext || !pCryptCATAdminReleaseContext)
64     {
65         skip("CryptCATAdminAcquireContext and/or CryptCATAdminReleaseContext are not available\n");
66         return;
67     }
68
69     /* When CryptCATAdminAcquireContext is successful it will create
70      * several directories if they don't exist:
71      *
72      * ...\system32\CatRoot\{GUID}, this directory holds the .cat files
73      * ...\system32\CatRoot2\{GUID}  (WinXP and up), here we find the catalog database for that GUID
74      *
75      * Windows Vista uses lowercase catroot and catroot2.
76      *
77      * When passed a NULL GUID it will create the following directories although on
78      * WinXP and up these directories are already present when Windows is installed:
79      *
80      * ...\system32\CatRoot\{127D0A1D-4EF2-11D1-8608-00C04FC295EE}
81      * ...\system32\CatRoot2\{127D0A1D-4EF2-11D1-8608-00C04FC295EE} (WinXP up)
82      *
83      * TODO: Find out what this GUID is/does.
84      *
85      * On WinXP and up there is also a TimeStamp file in some of directories that
86      * seem to indicate the last change to the catalog database for that GUID.
87      *
88      * On Windows 2000 some files are created/updated:
89      *
90      * ...\system32\CatRoot\SYSMAST.cbk
91      * ...\system32\CatRoot\SYSMAST.cbd
92      * ...\system32\CatRoot\{GUID}\CATMAST.cbk
93      * ...\system32\CatRoot\{GUID}\CATMAST.cbd
94      *
95      */
96
97     /* All NULL */
98     SetLastError(0xdeadbeef);
99     ret = pCryptCATAdminAcquireContext(NULL, NULL, 0);
100     ok(!ret, "Expected failure\n");
101     ok(GetLastError() == ERROR_INVALID_PARAMETER,
102        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
103
104     /* NULL GUID */
105     SetLastError(0xdeadbeef);
106     ret = pCryptCATAdminAcquireContext(&hca, NULL, 0);
107     ok(ret, "Expected success\n");
108     ok(GetLastError() == ERROR_SUCCESS ||
109        GetLastError() == 0xdeadbeef /* Vista */,
110        "Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError());
111     ok(hca != NULL, "Expected a context handle, got NULL\n");
112
113     /* All NULL */
114     SetLastError(0xdeadbeef);
115     ret = pCryptCATAdminReleaseContext(NULL, 0);
116     todo_wine
117     {
118     ok(!ret, "Expected failure\n");
119     ok(GetLastError() == ERROR_INVALID_PARAMETER,
120        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
121     }
122
123     /* Proper release */
124     SetLastError(0xdeadbeef);
125     ret = pCryptCATAdminReleaseContext(hca, 0);
126     ok(ret, "Expected success\n");
127     ok(GetLastError() == 0xdeadbeef,
128        "Expected no change in last error, got %d\n", GetLastError());
129
130     /* Try to release a second time */
131     SetLastError(0xdeadbeef);
132     ret = pCryptCATAdminReleaseContext(hca, 0);
133     todo_wine
134     {
135     ok(!ret, "Expected failure\n");
136     ok(GetLastError() == ERROR_INVALID_PARAMETER,
137        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
138     }
139
140     /* NULL context handle and dummy GUID */
141     SetLastError(0xdeadbeef);
142     ret = pCryptCATAdminAcquireContext(NULL, &dummy, 0);
143     ok(!ret, "Expected failure\n");
144     ok(GetLastError() == ERROR_INVALID_PARAMETER,
145        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
146
147     /* Correct context handle and dummy GUID
148      *
149      * The tests run in the past unfortunately made sure that some directories were created.
150      *
151      * FIXME:
152      * We don't want to mess too much with these for now so we should delete only the ones
153      * that shouldn't be there like the deadbeef ones. We first have to figure out if it's
154      * save to remove files and directories from CatRoot/CatRoot2.
155      */
156
157     SetLastError(0xdeadbeef);
158     ret = pCryptCATAdminAcquireContext(&hca, &dummy, 0);
159     ok(ret, "Expected success\n");
160     ok(GetLastError() == ERROR_SUCCESS ||
161        GetLastError() == 0xdeadbeef /* Vista */,
162        "Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError());
163     ok(hca != NULL, "Expected a context handle, got NULL\n");
164
165     GetWindowsDirectoryA(windir, MAX_PATH);
166     lstrcpyA(catroot, windir);
167     lstrcatA(catroot, "\\system32\\CatRoot");
168     lstrcpyA(catroot2, windir);
169     lstrcatA(catroot2, "\\system32\\CatRoot2");
170
171     attrs = GetFileAttributes(catroot);
172     /* On a clean Wine this will fail. When a native wintrust.dll was used in the past
173      * some tests will succeed.
174      */
175     todo_wine
176         ok(attrs != INVALID_FILE_ATTRIBUTES,
177             "Expected the CatRoot directory to exist\n");
178
179     /* Windows creates the GUID directory in capitals */
180     lstrcpyA(dummydir, catroot);
181     lstrcatA(dummydir, "\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}");
182     attrs = GetFileAttributes(dummydir);
183     todo_wine
184         ok(attrs != INVALID_FILE_ATTRIBUTES,
185             "Expected CatRoot\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF} directory to exist\n");
186
187     /* Only present on XP or higher. */
188     attrs = GetFileAttributes(catroot2);
189     if (attrs != INVALID_FILE_ATTRIBUTES)
190     {
191         lstrcpyA(dummydir, catroot2);
192         lstrcatA(dummydir, "\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}");
193         attrs = GetFileAttributes(dummydir);
194         ok(attrs != INVALID_FILE_ATTRIBUTES,
195             "Expected CatRoot2\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF} directory to exist\n");
196     }
197
198     ret = pCryptCATAdminReleaseContext(hca, 0);
199     ok(ret, "Expected success\n");
200
201     /* Correct context handle and GUID */
202     SetLastError(0xdeadbeef);
203     ret = pCryptCATAdminAcquireContext(&hca, &unknown, 0);
204     ok(ret, "Expected success\n");
205     ok(GetLastError() == ERROR_SUCCESS ||
206        GetLastError() == 0xdeadbeef /* Vista */,
207        "Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError());
208     ok(hca != NULL, "Expected a context handle, got NULL\n");
209
210     ret = pCryptCATAdminReleaseContext(hca, 0);
211     ok(ret, "Expected success\n");
212
213     /* Flags not equal to 0 */
214     SetLastError(0xdeadbeef);
215     ret = pCryptCATAdminAcquireContext(&hca, &unknown, 1);
216     ok(ret, "Expected success\n");
217     ok(GetLastError() == ERROR_SUCCESS ||
218        GetLastError() == 0xdeadbeef /* Vista */,
219        "Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError());
220     ok(hca != NULL, "Expected a context handle, got NULL\n");
221
222     ret = pCryptCATAdminReleaseContext(hca, 0);
223     ok(ret, "Expected success\n");
224 }
225
226 /* TODO: Check whether SHA-1 is the algorithm that's always used */
227 static void test_calchash(void)
228 {
229     BOOL ret;
230     HANDLE file;
231     DWORD hashsize = 0;
232     BYTE* hash;
233     BYTE expectedhash[20] = {0x3a,0xa1,0x19,0x08,0xec,0xa6,0x0d,0x2e,0x7e,0xcc,0x7a,0xca,0xf5,0xb8,0x2e,0x62,0x6a,0xda,0xf0,0x19};
234     CHAR temp[MAX_PATH];
235     DWORD written;
236
237     if (!pCryptCATAdminCalcHashFromFileHandle)
238     {
239         skip("CryptCATAdminCalcHashFromFileHandle is not available\n");
240         return;
241     }
242     
243     /* All NULL */
244     SetLastError(0xdeadbeef);
245     ret = pCryptCATAdminCalcHashFromFileHandle(NULL, NULL, NULL, 0);
246     todo_wine
247     {
248     ok(!ret, "Expected failure\n");
249     ok(GetLastError() == ERROR_INVALID_PARAMETER,
250        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
251     }
252
253     /* NULL filehandle, rest is legal */
254     SetLastError(0xdeadbeef);
255     ret = pCryptCATAdminCalcHashFromFileHandle(NULL, &hashsize, NULL, 0);
256     todo_wine
257     {
258     ok(!ret, "Expected failure\n");
259     ok(GetLastError() == ERROR_INVALID_PARAMETER,
260        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
261     }
262
263     /* Correct filehandle, rest is NULL */
264     file = CreateFileA(selfname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
265     SetLastError(0xdeadbeef);
266     ret = pCryptCATAdminCalcHashFromFileHandle(file, NULL, NULL, 0);
267     todo_wine
268     {
269     ok(!ret, "Expected failure\n");
270     ok(GetLastError() == ERROR_INVALID_PARAMETER,
271        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
272     }
273     CloseHandle(file);
274
275     /* All OK, but dwFlags set to 1 */
276     file = CreateFileA(selfname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
277     SetLastError(0xdeadbeef);
278     ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, NULL, 1);
279     todo_wine
280     {
281     ok(!ret, "Expected failure\n");
282     ok(GetLastError() == ERROR_INVALID_PARAMETER,
283        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
284     }
285     CloseHandle(file);
286
287     /* All OK, requesting the size of the hash */
288     file = CreateFileA(selfname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
289     SetLastError(0xdeadbeef);
290     ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, NULL, 0);
291     ok(ret, "Expected success\n");
292     todo_wine
293     {
294     ok(hashsize == 20," Expected a hash size of 20, got %d\n", hashsize);
295     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
296        "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
297     }
298     CloseHandle(file);
299
300     /* All OK, retrieve the hash
301      * Double the hash buffer to see what happens to the size parameter
302      */
303     file = CreateFileA(selfname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
304     hashsize *= 2;
305     hash = HeapAlloc(GetProcessHeap(), 0, hashsize);
306     SetLastError(0xdeadbeef);
307     ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, hash, 0);
308     ok(ret, "Expected success\n");
309     todo_wine
310     {
311     ok(hashsize == 20," Expected a hash size of 20, got %d\n", hashsize);
312     ok(GetLastError() == ERROR_SUCCESS,
313        "Expected ERROR_SUCCESS, got %d\n", GetLastError());
314     }
315     CloseHandle(file);
316     HeapFree(GetProcessHeap(), 0, hash);
317
318     /* Do the same test with a file created and filled by ourselves (and we thus
319      * have a known hash for).
320      */
321     GetTempFileNameA(CURR_DIR, "hsh", 0, temp); 
322     file = CreateFileA(temp, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
323     WriteFile(file, "Text in this file is needed to create a know hash", 49, &written, NULL);
324     CloseHandle(file);
325
326     /* All OK, first request the size and then retrieve the hash */
327     file = CreateFileA(temp, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
328     hashsize = 0;
329     pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, NULL, 0);
330     hash = HeapAlloc(GetProcessHeap(), 0, hashsize);
331     SetLastError(0xdeadbeef);
332     ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, hash, 0);
333     ok(ret, "Expected success\n");
334     todo_wine
335     {
336     ok(GetLastError() == ERROR_SUCCESS,
337        "Expected ERROR_SUCCESS, got %d\n", GetLastError());
338     ok(hashsize == sizeof(expectedhash) &&
339        !memcmp(hash, expectedhash, sizeof(expectedhash)),
340        "Hashes didn't match\n");
341     }
342     CloseHandle(file);
343
344     HeapFree(GetProcessHeap(), 0, hash);
345     DeleteFileA(temp);
346 }
347
348 START_TEST(crypt)
349 {
350     int myARGC;
351     char** myARGV;
352
353     InitFunctionPtrs();
354
355     myARGC = winetest_get_mainargs(&myARGV);
356     strcpy(selfname, myARGV[0]);
357
358     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
359    
360     test_context();
361     test_calchash();
362 }