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);
836 static const BYTE emptyAltName[] = { 0x30, 0x00 };
837 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
838 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
839 'h','q','.','o','r','g',0 };
840 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
841 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
843 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
844 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
845 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
846 static const BYTE localhost[] = { 127, 0, 0, 1 };
847 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
850 static void printBytes(const char *hdr, const BYTE *pb, size_t cb)
854 printf("%s:\n", hdr);
855 for (i = 0; i < cb; i++)
856 printf("%02x ", pb[i]);
860 static void test_encodeAltName(DWORD dwEncoding)
862 static const WCHAR nihongo[] = { 0x226f, 0x575b, 0 };
863 CERT_ALT_NAME_INFO info = { 0 };
864 CERT_ALT_NAME_ENTRY entry = { 0 };
869 /* Test with empty info */
870 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
871 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
874 ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n",
875 sizeof(emptyAltName), size);
876 ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n");
879 /* Test with an empty entry */
881 info.rgAltEntry = &entry;
882 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
883 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
884 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
885 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
887 /* Test with an empty pointer */
888 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
889 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
890 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
893 ok(size == sizeof(emptyURL), "Expected size %d, got %ld\n",
894 sizeof(emptyURL), size);
895 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
898 /* Test with a real URL */
899 U(entry).pwszURL = (LPWSTR)url;
900 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
901 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
904 ok(size == sizeof(encodedURL), "Expected size %d, got %ld\n",
905 sizeof(encodedURL), size);
906 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
909 /* Now with the URL containing an invalid IA5 char */
910 U(entry).pwszURL = (LPWSTR)nihongo;
911 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
912 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
913 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
914 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
915 /* Now with the URL missing a scheme */
916 U(entry).pwszURL = (LPWSTR)dnsName;
917 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
918 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
919 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
922 /* This succeeds, but it shouldn't, so don't worry about conforming */
925 /* Now with a DNS name */
926 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
927 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
928 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
929 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
932 ok(size == sizeof(encodedDnsName), "Expected size %d, got %ld\n",
933 sizeof(encodedDnsName), size);
934 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
937 /* Test with an IP address */
938 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
939 U(entry).IPAddress.cbData = sizeof(localhost);
940 U(entry).IPAddress.pbData = (LPBYTE)localhost;
941 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
942 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
945 ok(size == sizeof(encodedIPAddr), "Expected size %d, got %ld\n",
946 sizeof(encodedIPAddr), size);
947 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
952 static void test_decodeAltName(DWORD dwEncoding)
954 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
956 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
961 CERT_ALT_NAME_INFO *info;
963 /* Test some bogus ones first */
964 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
965 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
966 NULL, (BYTE *)&buf, &bufSize);
967 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
968 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
969 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
970 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
972 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
973 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
974 /* Now expected cases */
975 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName,
976 emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
978 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
981 info = (CERT_ALT_NAME_INFO *)buf;
983 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
987 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
988 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
990 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
993 info = (CERT_ALT_NAME_INFO *)buf;
995 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
997 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
998 "Expected CERT_ALT_NAME_URL, got %ld\n",
999 info->rgAltEntry[0].dwAltNameChoice);
1000 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1001 "Expected empty URL\n");
1004 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1005 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1007 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1010 info = (CERT_ALT_NAME_INFO *)buf;
1012 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1014 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1015 "Expected CERT_ALT_NAME_URL, got %ld\n",
1016 info->rgAltEntry[0].dwAltNameChoice);
1017 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1020 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1021 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1023 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1026 info = (CERT_ALT_NAME_INFO *)buf;
1028 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1030 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1031 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1032 info->rgAltEntry[0].dwAltNameChoice);
1033 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1034 "Unexpected DNS name\n");
1037 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1038 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1040 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1043 info = (CERT_ALT_NAME_INFO *)buf;
1045 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1047 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1048 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1049 info->rgAltEntry[0].dwAltNameChoice);
1050 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1051 "Unexpected IP address length %ld\n",
1052 U(info->rgAltEntry[0]).IPAddress.cbData);
1053 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1054 sizeof(localhost)), "Unexpected IP address value\n");
1059 struct encodedOctets
1062 const BYTE *encoded;
1065 static const struct encodedOctets octets[] = {
1066 { "hi", "\x04\x02hi" },
1067 { "somelong\xffstring", "\x04\x0fsomelong\xffstring" },
1071 static void test_encodeOctets(DWORD dwEncoding)
1073 CRYPT_DATA_BLOB blob;
1076 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1082 blob.cbData = strlen(octets[i].val);
1083 blob.pbData = (BYTE *)octets[i].val;
1084 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1085 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1086 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1090 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1091 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1092 buf[1], octets[i].encoded[1]);
1093 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1094 octets[i].encoded[1] + 1), "Got unexpected value\n");
1100 static void test_decodeOctets(DWORD dwEncoding)
1104 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1110 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1111 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1112 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1113 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1114 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1115 "Expected size >= %d, got %ld\n",
1116 sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1117 ok(buf != NULL, "Expected allocated buffer\n");
1120 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1123 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1124 "Unexpected value\n");
1130 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1135 const BYTE *encoded;
1137 const BYTE *decoded;
1140 static const struct encodedBits bits[] = {
1141 /* normal test cases */
1142 { 0, "\x03\x03\x00\xff\xff", 2, "\xff\xff" },
1143 { 1, "\x03\x03\x01\xff\xfe", 2, "\xff\xfe" },
1144 /* strange test case, showing cUnusedBits >= 8 is allowed */
1145 { 9, "\x03\x02\x01\xfe", 1, "\xfe" },
1146 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1147 { 17, "\x03\x01\x00", 0, NULL },
1150 static void test_encodeBits(DWORD dwEncoding)
1154 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1156 CRYPT_BIT_BLOB blob;
1161 blob.cbData = sizeof(bytesToEncode);
1162 blob.pbData = (BYTE *)bytesToEncode;
1163 blob.cUnusedBits = bits[i].cUnusedBits;
1164 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1165 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1166 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1169 ok(bufSize == bits[i].encoded[1] + 2,
1170 "Got unexpected size %ld, expected %d\n", bufSize,
1171 bits[i].encoded[1] + 2);
1172 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1173 "Unexpected value\n");
1179 static void test_decodeBits(DWORD dwEncoding)
1181 static const BYTE ber[] = "\x03\x02\x01\xff";
1182 static const BYTE berDecoded = 0xfe;
1189 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1191 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1192 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1194 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1197 CRYPT_BIT_BLOB *blob;
1199 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1200 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1201 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1202 blob = (CRYPT_BIT_BLOB *)buf;
1203 ok(blob->cbData == bits[i].cbDecoded,
1204 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1206 if (blob->cbData && bits[i].cbDecoded)
1207 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1208 "Unexpected value\n");
1212 /* special case: check that something that's valid in BER but not in DER
1213 * decodes successfully
1215 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1216 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1217 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1220 CRYPT_BIT_BLOB *blob;
1222 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1223 "Got unexpected size %ld, expected >= %d\n", bufSize,
1224 sizeof(CRYPT_BIT_BLOB) + berDecoded);
1225 blob = (CRYPT_BIT_BLOB *)buf;
1226 ok(blob->cbData == sizeof(berDecoded),
1227 "Got unexpected length %ld, expected %d\n", blob->cbData,
1228 sizeof(berDecoded));
1230 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1237 CERT_BASIC_CONSTRAINTS2_INFO info;
1238 const BYTE *encoded;
1241 static const struct Constraints2 constraints2[] = {
1242 /* empty constraints */
1243 { { FALSE, FALSE, 0}, "\x30\x00" },
1245 { { TRUE, FALSE, 0}, "\x30\x03\x01\x01\xff" },
1246 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1247 * but that's not the case
1249 { { FALSE, TRUE, 0}, "\x30\x03\x02\x01\x00" },
1250 /* can be a CA and has path length constraints set */
1251 { { TRUE, TRUE, 1}, "\x30\x06\x01\x01\xff\x02\x01\x01" },
1254 static void test_encodeBasicConstraints(DWORD dwEncoding)
1258 /* First test with the simpler info2 */
1259 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1265 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1266 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1268 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1271 ok(bufSize == constraints2[i].encoded[1] + 2,
1272 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1274 ok(!memcmp(buf, constraints2[i].encoded,
1275 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1281 static void test_decodeBasicConstraints(DWORD dwEncoding)
1283 static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
1284 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 },
1285 "\x30\x06\x01\x01\x01\x02\x01\x01" };
1291 /* First test with simpler info2 */
1292 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1294 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1295 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1296 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1297 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1300 CERT_BASIC_CONSTRAINTS2_INFO *info =
1301 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1303 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1304 "Unexpected value\n");
1308 /* Check with the order of encoded elements inverted */
1310 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1311 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1313 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1314 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1315 ok(!buf, "Expected buf to be set to NULL\n");
1316 /* Check with a non-DER bool */
1317 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1318 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1319 (BYTE *)&buf, &bufSize);
1320 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1323 CERT_BASIC_CONSTRAINTS2_INFO *info =
1324 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1326 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1329 /* Check with a non-basic constraints value */
1330 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1331 names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1332 (BYTE *)&buf, &bufSize);
1333 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1334 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1337 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1338 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1339 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1341 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1342 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1343 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1344 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1346 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1348 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1349 CRYPT_SEQUENCE_OF_ANY seq;
1355 /* Encode a homogenous sequence */
1356 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1358 blobs[i].cbData = ints[i].encoded[1] + 2;
1359 blobs[i].pbData = (BYTE *)ints[i].encoded;
1361 seq.cValue = sizeof(ints) / sizeof(ints[0]);
1362 seq.rgValue = blobs;
1364 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1365 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1366 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1369 ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1370 sizeof(intSequence), bufSize);
1371 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1374 /* Change the type of the first element in the sequence, and give it
1377 blobs[0].cbData = times[0].encodedTime[1] + 2;
1378 blobs[0].pbData = (BYTE *)times[0].encodedTime;
1379 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1380 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1381 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1384 ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1385 sizeof(mixedSequence), bufSize);
1386 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1387 "Unexpected value\n");
1392 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1398 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1399 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1400 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1403 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1406 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1407 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1409 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1411 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1412 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1413 seq->rgValue[i].cbData);
1414 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1415 ints[i].encoded[1] + 2), "Unexpected value\n");
1419 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1420 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1422 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1425 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1427 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1428 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1430 /* Just check the first element since it's all that changed */
1431 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1432 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1433 seq->rgValue[0].cbData);
1434 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1435 times[0].encodedTime[1] + 2), "Unexpected value\n");
1440 struct encodedExtensions
1442 CERT_EXTENSIONS exts;
1443 const BYTE *encoded;
1446 static CERT_EXTENSION criticalExt =
1447 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
1448 static CERT_EXTENSION nonCriticalExt =
1449 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
1451 static const struct encodedExtensions exts[] = {
1452 { { 0, NULL }, "\x30\x00" },
1453 { { 1, &criticalExt }, "\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff"
1454 "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
1455 { { 1, &nonCriticalExt }, "\x30\x11\x30\x0f\x06\x03\x55\x1d\x13"
1456 "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
1459 static void test_encodeExtensions(DWORD dwEncoding)
1463 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1469 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1470 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1471 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1474 ok(bufSize == exts[i].encoded[1] + 2,
1475 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1476 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1477 "Unexpected value\n");
1483 static void test_decodeExtensions(DWORD dwEncoding)
1487 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1493 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1494 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1495 NULL, (BYTE *)&buf, &bufSize);
1496 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1499 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1502 ok(ext->cExtension == exts[i].exts.cExtension,
1503 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1505 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1507 ok(!strcmp(ext->rgExtension[j].pszObjId,
1508 exts[i].exts.rgExtension[j].pszObjId),
1509 "Expected OID %s, got %s\n",
1510 exts[i].exts.rgExtension[j].pszObjId,
1511 ext->rgExtension[j].pszObjId);
1512 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1513 exts[i].exts.rgExtension[j].Value.pbData,
1514 exts[i].exts.rgExtension[j].Value.cbData),
1515 "Unexpected value\n");
1522 /* MS encodes public key info with a NULL if the algorithm identifier's
1523 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
1524 * it encodes them by omitting the algorithm parameters. This latter approach
1525 * seems more correct, so accept either form.
1527 struct encodedPublicKey
1529 CERT_PUBLIC_KEY_INFO info;
1530 const BYTE *encoded;
1531 const BYTE *encodedNoNull;
1532 CERT_PUBLIC_KEY_INFO decoded;
1535 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1537 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1539 static const struct encodedPublicKey pubKeys[] = {
1540 /* with a bogus OID */
1541 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1542 "\x30\x0b\x30\x06\x06\x02\x2a\x03\x05\x00\x03\x01\x00",
1543 "\x30\x09\x30\x04\x06\x02\x2a\x03\x03\x01\x00",
1544 { { "1.2.3", { 2, "\x05\x00" } }, { 0, NULL, 0 } } },
1545 /* some normal keys */
1546 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1547 "\x30\x0f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x01\x00",
1548 "\x30\x0d\x30\x08\x06\x06\x2a\x86\x48\x86\xf7\x0d\x03\x01\x00",
1549 { { szOID_RSA, { 2, "\x05\x00" } }, { 0, NULL, 0 } } },
1550 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
1551 "\x30\x1f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x11\x00\x00\x01"
1552 "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1553 "\x30\x1d\x30\x08\x06\x06\x2a\x86\x48\x86\xf7\x0d\x03\x11\x00\x00\x01"
1554 "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1555 { { szOID_RSA, { 2, "\x05\x00" } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
1556 /* with add'l parameters--note they must be DER-encoded */
1557 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1558 (BYTE *)aKey, 0 } },
1559 "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01"
1560 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1562 "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01"
1563 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1565 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1566 (BYTE *)aKey, 0 } } },
1569 static void test_encodePublicKeyInfo(DWORD dwEncoding)
1573 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1579 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1580 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1582 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1585 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
1586 bufSize == pubKeys[i].encodedNoNull[1] + 2,
1587 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
1588 pubKeys[i].encodedNoNull[1] + 2, bufSize);
1589 if (bufSize == pubKeys[i].encoded[1] + 2)
1590 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
1591 "Unexpected value\n");
1592 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
1593 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
1594 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
1600 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
1601 const CERT_PUBLIC_KEY_INFO *got)
1603 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
1604 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
1605 got->Algorithm.pszObjId);
1606 ok(expected->Algorithm.Parameters.cbData ==
1607 got->Algorithm.Parameters.cbData,
1608 "Expected parameters of %ld bytes, got %ld\n",
1609 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
1610 if (expected->Algorithm.Parameters.cbData)
1611 ok(!memcmp(expected->Algorithm.Parameters.pbData,
1612 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
1613 "Unexpected algorithm parameters\n");
1614 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
1615 "Expected public key of %ld bytes, got %ld\n",
1616 expected->PublicKey.cbData, got->PublicKey.cbData);
1617 if (expected->PublicKey.cbData)
1618 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
1619 got->PublicKey.cbData), "Unexpected public key value\n");
1622 static void test_decodePublicKeyInfo(DWORD dwEncoding)
1624 static const BYTE bogusPubKeyInfo[] =
1625 "\x30\x22\x30\x0d\x06\x06\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x01\x01"
1626 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1633 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1635 /* The NULL form decodes to the decoded member */
1636 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1637 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1638 NULL, (BYTE *)&buf, &bufSize);
1639 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1642 comparePublicKeyInfo(&pubKeys[i].decoded,
1643 (CERT_PUBLIC_KEY_INFO *)buf);
1646 /* The non-NULL form decodes to the original */
1647 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1648 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
1649 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1650 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1653 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
1657 /* Test with bogus (not valid DER) parameters */
1658 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1659 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1660 NULL, (BYTE *)&buf, &bufSize);
1661 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1662 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1665 static const BYTE v1Cert[] = "\x30\x33\x02\x00\x30\x02\x06\x00\x30\x22\x18"
1666 "\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x18\x0f\x31"
1667 "\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07\x30\x02\x06"
1669 static const BYTE v2Cert[] = "\x30\x38\xa0\x03\x02\x01\x01\x02\x00\x30\x02\x06"
1670 "\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30"
1671 "\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30"
1672 "\x07\x30\x02\x06\x00\x03\x01\x00";
1673 static const BYTE v3Cert[] = "\x30\x38\xa0\x03\x02\x01\x02\x02\x00\x30\x02\x06"
1674 "\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30"
1675 "\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30"
1676 "\x07\x30\x02\x06\x00\x03\x01\x00";
1677 static const BYTE v1CertWithConstraints[] = "\x30\x4b\x02\x00\x30\x02\x06\x00"
1678 "\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a"
1679 "\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07"
1680 "\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01"
1681 "\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01";
1682 static const BYTE v1CertWithSerial[] = "\x30\x4c\x02\x01\x01\x30\x02\x06\x00"
1683 "\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a"
1684 "\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07"
1685 "\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01"
1686 "\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01";
1687 static const BYTE bigCert[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
1688 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e\x20\x4c"
1689 "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
1690 "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
1691 "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e"
1692 "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
1693 "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
1695 /* This is the encoded form of the printable string "Juan Lang" */
1696 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
1697 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
1698 0x61, 0x6e, 0x67, 0x00 };
1699 static const BYTE serialNum[] = { 0x01 };
1701 static void test_encodeCertToBeSigned(DWORD dwEncoding)
1706 CERT_INFO info = { 0 };
1708 /* Test with NULL pvStructInfo */
1709 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
1710 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1711 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1712 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1713 /* Test with a V1 cert */
1714 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1715 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1716 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1719 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
1720 v1Cert[1] + 2, size);
1721 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
1725 info.dwVersion = CERT_V2;
1726 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1727 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1728 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1731 ok(size == v2Cert[1] + 2, "Expected size %d, got %ld\n",
1732 v3Cert[1] + 2, size);
1733 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
1737 info.dwVersion = CERT_V3;
1738 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1739 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1740 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1743 ok(size == v3Cert[1] + 2, "Expected size %d, got %ld\n",
1744 v3Cert[1] + 2, size);
1745 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
1748 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
1749 * API doesn't prevent it)
1751 info.dwVersion = CERT_V1;
1752 info.cExtension = 1;
1753 info.rgExtension = &criticalExt;
1754 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1755 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1756 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1759 ok(size == v1CertWithConstraints[1] + 2, "Expected size %d, got %ld\n",
1760 v1CertWithConstraints[1] + 2, size);
1761 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
1764 /* test v1 cert with a serial number */
1765 info.SerialNumber.cbData = sizeof(serialNum);
1766 info.SerialNumber.pbData = (BYTE *)serialNum;
1767 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1768 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1771 ok(size == v1CertWithSerial[1] + 2, "Expected size %d, got %ld\n",
1772 v1CertWithSerial[1] + 2, size);
1773 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
1776 /* Test v1 cert with an issuer name, a subject name, and a serial number */
1777 info.Issuer.cbData = sizeof(encodedCommonName);
1778 info.Issuer.pbData = (BYTE *)encodedCommonName;
1779 info.Subject.cbData = sizeof(encodedCommonName);
1780 info.Subject.pbData = (BYTE *)encodedCommonName;
1781 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1782 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1785 ok(size == bigCert[1] + 2, "Expected size %d, got %ld\n",
1786 bigCert[1] + 2, size);
1787 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
1790 /* for now, I let more interesting tests be done for each subcomponent,
1791 * rather than retesting them all here.
1795 static void test_decodeCertToBeSigned(DWORD dwEncoding)
1797 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
1798 v1CertWithConstraints, v1CertWithSerial };
1803 /* Test with NULL pbEncoded */
1804 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
1805 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1806 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1807 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
1808 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
1809 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1810 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1811 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1812 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
1813 * minimum a cert must have a non-zero serial number, an issuer, and a
1815 * It's hard to match the errors precisely sometimes, so accept one
1816 * that only wine gives as long as it fails
1818 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
1820 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
1821 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1822 (BYTE *)&buf, &size);
1823 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT ||
1824 GetLastError() == CRYPT_E_ASN1_BADTAG),
1825 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1827 /* Now check with serial number, subject and issuer specified */
1828 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
1829 bigCert[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1830 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1833 CERT_INFO *info = (CERT_INFO *)buf;
1835 ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
1836 sizeof(CERT_INFO), size);
1837 ok(info->SerialNumber.cbData == 1,
1838 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
1839 ok(*info->SerialNumber.pbData == *serialNum,
1840 "Expected serial number %d, got %d\n", *serialNum,
1841 *info->SerialNumber.pbData);
1842 ok(info->Issuer.cbData == sizeof(encodedCommonName),
1843 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
1844 info->Issuer.cbData);
1845 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
1846 "Unexpected issuer\n");
1847 ok(info->Subject.cbData == sizeof(encodedCommonName),
1848 "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
1849 info->Subject.cbData);
1850 ok(!memcmp(info->Subject.pbData, encodedCommonName,
1851 info->Subject.cbData), "Unexpected subject\n");
1856 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1859 static const BYTE signedBigCert[] = {
1860 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
1861 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
1862 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
1863 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1864 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
1865 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
1866 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
1867 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
1868 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
1869 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
1870 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1871 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
1873 static void test_encodeCert(DWORD dwEncoding)
1875 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
1876 * also that bigCert is a NULL-terminated string, so don't count its
1877 * last byte (otherwise the signed cert won't decode.)
1879 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert) - 1, (BYTE *)bigCert },
1880 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
1885 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
1886 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1887 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1890 ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
1891 sizeof(signedBigCert), bufSize);
1892 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
1897 static void test_decodeCert(DWORD dwEncoding)
1903 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
1904 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1905 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1908 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
1910 ok(info->ToBeSigned.cbData == sizeof(bigCert) - 1,
1911 "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert) - 1,
1912 info->ToBeSigned.cbData);
1913 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
1914 "Unexpected cert\n");
1915 ok(info->Signature.cbData == sizeof(hash),
1916 "Expected signature size %d, got %ld\n", sizeof(hash),
1917 info->Signature.cbData);
1918 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
1919 "Unexpected signature\n");
1924 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
1925 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1927 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
1928 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
1929 0x30, 0x30, 0x30, 0x30, 0x5a };
1930 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
1931 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
1932 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
1933 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1935 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
1936 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
1937 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
1938 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
1939 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
1940 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
1941 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
1942 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
1943 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
1944 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1945 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
1946 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
1947 static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
1948 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
1949 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
1950 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
1951 0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
1952 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
1953 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
1954 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1956 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
1961 CRL_INFO info = { 0 };
1962 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
1964 /* Test with a V1 CRL */
1965 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
1966 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1967 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1970 ok(size == sizeof(v1CRL), "Expected size %d, got %ld\n",
1971 sizeof(v1CRL), size);
1972 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
1976 info.dwVersion = CRL_V2;
1977 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
1978 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1979 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1982 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
1983 v2CRL[1] + 2, size);
1984 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
1987 /* v1 CRL with a name */
1988 info.dwVersion = CRL_V1;
1989 info.Issuer.cbData = sizeof(encodedCommonName);
1990 info.Issuer.pbData = (BYTE *)encodedCommonName;
1991 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
1992 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1993 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1996 ok(size == sizeof(v1CRLWithIssuer), "Expected size %d, got %ld\n",
1997 sizeof(v1CRLWithIssuer), size);
1998 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2001 /* v1 CRL with a name and a NULL entry pointer */
2003 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2004 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2005 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2006 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2007 /* now set an empty entry */
2008 info.rgCRLEntry = &entry;
2009 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2010 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2013 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2014 "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEmptyEntry),
2016 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2017 "Got unexpected value\n");
2020 /* an entry with a serial number */
2021 entry.SerialNumber.cbData = sizeof(serialNum);
2022 entry.SerialNumber.pbData = (BYTE *)serialNum;
2023 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2024 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2027 ok(size == sizeof(v1CRLWithIssuerAndEntry),
2028 "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEntry), size);
2029 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2030 "Got unexpected value\n");
2033 /* and finally, an entry with an extension */
2034 entry.cExtension = 1;
2035 entry.rgExtension = &criticalExt;
2036 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2037 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2038 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2041 ok(size == sizeof(v1CRLWithExt), "Expected size %d, got %ld\n",
2042 sizeof(v1CRLWithExt), size);
2043 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2048 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
2050 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
2055 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
2057 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2058 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2059 (BYTE *)&buf, &size);
2060 /* It's hard to match the errors precisely sometimes, so accept one
2061 * that only wine gives as long as it fails
2063 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT ||
2064 GetLastError() == CRYPT_E_ASN1_BADTAG),
2065 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2067 /* at a minimum, a CRL must contain an issuer: */
2068 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2069 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2070 (BYTE *)&buf, &size);
2071 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2074 CRL_INFO *info = (CRL_INFO *)buf;
2076 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2077 sizeof(CRL_INFO), size);
2078 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
2080 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2081 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2082 info->Issuer.cbData);
2083 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2084 "Unexpected issuer\n");
2087 /* check decoding with an empty CRL entry */
2088 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2089 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
2090 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2091 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2092 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2093 /* with a real CRL entry */
2094 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2095 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
2096 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2097 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2100 CRL_INFO *info = (CRL_INFO *)buf;
2103 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2104 sizeof(CRL_INFO), size);
2105 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2107 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2108 entry = info->rgCRLEntry;
2109 ok(entry->SerialNumber.cbData == 1,
2110 "Expected serial number size 1, got %ld\n",
2111 entry->SerialNumber.cbData);
2112 ok(*entry->SerialNumber.pbData == *serialNum,
2113 "Expected serial number %d, got %d\n", *serialNum,
2114 *entry->SerialNumber.pbData);
2115 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2116 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2117 info->Issuer.cbData);
2118 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2119 "Unexpected issuer\n");
2120 if (memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData))
2122 printBytes("Expected", encodedCommonName,
2123 sizeof(encodedCommonName));
2124 printBytes("Got", info->Issuer.pbData, info->Issuer.cbData);
2127 /* and finally, with an extension */
2128 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2129 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2130 NULL, (BYTE *)&buf, &size);
2131 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2134 CRL_INFO *info = (CRL_INFO *)buf;
2137 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2138 sizeof(CRL_INFO), size);
2139 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2141 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2142 entry = info->rgCRLEntry;
2143 ok(entry->SerialNumber.cbData == 1,
2144 "Expected serial number size 1, got %ld\n",
2145 entry->SerialNumber.cbData);
2146 ok(*entry->SerialNumber.pbData == *serialNum,
2147 "Expected serial number %d, got %d\n", *serialNum,
2148 *entry->SerialNumber.pbData);
2149 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2150 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2151 info->Issuer.cbData);
2152 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2153 "Unexpected issuer\n");
2154 /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2155 * bug, or am I missing something?
2157 ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2162 static void test_registerOIDFunction(void)
2164 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
2167 /* oddly, this succeeds under WinXP; the function name key is merely
2168 * omitted. This may be a side effect of the registry code, I don't know.
2169 * I don't check it because I doubt anyone would depend on it.
2170 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
2171 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2173 /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
2174 * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
2176 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
2178 ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
2179 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
2180 "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
2181 /* This has no effect, but "succeeds" on XP */
2182 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
2183 "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
2184 ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
2185 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
2186 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2187 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2188 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
2189 "1.2.3.4.5.6.7.8.9.10");
2190 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
2191 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
2192 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2193 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2194 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
2195 "1.2.3.4.5.6.7.8.9.10");
2196 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
2197 /* This has no effect */
2198 ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
2199 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2200 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2201 /* Check with bogus encoding type: */
2202 ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
2203 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2204 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2205 /* This is written with value 3 verbatim. Thus, the encoding type isn't
2206 * (for now) treated as a mask.
2208 ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
2209 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2210 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2211 ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
2212 "1.2.3.4.5.6.7.8.9.10");
2213 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
2218 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
2219 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
2222 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
2224 test_encodeInt(encodings[i]);
2225 test_decodeInt(encodings[i]);
2226 test_encodeEnumerated(encodings[i]);
2227 test_decodeEnumerated(encodings[i]);
2228 test_encodeFiletime(encodings[i]);
2229 test_decodeFiletime(encodings[i]);
2230 test_encodeName(encodings[i]);
2231 test_decodeName(encodings[i]);
2232 test_encodeAltName(encodings[i]);
2233 test_decodeAltName(encodings[i]);
2234 test_encodeOctets(encodings[i]);
2235 test_decodeOctets(encodings[i]);
2236 test_encodeBits(encodings[i]);
2237 test_decodeBits(encodings[i]);
2238 test_encodeBasicConstraints(encodings[i]);
2239 test_decodeBasicConstraints(encodings[i]);
2240 test_encodeSequenceOfAny(encodings[i]);
2241 test_decodeSequenceOfAny(encodings[i]);
2242 test_encodeExtensions(encodings[i]);
2243 test_decodeExtensions(encodings[i]);
2244 test_encodePublicKeyInfo(encodings[i]);
2245 test_decodePublicKeyInfo(encodings[i]);
2246 test_encodeCertToBeSigned(encodings[i]);
2247 test_decodeCertToBeSigned(encodings[i]);
2248 test_encodeCert(encodings[i]);
2249 test_decodeCert(encodings[i]);
2250 test_encodeCRLToBeSigned(encodings[i]);
2251 test_decodeCRLToBeSigned(encodings[i]);
2253 test_registerOIDFunction();