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[] = {
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" },
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)
74 CRYPT_INTEGER_BLOB blob;
77 /* CryptEncodeObjectEx with NULL bufSize crashes..
78 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
81 /* check bogus encoding */
82 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
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
89 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
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());
104 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
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);
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());
123 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
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);
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());
147 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
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");
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());
170 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
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");
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 bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
193 /* CryptDecodeObjectEx with NULL bufSize crashes..
194 ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
195 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
197 /* check bogus encoding */
198 ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
199 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
200 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
201 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
202 /* check with NULL integer buffer */
203 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
205 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
206 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
207 /* check with a valid, but too large, integer */
208 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
209 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
210 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
211 "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
212 /* check with a DER-encoded string */
213 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
214 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
215 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
216 "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
217 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
219 /* When the output buffer is NULL, this always succeeds */
220 SetLastError(0xdeadbeef);
221 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
222 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
224 ok(ret && GetLastError() == NOERROR,
225 "Expected success and NOERROR, got %ld\n", GetLastError());
226 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
227 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
228 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
229 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
230 ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
232 ok(buf != NULL, "Expected allocated buffer\n");
235 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
236 ints[i].val, *(int *)buf);
240 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
242 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
243 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
245 ok(ret && GetLastError() == NOERROR,
246 "Expected success and NOERROR, got %ld\n", GetLastError());
247 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
248 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
249 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
250 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
251 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
252 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
254 ok(buf != NULL, "Expected allocated buffer\n");
257 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
259 ok(blob->cbData == strlen(bigInts[i].decoded),
260 "Expected len %d, got %ld\n", strlen(bigInts[i].decoded),
262 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
263 "Unexpected value\n");
267 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
269 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
270 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
272 ok(ret && GetLastError() == NOERROR,
273 "Expected success and NOERROR, got %ld\n", GetLastError());
274 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
275 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
276 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
277 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
278 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
279 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
281 ok(buf != NULL, "Expected allocated buffer\n");
284 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
286 ok(blob->cbData == strlen(bigUInts[i].val),
287 "Expected len %d, got %ld\n", strlen(bigUInts[i].val),
289 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
290 "Unexpected value\n");
294 /* Decode the value 1 with long-form length */
295 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
296 sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
297 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
300 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
303 /* Try to decode some bogus large items */
304 /* The buffer size is smaller than the encoded length, so this should fail
305 * with CRYPT_E_ASN1_EOD if it's being decoded.
306 * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
307 * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
308 * So this test unfortunately isn't useful.
309 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
310 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
311 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
312 "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
314 /* This will try to decode the buffer and overflow it, check that it's
317 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
318 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
319 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
320 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
323 /* These are always encoded unsigned, and aren't constrained to be any
326 static const struct encodedInt enums[] = {
327 { 1, "\x0a\x01\x01" },
328 { -128, "\x0a\x05\x00\xff\xff\xff\x80" },
331 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
334 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
335 szOID_CRL_REASON_CODE };
337 static void test_encodeEnumerated(DWORD dwEncoding)
341 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
343 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
349 ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
350 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
352 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
356 "Got unexpected type %d for enumerated (expected 0xa)\n",
358 ok(buf[1] == enums[j].encoded[1],
359 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
360 ok(!memcmp(buf + 1, enums[j].encoded + 1,
361 enums[j].encoded[1] + 1),
362 "Encoded value of 0x%08x didn't match expected\n",
370 static void test_decodeEnumerated(DWORD dwEncoding)
374 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
376 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
379 DWORD bufSize = sizeof(int);
382 ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
383 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
384 (BYTE *)&val, &bufSize);
385 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
386 ok(bufSize == sizeof(int),
387 "Got unexpected size %ld for enumerated (expected %d)\n",
388 bufSize, sizeof(int));
389 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
395 struct encodedFiletime
398 const BYTE *encodedTime;
401 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
402 const struct encodedFiletime *time)
409 ret = SystemTimeToFileTime(&time->sysTime, &ft);
410 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
411 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
412 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
413 /* years other than 1950-2050 are not allowed for encodings other than
414 * X509_CHOICE_OF_TIME.
416 if (structType == X509_CHOICE_OF_TIME ||
417 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
419 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
421 ok(buf != NULL, "Expected an allocated buffer\n");
424 ok(buf[0] == time->encodedTime[0],
425 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
427 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
428 time->encodedTime[1], bufSize);
429 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
430 "Got unexpected value for time encoding\n");
435 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
436 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
439 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
440 const struct encodedFiletime *time)
442 FILETIME ft1 = { 0 }, ft2 = { 0 };
443 DWORD size = sizeof(ft2);
446 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
447 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
448 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
449 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
450 /* years other than 1950-2050 are not allowed for encodings other than
451 * X509_CHOICE_OF_TIME.
453 if (structType == X509_CHOICE_OF_TIME ||
454 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
456 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
458 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
459 "Got unexpected value for time decoding\n");
462 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
463 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
466 static const struct encodedFiletime times[] = {
467 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
468 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
469 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
472 static void test_encodeFiletime(DWORD dwEncoding)
476 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
478 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
479 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
480 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
484 static void test_decodeFiletime(DWORD dwEncoding)
486 static const struct encodedFiletime otherTimes[] = {
487 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x13" "19450606161000.000Z" },
488 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
489 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, "\x18" "\x13" "19450606161000+0100" },
490 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, "\x18" "\x13" "19450606161000-0100" },
491 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, "\x18" "\x13" "19450606161000-0115" },
492 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, "\x18" "\x0a" "2145060616" },
493 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0a" "4506061610" },
494 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0b" "4506061610Z" },
495 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0d" "4506061610+01" },
496 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0d" "4506061610-01" },
497 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0f" "4506061610+0100" },
498 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0f" "4506061610-0100" },
500 /* An oddball case that succeeds in Windows, but doesn't seem correct
501 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
503 static const char *bogusTimes[] = {
504 /* oddly, this succeeds on Windows, with year 2765
505 "\x18" "\x0f" "21r50606161000Z",
507 "\x17" "\x08" "45060616",
508 "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
509 "\x18" "\x04" "2145",
510 "\x18" "\x08" "21450606",
513 FILETIME ft1 = { 0 }, ft2 = { 0 };
516 /* Check bogus length with non-NULL buffer */
517 ret = SystemTimeToFileTime(×[0].sysTime, &ft1);
518 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
520 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
521 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
522 ok(!ret && GetLastError() == ERROR_MORE_DATA,
523 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
525 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
527 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
528 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
529 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
531 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
533 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
534 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
535 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
537 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
540 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
541 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
542 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
543 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
553 static const char commonName[] = "Juan Lang";
554 static const char surName[] = "Lang";
555 static const char bogusIA5[] = "\x80";
556 static const char bogusPrintable[] = "~";
557 static const char bogusNumeric[] = "A";
558 static const struct EncodedName names[] = {
559 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
560 { sizeof(commonName), (BYTE *)commonName } },
561 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0aJuan Lang" },
562 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
563 { sizeof(commonName), (BYTE *)commonName } },
564 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x16\x0aJuan Lang" },
565 { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
566 { sizeof(surName), (BYTE *)surName } },
567 "\x30\x10\x31\x0e\x30\x0c\x06\x03\x55\x04\x04\x16\x05Lang" },
568 { { NULL, CERT_RDN_PRINTABLE_STRING,
569 { sizeof(commonName), (BYTE *)commonName } },
570 "\x30\x12\x31\x10\x30\x0e\x06\x00\x13\x0aJuan Lang" },
571 /* The following test isn't a very good one, because it doesn't encode any
572 * Japanese characters. I'm leaving it out for now.
573 { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
574 { sizeof(commonName), (BYTE *)commonName } },
575 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
577 /* The following tests succeed under Windows, but really should fail,
578 * they contain characters that are illegal for the encoding. I'm
579 * including them to justify my lazy encoding.
581 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
582 { sizeof(bogusIA5), (BYTE *)bogusIA5 } },
583 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x16\x02\x80" },
584 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
585 { sizeof(bogusPrintable), (BYTE *)bogusPrintable } },
586 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13\x02\x7e" },
587 { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
588 { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
589 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x12\x02\x41" },
592 static const BYTE emptyName[] = { 0x30, 0 };
593 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
594 static const BYTE twoRDNs[] = "\x30\x23\x31\x21\x30\x0c\x06\x03\x55\x04\x04"
595 "\x13\x05\x4c\x61\x6e\x67\x00\x30\x11\x06\x03\x55\x04\x03"
596 "\x13\x0a\x4a\x75\x61\x6e\x20\x4c\x61\x6e\x67";
598 static void test_encodeName(DWORD dwEncoding)
600 CERT_RDN_ATTR attrs[2];
607 /* Test with NULL pvStructInfo */
608 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
609 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
610 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
611 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
612 /* Test with empty CERT_NAME_INFO */
615 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
616 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
617 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
620 ok(!memcmp(buf, emptyName, sizeof(emptyName)),
621 "Got unexpected encoding for empty name\n");
624 /* Test with bogus CERT_RDN */
626 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
627 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
628 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
629 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
630 /* Test with empty CERT_RDN */
632 rdn.rgRDNAttr = NULL;
635 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
636 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
637 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
640 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
641 "Got unexpected encoding for empty RDN array\n");
644 /* Test with bogus attr array */
646 rdn.rgRDNAttr = NULL;
647 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
648 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
649 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
650 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
651 /* oddly, a bogus OID is accepted by Windows XP; not testing.
652 attrs[0].pszObjId = "bogus";
653 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
654 attrs[0].Value.cbData = sizeof(commonName);
655 attrs[0].Value.pbData = (BYTE *)commonName;
657 rdn.rgRDNAttr = attrs;
658 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
659 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
660 ok(!ret, "Expected failure, got success\n");
662 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
663 * the encoded attributes to be swapped.
665 attrs[0].pszObjId = szOID_COMMON_NAME;
666 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
667 attrs[0].Value.cbData = sizeof(commonName);
668 attrs[0].Value.pbData = (BYTE *)commonName;
669 attrs[1].pszObjId = szOID_SUR_NAME;
670 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
671 attrs[1].Value.cbData = sizeof(surName);
672 attrs[1].Value.pbData = (BYTE *)surName;
674 rdn.rgRDNAttr = attrs;
675 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
676 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
677 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
680 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
681 "Got unexpected encoding for two RDN array\n");
684 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
686 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
687 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
688 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
689 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
690 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
691 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
694 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
695 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
696 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
697 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
700 ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
701 names[i].encoded[1] + 2, size);
702 ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
703 "Got unexpected encoding\n");
709 static void compareNames(const CERT_NAME_INFO *expected,
710 const CERT_NAME_INFO *got)
712 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
713 expected->cRDN, got->cRDN);
716 ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
717 "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
718 got->rgRDN[0].cRDNAttr);
719 if (expected->rgRDN[0].cRDNAttr)
721 if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
722 strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
724 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
725 "Expected OID %s, got NULL\n",
726 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
727 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
728 ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
729 expected->rgRDN[0].rgRDNAttr[0].pszObjId),
730 "Got unexpected OID %s, expected %s\n",
731 got->rgRDN[0].rgRDNAttr[0].pszObjId,
732 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
734 ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
735 expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
736 "Unexpected data size, got %ld, expected %ld\n",
737 got->rgRDN[0].rgRDNAttr[0].Value.cbData,
738 expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
739 if (expected->rgRDN[0].rgRDNAttr[0].Value.pbData)
740 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
741 expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
742 expected->rgRDN[0].rgRDNAttr[0].Value.cbData),
743 "Unexpected value\n");
748 static void test_decodeName(DWORD dwEncoding)
755 CERT_NAME_INFO info = { 1, &rdn };
757 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
759 /* When the output buffer is NULL, this always succeeds */
760 SetLastError(0xdeadbeef);
761 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
762 names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
763 ok(ret && GetLastError() == NOERROR,
764 "Expected success and NOERROR, got %08lx\n", GetLastError());
765 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
766 names[i].encoded[1] + 2,
767 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
768 (BYTE *)&buf, &bufSize);
769 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
771 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
774 compareNames((CERT_NAME_INFO *)buf, &info);
778 /* test empty name */
780 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
782 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
783 (BYTE *)&buf, &bufSize);
784 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
785 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
786 * decoder works the same way, so only test the count.
790 ok(bufSize == sizeof(CERT_NAME_INFO),
791 "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
792 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
793 "Expected 0 RDNs in empty info, got %ld\n",
794 ((CERT_NAME_INFO *)buf)->cRDN);
799 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
801 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
802 (BYTE *)&buf, &bufSize);
803 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
806 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
808 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
809 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
810 "Got unexpected value for empty RDN\n");
813 /* test two RDN attrs */
815 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
817 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
818 (BYTE *)&buf, &bufSize);
819 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
822 CERT_RDN_ATTR attrs[] = {
823 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
825 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
826 (BYTE *)commonName } },
829 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
830 rdn.rgRDNAttr = attrs;
831 compareNames((CERT_NAME_INFO *)buf, &info);
842 static const struct encodedOctets octets[] = {
843 { "hi", "\x04\x02hi" },
844 { "somelong\xffstring", "\x04\x0fsomelong\xffstring" },
848 static void test_encodeOctets(DWORD dwEncoding)
850 CRYPT_DATA_BLOB blob;
853 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
859 blob.cbData = strlen(octets[i].val);
860 blob.pbData = (BYTE *)octets[i].val;
861 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
862 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
863 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
867 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
868 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
869 buf[1], octets[i].encoded[1]);
870 ok(!memcmp(buf + 1, octets[i].encoded + 1,
871 octets[i].encoded[1] + 1), "Got unexpected value\n");
877 static void test_decodeOctets(DWORD dwEncoding)
881 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
887 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
888 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
889 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
890 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
891 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
892 "Expected size >= %d, got %ld\n",
893 sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
894 ok(buf != NULL, "Expected allocated buffer\n");
897 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
900 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
901 "Unexpected value\n");
907 static const BYTE bytesToEncode[] = { 0xff, 0xff };
917 static const struct encodedBits bits[] = {
918 /* normal test cases */
919 { 0, "\x03\x03\x00\xff\xff", 2, "\xff\xff" },
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)
931 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
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());
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");
956 static void test_decodeBits(DWORD dwEncoding)
958 static const BYTE ber[] = "\x03\x02\x01\xff";
959 static const BYTE berDecoded = 0xfe;
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,
971 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
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,
983 if (blob->cbData && bits[i].cbDecoded)
984 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
985 "Unexpected value\n");
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());
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));
1007 ok(*blob->pbData == berDecoded, "Unexpected value\n");
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" },
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)
1035 /* First test with the simpler info2 */
1036 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1042 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1043 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1045 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1048 ok(bufSize == constraints2[i].encoded[1] + 2,
1049 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1051 ok(!memcmp(buf, constraints2[i].encoded,
1052 constraints2[i].encoded[1] + 2), "Unexpected value\n");
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" };
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());
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");
1085 /* Check with the order of encoded elements inverted */
1087 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1088 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
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());
1100 CERT_BASIC_CONSTRAINTS2_INFO *info =
1101 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1103 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
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;
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());
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");
1151 /* Change the type of the first element in the sequence, and give it
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());
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");
1169 static void test_decodeSequenceOfAny(DWORD dwEncoding)
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());
1180 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1183 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1184 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
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");
1196 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1197 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1199 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
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]),
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");
1217 struct encodedExtensions
1219 CERT_EXTENSIONS exts;
1220 const BYTE *encoded;
1223 static CERT_EXTENSION criticalExt =
1224 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
1225 static CERT_EXTENSION nonCriticalExt =
1226 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
1228 static const struct encodedExtensions exts[] = {
1229 { { 0, NULL }, "\x30\x00" },
1230 { { 1, &criticalExt }, "\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff"
1231 "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
1232 { { 1, &nonCriticalExt }, "\x30\x11\x30\x0f\x06\x03\x55\x1d\x13"
1233 "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
1236 static void test_encodeExtensions(DWORD dwEncoding)
1240 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1246 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1247 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1248 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1251 ok(bufSize == exts[i].encoded[1] + 2,
1252 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1253 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1254 "Unexpected value\n");
1260 static void test_decodeExtensions(DWORD dwEncoding)
1264 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1270 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1271 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1272 NULL, (BYTE *)&buf, &bufSize);
1273 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1276 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1279 ok(ext->cExtension == exts[i].exts.cExtension,
1280 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1282 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1284 ok(!strcmp(ext->rgExtension[j].pszObjId,
1285 exts[i].exts.rgExtension[j].pszObjId),
1286 "Expected OID %s, got %s\n",
1287 exts[i].exts.rgExtension[j].pszObjId,
1288 ext->rgExtension[j].pszObjId);
1289 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1290 exts[i].exts.rgExtension[j].Value.pbData,
1291 exts[i].exts.rgExtension[j].Value.cbData),
1292 "Unexpected value\n");
1299 /* MS encodes public key info with a NULL if the algorithm identifier's
1300 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
1301 * it encodes them by omitting the algorithm parameters. This latter approach
1302 * seems more correct, so accept either form.
1304 struct encodedPublicKey
1306 CERT_PUBLIC_KEY_INFO info;
1307 const BYTE *encoded;
1308 const BYTE *encodedNoNull;
1309 CERT_PUBLIC_KEY_INFO decoded;
1312 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1314 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1316 static const struct encodedPublicKey pubKeys[] = {
1317 /* with a bogus OID */
1318 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1319 "\x30\x0b\x30\x06\x06\x02\x2a\x03\x05\x00\x03\x01\x00",
1320 "\x30\x09\x30\x04\x06\x02\x2a\x03\x03\x01\x00",
1321 { { "1.2.3", { 2, "\x05\x00" } }, { 0, NULL, 0 } } },
1322 /* some normal keys */
1323 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1324 "\x30\x0f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x01\x00",
1325 "\x30\x0d\x30\x08\x06\x06\x2a\x86\x48\x86\xf7\x0d\x03\x01\x00",
1326 { { szOID_RSA, { 2, "\x05\x00" } }, { 0, NULL, 0 } } },
1327 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
1328 "\x30\x1f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x11\x00\x00\x01"
1329 "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1330 "\x30\x1d\x30\x08\x06\x06\x2a\x86\x48\x86\xf7\x0d\x03\x11\x00\x00\x01"
1331 "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1332 { { szOID_RSA, { 2, "\x05\x00" } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
1333 /* with add'l parameters--note they must be DER-encoded */
1334 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1335 (BYTE *)aKey, 0 } },
1336 "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01"
1337 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1339 "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01"
1340 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1342 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1343 (BYTE *)aKey, 0 } } },
1346 static void test_encodePublicKeyInfo(DWORD dwEncoding)
1350 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1356 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1357 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1359 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1362 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
1363 bufSize == pubKeys[i].encodedNoNull[1] + 2,
1364 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
1365 pubKeys[i].encodedNoNull[1] + 2, bufSize);
1366 if (bufSize == pubKeys[i].encoded[1] + 2)
1367 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
1368 "Unexpected value\n");
1369 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
1370 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
1371 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
1377 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
1378 const CERT_PUBLIC_KEY_INFO *got)
1380 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
1381 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
1382 got->Algorithm.pszObjId);
1383 ok(expected->Algorithm.Parameters.cbData ==
1384 got->Algorithm.Parameters.cbData,
1385 "Expected parameters of %ld bytes, got %ld\n",
1386 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
1387 if (expected->Algorithm.Parameters.cbData)
1388 ok(!memcmp(expected->Algorithm.Parameters.pbData,
1389 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
1390 "Unexpected algorithm parameters\n");
1391 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
1392 "Expected public key of %ld bytes, got %ld\n",
1393 expected->PublicKey.cbData, got->PublicKey.cbData);
1394 if (expected->PublicKey.cbData)
1395 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
1396 got->PublicKey.cbData), "Unexpected public key value\n");
1399 static void test_decodePublicKeyInfo(DWORD dwEncoding)
1401 static const BYTE bogusPubKeyInfo[] =
1402 "\x30\x22\x30\x0d\x06\x06\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x01\x01"
1403 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1410 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1412 /* The NULL form decodes to the decoded member */
1413 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1414 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1415 NULL, (BYTE *)&buf, &bufSize);
1416 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1419 comparePublicKeyInfo(&pubKeys[i].decoded,
1420 (CERT_PUBLIC_KEY_INFO *)buf);
1423 /* The non-NULL form decodes to the original */
1424 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1425 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
1426 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1427 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1430 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
1434 /* Test with bogus (not valid DER) parameters */
1435 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1436 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1437 NULL, (BYTE *)&buf, &bufSize);
1438 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1439 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1442 static const BYTE v1Cert[] = "\x30\x33\x02\x00\x30\x02\x06\x00\x30\x22\x18"
1443 "\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x18\x0f\x31"
1444 "\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07\x30\x02\x06"
1446 static const BYTE v2Cert[] = "\x30\x38\xa0\x03\x02\x01\x01\x02\x00\x30\x02\x06"
1447 "\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30"
1448 "\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30"
1449 "\x07\x30\x02\x06\x00\x03\x01\x00";
1450 static const BYTE v3Cert[] = "\x30\x38\xa0\x03\x02\x01\x02\x02\x00\x30\x02\x06"
1451 "\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30"
1452 "\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30"
1453 "\x07\x30\x02\x06\x00\x03\x01\x00";
1454 static const BYTE v1CertWithConstraints[] = "\x30\x4b\x02\x00\x30\x02\x06\x00"
1455 "\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a"
1456 "\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07"
1457 "\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01"
1458 "\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01";
1459 static const BYTE v1CertWithSerial[] = "\x30\x4c\x02\x01\x01\x30\x02\x06\x00"
1460 "\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a"
1461 "\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07"
1462 "\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01"
1463 "\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01";
1464 static const BYTE bigCert[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
1465 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e\x20\x4c"
1466 "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
1467 "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
1468 "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e"
1469 "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
1470 "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
1472 /* This is the encoded form of the printable string "Juan Lang" */
1473 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
1474 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
1475 0x61, 0x6e, 0x67, 0x00 };
1476 static const BYTE serialNum[] = { 0x01 };
1478 static void test_encodeCertToBeSigned(DWORD dwEncoding)
1483 CERT_INFO info = { 0 };
1485 /* Test with NULL pvStructInfo */
1486 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
1487 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1488 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1489 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1490 /* Test with a V1 cert */
1491 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1492 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1493 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1496 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
1497 v1Cert[1] + 2, size);
1498 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
1502 info.dwVersion = CERT_V2;
1503 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1504 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1505 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1508 ok(size == v2Cert[1] + 2, "Expected size %d, got %ld\n",
1509 v3Cert[1] + 2, size);
1510 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
1514 info.dwVersion = CERT_V3;
1515 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1516 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1517 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1520 ok(size == v3Cert[1] + 2, "Expected size %d, got %ld\n",
1521 v3Cert[1] + 2, size);
1522 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
1525 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
1526 * API doesn't prevent it)
1528 info.dwVersion = CERT_V1;
1529 info.cExtension = 1;
1530 info.rgExtension = &criticalExt;
1531 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1532 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1533 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1536 ok(size == v1CertWithConstraints[1] + 2, "Expected size %d, got %ld\n",
1537 v1CertWithConstraints[1] + 2, size);
1538 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
1541 /* test v1 cert with a serial number */
1542 info.SerialNumber.cbData = sizeof(serialNum);
1543 info.SerialNumber.pbData = (BYTE *)serialNum;
1544 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1545 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1548 ok(size == v1CertWithSerial[1] + 2, "Expected size %d, got %ld\n",
1549 v1CertWithSerial[1] + 2, size);
1550 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
1553 /* Test v1 cert with an issuer name, a subject name, and a serial number */
1554 info.Issuer.cbData = sizeof(encodedCommonName);
1555 info.Issuer.pbData = (BYTE *)encodedCommonName;
1556 info.Subject.cbData = sizeof(encodedCommonName);
1557 info.Subject.pbData = (BYTE *)encodedCommonName;
1558 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1559 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1562 ok(size == bigCert[1] + 2, "Expected size %d, got %ld\n",
1563 bigCert[1] + 2, size);
1564 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
1567 /* for now, I let more interesting tests be done for each subcomponent,
1568 * rather than retesting them all here.
1572 static void test_decodeCertToBeSigned(DWORD dwEncoding)
1574 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
1575 v1CertWithConstraints, v1CertWithSerial };
1580 /* Test with NULL pbEncoded */
1581 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
1582 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1583 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1584 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
1585 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
1586 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1587 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1588 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1589 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
1590 * minimum a cert must have a non-zero serial number, an issuer, and a
1593 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
1595 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
1596 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1597 (BYTE *)&buf, &size);
1598 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1599 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1601 /* Now check with serial number, subject and issuer specified */
1602 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
1603 bigCert[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1604 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1607 CERT_INFO *info = (CERT_INFO *)buf;
1609 ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
1610 sizeof(CERT_INFO), size);
1611 ok(info->SerialNumber.cbData == 1,
1612 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
1613 ok(*info->SerialNumber.pbData == *serialNum,
1614 "Expected serial number %d, got %d\n", *serialNum,
1615 *info->SerialNumber.pbData);
1616 ok(info->Issuer.cbData == sizeof(encodedCommonName),
1617 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
1618 info->Issuer.cbData);
1619 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
1620 "Unexpected issuer\n");
1621 ok(info->Subject.cbData == sizeof(encodedCommonName),
1622 "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
1623 info->Subject.cbData);
1624 ok(!memcmp(info->Subject.pbData, encodedCommonName,
1625 info->Subject.cbData), "Unexpected subject\n");
1630 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1633 static const BYTE signedBigCert[] = {
1634 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
1635 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
1636 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
1637 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1638 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
1639 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
1640 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
1641 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
1642 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
1643 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
1644 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1645 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
1647 static void test_encodeCert(DWORD dwEncoding)
1649 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
1650 * also that bigCert is a NULL-terminated string, so don't count its
1651 * last byte (otherwise the signed cert won't decode.)
1653 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert) - 1, (BYTE *)bigCert },
1654 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
1659 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
1660 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1661 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1664 ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
1665 sizeof(signedBigCert), bufSize);
1666 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
1671 static void test_decodeCert(DWORD dwEncoding)
1677 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
1678 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1679 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1682 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
1684 ok(info->ToBeSigned.cbData == sizeof(bigCert) - 1,
1685 "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert) - 1,
1686 info->ToBeSigned.cbData);
1687 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
1688 "Unexpected cert\n");
1689 ok(info->Signature.cbData == sizeof(hash),
1690 "Expected signature size %d, got %ld\n", sizeof(hash),
1691 info->Signature.cbData);
1692 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
1693 "Unexpected signature\n");
1698 static void test_registerOIDFunction(void)
1700 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
1703 /* oddly, this succeeds under WinXP; the function name key is merely
1704 * omitted. This may be a side effect of the registry code, I don't know.
1705 * I don't check it because I doubt anyone would depend on it.
1706 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
1707 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1709 /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
1710 * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
1712 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
1714 ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
1715 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
1716 "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
1717 /* This has no effect, but "succeeds" on XP */
1718 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
1719 "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
1720 ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
1721 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1722 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1723 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1724 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1725 "1.2.3.4.5.6.7.8.9.10");
1726 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1727 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
1728 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1729 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1730 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
1731 "1.2.3.4.5.6.7.8.9.10");
1732 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1733 /* This has no effect */
1734 ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
1735 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1736 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1737 /* Check with bogus encoding type: */
1738 ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
1739 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1740 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1741 /* This is written with value 3 verbatim. Thus, the encoding type isn't
1742 * (for now) treated as a mask.
1744 ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
1745 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1746 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1747 ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
1748 "1.2.3.4.5.6.7.8.9.10");
1749 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1754 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
1755 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
1758 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
1760 test_encodeInt(encodings[i]);
1761 test_decodeInt(encodings[i]);
1762 test_encodeEnumerated(encodings[i]);
1763 test_decodeEnumerated(encodings[i]);
1764 test_encodeFiletime(encodings[i]);
1765 test_decodeFiletime(encodings[i]);
1766 test_encodeName(encodings[i]);
1767 test_decodeName(encodings[i]);
1768 test_encodeOctets(encodings[i]);
1769 test_decodeOctets(encodings[i]);
1770 test_encodeBits(encodings[i]);
1771 test_decodeBits(encodings[i]);
1772 test_encodeBasicConstraints(encodings[i]);
1773 test_decodeBasicConstraints(encodings[i]);
1774 test_encodeSequenceOfAny(encodings[i]);
1775 test_decodeSequenceOfAny(encodings[i]);
1776 test_encodeExtensions(encodings[i]);
1777 test_decodeExtensions(encodings[i]);
1778 test_encodePublicKeyInfo(encodings[i]);
1779 test_decodePublicKeyInfo(encodings[i]);
1780 test_encodeCertToBeSigned(encodings[i]);
1781 test_decodeCertToBeSigned(encodings[i]);
1782 test_encodeCert(encodings[i]);
1783 test_decodeCert(encodings[i]);
1785 test_registerOIDFunction();