2 * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
4 * Copyright 2005 Juan Lang
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.
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.
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
27 #include "wine/test.h"
35 static const struct encodedInt ints[] = {
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 } },
45 static void test_encodeint(void)
51 /* CryptEncodeObjectEx with NULL bufSize crashes..
52 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
55 /* check bogus encoding */
56 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
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
63 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_INTEGER, NULL, 0, NULL,
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++)
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",
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);
87 static void test_decodeint(void)
89 static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
90 static const char testStr[] = { 16, 4, 't', 'e', 's', 't' };
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);
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).
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++)
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,
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),
137 ok(buf != NULL, "Expected allocated buffer\n");
140 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
141 ints[i].val, *(int *)buf);
147 struct encodedFiletime
153 static void testTimeEncoding(LPCSTR encoding,
154 const struct encodedFiletime *time)
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.
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.
171 if (encoding == X509_CHOICE_OF_TIME ||
172 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
174 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
176 ok(buf != NULL, "Expected an allocated buffer\n");
179 ok(buf[0] == time->encodedTime[0],
180 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[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");
190 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
191 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
194 static void testTimeDecoding(LPCSTR encoding,
195 const struct encodedFiletime *time)
197 FILETIME ft1 = { 0 }, ft2 = { 0 };
198 DWORD size = sizeof(ft2);
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.
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.
211 if (encoding == X509_CHOICE_OF_TIME ||
212 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
214 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
216 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
217 "Got unexpected value for time decoding\n");
220 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
221 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
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" },
230 static void test_encodeFiletime(void)
234 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
236 testTimeEncoding(X509_CHOICE_OF_TIME, ×[i]);
237 testTimeEncoding(PKCS_UTC_TIME, ×[i]);
238 testTimeEncoding(szOID_RSA_signingTime, ×[i]);
242 static void test_decodeFiletime(void)
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" },
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" },
256 static const char *bogusTimes[] = {
257 /* oddly, this succeeds on Windows, with year 2765
258 "\x18" "\x0f" "21r50606161000Z",
260 "\x17" "\x08" "45060616",
261 "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
262 "\x18" "\x04" "2145",
263 "\x18" "\x08" "21450606",
267 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
269 testTimeDecoding(X509_CHOICE_OF_TIME, ×[i]);
270 testTimeDecoding(PKCS_UTC_TIME, ×[i]);
271 testTimeDecoding(szOID_RSA_signingTime, ×[i]);
273 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
275 testTimeDecoding(X509_CHOICE_OF_TIME, &otherTimes[i]);
276 testTimeDecoding(PKCS_UTC_TIME, &otherTimes[i]);
277 testTimeDecoding(szOID_RSA_signingTime, &otherTimes[i]);
279 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
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);
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,
294 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
295 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
299 static void test_registerOIDFunction(void)
301 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
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);
310 /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
311 * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
313 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
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.
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());
357 test_encodeFiletime();
358 test_decodeFiletime();
359 test_registerOIDFunction();