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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/test.h"
35 static const BYTE bin1[] = {0x02,0x01,0x01};
36 static const BYTE bin2[] = {0x02,0x01,0x7f};
37 static const BYTE bin3[] = {0x02,0x02,0x00,0x80};
38 static const BYTE bin4[] = {0x02,0x02,0x01,0x00};
39 static const BYTE bin5[] = {0x02,0x01,0x80};
40 static const BYTE bin6[] = {0x02,0x02,0xff,0x7f};
41 static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d};
43 static const struct encodedInt ints[] = {
60 static const BYTE bin8[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
61 static const BYTE bin9[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
62 static const BYTE bin10[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
64 static const BYTE bin11[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
65 static const BYTE bin12[] = {0x02,0x09,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
66 static const BYTE bin13[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0};
68 static const struct encodedBigInt bigInts[] = {
69 { bin8, bin9, bin10 },
70 { bin11, bin12, bin13 },
73 static const BYTE bin14[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
74 static const BYTE bin15[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
75 static const BYTE bin16[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
76 static const BYTE bin17[] = {0x02,0x0c,0x00,0xff,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
78 /* Decoded is the same as original, so don't bother storing a separate copy */
79 static const struct encodedBigInt bigUInts[] = {
80 { bin14, bin15, NULL },
81 { bin16, bin17, NULL },
84 static void test_encodeInt(DWORD dwEncoding)
89 CRYPT_INTEGER_BLOB blob;
92 /* CryptEncodeObjectEx with NULL bufSize crashes..
93 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
96 /* check bogus encoding */
97 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
99 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
100 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
101 /* check with NULL integer buffer. Windows XP incorrectly returns an
104 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
106 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
107 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
108 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
110 /* encode as normal integer */
111 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
112 NULL, NULL, &bufSize);
113 ok(ret, "Expected success, got %ld\n", GetLastError());
114 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
115 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
116 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
119 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
121 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
122 buf[1], ints[i].encoded[1]);
123 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
124 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
127 /* encode as multibyte integer */
128 blob.cbData = sizeof(ints[i].val);
129 blob.pbData = (BYTE *)&ints[i].val;
130 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
131 0, NULL, NULL, &bufSize);
132 ok(ret, "Expected success, got %ld\n", GetLastError());
133 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
134 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
135 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
138 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
140 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
141 buf[1], ints[i].encoded[1]);
142 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
143 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
147 /* encode a couple bigger ints, just to show it's little-endian and leading
148 * sign bytes are dropped
150 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
152 blob.cbData = strlen((const char*)bigInts[i].val);
153 blob.pbData = (BYTE *)bigInts[i].val;
154 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
155 0, NULL, NULL, &bufSize);
156 ok(ret, "Expected success, got %ld\n", GetLastError());
157 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
158 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
159 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
162 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
164 ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
165 buf[1], bigInts[i].encoded[1]);
166 ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
167 bigInts[i].encoded[1] + 1),
168 "Encoded value didn't match expected\n");
172 /* and, encode some uints */
173 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
175 blob.cbData = strlen((const char*)bigUInts[i].val);
176 blob.pbData = (BYTE*)bigUInts[i].val;
177 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
178 0, NULL, NULL, &bufSize);
179 ok(ret, "Expected success, got %ld\n", GetLastError());
180 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
181 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
182 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
185 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
187 ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
188 buf[1], bigUInts[i].encoded[1]);
189 ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
190 bigUInts[i].encoded[1] + 1),
191 "Encoded value didn't match expected\n");
197 static void test_decodeInt(DWORD dwEncoding)
199 static const BYTE bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
200 static const BYTE testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
201 static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
202 static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
208 /* CryptDecodeObjectEx with NULL bufSize crashes..
209 ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
210 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
212 /* check bogus encoding */
213 ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
214 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
215 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
216 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
217 /* check with NULL integer buffer */
218 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
220 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
221 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
222 /* check with a valid, but too large, integer */
223 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
224 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
225 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
226 "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
227 /* check with a DER-encoded string */
228 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
229 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
230 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
231 "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
232 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
234 /* When the output buffer is NULL, this always succeeds */
235 SetLastError(0xdeadbeef);
236 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
237 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
239 ok(ret && GetLastError() == NOERROR,
240 "Expected success and NOERROR, got %ld\n", GetLastError());
241 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
242 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
243 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
244 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
245 ok(bufSize == sizeof(int), "Wrong size %ld\n", bufSize);
246 ok(buf != NULL, "Expected allocated buffer\n");
249 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
250 ints[i].val, *(int *)buf);
254 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
256 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
257 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
259 ok(ret && GetLastError() == NOERROR,
260 "Expected success and NOERROR, got %ld\n", GetLastError());
261 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
262 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
263 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
264 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
265 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %ld\n", bufSize);
266 ok(buf != NULL, "Expected allocated buffer\n");
269 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
271 ok(blob->cbData == strlen((const char*)bigInts[i].decoded),
272 "Expected len %d, got %ld\n", lstrlenA((const char*)bigInts[i].decoded),
274 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
275 "Unexpected value\n");
279 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
281 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
282 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
284 ok(ret && GetLastError() == NOERROR,
285 "Expected success and NOERROR, got %ld\n", GetLastError());
286 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
287 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
288 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
289 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
290 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %ld\n", bufSize);
291 ok(buf != NULL, "Expected allocated buffer\n");
294 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
296 ok(blob->cbData == strlen((const char*)bigUInts[i].val),
297 "Expected len %d, got %ld\n", lstrlenA((const char*)bigUInts[i].val),
299 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
300 "Unexpected value\n");
304 /* Decode the value 1 with long-form length */
305 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
306 sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
307 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
310 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
313 /* Try to decode some bogus large items */
314 /* The buffer size is smaller than the encoded length, so this should fail
315 * with CRYPT_E_ASN1_EOD if it's being decoded.
316 * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
317 * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
318 * So this test unfortunately isn't useful.
319 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
320 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
321 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
322 "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
324 /* This will try to decode the buffer and overflow it, check that it's
327 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
328 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
329 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
330 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
333 static const BYTE bin18[] = {0x0a,0x01,0x01};
334 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80};
336 /* These are always encoded unsigned, and aren't constrained to be any
339 static const struct encodedInt enums[] = {
344 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
347 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
348 szOID_CRL_REASON_CODE };
350 static void test_encodeEnumerated(DWORD dwEncoding)
354 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
356 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
362 ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
363 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
365 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
369 "Got unexpected type %d for enumerated (expected 0xa)\n",
371 ok(buf[1] == enums[j].encoded[1],
372 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
373 ok(!memcmp(buf + 1, enums[j].encoded + 1,
374 enums[j].encoded[1] + 1),
375 "Encoded value of 0x%08x didn't match expected\n",
383 static void test_decodeEnumerated(DWORD dwEncoding)
387 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
389 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
392 DWORD bufSize = sizeof(int);
395 ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
396 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
397 (BYTE *)&val, &bufSize);
398 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
399 ok(bufSize == sizeof(int),
400 "Got unexpected size %ld for enumerated\n", bufSize);
401 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
407 struct encodedFiletime
410 const BYTE *encodedTime;
413 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
414 const struct encodedFiletime *time)
421 ret = SystemTimeToFileTime(&time->sysTime, &ft);
422 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
423 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
424 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
425 /* years other than 1950-2050 are not allowed for encodings other than
426 * X509_CHOICE_OF_TIME.
428 if (structType == X509_CHOICE_OF_TIME ||
429 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
431 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
433 ok(buf != NULL, "Expected an allocated buffer\n");
436 ok(buf[0] == time->encodedTime[0],
437 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
439 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
440 time->encodedTime[1], bufSize);
441 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
442 "Got unexpected value for time encoding\n");
447 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
448 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
451 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
452 const struct encodedFiletime *time)
454 FILETIME ft1 = { 0 }, ft2 = { 0 };
455 DWORD size = sizeof(ft2);
458 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
459 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
460 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
461 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
462 /* years other than 1950-2050 are not allowed for encodings other than
463 * X509_CHOICE_OF_TIME.
465 if (structType == X509_CHOICE_OF_TIME ||
466 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
468 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
470 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
471 "Got unexpected value for time decoding\n");
474 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
475 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
478 static const BYTE bin20[] = {
479 0x17,0x0d,'0','5','0','6','0','6','1','6','1','0','0','0','Z'};
480 static const BYTE bin21[] = {
481 0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
482 static const BYTE bin22[] = {
483 0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
485 static const struct encodedFiletime times[] = {
486 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 },
487 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 },
488 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 },
491 static void test_encodeFiletime(DWORD dwEncoding)
495 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
497 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
498 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
499 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
503 static const BYTE bin23[] = {
504 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','0','0','0','Z'};
505 static const BYTE bin24[] = {
506 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','9','9','9','Z'};
507 static const BYTE bin25[] = {
508 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','+','0','1','0','0'};
509 static const BYTE bin26[] = {
510 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','0','0'};
511 static const BYTE bin27[] = {
512 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','1','5'};
513 static const BYTE bin28[] = {
514 0x18,0x0a,'2','1','4','5','0','6','0','6','1','6'};
515 static const BYTE bin29[] = {
516 0x17,0x0a,'4','5','0','6','0','6','1','6','1','0'};
517 static const BYTE bin30[] = {
518 0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z'};
519 static const BYTE bin31[] = {
520 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1'};
521 static const BYTE bin32[] = {
522 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1'};
523 static const BYTE bin33[] = {
524 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0'};
525 static const BYTE bin34[] = {
526 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0'};
527 static const BYTE bin35[] = {
528 0x17,0x08, '4','5','0','6','0','6','1','6'};
529 static const BYTE bin36[] = {
530 0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z'};
531 static const BYTE bin37[] = {
532 0x18,0x04, '2','1','4','5'};
533 static const BYTE bin38[] = {
534 0x18,0x08, '2','1','4','5','0','6','0','6'};
536 static void test_decodeFiletime(DWORD dwEncoding)
538 static const struct encodedFiletime otherTimes[] = {
539 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin23 },
540 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 },
541 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, bin25 },
542 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, bin26 },
543 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, bin27 },
544 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, bin28 },
545 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin29 },
546 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin30 },
547 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin31 },
548 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin32 },
549 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin33 },
550 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin34 },
552 /* An oddball case that succeeds in Windows, but doesn't seem correct
553 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
555 static const unsigned char *bogusTimes[] = {
556 /* oddly, this succeeds on Windows, with year 2765
557 "\x18" "\x0f" "21r50606161000Z",
565 FILETIME ft1 = { 0 }, ft2 = { 0 };
568 /* Check bogus length with non-NULL buffer */
569 ret = SystemTimeToFileTime(×[0].sysTime, &ft1);
570 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
572 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
573 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
574 ok(!ret && GetLastError() == ERROR_MORE_DATA,
575 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
577 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
579 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
580 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
581 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
583 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
585 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
586 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
587 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
589 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
592 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
593 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
594 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
595 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
599 static const char commonName[] = "Juan Lang";
600 static const char surName[] = "Lang";
602 static const BYTE emptySequence[] = { 0x30, 0 };
603 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
604 static const BYTE twoRDNs[] = {
605 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
606 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
607 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
609 static const BYTE us[] = { 0x55, 0x53 };
610 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
612 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
613 0x6f, 0x6c, 0x69, 0x73 };
614 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
615 0x76, 0x65, 0x72, 0x73 };
616 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
617 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
618 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
620 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
621 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
623 #define _blob_of(arr) { sizeof(arr), (LPBYTE)arr }
624 const CERT_RDN_ATTR rdnAttrs[] = {
625 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
626 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
627 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
628 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
629 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
630 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
631 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
633 const CERT_RDN_ATTR decodedRdnAttrs[] = {
634 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
635 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
636 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
637 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
638 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
639 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
640 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
644 static const BYTE encodedRDNAttrs[] = {
645 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
646 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
647 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
648 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
649 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
650 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
651 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
652 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
653 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
654 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
657 static void test_encodeName(DWORD dwEncoding)
659 CERT_RDN_ATTR attrs[2];
662 static CHAR oid_common_name[] = szOID_COMMON_NAME,
663 oid_sur_name[] = szOID_SUR_NAME;
668 /* Test with NULL pvStructInfo */
669 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
670 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
671 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
672 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
673 /* Test with empty CERT_NAME_INFO */
676 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
677 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
678 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
681 ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
682 "Got unexpected encoding for empty name\n");
685 /* Test with bogus CERT_RDN */
687 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
688 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
689 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
690 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
691 /* Test with empty CERT_RDN */
693 rdn.rgRDNAttr = NULL;
696 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
697 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
698 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
701 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
702 "Got unexpected encoding for empty RDN array\n");
705 /* Test with bogus attr array */
707 rdn.rgRDNAttr = NULL;
708 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
709 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
710 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
711 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
712 /* oddly, a bogus OID is accepted by Windows XP; not testing.
713 attrs[0].pszObjId = "bogus";
714 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
715 attrs[0].Value.cbData = sizeof(commonName);
716 attrs[0].Value.pbData = (BYTE *)commonName;
718 rdn.rgRDNAttr = attrs;
719 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
720 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
721 ok(!ret, "Expected failure, got success\n");
723 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
724 * the encoded attributes to be swapped.
726 attrs[0].pszObjId = oid_common_name;
727 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
728 attrs[0].Value.cbData = sizeof(commonName);
729 attrs[0].Value.pbData = (BYTE *)commonName;
730 attrs[1].pszObjId = oid_sur_name;
731 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
732 attrs[1].Value.cbData = sizeof(surName);
733 attrs[1].Value.pbData = (BYTE *)surName;
735 rdn.rgRDNAttr = attrs;
736 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
737 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
738 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
741 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
742 "Got unexpected encoding for two RDN array\n");
745 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
747 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
748 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
749 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
750 ok(!ret && GetLastError() == E_INVALIDARG,
751 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
752 /* Test a more complex name */
753 rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
754 rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
759 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
760 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
761 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
764 ok(size == sizeof(encodedRDNAttrs), "Wrong size %ld\n", size);
765 ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
770 static void compareNameValues(const CERT_NAME_VALUE *expected,
771 const CERT_NAME_VALUE *got)
773 ok(got->dwValueType == expected->dwValueType,
774 "Expected string type %ld, got %ld\n", expected->dwValueType,
776 ok(got->Value.cbData == expected->Value.cbData,
777 "Unexpected data size, got %ld, expected %ld\n", got->Value.cbData,
778 expected->Value.cbData);
779 if (got->Value.cbData && got->Value.pbData)
780 ok(!memcmp(got->Value.pbData, expected->Value.pbData,
781 min(got->Value.cbData, expected->Value.cbData)), "Unexpected value\n");
784 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
785 const CERT_RDN_ATTR *got)
787 if (expected->pszObjId && strlen(expected->pszObjId))
789 ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
793 ok(!strcmp(got->pszObjId, expected->pszObjId),
794 "Got unexpected OID %s, expected %s\n", got->pszObjId,
798 compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType,
799 (const CERT_NAME_VALUE *)&got->dwValueType);
802 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
804 ok(got->cRDNAttr == expected->cRDNAttr,
805 "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
810 for (i = 0; i < got->cRDNAttr; i++)
811 compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
815 static void compareNames(const CERT_NAME_INFO *expected,
816 const CERT_NAME_INFO *got)
818 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
819 expected->cRDN, got->cRDN);
824 for (i = 0; i < got->cRDN; i++)
825 compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
829 static void test_decodeName(DWORD dwEncoding)
835 CERT_NAME_INFO info = { 1, &rdn };
837 /* test empty name */
839 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
840 emptySequence[1] + 2,
841 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
842 (BYTE *)&buf, &bufSize);
843 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
844 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
845 * decoder works the same way, so only test the count.
849 ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %ld\n", bufSize);
850 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
851 "Expected 0 RDNs in empty info, got %ld\n",
852 ((CERT_NAME_INFO *)buf)->cRDN);
857 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
859 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
860 (BYTE *)&buf, &bufSize);
861 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
864 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
866 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
867 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
868 "Got unexpected value for empty RDN\n");
871 /* test two RDN attrs */
873 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
875 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
876 (BYTE *)&buf, &bufSize);
877 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
880 CERT_RDN_ATTR attrs[] = {
881 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
883 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
884 (BYTE *)commonName } },
887 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
888 rdn.rgRDNAttr = attrs;
889 compareNames(&info, (CERT_NAME_INFO *)buf);
892 /* And, a slightly more complicated name */
895 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
896 sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
897 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
900 rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
901 rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
902 compareNames(&info, (CERT_NAME_INFO *)buf);
907 struct EncodedNameValue
909 CERT_NAME_VALUE value;
913 static const char bogusIA5[] = "\x80";
914 static const char bogusPrintable[] = "~";
915 static const char bogusNumeric[] = "A";
916 static const char bogusT61[] = "\xff";
917 static const BYTE bin39[] = { 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
919 static const BYTE bin40[] = { 0x16,0x05,0x4c,0x61,0x6e,0x67,0x00 };
920 static const BYTE bin41[] = { 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
922 static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
923 static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
924 static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
925 static const BYTE bin45[] = { 0x14,0x02,0xff,0x00 };
927 struct EncodedNameValue nameValues[] = {
928 { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
930 { { CERT_RDN_IA5_STRING, { sizeof(surName), (BYTE *)surName } }, bin40 },
931 { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } }, bin41 },
932 /* The following tests succeed under Windows, but really should fail,
933 * they contain characters that are illegal for the encoding. I'm
934 * including them to justify my lazy encoding.
936 { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42 },
937 { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable),
938 (BYTE *)bogusPrintable } }, bin43 },
939 { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
941 { { CERT_RDN_T61_STRING, { sizeof(bogusT61), (BYTE *)bogusT61 } }, bin45 },
945 static void test_encodeNameValue(DWORD dwEncoding)
951 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
953 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE,
954 &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
956 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
959 ok(size == nameValues[i].encoded[1] + 2,
960 "Expected size %d, got %ld\n", nameValues[i].encoded[1] + 2, size);
961 ok(!memcmp(buf, nameValues[i].encoded, size),
962 "Got unexpected encoding\n");
968 static void test_decodeNameValue(DWORD dwEncoding)
975 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
977 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE,
978 nameValues[i].encoded, nameValues[i].encoded[1] + 2,
979 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
980 (BYTE *)&buf, &bufSize);
981 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
984 compareNameValues(&nameValues[i].value,
985 (const CERT_NAME_VALUE *)buf);
991 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
992 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
993 'h','q','.','o','r','g',0 };
994 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
995 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
997 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
999 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1000 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1001 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1002 static const BYTE localhost[] = { 127, 0, 0, 1 };
1003 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1006 static void test_encodeAltName(DWORD dwEncoding)
1008 CERT_ALT_NAME_INFO info = { 0 };
1009 CERT_ALT_NAME_ENTRY entry = { 0 };
1014 /* Test with empty info */
1015 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1016 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1019 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
1020 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1023 /* Test with an empty entry */
1025 info.rgAltEntry = &entry;
1026 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1027 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1028 ok(!ret && GetLastError() == E_INVALIDARG,
1029 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1030 /* Test with an empty pointer */
1031 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1032 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1033 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1036 ok(size == sizeof(emptyURL), "Wrong size %ld\n", size);
1037 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1040 /* Test with a real URL */
1041 U(entry).pwszURL = (LPWSTR)url;
1042 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1043 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1046 ok(size == sizeof(encodedURL), "Wrong size %ld\n", size);
1047 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1050 /* Now with the URL containing an invalid IA5 char */
1051 U(entry).pwszURL = (LPWSTR)nihongoURL;
1052 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1053 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1054 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1055 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1056 /* The first invalid character is at index 7 */
1057 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1058 "Expected invalid char at index 7, got %ld\n",
1059 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1060 /* Now with the URL missing a scheme */
1061 U(entry).pwszURL = (LPWSTR)dnsName;
1062 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1063 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1064 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1067 /* This succeeds, but it shouldn't, so don't worry about conforming */
1070 /* Now with a DNS name */
1071 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1072 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1073 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1074 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1077 ok(size == sizeof(encodedDnsName), "Wrong size %ld\n", size);
1078 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1081 /* Test with an IP address */
1082 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1083 U(entry).IPAddress.cbData = sizeof(localhost);
1084 U(entry).IPAddress.pbData = (LPBYTE)localhost;
1085 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1086 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1089 ok(size == sizeof(encodedIPAddr), "Wrong size %ld\n", size);
1090 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1095 static void test_decodeAltName(DWORD dwEncoding)
1097 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1099 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1104 CERT_ALT_NAME_INFO *info;
1106 /* Test some bogus ones first */
1107 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1108 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1109 NULL, (BYTE *)&buf, &bufSize);
1110 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1111 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1112 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1113 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1115 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1116 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1117 /* Now expected cases */
1118 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1119 emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1121 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1124 info = (CERT_ALT_NAME_INFO *)buf;
1126 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1130 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1131 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1133 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1136 info = (CERT_ALT_NAME_INFO *)buf;
1138 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1140 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1141 "Expected CERT_ALT_NAME_URL, got %ld\n",
1142 info->rgAltEntry[0].dwAltNameChoice);
1143 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1144 "Expected empty URL\n");
1147 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1148 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1150 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1153 info = (CERT_ALT_NAME_INFO *)buf;
1155 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1157 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1158 "Expected CERT_ALT_NAME_URL, got %ld\n",
1159 info->rgAltEntry[0].dwAltNameChoice);
1160 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1163 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1164 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1166 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1169 info = (CERT_ALT_NAME_INFO *)buf;
1171 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1173 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1174 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1175 info->rgAltEntry[0].dwAltNameChoice);
1176 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1177 "Unexpected DNS name\n");
1180 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1181 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1183 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1186 info = (CERT_ALT_NAME_INFO *)buf;
1188 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1190 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1191 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1192 info->rgAltEntry[0].dwAltNameChoice);
1193 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1194 "Unexpected IP address length %ld\n",
1195 U(info->rgAltEntry[0]).IPAddress.cbData);
1196 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1197 sizeof(localhost)), "Unexpected IP address value\n");
1202 struct encodedOctets
1205 const BYTE *encoded;
1208 static const unsigned char bin46[] = { 'h','i',0 };
1209 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1210 static const unsigned char bin48[] = {
1211 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1212 static const unsigned char bin49[] = {
1213 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1214 static const unsigned char bin50[] = { 0 };
1215 static const unsigned char bin51[] = { 0x04,0x00,0 };
1217 static const struct encodedOctets octets[] = {
1223 static void test_encodeOctets(DWORD dwEncoding)
1225 CRYPT_DATA_BLOB blob;
1228 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1234 blob.cbData = strlen((const char*)octets[i].val);
1235 blob.pbData = (BYTE*)octets[i].val;
1236 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1237 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1238 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1242 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1243 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1244 buf[1], octets[i].encoded[1]);
1245 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1246 octets[i].encoded[1] + 1), "Got unexpected value\n");
1252 static void test_decodeOctets(DWORD dwEncoding)
1256 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1262 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1263 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1264 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1265 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1266 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1267 "Expected size >= %d, got %ld\n",
1268 (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1269 ok(buf != NULL, "Expected allocated buffer\n");
1272 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1275 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1276 "Unexpected value\n");
1282 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1287 const BYTE *encoded;
1289 const BYTE *decoded;
1292 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1293 static const unsigned char bin53[] = { 0xff,0xff };
1294 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1295 static const unsigned char bin55[] = { 0xff,0xfe };
1296 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1297 static const unsigned char bin57[] = { 0xfe };
1298 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1300 static const struct encodedBits bits[] = {
1301 /* normal test cases */
1302 { 0, bin52, 2, bin53 },
1303 { 1, bin54, 2, bin55 },
1304 /* strange test case, showing cUnusedBits >= 8 is allowed */
1305 { 9, bin56, 1, bin57 },
1306 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1307 { 17, bin58, 0, NULL },
1310 static void test_encodeBits(DWORD dwEncoding)
1314 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1316 CRYPT_BIT_BLOB blob;
1321 blob.cbData = sizeof(bytesToEncode);
1322 blob.pbData = (BYTE *)bytesToEncode;
1323 blob.cUnusedBits = bits[i].cUnusedBits;
1324 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1325 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1326 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1329 ok(bufSize == bits[i].encoded[1] + 2,
1330 "Got unexpected size %ld, expected %d\n", bufSize,
1331 bits[i].encoded[1] + 2);
1332 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1333 "Unexpected value\n");
1339 static void test_decodeBits(DWORD dwEncoding)
1341 static const BYTE ber[] = "\x03\x02\x01\xff";
1342 static const BYTE berDecoded = 0xfe;
1349 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1351 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1352 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1354 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1357 CRYPT_BIT_BLOB *blob;
1359 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1360 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1361 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1362 blob = (CRYPT_BIT_BLOB *)buf;
1363 ok(blob->cbData == bits[i].cbDecoded,
1364 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1366 if (blob->cbData && bits[i].cbDecoded)
1367 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1368 "Unexpected value\n");
1372 /* special case: check that something that's valid in BER but not in DER
1373 * decodes successfully
1375 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1376 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1377 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1380 CRYPT_BIT_BLOB *blob;
1382 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1383 "Got unexpected size %ld\n", bufSize);
1384 blob = (CRYPT_BIT_BLOB *)buf;
1385 ok(blob->cbData == sizeof(berDecoded),
1386 "Got unexpected length %ld\n", blob->cbData);
1388 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1395 CERT_BASIC_CONSTRAINTS2_INFO info;
1396 const BYTE *encoded;
1399 static const unsigned char bin59[] = { 0x30,0x00 };
1400 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1401 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1402 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1403 static const struct Constraints2 constraints2[] = {
1404 /* empty constraints */
1405 { { FALSE, FALSE, 0}, bin59 },
1407 { { TRUE, FALSE, 0}, bin60 },
1408 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1409 * but that's not the case
1411 { { FALSE, TRUE, 0}, bin61 },
1412 /* can be a CA and has path length constraints set */
1413 { { TRUE, TRUE, 1}, bin62 },
1416 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1417 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1418 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1419 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1420 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1421 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1422 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1423 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1424 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1425 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1427 static void test_encodeBasicConstraints(DWORD dwEncoding)
1429 DWORD i, bufSize = 0;
1430 CERT_BASIC_CONSTRAINTS_INFO info;
1431 CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1432 (LPBYTE)encodedDomainName };
1436 /* First test with the simpler info2 */
1437 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1439 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1440 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1442 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1445 ok(bufSize == constraints2[i].encoded[1] + 2,
1446 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1448 ok(!memcmp(buf, constraints2[i].encoded,
1449 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1453 /* Now test with more complex basic constraints */
1454 info.SubjectType.cbData = 0;
1455 info.fPathLenConstraint = FALSE;
1456 info.cSubtreesConstraint = 0;
1457 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1458 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1459 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1462 ok(bufSize == sizeof(emptyConstraint), "Wrong size %ld\n", bufSize);
1463 ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1464 "Unexpected value\n");
1467 /* None of the certs I examined had any subtree constraint, but I test one
1468 * anyway just in case.
1470 info.cSubtreesConstraint = 1;
1471 info.rgSubtreesConstraint = &nameBlob;
1472 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1473 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1474 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1477 ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %ld\n", bufSize);
1478 ok(!memcmp(buf, constraintWithDomainName,
1479 sizeof(constraintWithDomainName)), "Unexpected value\n");
1482 /* FIXME: test encoding with subject type. */
1485 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1486 static const unsigned char encodedCommonName[] = {
1487 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
1489 static void test_decodeBasicConstraints(DWORD dwEncoding)
1491 static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1493 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1499 /* First test with simpler info2 */
1500 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1502 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1503 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1504 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1505 ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1509 CERT_BASIC_CONSTRAINTS2_INFO *info =
1510 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1512 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1513 "Unexpected value for item %ld\n", i);
1517 /* Check with the order of encoded elements inverted */
1519 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1520 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1522 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1523 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1524 ok(!buf, "Expected buf to be set to NULL\n");
1525 /* Check with a non-DER bool */
1526 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1527 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1528 (BYTE *)&buf, &bufSize);
1529 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1532 CERT_BASIC_CONSTRAINTS2_INFO *info =
1533 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1535 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1538 /* Check with a non-basic constraints value */
1539 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1540 (LPBYTE)encodedCommonName, encodedCommonName[1] + 2,
1541 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1542 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1543 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1544 /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
1545 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1546 emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
1547 (BYTE *)&buf, &bufSize);
1548 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1551 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1553 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1554 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1555 ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
1558 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1559 constraintWithDomainName, sizeof(constraintWithDomainName),
1560 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1561 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1564 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1566 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1567 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1568 ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
1569 if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
1571 ok(info->rgSubtreesConstraint[0].cbData ==
1572 sizeof(encodedDomainName), "Wrong size %ld\n",
1573 info->rgSubtreesConstraint[0].cbData);
1574 ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
1575 sizeof(encodedDomainName)), "Unexpected value\n");
1581 /* These are terrible public keys of course, I'm just testing encoding */
1582 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1583 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1584 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1585 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1586 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1587 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1588 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1589 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1591 struct EncodedRSAPubKey
1593 const BYTE *modulus;
1595 const BYTE *encoded;
1596 size_t decodedModulusLen;
1599 struct EncodedRSAPubKey rsaPubKeys[] = {
1600 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1601 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1602 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1603 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1606 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1608 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1609 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1610 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1613 DWORD bufSize = 0, i;
1615 /* Try with a bogus blob type */
1617 hdr->bVersion = CUR_BLOB_VERSION;
1619 hdr->aiKeyAlg = CALG_RSA_KEYX;
1620 rsaPubKey->magic = 0x31415352;
1621 rsaPubKey->bitlen = sizeof(modulus1) * 8;
1622 rsaPubKey->pubexp = 65537;
1623 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1626 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1627 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1629 ok(!ret && GetLastError() == E_INVALIDARG,
1630 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1631 /* Now with a bogus reserved field */
1632 hdr->bType = PUBLICKEYBLOB;
1634 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1635 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1639 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1640 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1641 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1644 /* Now with a bogus blob version */
1647 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1648 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1652 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1653 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1654 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1657 /* And with a bogus alg ID */
1658 hdr->bVersion = CUR_BLOB_VERSION;
1659 hdr->aiKeyAlg = CALG_DES;
1660 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1661 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1665 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1666 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1667 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1670 /* Check a couple of RSA-related OIDs */
1671 hdr->aiKeyAlg = CALG_RSA_KEYX;
1672 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1673 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1674 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1675 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1676 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1677 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1678 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1679 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1680 /* Finally, all valid */
1681 hdr->aiKeyAlg = CALG_RSA_KEYX;
1682 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1684 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1685 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1686 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1687 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1688 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1691 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1692 "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1694 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1695 "Unexpected value\n");
1701 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1708 /* Try with a bad length */
1709 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1710 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1711 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1712 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1713 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1714 /* Try with a couple of RSA-related OIDs */
1715 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1716 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1717 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1718 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1719 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1720 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1721 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1722 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1723 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1724 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1725 /* Now try success cases */
1726 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1729 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1730 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1731 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1732 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1735 BLOBHEADER *hdr = (BLOBHEADER *)buf;
1736 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1738 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1739 rsaPubKeys[i].decodedModulusLen,
1740 "Wrong size %ld\n", bufSize);
1741 ok(hdr->bType == PUBLICKEYBLOB,
1742 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1744 ok(hdr->bVersion == CUR_BLOB_VERSION,
1745 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1746 CUR_BLOB_VERSION, hdr->bVersion);
1747 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1749 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1750 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1751 ok(rsaPubKey->magic == 0x31415352,
1752 "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1753 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1754 "Wrong bit len %ld\n", rsaPubKey->bitlen);
1755 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1757 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1758 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1759 "Unexpected modulus\n");
1765 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1766 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1767 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1769 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1770 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1771 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1772 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1774 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1776 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1777 CRYPT_SEQUENCE_OF_ANY seq;
1783 /* Encode a homogenous sequence */
1784 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1786 blobs[i].cbData = ints[i].encoded[1] + 2;
1787 blobs[i].pbData = (BYTE *)ints[i].encoded;
1789 seq.cValue = sizeof(ints) / sizeof(ints[0]);
1790 seq.rgValue = blobs;
1792 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1793 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1794 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1797 ok(bufSize == sizeof(intSequence), "Wrong size %ld\n", bufSize);
1798 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1801 /* Change the type of the first element in the sequence, and give it
1804 blobs[0].cbData = times[0].encodedTime[1] + 2;
1805 blobs[0].pbData = (BYTE *)times[0].encodedTime;
1806 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1807 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1808 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1811 ok(bufSize == sizeof(mixedSequence), "Wrong size %ld\n", bufSize);
1812 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1813 "Unexpected value\n");
1818 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1824 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1825 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1826 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1829 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1832 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1833 "Wrong elements %ld\n", seq->cValue);
1834 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1836 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1837 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1838 seq->rgValue[i].cbData);
1839 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1840 ints[i].encoded[1] + 2), "Unexpected value\n");
1844 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1845 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1847 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1850 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1852 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1853 "Wrong elements %ld\n", seq->cValue);
1854 /* Just check the first element since it's all that changed */
1855 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1856 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1857 seq->rgValue[0].cbData);
1858 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1859 times[0].encodedTime[1] + 2), "Unexpected value\n");
1864 struct encodedExtensions
1866 CERT_EXTENSIONS exts;
1867 const BYTE *encoded;
1870 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1871 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1873 static CERT_EXTENSION criticalExt =
1874 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1875 static CERT_EXTENSION nonCriticalExt =
1876 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1878 static const BYTE ext0[] = { 0x30,0x00 };
1879 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1880 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1881 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1882 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1884 static const struct encodedExtensions exts[] = {
1885 { { 0, NULL }, ext0 },
1886 { { 1, &criticalExt }, ext1 },
1887 { { 1, &nonCriticalExt }, ext2 },
1890 static void test_encodeExtensions(DWORD dwEncoding)
1894 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1900 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1901 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1902 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1905 ok(bufSize == exts[i].encoded[1] + 2,
1906 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1907 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1908 "Unexpected value\n");
1914 static void test_decodeExtensions(DWORD dwEncoding)
1918 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1924 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1925 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1926 NULL, (BYTE *)&buf, &bufSize);
1927 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1930 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1933 ok(ext->cExtension == exts[i].exts.cExtension,
1934 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1936 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1938 ok(!strcmp(ext->rgExtension[j].pszObjId,
1939 exts[i].exts.rgExtension[j].pszObjId),
1940 "Expected OID %s, got %s\n",
1941 exts[i].exts.rgExtension[j].pszObjId,
1942 ext->rgExtension[j].pszObjId);
1943 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1944 exts[i].exts.rgExtension[j].Value.pbData,
1945 exts[i].exts.rgExtension[j].Value.cbData),
1946 "Unexpected value\n");
1953 /* MS encodes public key info with a NULL if the algorithm identifier's
1954 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
1955 * it encodes them by omitting the algorithm parameters. This latter approach
1956 * seems more correct, so accept either form.
1958 struct encodedPublicKey
1960 CERT_PUBLIC_KEY_INFO info;
1961 const BYTE *encoded;
1962 const BYTE *encodedNoNull;
1963 CERT_PUBLIC_KEY_INFO decoded;
1966 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1968 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1970 static const unsigned char bin64[] = {
1971 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
1972 static const unsigned char bin65[] = {
1973 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
1974 static const unsigned char bin66[] = {
1975 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
1976 static const unsigned char bin67[] = {
1977 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
1978 static const unsigned char bin68[] = {
1979 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1980 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
1981 static const unsigned char bin69[] = {
1982 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
1983 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
1984 static const unsigned char bin70[] = {
1985 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1986 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1988 static const unsigned char bin71[] = {
1989 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1990 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1992 static unsigned char bin72[] = { 0x05,0x00};
1994 static const struct encodedPublicKey pubKeys[] = {
1995 /* with a bogus OID */
1996 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1998 { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
1999 /* some normal keys */
2000 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
2002 { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
2003 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2005 { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2006 /* with add'l parameters--note they must be DER-encoded */
2007 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2008 (BYTE *)aKey, 0 } },
2010 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2011 (BYTE *)aKey, 0 } } },
2014 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2018 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2024 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2025 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2027 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2030 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2031 bufSize == pubKeys[i].encodedNoNull[1] + 2,
2032 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2033 pubKeys[i].encodedNoNull[1] + 2, bufSize);
2034 if (bufSize == pubKeys[i].encoded[1] + 2)
2035 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2036 "Unexpected value\n");
2037 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2038 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2039 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2045 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2046 const CERT_PUBLIC_KEY_INFO *got)
2048 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2049 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2050 got->Algorithm.pszObjId);
2051 ok(expected->Algorithm.Parameters.cbData ==
2052 got->Algorithm.Parameters.cbData,
2053 "Expected parameters of %ld bytes, got %ld\n",
2054 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2055 if (expected->Algorithm.Parameters.cbData)
2056 ok(!memcmp(expected->Algorithm.Parameters.pbData,
2057 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2058 "Unexpected algorithm parameters\n");
2059 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2060 "Expected public key of %ld bytes, got %ld\n",
2061 expected->PublicKey.cbData, got->PublicKey.cbData);
2062 if (expected->PublicKey.cbData)
2063 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2064 got->PublicKey.cbData), "Unexpected public key value\n");
2067 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2069 static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2070 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2071 0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2072 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2078 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2080 /* The NULL form decodes to the decoded member */
2081 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2082 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2083 NULL, (BYTE *)&buf, &bufSize);
2084 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2087 comparePublicKeyInfo(&pubKeys[i].decoded,
2088 (CERT_PUBLIC_KEY_INFO *)buf);
2091 /* The non-NULL form decodes to the original */
2092 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2093 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2094 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2095 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2098 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2102 /* Test with bogus (not valid DER) parameters */
2103 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2104 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2105 NULL, (BYTE *)&buf, &bufSize);
2106 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2107 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2110 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2111 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2112 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2113 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2114 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2115 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2116 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2117 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2118 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2119 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2120 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2121 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2122 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2123 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2124 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2125 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2126 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2127 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2128 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2129 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2130 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2131 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2132 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2133 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2134 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2135 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2136 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2137 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2138 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2139 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2140 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2141 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2142 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2143 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2144 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2145 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2146 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2147 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2148 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2150 static const BYTE serialNum[] = { 0x01 };
2152 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2157 CERT_INFO info = { 0 };
2159 /* Test with NULL pvStructInfo */
2160 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2161 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2162 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2163 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2164 /* Test with a V1 cert */
2165 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2166 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2167 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2170 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2171 v1Cert[1] + 2, size);
2172 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2176 info.dwVersion = CERT_V2;
2177 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2178 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2179 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2182 ok(size == sizeof(v2Cert), "Wrong size %ld\n", size);
2183 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2187 info.dwVersion = CERT_V3;
2188 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2189 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2190 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2193 ok(size == sizeof(v3Cert), "Wrong size %ld\n", size);
2194 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2197 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2198 * API doesn't prevent it)
2200 info.dwVersion = CERT_V1;
2201 info.cExtension = 1;
2202 info.rgExtension = &criticalExt;
2203 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2204 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2205 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2208 ok(size == sizeof(v1CertWithConstraints), "Wrong size %ld\n", size);
2209 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2212 /* test v1 cert with a serial number */
2213 info.SerialNumber.cbData = sizeof(serialNum);
2214 info.SerialNumber.pbData = (BYTE *)serialNum;
2215 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2216 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2219 ok(size == sizeof(v1CertWithSerial), "Wrong size %ld\n", size);
2220 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2223 /* Test v1 cert with an issuer name, a subject name, and a serial number */
2224 info.Issuer.cbData = sizeof(encodedCommonName);
2225 info.Issuer.pbData = (BYTE *)encodedCommonName;
2226 info.Subject.cbData = sizeof(encodedCommonName);
2227 info.Subject.pbData = (BYTE *)encodedCommonName;
2228 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2229 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2232 ok(size == sizeof(bigCert), "Wrong size %ld\n", size);
2233 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2236 /* for now, I let more interesting tests be done for each subcomponent,
2237 * rather than retesting them all here.
2241 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2243 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2244 v1CertWithConstraints, v1CertWithSerial };
2249 /* Test with NULL pbEncoded */
2250 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2251 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2252 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2253 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2254 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2255 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2256 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2257 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2258 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2259 * minimum a cert must have a non-zero serial number, an issuer, and a
2262 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2264 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2265 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2266 (BYTE *)&buf, &size);
2267 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2268 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2270 /* Now check with serial number, subject and issuer specified */
2271 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2272 sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2273 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2276 CERT_INFO *info = (CERT_INFO *)buf;
2278 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2279 ok(info->SerialNumber.cbData == 1,
2280 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2281 ok(*info->SerialNumber.pbData == *serialNum,
2282 "Expected serial number %d, got %d\n", *serialNum,
2283 *info->SerialNumber.pbData);
2284 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2285 "Wrong size %ld\n", info->Issuer.cbData);
2286 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2287 "Unexpected issuer\n");
2288 ok(info->Subject.cbData == sizeof(encodedCommonName),
2289 "Wrong size %ld\n", info->Subject.cbData);
2290 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2291 info->Subject.cbData), "Unexpected subject\n");
2296 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2299 static const BYTE signedBigCert[] = {
2300 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2301 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2302 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2303 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2304 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2305 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2306 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2307 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2308 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2309 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2310 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2311 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2313 static void test_encodeCert(DWORD dwEncoding)
2315 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
2316 * also that bigCert is a NULL-terminated string, so don't count its
2317 * last byte (otherwise the signed cert won't decode.)
2319 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2320 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2325 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2326 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2327 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2330 ok(bufSize == sizeof(signedBigCert), "Wrong size %ld\n", bufSize);
2331 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2336 static void test_decodeCert(DWORD dwEncoding)
2342 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2343 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2344 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2347 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2349 ok(info->ToBeSigned.cbData == sizeof(bigCert),
2350 "Wrong cert size %ld\n", info->ToBeSigned.cbData);
2351 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2352 "Unexpected cert\n");
2353 ok(info->Signature.cbData == sizeof(hash),
2354 "Wrong signature size %ld\n", info->Signature.cbData);
2355 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2356 "Unexpected signature\n");
2359 /* A signed cert decodes as a CERT_INFO too */
2360 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, signedBigCert,
2361 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2362 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2365 CERT_INFO *info = (CERT_INFO *)buf;
2367 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2368 ok(info->SerialNumber.cbData == 1,
2369 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2370 ok(*info->SerialNumber.pbData == *serialNum,
2371 "Expected serial number %d, got %d\n", *serialNum,
2372 *info->SerialNumber.pbData);
2373 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2374 "Wrong size %ld\n", info->Issuer.cbData);
2375 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2376 "Unexpected issuer\n");
2377 ok(info->Subject.cbData == sizeof(encodedCommonName),
2378 "Wrong size %ld\n", info->Subject.cbData);
2379 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2380 info->Subject.cbData), "Unexpected subject\n");
2385 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2386 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2387 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2388 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2389 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2391 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2392 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2393 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2394 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2395 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2396 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2397 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2398 0x2e, 0x6f, 0x72, 0x67 };
2399 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2400 CRL_REASON_AFFILIATION_CHANGED;
2402 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2404 CRL_DIST_POINTS_INFO info = { 0 };
2405 CRL_DIST_POINT point = { { 0 } };
2406 CERT_ALT_NAME_ENTRY entry = { 0 };
2411 /* Test with an empty info */
2412 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2413 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2414 ok(!ret && GetLastError() == E_INVALIDARG,
2415 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2416 /* Test with one empty dist point */
2417 info.cDistPoint = 1;
2418 info.rgDistPoint = &point;
2419 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2420 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2423 ok(size == sizeof(emptyDistPoint), "Wrong size %ld\n", size);
2424 ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2427 /* A dist point with an invalid name */
2428 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2429 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2430 U(entry).pwszURL = (LPWSTR)nihongoURL;
2431 U(point.DistPointName).FullName.cAltEntry = 1;
2432 U(point.DistPointName).FullName.rgAltEntry = &entry;
2433 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2434 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2435 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2436 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2437 /* The first invalid character is at index 7 */
2438 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2439 "Expected invalid char at index 7, got %ld\n",
2440 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2441 /* A dist point with (just) a valid name */
2442 U(entry).pwszURL = (LPWSTR)url;
2443 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2444 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2447 ok(size == sizeof(distPointWithUrl), "Wrong size %ld\n", size);
2448 ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2451 /* A dist point with (just) reason flags */
2452 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2453 point.ReasonFlags.cbData = sizeof(crlReason);
2454 point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2455 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2456 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2459 ok(size == sizeof(distPointWithReason), "Wrong size %ld\n", size);
2460 ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2463 /* A dist point with just an issuer */
2464 point.ReasonFlags.cbData = 0;
2465 point.CRLIssuer.cAltEntry = 1;
2466 point.CRLIssuer.rgAltEntry = &entry;
2467 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2468 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2471 ok(size == sizeof(distPointWithIssuer), "Wrong size %ld\n", size);
2472 ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2475 /* A dist point with both a name and an issuer */
2476 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2477 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2478 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2481 ok(size == sizeof(distPointWithUrlAndIssuer),
2482 "Wrong size %ld\n", size);
2483 ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2488 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2493 PCRL_DIST_POINTS_INFO info;
2494 PCRL_DIST_POINT point;
2495 PCERT_ALT_NAME_ENTRY entry;
2497 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2498 emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2499 (BYTE *)&buf, &size);
2502 info = (PCRL_DIST_POINTS_INFO)buf;
2503 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2504 "Wrong size %ld\n", size);
2505 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2507 point = info->rgDistPoint;
2508 ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2509 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2510 point->DistPointName.dwDistPointNameChoice);
2511 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2512 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2515 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2516 distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2517 (BYTE *)&buf, &size);
2520 info = (PCRL_DIST_POINTS_INFO)buf;
2521 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2522 "Wrong size %ld\n", size);
2523 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2525 point = info->rgDistPoint;
2526 ok(point->DistPointName.dwDistPointNameChoice ==
2527 CRL_DIST_POINT_FULL_NAME,
2528 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2529 point->DistPointName.dwDistPointNameChoice);
2530 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2531 "Expected 1 name entry, got %ld\n",
2532 U(point->DistPointName).FullName.cAltEntry);
2533 entry = U(point->DistPointName).FullName.rgAltEntry;
2534 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2535 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2536 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2537 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2538 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2541 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2542 distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2543 NULL, (BYTE *)&buf, &size);
2546 info = (PCRL_DIST_POINTS_INFO)buf;
2547 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2548 "Wrong size %ld\n", size);
2549 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2551 point = info->rgDistPoint;
2552 ok(point->DistPointName.dwDistPointNameChoice ==
2553 CRL_DIST_POINT_NO_NAME,
2554 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2555 point->DistPointName.dwDistPointNameChoice);
2556 ok(point->ReasonFlags.cbData == sizeof(crlReason),
2557 "Expected reason length\n");
2558 ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2559 "Unexpected reason\n");
2560 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2563 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2564 distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2565 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2568 info = (PCRL_DIST_POINTS_INFO)buf;
2569 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2570 "Wrong size %ld\n", size);
2571 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2573 point = info->rgDistPoint;
2574 ok(point->DistPointName.dwDistPointNameChoice ==
2575 CRL_DIST_POINT_FULL_NAME,
2576 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2577 point->DistPointName.dwDistPointNameChoice);
2578 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2579 "Expected 1 name entry, got %ld\n",
2580 U(point->DistPointName).FullName.cAltEntry);
2581 entry = U(point->DistPointName).FullName.rgAltEntry;
2582 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2583 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2584 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2585 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2586 ok(point->CRLIssuer.cAltEntry == 1,
2587 "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2588 entry = point->CRLIssuer.rgAltEntry;
2589 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2590 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2591 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2596 static const BYTE badFlagsIDP[] = { 0x30,0x06,0x81,0x01,0xff,0x82,0x01,0xff };
2597 static const BYTE emptyNameIDP[] = { 0x30,0x04,0xa0,0x02,0xa0,0x00 };
2598 static const BYTE urlIDP[] = { 0x30,0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,
2599 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,
2602 static void test_encodeCRLIssuingDistPoint(DWORD dwEncoding)
2607 CRL_ISSUING_DIST_POINT point = { { 0 } };
2608 CERT_ALT_NAME_ENTRY entry;
2610 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, NULL,
2611 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2612 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2613 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2614 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2615 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2616 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2619 ok(size == sizeof(emptySequence), "Unexpected size %ld\n", size);
2620 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
2623 /* nonsensical flags */
2624 point.fOnlyContainsUserCerts = TRUE;
2625 point.fOnlyContainsCACerts = TRUE;
2626 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2627 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2628 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2631 ok(size == sizeof(badFlagsIDP), "Unexpected size %ld\n", size);
2632 ok(!memcmp(buf, badFlagsIDP, size), "Unexpected value\n");
2635 /* unimplemented name type */
2636 point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
2637 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_ISSUER_RDN_NAME;
2638 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2639 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2640 ok(!ret && GetLastError() == E_INVALIDARG,
2641 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2643 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2644 U(point.DistPointName).FullName.cAltEntry = 0;
2645 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2646 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2647 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2650 ok(size == sizeof(emptyNameIDP), "Unexpected size %ld\n", size);
2651 ok(!memcmp(buf, emptyNameIDP, size), "Unexpected value\n");
2654 /* name with URL entry */
2655 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2656 U(entry).pwszURL = (LPWSTR)url;
2657 U(point.DistPointName).FullName.cAltEntry = 1;
2658 U(point.DistPointName).FullName.rgAltEntry = &entry;
2659 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2660 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2661 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2664 ok(size == sizeof(urlIDP), "Unexpected size %ld\n", size);
2665 ok(!memcmp(buf, urlIDP, size), "Unexpected value\n");
2670 static void compareAltNameEntry(const CERT_ALT_NAME_ENTRY *expected,
2671 const CERT_ALT_NAME_ENTRY *got)
2673 ok(expected->dwAltNameChoice == got->dwAltNameChoice,
2674 "Expected name choice %ld, got %ld\n", expected->dwAltNameChoice,
2675 got->dwAltNameChoice);
2676 if (expected->dwAltNameChoice == got->dwAltNameChoice)
2678 switch (got->dwAltNameChoice)
2680 case CERT_ALT_NAME_RFC822_NAME:
2681 case CERT_ALT_NAME_DNS_NAME:
2682 case CERT_ALT_NAME_EDI_PARTY_NAME:
2683 case CERT_ALT_NAME_URL:
2684 case CERT_ALT_NAME_REGISTERED_ID:
2685 ok((!U(*expected).pwszURL && !U(*got).pwszURL) ||
2686 !lstrcmpW(U(*expected).pwszURL, U(*got).pwszURL), "Unexpected name\n");
2688 case CERT_ALT_NAME_X400_ADDRESS:
2689 case CERT_ALT_NAME_DIRECTORY_NAME:
2690 case CERT_ALT_NAME_IP_ADDRESS:
2691 ok(U(*got).IPAddress.cbData == U(*expected).IPAddress.cbData,
2692 "Unexpected IP address length %ld\n", U(*got).IPAddress.cbData);
2693 ok(!memcmp(U(*got).IPAddress.pbData, U(*got).IPAddress.pbData,
2694 U(*got).IPAddress.cbData), "Unexpected value\n");
2700 static void compareAltNameInfo(const CERT_ALT_NAME_INFO *expected,
2701 const CERT_ALT_NAME_INFO *got)
2705 ok(expected->cAltEntry == got->cAltEntry, "Expected %ld entries, got %ld\n",
2706 expected->cAltEntry, got->cAltEntry);
2707 for (i = 0; i < min(expected->cAltEntry, got->cAltEntry); i++)
2708 compareAltNameEntry(&expected->rgAltEntry[i], &got->rgAltEntry[i]);
2711 static void compareDistPointName(const CRL_DIST_POINT_NAME *expected,
2712 const CRL_DIST_POINT_NAME *got)
2714 ok(got->dwDistPointNameChoice == expected->dwDistPointNameChoice,
2715 "Unexpected name choice %ld\n", got->dwDistPointNameChoice);
2716 if (got->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
2717 compareAltNameInfo(&(U(*expected).FullName), &(U(*got).FullName));
2720 static void compareCRLIssuingDistPoints(const CRL_ISSUING_DIST_POINT *expected,
2721 const CRL_ISSUING_DIST_POINT *got)
2723 compareDistPointName(&expected->DistPointName, &got->DistPointName);
2724 ok(got->fOnlyContainsUserCerts == expected->fOnlyContainsUserCerts,
2725 "Unexpected fOnlyContainsUserCerts\n");
2726 ok(got->fOnlyContainsCACerts == expected->fOnlyContainsCACerts,
2727 "Unexpected fOnlyContainsCACerts\n");
2728 ok(got->OnlySomeReasonFlags.cbData == expected->OnlySomeReasonFlags.cbData,
2729 "Unexpected reason flags\n");
2730 ok(got->fIndirectCRL == expected->fIndirectCRL,
2731 "Unexpected fIndirectCRL\n");
2734 static void test_decodeCRLIssuingDistPoint(DWORD dwEncoding)
2739 CRL_ISSUING_DIST_POINT point = { { 0 } };
2741 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2742 emptySequence, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2743 (BYTE *)&buf, &size);
2744 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2747 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2750 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2751 badFlagsIDP, badFlagsIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2752 (BYTE *)&buf, &size);
2753 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2756 point.fOnlyContainsUserCerts = point.fOnlyContainsCACerts = TRUE;
2757 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2760 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2761 emptyNameIDP, emptyNameIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2762 (BYTE *)&buf, &size);
2763 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2766 point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
2767 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2768 U(point.DistPointName).FullName.cAltEntry = 0;
2769 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2772 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2773 urlIDP, urlIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2774 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2777 CERT_ALT_NAME_ENTRY entry;
2779 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2780 U(entry).pwszURL = (LPWSTR)url;
2781 U(point.DistPointName).FullName.cAltEntry = 1;
2782 U(point.DistPointName).FullName.rgAltEntry = &entry;
2783 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2788 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2789 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2791 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2792 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2793 0x30, 0x30, 0x30, 0x30, 0x5a };
2794 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2795 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2796 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2797 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2799 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2800 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2801 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2802 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2803 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2804 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2805 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2806 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2807 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2808 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2809 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2810 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2811 static const BYTE v1CRLWithEntryExt[] = { 0x30,0x5a,0x30,0x02,0x06,0x00,0x30,
2812 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
2813 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
2814 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x2c,0x30,0x2a,0x02,0x01,
2815 0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,
2816 0x30,0x30,0x5a,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,
2817 0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2818 static const BYTE v1CRLWithExt[] = { 0x30,0x5c,0x30,0x02,0x06,0x00,0x30,0x15,
2819 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
2820 0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
2821 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,
2822 0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,
2823 0x30,0x5a,0xa0,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
2824 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2825 static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06,
2826 0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,
2827 0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,
2828 0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,
2829 0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,
2830 0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,
2831 0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2832 static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01,
2833 0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
2834 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,
2835 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,
2836 0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
2837 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,
2838 0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2840 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2844 static CHAR oid_issuing_dist_point[] = szOID_ISSUING_DIST_POINT;
2846 CRL_INFO info = { 0 };
2847 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2850 /* Test with a V1 CRL */
2851 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2852 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2853 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2856 ok(size == sizeof(v1CRL), "Wrong size %ld\n", size);
2857 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2861 info.dwVersion = CRL_V2;
2862 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2863 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2864 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2867 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2868 v2CRL[1] + 2, size);
2869 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2872 /* v1 CRL with a name */
2873 info.dwVersion = CRL_V1;
2874 info.Issuer.cbData = sizeof(encodedCommonName);
2875 info.Issuer.pbData = (BYTE *)encodedCommonName;
2876 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2877 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2878 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2881 ok(size == sizeof(v1CRLWithIssuer), "Wrong size %ld\n", size);
2882 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2885 /* v1 CRL with a name and a NULL entry pointer */
2887 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2888 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2889 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2890 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2891 /* now set an empty entry */
2892 info.rgCRLEntry = &entry;
2893 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2894 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2897 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2898 "Wrong size %ld\n", size);
2899 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2900 "Got unexpected value\n");
2903 /* an entry with a serial number */
2904 entry.SerialNumber.cbData = sizeof(serialNum);
2905 entry.SerialNumber.pbData = (BYTE *)serialNum;
2906 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2907 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2910 ok(size == sizeof(v1CRLWithIssuerAndEntry),
2911 "Wrong size %ld\n", size);
2912 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2913 "Got unexpected value\n");
2916 /* an entry with an extension */
2917 entry.cExtension = 1;
2918 entry.rgExtension = &criticalExt;
2919 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2920 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2921 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2924 ok(size == sizeof(v1CRLWithEntryExt), "Wrong size %ld\n", size);
2925 ok(!memcmp(buf, v1CRLWithEntryExt, size), "Got unexpected value\n");
2928 /* a CRL with an extension */
2929 entry.cExtension = 0;
2930 info.cExtension = 1;
2931 info.rgExtension = &criticalExt;
2932 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2933 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2934 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2937 ok(size == sizeof(v1CRLWithExt), "Wrong size %ld\n", size);
2938 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2941 /* a v2 CRL with an extension, this time non-critical */
2942 info.dwVersion = CRL_V2;
2943 info.rgExtension = &nonCriticalExt;
2944 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2945 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2946 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2949 ok(size == sizeof(v2CRLWithExt), "Wrong size %ld\n", size);
2950 ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n");
2953 /* a v2 CRL with an issuing dist point extension */
2954 ext.pszObjId = oid_issuing_dist_point;
2955 ext.fCritical = TRUE;
2956 ext.Value.cbData = sizeof(urlIDP);
2957 ext.Value.pbData = (LPBYTE)urlIDP;
2958 entry.rgExtension = &ext;
2959 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2960 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2961 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2964 ok(size == sizeof(v2CRLWithIssuingDistPoint), "Wrong size %ld\n", size);
2965 ok(!memcmp(buf, v2CRLWithIssuingDistPoint, size), "Unexpected value\n");
2970 static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01,
2971 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
2972 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06,
2973 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
2974 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56,
2975 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
2976 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65,
2977 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
2978 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
2979 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43,
2980 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30,
2981 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33,
2982 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51,
2983 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99,
2984 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31,
2985 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0,
2986 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30,
2987 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30,
2988 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75,
2989 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33,
2990 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30,
2991 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
2992 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06,
2993 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03,
2994 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88,
2995 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd,
2996 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf,
2997 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46,
2998 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f,
2999 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75,
3000 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f,
3001 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82,
3002 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07,
3003 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c,
3006 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
3008 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
3013 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
3015 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3016 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3017 (BYTE *)&buf, &size);
3018 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
3019 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3021 /* at a minimum, a CRL must contain an issuer: */
3022 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3023 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3024 (BYTE *)&buf, &size);
3025 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3028 CRL_INFO *info = (CRL_INFO *)buf;
3030 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3031 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
3033 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3034 "Wrong issuer size %ld\n", info->Issuer.cbData);
3035 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3036 "Unexpected issuer\n");
3039 /* check decoding with an empty CRL entry */
3040 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3041 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
3042 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3043 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
3044 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3045 /* with a real CRL entry */
3046 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3047 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
3048 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3049 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3052 CRL_INFO *info = (CRL_INFO *)buf;
3055 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3056 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3058 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3059 entry = info->rgCRLEntry;
3060 ok(entry->SerialNumber.cbData == 1,
3061 "Expected serial number size 1, got %ld\n",
3062 entry->SerialNumber.cbData);
3063 ok(*entry->SerialNumber.pbData == *serialNum,
3064 "Expected serial number %d, got %d\n", *serialNum,
3065 *entry->SerialNumber.pbData);
3066 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3067 "Wrong issuer size %ld\n", info->Issuer.cbData);
3068 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3069 "Unexpected issuer\n");
3071 /* a real CRL from verisign that has extensions */
3072 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3073 verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG,
3074 NULL, (BYTE *)&buf, &size);
3075 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3078 CRL_INFO *info = (CRL_INFO *)buf;
3081 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3082 ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %ld\n",
3084 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3085 entry = info->rgCRLEntry;
3086 ok(info->cExtension == 2, "Expected 2 extensions, got %ld\n",
3089 /* and finally, with an extension */
3090 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3091 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3092 NULL, (BYTE *)&buf, &size);
3093 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3096 CRL_INFO *info = (CRL_INFO *)buf;
3099 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3100 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3102 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3103 entry = info->rgCRLEntry;
3104 ok(entry->SerialNumber.cbData == 1,
3105 "Expected serial number size 1, got %ld\n",
3106 entry->SerialNumber.cbData);
3107 ok(*entry->SerialNumber.pbData == *serialNum,
3108 "Expected serial number %d, got %d\n", *serialNum,
3109 *entry->SerialNumber.pbData);
3110 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3111 "Wrong issuer size %ld\n", info->Issuer.cbData);
3112 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3113 "Unexpected issuer\n");
3114 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3117 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3118 v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3119 NULL, (BYTE *)&buf, &size);
3120 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3123 CRL_INFO *info = (CRL_INFO *)buf;
3125 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3129 /* And again, with an issuing dist point */
3130 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3131 v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint),
3132 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3133 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3136 CRL_INFO *info = (CRL_INFO *)buf;
3138 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3144 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
3145 szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
3146 static const BYTE encodedUsage[] = {
3147 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
3148 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
3149 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
3151 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
3156 CERT_ENHKEY_USAGE usage;
3158 /* Test with empty usage */
3159 usage.cUsageIdentifier = 0;
3160 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3161 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3162 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3165 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
3166 ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
3169 /* Test with a few usages */
3170 usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
3171 usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
3172 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3173 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3174 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3177 ok(size == sizeof(encodedUsage), "Wrong size %ld\n", size);
3178 ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
3183 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
3189 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3190 emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
3191 (BYTE *)&buf, &size);
3192 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3195 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3197 ok(size >= sizeof(CERT_ENHKEY_USAGE),
3198 "Wrong size %ld\n", size);
3199 ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
3200 usage->cUsageIdentifier);
3203 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3204 encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
3205 (BYTE *)&buf, &size);
3206 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3209 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3212 ok(size >= sizeof(CERT_ENHKEY_USAGE),
3213 "Wrong size %ld\n", size);
3214 ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
3215 "Wrong CRL entries count %ld\n", usage->cUsageIdentifier);
3216 for (i = 0; i < usage->cUsageIdentifier; i++)
3217 ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
3218 "Expected OID %s, got %s\n", keyUsages[i],
3219 usage->rgpszUsageIdentifier[i]);
3224 /* Free *pInfo with HeapFree */
3225 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
3232 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
3234 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
3235 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3236 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3237 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
3239 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3240 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3241 ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
3243 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3244 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3245 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3246 0, NULL, NULL, &size);
3247 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3248 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3249 /* Test with no key */
3250 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3251 0, NULL, NULL, &size);
3252 ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
3254 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
3255 ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
3258 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
3259 NULL, 0, NULL, NULL, &size);
3260 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3261 *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
3264 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
3265 X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
3266 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
3270 /* By default (we passed NULL as the OID) the OID is
3273 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
3274 "Expected %s, got %s\n", szOID_RSA_RSA,
3275 (*pInfo)->Algorithm.pszObjId);
3281 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
3282 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
3283 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
3284 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3285 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3286 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3287 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
3288 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
3289 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3290 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3291 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3292 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3293 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
3294 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
3295 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
3296 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
3297 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
3298 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
3299 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
3300 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
3301 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
3302 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
3303 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
3304 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
3305 0x49, 0xe5, 0xf9, 0x65, 0xf3 };
3307 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
3311 PCCERT_CONTEXT context;
3314 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
3315 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
3316 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
3317 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3320 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3321 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3322 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3323 ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3324 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3325 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3326 ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3328 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3329 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3330 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3332 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3333 CryptDestroyKey(key);
3335 /* Test importing a public key from a certificate context */
3336 context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert,
3337 sizeof(expiredCert));
3338 ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
3342 ok(!strcmp(szOID_RSA_RSA,
3343 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId),
3344 "Expected %s, got %s\n", szOID_RSA_RSA,
3345 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
3346 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING,
3347 &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key);
3348 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3349 CryptDestroyKey(key);
3350 CertFreeCertificateContext(context);
3354 static const char cspName[] = "WineCryptTemp";
3356 static void testPortPublicKeyInfo(void)
3360 PCERT_PUBLIC_KEY_INFO info = NULL;
3362 /* Just in case a previous run failed, delete this thing */
3363 CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3364 CRYPT_DELETEKEYSET);
3365 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3368 testExportPublicKey(csp, &info);
3369 testImportPublicKey(csp, info);
3371 HeapFree(GetProcessHeap(), 0, info);
3372 CryptReleaseContext(csp, 0);
3373 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3374 CRYPT_DELETEKEYSET);
3379 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3380 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3383 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3385 test_encodeInt(encodings[i]);
3386 test_decodeInt(encodings[i]);
3387 test_encodeEnumerated(encodings[i]);
3388 test_decodeEnumerated(encodings[i]);
3389 test_encodeFiletime(encodings[i]);
3390 test_decodeFiletime(encodings[i]);
3391 test_encodeName(encodings[i]);
3392 test_decodeName(encodings[i]);
3393 test_encodeNameValue(encodings[i]);
3394 test_decodeNameValue(encodings[i]);
3395 test_encodeAltName(encodings[i]);
3396 test_decodeAltName(encodings[i]);
3397 test_encodeOctets(encodings[i]);
3398 test_decodeOctets(encodings[i]);
3399 test_encodeBits(encodings[i]);
3400 test_decodeBits(encodings[i]);
3401 test_encodeBasicConstraints(encodings[i]);
3402 test_decodeBasicConstraints(encodings[i]);
3403 test_encodeRsaPublicKey(encodings[i]);
3404 test_decodeRsaPublicKey(encodings[i]);
3405 test_encodeSequenceOfAny(encodings[i]);
3406 test_decodeSequenceOfAny(encodings[i]);
3407 test_encodeExtensions(encodings[i]);
3408 test_decodeExtensions(encodings[i]);
3409 test_encodePublicKeyInfo(encodings[i]);
3410 test_decodePublicKeyInfo(encodings[i]);
3411 test_encodeCertToBeSigned(encodings[i]);
3412 test_decodeCertToBeSigned(encodings[i]);
3413 test_encodeCert(encodings[i]);
3414 test_decodeCert(encodings[i]);
3415 test_encodeCRLDistPoints(encodings[i]);
3416 test_decodeCRLDistPoints(encodings[i]);
3417 test_encodeCRLIssuingDistPoint(encodings[i]);
3418 test_decodeCRLIssuingDistPoint(encodings[i]);
3419 test_encodeCRLToBeSigned(encodings[i]);
3420 test_decodeCRLToBeSigned(encodings[i]);
3421 test_encodeEnhancedKeyUsage(encodings[i]);
3422 test_decodeEnhancedKeyUsage(encodings[i]);
3424 testPortPublicKeyInfo();