Use shell icon cache instead of an own IExtractIcon implementation.
[wine] / dlls / crypt32 / tests / encode.c
1 /*
2  * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
3  *
4  * Copyright 2005 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
26
27 #include "wine/test.h"
28
29 struct encodedInt
30 {
31     int val;
32     BYTE encoded[6];
33 };
34
35 static const struct encodedInt ints[] = {
36  { 1,          { 2, 1, 1 } },
37  { 127,        { 2, 1, 0x7f } },
38  { 128,        { 2, 2, 0x00, 0x80 } },
39  { 256,        { 2, 2, 0x01, 0x00 } },
40  { -128,       { 2, 1, 0x80 } },
41  { -129,       { 2, 2, 0xff, 0x7f } },
42  { 0xbaddf00d, { 2, 4, 0xba, 0xdd, 0xf0, 0x0d } },
43 };
44
45 static void test_encodeint(void)
46 {
47     DWORD bufSize = 0;
48     int i;
49     BOOL ret;
50
51     /* CryptEncodeObjectEx with NULL bufSize crashes..
52     ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
53      NULL);
54      */
55     /* check bogus encoding */
56     ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
57      &bufSize);
58     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
59      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
60     /* check with NULL integer buffer.  Windows XP incorrectly returns an
61      * NTSTATUS.
62      */
63     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_INTEGER, NULL, 0, NULL,
64      NULL, &bufSize);
65     ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
66      STATUS_ACCESS_VIOLATION), "Unexpected error code %ld\n", GetLastError());
67     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
68     {
69         BYTE *buf = NULL;
70
71         ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
72          X509_INTEGER, &ints[i].val, 0, NULL, NULL, &bufSize);
73         ok(ret || GetLastError() == ERROR_MORE_DATA,
74          "Expected success or ERROR_MORE_DATA, got %ld\n", GetLastError());
75         ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
76          X509_INTEGER, &ints[i].val, CRYPT_ENCODE_ALLOC_FLAG, NULL,
77          (BYTE *)&buf, &bufSize);
78         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
79         ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
80          buf[0]);
81         ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
82          "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
83         LocalFree(buf);
84     }
85 }
86
87 static void test_decodeint(void)
88 {
89     static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
90     static const char testStr[] = { 16, 4, 't', 'e', 's', 't' };
91     BYTE *buf = NULL;
92     DWORD bufSize = 0;
93     int i;
94     BOOL ret;
95
96     /* CryptDecodeObjectEx with NULL bufSize crashes..
97     ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded, 
98      ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
99      */
100     /* check bogus encoding */
101     ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded, 
102      ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
103     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
104      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
105     /* check with NULL integer buffer.  Windows XP returns an apparently random
106      * error code (0x01c567df).
107      */
108     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_INTEGER, NULL, 0, 0,
109      NULL, NULL, &bufSize);
110     ok(!ret, "Expected failure, got success\n");
111     /* check with a valid, but too large, integer */
112     ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
113      X509_INTEGER, bigInt, bigInt[1] + 2, CRYPT_ENCODE_ALLOC_FLAG, NULL,
114      (BYTE *)&buf, &bufSize);
115     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
116      "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
117     /* check with a DER-encoded string */
118     ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
119      X509_INTEGER, testStr, testStr[1] + 2, CRYPT_ENCODE_ALLOC_FLAG, NULL,
120      (BYTE *)&buf, &bufSize);
121     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
122      "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
123     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
124     {
125         /* WinXP succeeds rather than failing with ERROR_MORE_DATA */
126         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_INTEGER,
127          (BYTE *)&ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
128          &bufSize);
129         ok(ret || GetLastError() == ERROR_MORE_DATA,
130          "Expected success or ERROR_MORE_DATA, got %ld\n", GetLastError());
131         ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
132          X509_INTEGER, (BYTE *)&ints[i].encoded, ints[i].encoded[1] + 2,
133          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
134         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
135         ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
136          bufSize);
137         ok(buf != NULL, "Expected allocated buffer\n");
138         if (buf)
139         {
140             ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
141              ints[i].val, *(int *)buf);
142             LocalFree(buf);
143         }
144     }
145 }
146
147 struct encodedFiletime
148 {
149     SYSTEMTIME sysTime;
150     BYTE *encodedTime;
151 };
152
153 static void testTimeEncoding(LPCSTR encoding,
154  const struct encodedFiletime *time)
155 {
156     FILETIME ft = { 0 };
157     BYTE *buf = NULL;
158     DWORD bufSize = 0;
159     BOOL ret;
160
161     ret = SystemTimeToFileTime(&time->sysTime, &ft);
162     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
163     /* No test case, but both X509_ASN_ENCODING and PKCS_7_ASN_ENCODING have
164      * the same effect for time encodings.
165      */
166     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, encoding, &ft,
167      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
168     /* years other than 1950-2050 are not allowed for encodings other than
169      * X509_CHOICE_OF_TIME.
170      */
171     if (encoding == X509_CHOICE_OF_TIME ||
172      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
173     {
174         ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
175          GetLastError());
176         ok(buf != NULL, "Expected an allocated buffer\n");
177         if (buf)
178         {
179             ok(buf[0] == time->encodedTime[0],
180              "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
181              buf[0]);
182             ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
183              time->encodedTime[1], bufSize);
184             ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
185              "Got unexpected value for time encoding\n");
186             LocalFree(buf);
187         }
188     }
189     else
190         ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
191          "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
192 }
193
194 static void testTimeDecoding(LPCSTR encoding,
195  const struct encodedFiletime *time)
196 {
197     FILETIME ft1 = { 0 }, ft2 = { 0 };
198     DWORD size = sizeof(ft2);
199     BOOL ret;
200
201     ret = SystemTimeToFileTime(&time->sysTime, &ft1);
202     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
203     /* No test case, but both X509_ASN_ENCODING and PKCS_7_ASN_ENCODING have
204      * the same effect for time encodings.
205      */
206     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, encoding, time->encodedTime,
207      time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
208     /* years other than 1950-2050 are not allowed for encodings other than
209      * X509_CHOICE_OF_TIME.
210      */
211     if (encoding == X509_CHOICE_OF_TIME ||
212      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
213     {
214         ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
215          GetLastError());
216         ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
217          "Got unexpected value for time decoding\n");
218     }
219     else
220         ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
221          "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
222 }
223
224 static const struct encodedFiletime times[] = {
225  { { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
226  { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
227  { { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
228 };
229
230 static void test_encodeFiletime(void)
231 {
232     DWORD i;
233
234     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
235     {
236         testTimeEncoding(X509_CHOICE_OF_TIME, &times[i]);
237         testTimeEncoding(PKCS_UTC_TIME, &times[i]);
238         testTimeEncoding(szOID_RSA_signingTime, &times[i]);
239     }
240 }
241
242 static void test_decodeFiletime(void)
243 {
244     static const struct encodedFiletime otherTimes[] = {
245      { { 1945, 6, 1, 6, 16, 10, 0, 0 },   "\x18" "\x13" "19450606161000.000Z" },
246      { { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
247      { { 1945, 6, 1, 6, 17, 10, 0, 0 },   "\x18" "\x13" "19450606161000+0100" },
248      { { 1945, 6, 1, 6, 15, 10, 0, 0 },   "\x18" "\x13" "19450606161000-0100" },
249      { { 1945, 6, 1, 6, 14, 55, 0, 0 },   "\x18" "\x13" "19450606161000-0115" },
250      { { 2145, 6, 1, 6, 16,  0, 0, 0 },   "\x18" "\x0a" "2145060616" },
251      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   "\x17" "\x0a" "4506061610" },
252     };
253     /* An oddball case that succeeds in Windows, but doesn't seem correct
254      { { 2145, 6, 1, 2, 11, 31, 0, 0 },   "\x18" "\x13" "21450606161000-9999" },
255      */
256     static const char *bogusTimes[] = {
257      /* oddly, this succeeds on Windows, with year 2765
258      "\x18" "\x0f" "21r50606161000Z",
259       */
260      "\x17" "\x08" "45060616",
261      "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
262      "\x18" "\x04" "2145",
263      "\x18" "\x08" "21450606",
264     };
265     DWORD i;
266
267     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
268     {
269         testTimeDecoding(X509_CHOICE_OF_TIME, &times[i]);
270         testTimeDecoding(PKCS_UTC_TIME, &times[i]);
271         testTimeDecoding(szOID_RSA_signingTime, &times[i]);
272     }
273     for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
274     {
275         testTimeDecoding(X509_CHOICE_OF_TIME, &otherTimes[i]);
276         testTimeDecoding(PKCS_UTC_TIME, &otherTimes[i]);
277         testTimeDecoding(szOID_RSA_signingTime, &otherTimes[i]);
278     }
279     for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
280     {
281         FILETIME ft;
282         SYSTEMTIME sysTime;
283         DWORD size = sizeof(ft);
284         BOOL ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
285          bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft, &size);
286
287         if (ret)
288         {
289             ret = FileTimeToSystemTime(&ft, &sysTime);
290             printf("%02d %02d %04d %02d:%02d.%02d\n", sysTime.wMonth,
291              sysTime.wDay, sysTime.wYear, sysTime.wHour, sysTime.wMinute,
292              sysTime.wSecond);
293         }
294         ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
295          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
296     }
297 }
298
299 static void test_registerOIDFunction(void)
300 {
301     static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
302     BOOL ret;
303
304     /* oddly, this succeeds under WinXP; the function name key is merely
305      * omitted.  This may be a side effect of the registry code, I don't know.
306      * I don't check it because I doubt anyone would depend on it.
307     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
308      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
309      */
310     /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
311      * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
312      */
313     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
314      NULL);
315     ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
316      HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
317      "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
318     /* This has no effect, but "succeeds" on XP */
319     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
320      "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
321     ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
322     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
323      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
324     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
325     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
326      "1.2.3.4.5.6.7.8.9.10");
327     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
328     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
329      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
330     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
331     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
332      "1.2.3.4.5.6.7.8.9.10");
333     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
334     /* This has no effect */
335     ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
336      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
337     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
338     /* Check with bogus encoding type: */
339     ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
340      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
341     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
342     /* This is written with value 3 verbatim.  Thus, the encoding type isn't
343      * (for now) treated as a mask.
344      */
345     ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
346      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
347     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
348     ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
349      "1.2.3.4.5.6.7.8.9.10");
350     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
351 }
352
353 START_TEST(encode)
354 {
355     test_encodeint();
356     test_decodeint();
357     test_encodeFiletime();
358     test_decodeFiletime();
359     test_registerOIDFunction();
360 }