- fix decoding of long-form data lengths
[wine/wine-kai.git] / dlls / crypt32 / tests / encode.c
blobd9c671a51089f922f4869a70be388ceeaf87a3a3
1 /*
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
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
27 #include "wine/test.h"
29 struct encodedInt
31 int val;
32 const BYTE *encoded;
35 static const struct encodedInt ints[] = {
36 { 1, "\x02\x01\x01" },
37 { 127, "\x02\x01\x7f" },
38 { 128, "\x02\x02\x00\x80" },
39 { 256, "\x02\x02\x01\x00" },
40 { -128, "\x02\x01\x80" },
41 { -129, "\x02\x02\xff\x7f" },
42 { 0xbaddf00d, "\x02\x04\xba\xdd\xf0\x0d" },
45 struct encodedBigInt
47 const BYTE *val;
48 const BYTE *encoded;
49 const BYTE *decoded;
52 static const struct encodedBigInt bigInts[] = {
53 { "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08",
54 "\x02\x0a\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff",
55 "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08" },
56 { "\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff\xff",
57 "\x02\x09\xff\x01\x02\x03\x04\x05\x06\x07\x08",
58 "\x08\x07\x06\x05\x04\x03\x02\x01\xff" },
61 /* Decoded is the same as original, so don't bother storing a separate copy */
62 static const struct encodedBigInt bigUInts[] = {
63 { "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08",
64 "\x02\x0a\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff", NULL },
65 { "\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff\xff",
66 "\x02\x0c\x00\xff\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08", NULL },
69 static void test_encodeInt(DWORD dwEncoding)
71 DWORD bufSize = 0;
72 int i;
73 BOOL ret;
74 CRYPT_INTEGER_BLOB blob;
75 BYTE *buf = NULL;
77 /* CryptEncodeObjectEx with NULL bufSize crashes..
78 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
79 NULL);
81 /* check bogus encoding */
82 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
83 &bufSize);
84 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
85 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
86 /* check with NULL integer buffer. Windows XP incorrectly returns an
87 * NTSTATUS.
89 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
90 &bufSize);
91 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
92 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
93 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
95 /* encode as normal integer */
96 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
97 NULL, NULL, &bufSize);
98 ok(ret, "Expected success, got %ld\n", GetLastError());
99 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
100 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
101 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
102 if (buf)
104 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
105 buf[0]);
106 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
107 buf[1], ints[i].encoded[1]);
108 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
109 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
110 LocalFree(buf);
112 /* encode as multibyte integer */
113 blob.cbData = sizeof(ints[i].val);
114 blob.pbData = (BYTE *)&ints[i].val;
115 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
116 0, NULL, NULL, &bufSize);
117 ok(ret, "Expected success, got %ld\n", GetLastError());
118 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
119 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
120 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
121 if (buf)
123 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
124 buf[0]);
125 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
126 buf[1], ints[i].encoded[1]);
127 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
128 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
129 LocalFree(buf);
132 /* encode a couple bigger ints, just to show it's little-endian and leading
133 * sign bytes are dropped
135 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
137 blob.cbData = strlen(bigInts[i].val);
138 blob.pbData = (BYTE *)bigInts[i].val;
139 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
140 0, NULL, NULL, &bufSize);
141 ok(ret, "Expected success, got %ld\n", GetLastError());
142 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
143 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
144 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
145 if (buf)
147 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
148 buf[0]);
149 ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
150 buf[1], bigInts[i].encoded[1]);
151 ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
152 bigInts[i].encoded[1] + 1),
153 "Encoded value didn't match expected\n");
154 LocalFree(buf);
157 /* and, encode some uints */
158 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
160 blob.cbData = strlen(bigUInts[i].val);
161 blob.pbData = (BYTE *)bigUInts[i].val;
162 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
163 0, NULL, NULL, &bufSize);
164 ok(ret, "Expected success, got %ld\n", GetLastError());
165 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
166 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
167 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
168 if (buf)
170 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
171 buf[0]);
172 ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
173 buf[1], bigUInts[i].encoded[1]);
174 ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
175 bigUInts[i].encoded[1] + 1),
176 "Encoded value didn't match expected\n");
177 LocalFree(buf);
182 static void test_decodeInt(DWORD dwEncoding)
184 static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
185 static const char testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
186 static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
187 static const BYTE tooBig[] = { 0x02, 0x84, 0xff, 0xff, 0xff, 0xff };
188 static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
189 BYTE *buf = NULL;
190 DWORD bufSize = 0;
191 int i;
192 BOOL ret;
194 /* CryptDecodeObjectEx with NULL bufSize crashes..
195 ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
196 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
198 /* check bogus encoding */
199 ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
200 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
201 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
202 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
203 /* check with NULL integer buffer */
204 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
205 &bufSize);
206 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
207 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
208 /* check with a valid, but too large, integer */
209 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
210 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
211 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
212 "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
213 /* check with a DER-encoded string */
214 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
215 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
216 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
217 "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
218 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
220 /* When the output buffer is NULL, this always succeeds */
221 SetLastError(0xdeadbeef);
222 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
223 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
224 &bufSize);
225 ok(ret && GetLastError() == NOERROR,
226 "Expected success and NOERROR, got %ld\n", GetLastError());
227 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
228 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
229 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
230 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
231 ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
232 bufSize);
233 ok(buf != NULL, "Expected allocated buffer\n");
234 if (buf)
236 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
237 ints[i].val, *(int *)buf);
238 LocalFree(buf);
241 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
243 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
244 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
245 &bufSize);
246 ok(ret && GetLastError() == NOERROR,
247 "Expected success and NOERROR, got %ld\n", GetLastError());
248 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
249 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
250 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
251 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
252 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
253 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
254 bufSize);
255 ok(buf != NULL, "Expected allocated buffer\n");
256 if (buf)
258 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
260 ok(blob->cbData == strlen(bigInts[i].decoded),
261 "Expected len %d, got %ld\n", strlen(bigInts[i].decoded),
262 blob->cbData);
263 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
264 "Unexpected value\n");
265 LocalFree(buf);
268 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
270 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
271 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
272 &bufSize);
273 ok(ret && GetLastError() == NOERROR,
274 "Expected success and NOERROR, got %ld\n", GetLastError());
275 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
276 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
277 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
278 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
279 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
280 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
281 bufSize);
282 ok(buf != NULL, "Expected allocated buffer\n");
283 if (buf)
285 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
287 ok(blob->cbData == strlen(bigUInts[i].val),
288 "Expected len %d, got %ld\n", strlen(bigUInts[i].val),
289 blob->cbData);
290 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
291 "Unexpected value\n");
292 LocalFree(buf);
295 /* Decode the value 1 with long-form length */
296 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
297 sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
298 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
299 if (buf)
301 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
302 LocalFree(buf);
304 /* Try to decode some bogus large items */
305 /* The buffer size is smaller than the encoded length, so this should fail
306 * with CRYPT_E_ASN1_EOD if it's being decoded. It's failing with
307 * CRYPT_E_ASN1_LARGE, meaning there's a limit on the size decoded.
308 * The magic limit under XP seems to be 0x061a8000 bytes--more than this
309 * fails with CRYPT_E_ASN1_LARGE.
311 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
312 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
313 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
314 "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
315 /* This will try to decode the buffer and overflow it, check that it's
316 * caught.
318 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
319 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
320 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
321 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
324 /* These are always encoded unsigned, and aren't constrained to be any
325 * particular value
327 static const struct encodedInt enums[] = {
328 { 1, "\x0a\x01\x01" },
329 { -128, "\x0a\x05\x00\xff\xff\xff\x80" },
332 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
333 * X509_ENUMERATED.
335 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
336 szOID_CRL_REASON_CODE };
338 static void test_encodeEnumerated(DWORD dwEncoding)
340 DWORD i, j;
342 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
344 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
346 BOOL ret;
347 BYTE *buf = NULL;
348 DWORD bufSize = 0;
350 ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
351 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
352 &bufSize);
353 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
354 if (buf)
356 ok(buf[0] == 0xa,
357 "Got unexpected type %d for enumerated (expected 0xa)\n",
358 buf[0]);
359 ok(buf[1] == enums[j].encoded[1],
360 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
361 ok(!memcmp(buf + 1, enums[j].encoded + 1,
362 enums[j].encoded[1] + 1),
363 "Encoded value of 0x%08x didn't match expected\n",
364 enums[j].val);
365 LocalFree(buf);
371 static void test_decodeEnumerated(DWORD dwEncoding)
373 DWORD i, j;
375 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
377 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
379 BOOL ret;
380 DWORD bufSize = sizeof(int);
381 int val;
383 ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
384 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
385 (BYTE *)&val, &bufSize);
386 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
387 ok(bufSize == sizeof(int),
388 "Got unexpected size %ld for enumerated (expected %d)\n",
389 bufSize, sizeof(int));
390 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
391 val, enums[j].val);
396 struct encodedFiletime
398 SYSTEMTIME sysTime;
399 const BYTE *encodedTime;
402 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
403 const struct encodedFiletime *time)
405 FILETIME ft = { 0 };
406 BYTE *buf = NULL;
407 DWORD bufSize = 0;
408 BOOL ret;
410 ret = SystemTimeToFileTime(&time->sysTime, &ft);
411 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
412 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
413 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
414 /* years other than 1950-2050 are not allowed for encodings other than
415 * X509_CHOICE_OF_TIME.
417 if (structType == X509_CHOICE_OF_TIME ||
418 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
420 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
421 GetLastError());
422 ok(buf != NULL, "Expected an allocated buffer\n");
423 if (buf)
425 ok(buf[0] == time->encodedTime[0],
426 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
427 buf[0]);
428 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
429 time->encodedTime[1], bufSize);
430 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
431 "Got unexpected value for time encoding\n");
432 LocalFree(buf);
435 else
436 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
437 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
440 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
441 const struct encodedFiletime *time)
443 FILETIME ft1 = { 0 }, ft2 = { 0 };
444 DWORD size = sizeof(ft2);
445 BOOL ret;
447 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
448 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
449 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
450 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
451 /* years other than 1950-2050 are not allowed for encodings other than
452 * X509_CHOICE_OF_TIME.
454 if (structType == X509_CHOICE_OF_TIME ||
455 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
457 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
458 GetLastError());
459 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
460 "Got unexpected value for time decoding\n");
462 else
463 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
464 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
467 static const struct encodedFiletime times[] = {
468 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
469 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
470 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
473 static void test_encodeFiletime(DWORD dwEncoding)
475 DWORD i;
477 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
479 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
480 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
481 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
485 static void test_decodeFiletime(DWORD dwEncoding)
487 static const struct encodedFiletime otherTimes[] = {
488 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x13" "19450606161000.000Z" },
489 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
490 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, "\x18" "\x13" "19450606161000+0100" },
491 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, "\x18" "\x13" "19450606161000-0100" },
492 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, "\x18" "\x13" "19450606161000-0115" },
493 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, "\x18" "\x0a" "2145060616" },
494 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0a" "4506061610" },
495 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0b" "4506061610Z" },
496 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0d" "4506061610+01" },
497 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0d" "4506061610-01" },
498 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0f" "4506061610+0100" },
499 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0f" "4506061610-0100" },
501 /* An oddball case that succeeds in Windows, but doesn't seem correct
502 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
504 static const char *bogusTimes[] = {
505 /* oddly, this succeeds on Windows, with year 2765
506 "\x18" "\x0f" "21r50606161000Z",
508 "\x17" "\x08" "45060616",
509 "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
510 "\x18" "\x04" "2145",
511 "\x18" "\x08" "21450606",
513 DWORD i, size;
514 FILETIME ft1 = { 0 }, ft2 = { 0 };
515 BOOL ret;
517 /* Check bogus length with non-NULL buffer */
518 ret = SystemTimeToFileTime(&times[0].sysTime, &ft1);
519 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
520 size = 1;
521 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
522 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
523 ok(!ret && GetLastError() == ERROR_MORE_DATA,
524 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
525 /* Normal tests */
526 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
528 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
529 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
530 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
532 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
534 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
535 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
536 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
538 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
540 size = sizeof(ft1);
541 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
542 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
543 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
544 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
548 struct EncodedName
550 CERT_RDN_ATTR attr;
551 const BYTE *encoded;
554 static const char commonName[] = "Juan Lang";
555 static const char surName[] = "Lang";
556 static const char bogusIA5[] = "\x80";
557 static const char bogusPrintable[] = "~";
558 static const char bogusNumeric[] = "A";
559 static const struct EncodedName names[] = {
560 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
561 { sizeof(commonName), (BYTE *)commonName } },
562 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0aJuan Lang" },
563 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
564 { sizeof(commonName), (BYTE *)commonName } },
565 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x16\x0aJuan Lang" },
566 { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
567 { sizeof(surName), (BYTE *)surName } },
568 "\x30\x10\x31\x0e\x30\x0c\x06\x03\x55\x04\x04\x16\x05Lang" },
569 { { NULL, CERT_RDN_PRINTABLE_STRING,
570 { sizeof(commonName), (BYTE *)commonName } },
571 "\x30\x12\x31\x10\x30\x0e\x06\x00\x13\x0aJuan Lang" },
572 /* The following test isn't a very good one, because it doesn't encode any
573 * Japanese characters. I'm leaving it out for now.
574 { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
575 { sizeof(commonName), (BYTE *)commonName } },
576 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
578 /* The following tests succeed under Windows, but really should fail,
579 * they contain characters that are illegal for the encoding. I'm
580 * including them to justify my lazy encoding.
582 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
583 { sizeof(bogusIA5), (BYTE *)bogusIA5 } },
584 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x16\x02\x80" },
585 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
586 { sizeof(bogusPrintable), (BYTE *)bogusPrintable } },
587 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13\x02\x7e" },
588 { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
589 { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
590 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x12\x02\x41" },
593 static const BYTE emptyName[] = { 0x30, 0 };
594 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
595 static const BYTE twoRDNs[] = "\x30\x23\x31\x21\x30\x0c\x06\x03\x55\x04\x04"
596 "\x13\x05\x4c\x61\x6e\x67\x00\x30\x11\x06\x03\x55\x04\x03"
597 "\x13\x0a\x4a\x75\x61\x6e\x20\x4c\x61\x6e\x67";
599 static void test_encodeName(DWORD dwEncoding)
601 CERT_RDN_ATTR attrs[2];
602 CERT_RDN rdn;
603 CERT_NAME_INFO info;
604 BYTE *buf = NULL;
605 DWORD size = 0, i;
606 BOOL ret;
608 /* Test with NULL pvStructInfo */
609 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
610 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
611 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
612 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
613 /* Test with empty CERT_NAME_INFO */
614 info.cRDN = 0;
615 info.rgRDN = NULL;
616 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
617 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
618 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
619 if (buf)
621 ok(!memcmp(buf, emptyName, sizeof(emptyName)),
622 "Got unexpected encoding for empty name\n");
623 LocalFree(buf);
625 /* Test with bogus CERT_RDN */
626 info.cRDN = 1;
627 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
628 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
629 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
630 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
631 /* Test with empty CERT_RDN */
632 rdn.cRDNAttr = 0;
633 rdn.rgRDNAttr = NULL;
634 info.cRDN = 1;
635 info.rgRDN = &rdn;
636 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
637 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
638 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
639 if (buf)
641 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
642 "Got unexpected encoding for empty RDN array\n");
643 LocalFree(buf);
645 /* Test with bogus attr array */
646 rdn.cRDNAttr = 1;
647 rdn.rgRDNAttr = NULL;
648 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
649 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
650 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
651 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
652 /* oddly, a bogus OID is accepted by Windows XP; not testing.
653 attrs[0].pszObjId = "bogus";
654 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
655 attrs[0].Value.cbData = sizeof(commonName);
656 attrs[0].Value.pbData = (BYTE *)commonName;
657 rdn.cRDNAttr = 1;
658 rdn.rgRDNAttr = attrs;
659 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
660 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
661 ok(!ret, "Expected failure, got success\n");
663 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
664 * the encoded attributes to be swapped.
666 attrs[0].pszObjId = szOID_COMMON_NAME;
667 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
668 attrs[0].Value.cbData = sizeof(commonName);
669 attrs[0].Value.pbData = (BYTE *)commonName;
670 attrs[1].pszObjId = szOID_SUR_NAME;
671 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
672 attrs[1].Value.cbData = sizeof(surName);
673 attrs[1].Value.pbData = (BYTE *)surName;
674 rdn.cRDNAttr = 2;
675 rdn.rgRDNAttr = attrs;
676 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
677 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
678 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
679 if (buf)
681 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
682 "Got unexpected encoding for two RDN array\n");
683 LocalFree(buf);
685 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
686 rdn.cRDNAttr = 1;
687 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
688 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
689 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
690 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
691 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
692 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
694 rdn.cRDNAttr = 1;
695 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
696 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
697 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
698 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
699 if (buf)
701 ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
702 names[i].encoded[1] + 2, size);
703 ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
704 "Got unexpected encoding\n");
705 LocalFree(buf);
710 static void compareNames(const CERT_NAME_INFO *expected,
711 const CERT_NAME_INFO *got)
713 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
714 expected->cRDN, got->cRDN);
715 if (expected->cRDN)
717 ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
718 "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
719 got->rgRDN[0].cRDNAttr);
720 if (expected->rgRDN[0].cRDNAttr)
722 if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
723 strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
725 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
726 "Expected OID %s, got NULL\n",
727 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
728 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
729 ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
730 expected->rgRDN[0].rgRDNAttr[0].pszObjId),
731 "Got unexpected OID %s, expected %s\n",
732 got->rgRDN[0].rgRDNAttr[0].pszObjId,
733 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
735 ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
736 expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
737 "Unexpected data size, got %ld, expected %ld\n",
738 got->rgRDN[0].rgRDNAttr[0].Value.cbData,
739 expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
740 if (expected->rgRDN[0].rgRDNAttr[0].Value.pbData)
741 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
742 expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
743 expected->rgRDN[0].rgRDNAttr[0].Value.cbData),
744 "Unexpected value\n");
749 static void test_decodeName(DWORD dwEncoding)
751 int i;
752 BYTE *buf = NULL;
753 DWORD bufSize = 0;
754 BOOL ret;
755 CERT_RDN rdn;
756 CERT_NAME_INFO info = { 1, &rdn };
758 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
760 /* When the output buffer is NULL, this always succeeds */
761 SetLastError(0xdeadbeef);
762 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
763 names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
764 ok(ret && GetLastError() == NOERROR,
765 "Expected success and NOERROR, got %08lx\n", GetLastError());
766 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
767 names[i].encoded[1] + 2,
768 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
769 (BYTE *)&buf, &bufSize);
770 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
771 rdn.cRDNAttr = 1;
772 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
773 if (buf)
775 compareNames((CERT_NAME_INFO *)buf, &info);
776 LocalFree(buf);
779 /* test empty name */
780 bufSize = 0;
781 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
782 emptyName[1] + 2,
783 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
784 (BYTE *)&buf, &bufSize);
785 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
786 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
787 * decoder works the same way, so only test the count.
789 if (buf)
791 ok(bufSize == sizeof(CERT_NAME_INFO),
792 "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
793 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
794 "Expected 0 RDNs in empty info, got %ld\n",
795 ((CERT_NAME_INFO *)buf)->cRDN);
796 LocalFree(buf);
798 /* test empty RDN */
799 bufSize = 0;
800 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
801 emptyRDNs[1] + 2,
802 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
803 (BYTE *)&buf, &bufSize);
804 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
805 if (buf)
807 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
809 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
810 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
811 "Got unexpected value for empty RDN\n");
812 LocalFree(buf);
814 /* test two RDN attrs */
815 bufSize = 0;
816 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
817 twoRDNs[1] + 2,
818 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
819 (BYTE *)&buf, &bufSize);
820 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
821 if (buf)
823 CERT_RDN_ATTR attrs[] = {
824 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
825 (BYTE *)surName } },
826 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
827 (BYTE *)commonName } },
830 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
831 rdn.rgRDNAttr = attrs;
832 compareNames((CERT_NAME_INFO *)buf, &info);
833 LocalFree(buf);
837 struct encodedOctets
839 const BYTE *val;
840 const BYTE *encoded;
843 static const struct encodedOctets octets[] = {
844 { "hi", "\x04\x02hi" },
845 { "somelong\xffstring", "\x04\x0fsomelong\xffstring" },
846 { "", "\x04\x00" },
849 static void test_encodeOctets(DWORD dwEncoding)
851 CRYPT_DATA_BLOB blob;
852 DWORD i;
854 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
856 BYTE *buf = NULL;
857 BOOL ret;
858 DWORD bufSize = 0;
860 blob.cbData = strlen(octets[i].val);
861 blob.pbData = (BYTE *)octets[i].val;
862 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
863 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
864 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
865 if (buf)
867 ok(buf[0] == 4,
868 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
869 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
870 buf[1], octets[i].encoded[1]);
871 ok(!memcmp(buf + 1, octets[i].encoded + 1,
872 octets[i].encoded[1] + 1), "Got unexpected value\n");
873 LocalFree(buf);
878 static void test_decodeOctets(DWORD dwEncoding)
880 DWORD i;
882 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
884 BYTE *buf = NULL;
885 BOOL ret;
886 DWORD bufSize = 0;
888 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
889 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
890 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
891 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
892 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
893 "Expected size >= %d, got %ld\n",
894 sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
895 ok(buf != NULL, "Expected allocated buffer\n");
896 if (buf)
898 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
900 if (blob->cbData)
901 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
902 "Unexpected value\n");
903 LocalFree(buf);
908 static const BYTE bytesToEncode[] = { 0xff, 0xff };
910 struct encodedBits
912 DWORD cUnusedBits;
913 const BYTE *encoded;
914 DWORD cbDecoded;
915 const BYTE *decoded;
918 static const struct encodedBits bits[] = {
919 /* normal test case */
920 { 1, "\x03\x03\x01\xff\xfe", 2, "\xff\xfe" },
921 /* strange test case, showing cUnusedBits >= 8 is allowed */
922 { 9, "\x03\x02\x01\xfe", 1, "\xfe" },
923 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
924 { 17, "\x03\x01\x00", 0, NULL },
927 static void test_encodeBits(DWORD dwEncoding)
929 DWORD i;
931 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
933 CRYPT_BIT_BLOB blob;
934 BOOL ret;
935 BYTE *buf = NULL;
936 DWORD bufSize = 0;
938 blob.cbData = sizeof(bytesToEncode);
939 blob.pbData = (BYTE *)bytesToEncode;
940 blob.cUnusedBits = bits[i].cUnusedBits;
941 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
942 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
943 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
944 if (buf)
946 ok(bufSize == bits[i].encoded[1] + 2,
947 "Got unexpected size %ld, expected %d\n", bufSize,
948 bits[i].encoded[1] + 2);
949 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
950 "Unexpected value\n");
951 LocalFree(buf);
956 static void test_decodeBits(DWORD dwEncoding)
958 static const BYTE ber[] = "\x03\x02\x01\xff";
959 static const BYTE berDecoded = 0xfe;
960 DWORD i;
961 BOOL ret;
962 BYTE *buf = NULL;
963 DWORD bufSize = 0;
965 /* normal cases */
966 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
968 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
969 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
970 &bufSize);
971 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
972 if (buf)
974 CRYPT_BIT_BLOB *blob;
976 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
977 "Got unexpected size %ld, expected >= %ld\n", bufSize,
978 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
979 blob = (CRYPT_BIT_BLOB *)buf;
980 ok(blob->cbData == bits[i].cbDecoded,
981 "Got unexpected length %ld, expected %ld\n", blob->cbData,
982 bits[i].cbDecoded);
983 if (blob->cbData && bits[i].cbDecoded)
984 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
985 "Unexpected value\n");
986 LocalFree(buf);
989 /* special case: check that something that's valid in BER but not in DER
990 * decodes successfully
992 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
993 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
994 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
995 if (buf)
997 CRYPT_BIT_BLOB *blob;
999 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1000 "Got unexpected size %ld, expected >= %d\n", bufSize,
1001 sizeof(CRYPT_BIT_BLOB) + berDecoded);
1002 blob = (CRYPT_BIT_BLOB *)buf;
1003 ok(blob->cbData == sizeof(berDecoded),
1004 "Got unexpected length %ld, expected %d\n", blob->cbData,
1005 sizeof(berDecoded));
1006 if (blob->cbData)
1007 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1008 LocalFree(buf);
1012 struct Constraints2
1014 CERT_BASIC_CONSTRAINTS2_INFO info;
1015 const BYTE *encoded;
1018 static const struct Constraints2 constraints2[] = {
1019 /* empty constraints */
1020 { { FALSE, FALSE, 0}, "\x30\x00" },
1021 /* can be a CA */
1022 { { TRUE, FALSE, 0}, "\x30\x03\x01\x01\xff" },
1023 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1024 * but that's not the case
1026 { { FALSE, TRUE, 0}, "\x30\x03\x02\x01\x00" },
1027 /* can be a CA and has path length constraints set */
1028 { { TRUE, TRUE, 1}, "\x30\x06\x01\x01\xff\x02\x01\x01" },
1031 static void test_encodeBasicConstraints(DWORD dwEncoding)
1033 DWORD i;
1035 /* First test with the simpler info2 */
1036 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1038 BOOL ret;
1039 BYTE *buf = NULL;
1040 DWORD bufSize = 0;
1042 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1043 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1044 &bufSize);
1045 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1046 if (buf)
1048 ok(bufSize == constraints2[i].encoded[1] + 2,
1049 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1050 bufSize);
1051 ok(!memcmp(buf, constraints2[i].encoded,
1052 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1053 LocalFree(buf);
1058 static void test_decodeBasicConstraints(DWORD dwEncoding)
1060 static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
1061 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 },
1062 "\x30\x06\x01\x01\x01\x02\x01\x01" };
1063 DWORD i;
1064 BOOL ret;
1065 BYTE *buf = NULL;
1066 DWORD bufSize = 0;
1068 /* First test with simpler info2 */
1069 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1071 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1072 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1073 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1074 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1075 if (buf)
1077 CERT_BASIC_CONSTRAINTS2_INFO *info =
1078 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1080 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1081 "Unexpected value\n");
1082 LocalFree(buf);
1085 /* Check with the order of encoded elements inverted */
1086 buf = (PBYTE)1;
1087 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1088 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1089 &bufSize);
1090 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1091 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1092 ok(!buf, "Expected buf to be set to NULL\n");
1093 /* Check with a non-DER bool */
1094 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1095 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1096 (BYTE *)&buf, &bufSize);
1097 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1098 if (buf)
1100 CERT_BASIC_CONSTRAINTS2_INFO *info =
1101 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1103 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1104 LocalFree(buf);
1106 /* Check with a non-basic constraints value */
1107 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1108 names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1109 (BYTE *)&buf, &bufSize);
1110 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1111 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1114 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1115 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1116 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1118 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1119 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1120 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1121 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1123 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1125 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1126 CRYPT_SEQUENCE_OF_ANY seq;
1127 DWORD i;
1128 BOOL ret;
1129 BYTE *buf = NULL;
1130 DWORD bufSize = 0;
1132 /* Encode a homogenous sequence */
1133 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1135 blobs[i].cbData = ints[i].encoded[1] + 2;
1136 blobs[i].pbData = (BYTE *)ints[i].encoded;
1138 seq.cValue = sizeof(ints) / sizeof(ints[0]);
1139 seq.rgValue = blobs;
1141 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1142 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1143 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1144 if (buf)
1146 ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1147 sizeof(intSequence), bufSize);
1148 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1149 LocalFree(buf);
1151 /* Change the type of the first element in the sequence, and give it
1152 * another go
1154 blobs[0].cbData = times[0].encodedTime[1] + 2;
1155 blobs[0].pbData = (BYTE *)times[0].encodedTime;
1156 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1157 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1158 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1159 if (buf)
1161 ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1162 sizeof(mixedSequence), bufSize);
1163 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1164 "Unexpected value\n");
1165 LocalFree(buf);
1169 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1171 BOOL ret;
1172 BYTE *buf = NULL;
1173 DWORD bufSize = 0;
1175 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1176 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1177 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1178 if (buf)
1180 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1181 DWORD i;
1183 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1184 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1185 seq->cValue);
1186 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1188 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1189 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1190 seq->rgValue[i].cbData);
1191 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1192 ints[i].encoded[1] + 2), "Unexpected value\n");
1194 LocalFree(buf);
1196 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1197 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1198 &bufSize);
1199 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1200 if (buf)
1202 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1204 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1205 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1206 seq->cValue);
1207 /* Just check the first element since it's all that changed */
1208 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1209 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1210 seq->rgValue[0].cbData);
1211 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1212 times[0].encodedTime[1] + 2), "Unexpected value\n");
1213 LocalFree(buf);
1217 static void test_registerOIDFunction(void)
1219 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
1220 BOOL ret;
1222 /* oddly, this succeeds under WinXP; the function name key is merely
1223 * omitted. This may be a side effect of the registry code, I don't know.
1224 * I don't check it because I doubt anyone would depend on it.
1225 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
1226 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1228 /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
1229 * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
1231 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
1232 NULL);
1233 ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
1234 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
1235 "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
1236 /* This has no effect, but "succeeds" on XP */
1237 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
1238 "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
1239 ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
1240 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1241 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1242 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1243 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1244 "1.2.3.4.5.6.7.8.9.10");
1245 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1246 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
1247 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1248 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1249 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
1250 "1.2.3.4.5.6.7.8.9.10");
1251 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1252 /* This has no effect */
1253 ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
1254 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1255 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1256 /* Check with bogus encoding type: */
1257 ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
1258 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1259 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1260 /* This is written with value 3 verbatim. Thus, the encoding type isn't
1261 * (for now) treated as a mask.
1263 ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
1264 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1265 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1266 ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
1267 "1.2.3.4.5.6.7.8.9.10");
1268 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1271 START_TEST(encode)
1273 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
1274 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
1275 DWORD i;
1277 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
1279 test_encodeInt(encodings[i]);
1280 test_decodeInt(encodings[i]);
1281 test_encodeEnumerated(encodings[i]);
1282 test_decodeEnumerated(encodings[i]);
1283 test_encodeFiletime(encodings[i]);
1284 test_decodeFiletime(encodings[i]);
1285 test_encodeName(encodings[i]);
1286 test_decodeName(encodings[i]);
1287 test_encodeOctets(encodings[i]);
1288 test_decodeOctets(encodings[i]);
1289 test_encodeBits(encodings[i]);
1290 test_decodeBits(encodings[i]);
1291 test_encodeBasicConstraints(encodings[i]);
1292 test_decodeBasicConstraints(encodings[i]);
1293 test_encodeSequenceOfAny(encodings[i]);
1294 test_decodeSequenceOfAny(encodings[i]);
1296 test_registerOIDFunction();