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};
608 static const BYTE encodedTwoRDNs[] = {
609 0x30,0x2e,0x31,0x2c,0x30,0x2a,0x06,0x03,0x55,0x04,0x03,0x30,0x23,0x31,0x21,
610 0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,
611 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
615 static const BYTE us[] = { 0x55, 0x53 };
616 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
618 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
619 0x6f, 0x6c, 0x69, 0x73 };
620 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
621 0x76, 0x65, 0x72, 0x73 };
622 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
623 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
624 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
626 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
627 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
629 #define RDNA(arr) oid_ ## arr, CERT_RDN_PRINTABLE_STRING, { sizeof(arr), (LPBYTE)arr }
630 #define RDNIA5(arr) oid_ ## arr, CERT_RDN_IA5_STRING, { sizeof(arr), (LPBYTE)arr }
632 static CHAR oid_us[] = "2.5.4.6",
633 oid_minnesota[] = "2.5.4.8",
634 oid_minneapolis[] = "2.5.4.7",
635 oid_codeweavers[] = "2.5.4.10",
636 oid_wine[] = "2.5.4.11",
637 oid_localhostAttr[] = "2.5.4.3",
638 oid_aric[] = "1.2.840.113549.1.9.1";
639 static CERT_RDN_ATTR rdnAttrs[] = { { RDNA(us) },
641 { RDNA(minneapolis) },
642 { RDNA(codeweavers) },
644 { RDNA(localhostAttr) },
646 static CERT_RDN_ATTR decodedRdnAttrs[] = { { RDNA(us) },
647 { RDNA(localhostAttr) },
649 { RDNA(minneapolis) },
650 { RDNA(codeweavers) },
657 static const BYTE encodedRDNAttrs[] = {
658 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
659 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
660 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
661 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
662 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
663 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
664 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
665 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
666 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
667 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
670 static void test_encodeName(DWORD dwEncoding)
672 CERT_RDN_ATTR attrs[2];
675 static CHAR oid_common_name[] = szOID_COMMON_NAME,
676 oid_sur_name[] = szOID_SUR_NAME;
681 /* Test with NULL pvStructInfo */
682 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
683 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
684 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
685 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
686 /* Test with empty CERT_NAME_INFO */
689 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
690 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
691 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
694 ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
695 "Got unexpected encoding for empty name\n");
698 /* Test with bogus CERT_RDN */
700 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
701 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
702 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
703 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
704 /* Test with empty CERT_RDN */
706 rdn.rgRDNAttr = NULL;
709 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
710 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
711 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
714 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
715 "Got unexpected encoding for empty RDN array\n");
718 /* Test with bogus attr array */
720 rdn.rgRDNAttr = NULL;
721 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
722 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
723 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
724 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
725 /* oddly, a bogus OID is accepted by Windows XP; not testing.
726 attrs[0].pszObjId = "bogus";
727 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
728 attrs[0].Value.cbData = sizeof(commonName);
729 attrs[0].Value.pbData = (BYTE *)commonName;
731 rdn.rgRDNAttr = attrs;
732 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
733 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
734 ok(!ret, "Expected failure, got success\n");
736 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
737 * the encoded attributes to be swapped.
739 attrs[0].pszObjId = oid_common_name;
740 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
741 attrs[0].Value.cbData = sizeof(commonName);
742 attrs[0].Value.pbData = (BYTE *)commonName;
743 attrs[1].pszObjId = oid_sur_name;
744 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
745 attrs[1].Value.cbData = sizeof(surName);
746 attrs[1].Value.pbData = (BYTE *)surName;
748 rdn.rgRDNAttr = attrs;
749 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
750 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
751 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
754 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
755 "Got unexpected encoding for two RDN array\n");
758 /* A name can be "encoded" with previously encoded RDN attrs. */
759 attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB;
760 attrs[0].Value.pbData = (LPBYTE)twoRDNs;
761 attrs[0].Value.cbData = sizeof(twoRDNs);
763 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
764 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
765 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
768 ok(size == sizeof(encodedTwoRDNs), "Unexpected size %ld\n", size);
769 ok(!memcmp(buf, encodedTwoRDNs, size),
770 "Unexpected value for re-endoded two RDN array\n");
773 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
775 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
776 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
777 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
778 ok(!ret && GetLastError() == E_INVALIDARG,
779 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
780 /* Test a more complex name */
781 rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
782 rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
787 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
788 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
789 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
792 ok(size == sizeof(encodedRDNAttrs), "Wrong size %ld\n", size);
793 ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
798 static WCHAR commonNameW[] = { 'J','u','a','n',' ','L','a','n','g',0 };
799 static WCHAR surNameW[] = { 'L','a','n','g',0 };
801 static const BYTE twoRDNsNoNull[] = {
802 0x30,0x21,0x31,0x1f,0x30,0x0b,0x06,0x03,0x55,0x04,0x04,0x13,0x04,0x4c,0x61,
803 0x6e,0x67,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,
804 0x20,0x4c,0x61,0x6e,0x67 };
805 static const BYTE anyType[] = {
806 0x30,0x2f,0x31,0x2d,0x30,0x2b,0x06,0x03,0x55,0x04,0x03,0x1e,0x24,0x23,0x30,
807 0x21,0x31,0x0c,0x30,0x03,0x06,0x04,0x55,0x13,0x04,0x4c,0x05,0x6e,0x61,0x00,
808 0x67,0x11,0x30,0x03,0x06,0x04,0x55,0x13,0x03,0x4a,0x0a,0x61,0x75,0x20,0x6e,
809 0x61,0x4c,0x67,0x6e };
811 static void test_encodeUnicodeName(DWORD dwEncoding)
813 CERT_RDN_ATTR attrs[2];
816 static CHAR oid_common_name[] = szOID_COMMON_NAME,
817 oid_sur_name[] = szOID_SUR_NAME;
822 /* Test with NULL pvStructInfo */
823 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, NULL,
824 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
825 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
826 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
827 /* Test with empty CERT_NAME_INFO */
830 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
831 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
832 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
835 ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
836 "Got unexpected encoding for empty name\n");
839 /* Check with one CERT_RDN_ATTR, that has an invalid character for the
840 * encoding (the NULL).
842 attrs[0].pszObjId = oid_common_name;
843 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
844 attrs[0].Value.cbData = sizeof(commonNameW);
845 attrs[0].Value.pbData = (BYTE *)commonNameW;
847 rdn.rgRDNAttr = attrs;
850 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
851 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
852 ok(!ret && GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING,
853 "Expected CRYPT_E_INVALID_PRINTABLE_STRING, got %08lx\n", GetLastError());
854 ok(size == 9, "Unexpected error index %08lx\n", size);
855 /* Check with two NULL-terminated CERT_RDN_ATTRs. Note DER encoding
856 * forces the order of the encoded attributes to be swapped.
858 attrs[0].pszObjId = oid_common_name;
859 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
860 attrs[0].Value.cbData = 0;
861 attrs[0].Value.pbData = (BYTE *)commonNameW;
862 attrs[1].pszObjId = oid_sur_name;
863 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
864 attrs[1].Value.cbData = 0;
865 attrs[1].Value.pbData = (BYTE *)surNameW;
867 rdn.rgRDNAttr = attrs;
870 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
871 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
872 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
875 ok(!memcmp(buf, twoRDNsNoNull, sizeof(twoRDNsNoNull)),
876 "Got unexpected encoding for two RDN array\n");
879 /* A name can be "encoded" with previously encoded RDN attrs. */
880 attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB;
881 attrs[0].Value.pbData = (LPBYTE)twoRDNs;
882 attrs[0].Value.cbData = sizeof(twoRDNs);
884 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
885 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
886 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
889 ok(size == sizeof(encodedTwoRDNs), "Unexpected size %ld\n", size);
890 ok(!memcmp(buf, encodedTwoRDNs, size),
891 "Unexpected value for re-endoded two RDN array\n");
894 /* Unicode names infer the type for CERT_RDN_ANY_TYPE */
896 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
897 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
898 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
899 todo_wine ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
902 ok(size == sizeof(anyType), "Unexpected size %ld\n", size);
903 ok(!memcmp(buf, anyType, size), "Unexpected value\n");
908 static void compareNameValues(const CERT_NAME_VALUE *expected,
909 const CERT_NAME_VALUE *got)
911 ok(got->dwValueType == expected->dwValueType,
912 "Expected string type %ld, got %ld\n", expected->dwValueType,
914 ok(got->Value.cbData == expected->Value.cbData,
915 "String type %ld: unexpected data size, got %ld, expected %ld\n",
916 expected->dwValueType, got->Value.cbData, expected->Value.cbData);
917 if (got->Value.cbData && got->Value.pbData)
918 ok(!memcmp(got->Value.pbData, expected->Value.pbData,
919 min(got->Value.cbData, expected->Value.cbData)),
920 "String type %ld: unexpected value\n", expected->dwValueType);
923 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
924 const CERT_RDN_ATTR *got)
926 if (expected->pszObjId && strlen(expected->pszObjId))
928 ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
932 ok(!strcmp(got->pszObjId, expected->pszObjId),
933 "Got unexpected OID %s, expected %s\n", got->pszObjId,
937 compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType,
938 (const CERT_NAME_VALUE *)&got->dwValueType);
941 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
943 ok(got->cRDNAttr == expected->cRDNAttr,
944 "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
949 for (i = 0; i < got->cRDNAttr; i++)
950 compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
954 static void compareNames(const CERT_NAME_INFO *expected,
955 const CERT_NAME_INFO *got)
957 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
958 expected->cRDN, got->cRDN);
963 for (i = 0; i < got->cRDN; i++)
964 compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
968 static void test_decodeName(DWORD dwEncoding)
974 CERT_NAME_INFO info = { 1, &rdn };
976 /* test empty name */
978 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
979 emptySequence[1] + 2,
980 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
981 (BYTE *)&buf, &bufSize);
982 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
983 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
984 * decoder works the same way, so only test the count.
988 ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %ld\n", bufSize);
989 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
990 "Expected 0 RDNs in empty info, got %ld\n",
991 ((CERT_NAME_INFO *)buf)->cRDN);
996 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
998 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
999 (BYTE *)&buf, &bufSize);
1000 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1003 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
1005 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
1006 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
1007 "Got unexpected value for empty RDN\n");
1010 /* test two RDN attrs */
1012 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
1014 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1015 (BYTE *)&buf, &bufSize);
1016 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1019 static CHAR oid_sur_name[] = szOID_SUR_NAME,
1020 oid_common_name[] = szOID_COMMON_NAME;
1022 CERT_RDN_ATTR attrs[] = {
1023 { oid_sur_name, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
1024 (BYTE *)surName } },
1025 { oid_common_name, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
1026 (BYTE *)commonName } },
1029 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
1030 rdn.rgRDNAttr = attrs;
1031 compareNames(&info, (CERT_NAME_INFO *)buf);
1034 /* And, a slightly more complicated name */
1037 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
1038 sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1039 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1042 rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
1043 rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
1044 compareNames(&info, (CERT_NAME_INFO *)buf);
1049 static void test_decodeUnicodeName(DWORD dwEncoding)
1055 CERT_NAME_INFO info = { 1, &rdn };
1057 /* test empty name */
1059 ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptySequence,
1060 emptySequence[1] + 2,
1061 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1062 (BYTE *)&buf, &bufSize);
1063 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1066 ok(bufSize == sizeof(CERT_NAME_INFO),
1067 "Got wrong bufSize %ld\n", bufSize);
1068 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
1069 "Expected 0 RDNs in empty info, got %ld\n",
1070 ((CERT_NAME_INFO *)buf)->cRDN);
1073 /* test empty RDN */
1075 ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptyRDNs,
1077 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1078 (BYTE *)&buf, &bufSize);
1079 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1082 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
1084 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
1085 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
1086 "Got unexpected value for empty RDN\n");
1089 /* test two RDN attrs */
1091 ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, twoRDNsNoNull,
1092 sizeof(twoRDNsNoNull),
1093 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1094 (BYTE *)&buf, &bufSize);
1095 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1098 static CHAR oid_sur_name[] = szOID_SUR_NAME,
1099 oid_common_name[] = szOID_COMMON_NAME;
1101 CERT_RDN_ATTR attrs[] = {
1102 { oid_sur_name, CERT_RDN_PRINTABLE_STRING,
1103 { lstrlenW(surNameW) * sizeof(WCHAR), (BYTE *)surNameW } },
1104 { oid_common_name, CERT_RDN_PRINTABLE_STRING,
1105 { lstrlenW(commonNameW) * sizeof(WCHAR), (BYTE *)commonNameW } },
1108 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
1109 rdn.rgRDNAttr = attrs;
1110 compareNames(&info, (CERT_NAME_INFO *)buf);
1115 struct EncodedNameValue
1117 CERT_NAME_VALUE value;
1118 const BYTE *encoded;
1122 static const char bogusIA5[] = "\x80";
1123 static const char bogusPrintable[] = "~";
1124 static const char bogusNumeric[] = "A";
1125 static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
1126 static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
1127 static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
1128 static BYTE octetCommonNameValue[] = {
1129 0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1130 static BYTE numericCommonNameValue[] = {
1131 0x12,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1132 static BYTE printableCommonNameValue[] = {
1133 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1134 static BYTE t61CommonNameValue[] = {
1135 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1136 static BYTE videotexCommonNameValue[] = {
1137 0x15,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1138 static BYTE ia5CommonNameValue[] = {
1139 0x16,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1140 static BYTE graphicCommonNameValue[] = {
1141 0x19,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1142 static BYTE visibleCommonNameValue[] = {
1143 0x1a,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1144 static BYTE generalCommonNameValue[] = {
1145 0x1b,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1146 static BYTE bmpCommonNameValue[] = {
1147 0x1e,0x14,0x00,0x4a,0x00,0x75,0x00,0x61,0x00,0x6e,0x00,0x20,0x00,0x4c,0x00,
1148 0x61,0x00,0x6e,0x00,0x67,0x00,0x00 };
1149 static BYTE utf8CommonNameValue[] = {
1150 0x0c,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1152 static struct EncodedNameValue nameValues[] = {
1153 { { CERT_RDN_OCTET_STRING, { sizeof(commonName), (BYTE *)commonName } },
1154 octetCommonNameValue, sizeof(octetCommonNameValue) },
1155 { { CERT_RDN_NUMERIC_STRING, { sizeof(commonName), (BYTE *)commonName } },
1156 numericCommonNameValue, sizeof(numericCommonNameValue) },
1157 { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
1158 printableCommonNameValue, sizeof(printableCommonNameValue) },
1159 { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } },
1160 t61CommonNameValue, sizeof(t61CommonNameValue) },
1161 { { CERT_RDN_VIDEOTEX_STRING, { sizeof(commonName), (BYTE *)commonName } },
1162 videotexCommonNameValue, sizeof(videotexCommonNameValue) },
1163 { { CERT_RDN_IA5_STRING, { sizeof(commonName), (BYTE *)commonName } },
1164 ia5CommonNameValue, sizeof(ia5CommonNameValue) },
1165 { { CERT_RDN_GRAPHIC_STRING, { sizeof(commonName), (BYTE *)commonName } },
1166 graphicCommonNameValue, sizeof(graphicCommonNameValue) },
1167 { { CERT_RDN_VISIBLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
1168 visibleCommonNameValue, sizeof(visibleCommonNameValue) },
1169 { { CERT_RDN_GENERAL_STRING, { sizeof(commonName), (BYTE *)commonName } },
1170 generalCommonNameValue, sizeof(generalCommonNameValue) },
1171 { { CERT_RDN_BMP_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } },
1172 bmpCommonNameValue, sizeof(bmpCommonNameValue) },
1173 { { CERT_RDN_UTF8_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } },
1174 utf8CommonNameValue, sizeof(utf8CommonNameValue) },
1175 /* The following tests succeed under Windows, but really should fail,
1176 * they contain characters that are illegal for the encoding. I'm
1177 * including them to justify my lazy encoding.
1179 { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42,
1181 { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable),
1182 (BYTE *)bogusPrintable } }, bin43, sizeof(bin43) },
1183 { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
1184 bin44, sizeof(bin44) },
1187 static void test_encodeNameValue(DWORD dwEncoding)
1192 CERT_NAME_VALUE value = { 0, { 0, NULL } };
1194 value.dwValueType = 14;
1195 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value,
1196 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1197 ok(!ret && GetLastError() == CRYPT_E_ASN1_CHOICE,
1198 "Expected CRYPT_E_ASN1_CHOICE, got %08lx\n", GetLastError());
1199 value.dwValueType = CERT_RDN_ENCODED_BLOB;
1200 value.Value.pbData = printableCommonNameValue;
1201 value.Value.cbData = sizeof(printableCommonNameValue);
1202 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value,
1203 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1204 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1207 ok(size == sizeof(printableCommonNameValue), "Unexpected size %ld\n",
1209 ok(!memcmp(buf, printableCommonNameValue, size),
1210 "Unexpected encoding\n");
1213 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
1215 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE,
1216 &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1218 ok(ret, "Type %ld: CryptEncodeObjectEx failed: %08lx\n",
1219 nameValues[i].value.dwValueType, GetLastError());
1222 ok(size == nameValues[i].encodedSize,
1223 "Expected size %ld, got %ld\n", nameValues[i].encodedSize, size);
1224 ok(!memcmp(buf, nameValues[i].encoded, size),
1225 "Got unexpected encoding\n");
1231 static void test_decodeNameValue(DWORD dwEncoding)
1238 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
1240 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE,
1241 nameValues[i].encoded, nameValues[i].encoded[1] + 2,
1242 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1243 (BYTE *)&buf, &bufSize);
1244 ok(ret, "Value type %ld: CryptDecodeObjectEx failed: %08lx\n",
1245 nameValues[i].value.dwValueType, GetLastError());
1248 compareNameValues(&nameValues[i].value,
1249 (const CERT_NAME_VALUE *)buf);
1255 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
1256 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
1257 'h','q','.','o','r','g',0 };
1258 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
1259 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
1261 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
1263 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1264 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1265 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1266 static const BYTE localhost[] = { 127, 0, 0, 1 };
1267 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1270 static void test_encodeAltName(DWORD dwEncoding)
1272 CERT_ALT_NAME_INFO info = { 0 };
1273 CERT_ALT_NAME_ENTRY entry = { 0 };
1278 /* Test with empty info */
1279 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1280 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1283 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
1284 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1287 /* Test with an empty entry */
1289 info.rgAltEntry = &entry;
1290 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1291 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1292 ok(!ret && GetLastError() == E_INVALIDARG,
1293 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1294 /* Test with an empty pointer */
1295 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1296 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1297 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1300 ok(size == sizeof(emptyURL), "Wrong size %ld\n", size);
1301 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1304 /* Test with a real URL */
1305 U(entry).pwszURL = (LPWSTR)url;
1306 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1307 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1310 ok(size == sizeof(encodedURL), "Wrong size %ld\n", size);
1311 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1314 /* Now with the URL containing an invalid IA5 char */
1315 U(entry).pwszURL = (LPWSTR)nihongoURL;
1316 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1317 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1318 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1319 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1320 /* The first invalid character is at index 7 */
1321 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1322 "Expected invalid char at index 7, got %ld\n",
1323 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1324 /* Now with the URL missing a scheme */
1325 U(entry).pwszURL = (LPWSTR)dnsName;
1326 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1327 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1328 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1331 /* This succeeds, but it shouldn't, so don't worry about conforming */
1334 /* Now with a DNS name */
1335 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1336 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1337 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1338 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1341 ok(size == sizeof(encodedDnsName), "Wrong size %ld\n", size);
1342 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1345 /* Test with an IP address */
1346 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1347 U(entry).IPAddress.cbData = sizeof(localhost);
1348 U(entry).IPAddress.pbData = (LPBYTE)localhost;
1349 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1350 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1353 ok(size == sizeof(encodedIPAddr), "Wrong size %ld\n", size);
1354 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1359 static void test_decodeAltName(DWORD dwEncoding)
1361 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1363 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1368 CERT_ALT_NAME_INFO *info;
1370 /* Test some bogus ones first */
1371 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1372 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1373 NULL, (BYTE *)&buf, &bufSize);
1374 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1375 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1376 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1377 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1379 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1380 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1381 /* Now expected cases */
1382 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1383 emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1385 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1388 info = (CERT_ALT_NAME_INFO *)buf;
1390 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1394 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1395 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1397 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1400 info = (CERT_ALT_NAME_INFO *)buf;
1402 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1404 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1405 "Expected CERT_ALT_NAME_URL, got %ld\n",
1406 info->rgAltEntry[0].dwAltNameChoice);
1407 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1408 "Expected empty URL\n");
1411 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1412 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1414 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1417 info = (CERT_ALT_NAME_INFO *)buf;
1419 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1421 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1422 "Expected CERT_ALT_NAME_URL, got %ld\n",
1423 info->rgAltEntry[0].dwAltNameChoice);
1424 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1427 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1428 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1430 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1433 info = (CERT_ALT_NAME_INFO *)buf;
1435 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1437 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1438 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1439 info->rgAltEntry[0].dwAltNameChoice);
1440 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1441 "Unexpected DNS name\n");
1444 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1445 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1447 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1450 info = (CERT_ALT_NAME_INFO *)buf;
1452 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1454 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1455 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1456 info->rgAltEntry[0].dwAltNameChoice);
1457 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1458 "Unexpected IP address length %ld\n",
1459 U(info->rgAltEntry[0]).IPAddress.cbData);
1460 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1461 sizeof(localhost)), "Unexpected IP address value\n");
1466 struct UnicodeExpectedError
1474 static const WCHAR oneW[] = { '1',0 };
1475 static const WCHAR aW[] = { 'a',0 };
1476 static const WCHAR quoteW[] = { '"', 0 };
1478 static struct UnicodeExpectedError unicodeErrors[] = {
1479 { CERT_RDN_ANY_TYPE, oneW, 0, CRYPT_E_NOT_CHAR_STRING },
1480 { CERT_RDN_ENCODED_BLOB, oneW, 0, CRYPT_E_NOT_CHAR_STRING },
1481 { CERT_RDN_OCTET_STRING, oneW, 0, CRYPT_E_NOT_CHAR_STRING },
1482 { 14, oneW, 0, CRYPT_E_ASN1_CHOICE },
1483 { CERT_RDN_NUMERIC_STRING, aW, 0, CRYPT_E_INVALID_NUMERIC_STRING },
1484 { CERT_RDN_PRINTABLE_STRING, quoteW, 0, CRYPT_E_INVALID_PRINTABLE_STRING },
1485 { CERT_RDN_IA5_STRING, nihongoURL, 7, CRYPT_E_INVALID_IA5_STRING },
1488 struct UnicodeExpectedResult
1492 CRYPT_DATA_BLOB encoded;
1495 static BYTE oneNumeric[] = { 0x12, 0x01, 0x31 };
1496 static BYTE onePrintable[] = { 0x13, 0x01, 0x31 };
1497 static BYTE oneTeletex[] = { 0x14, 0x01, 0x31 };
1498 static BYTE oneVideotex[] = { 0x15, 0x01, 0x31 };
1499 static BYTE oneIA5[] = { 0x16, 0x01, 0x31 };
1500 static BYTE oneGraphic[] = { 0x19, 0x01, 0x31 };
1501 static BYTE oneVisible[] = { 0x1a, 0x01, 0x31 };
1502 static BYTE oneUniversal[] = { 0x1c, 0x04, 0x00, 0x00, 0x00, 0x31 };
1503 static BYTE oneGeneral[] = { 0x1b, 0x01, 0x31 };
1504 static BYTE oneBMP[] = { 0x1e, 0x02, 0x00, 0x31 };
1505 static BYTE oneUTF8[] = { 0x0c, 0x01, 0x31 };
1506 static BYTE nihongoT61[] = { 0x14,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,
1508 static BYTE nihongoGeneral[] = { 0x1b,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
1510 static BYTE nihongoBMP[] = { 0x1e,0x12,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,
1511 0x00,0x3a,0x00,0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b };
1512 static BYTE nihongoUTF8[] = { 0x0c,0x0d,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
1513 0xe2,0x89,0xaf,0xe5,0x9d,0x9b };
1515 static struct UnicodeExpectedResult unicodeResults[] = {
1516 { CERT_RDN_NUMERIC_STRING, oneW, { sizeof(oneNumeric), oneNumeric } },
1517 { CERT_RDN_PRINTABLE_STRING, oneW, { sizeof(onePrintable), onePrintable } },
1518 { CERT_RDN_TELETEX_STRING, oneW, { sizeof(oneTeletex), oneTeletex } },
1519 { CERT_RDN_VIDEOTEX_STRING, oneW, { sizeof(oneVideotex), oneVideotex } },
1520 { CERT_RDN_IA5_STRING, oneW, { sizeof(oneIA5), oneIA5 } },
1521 { CERT_RDN_GRAPHIC_STRING, oneW, { sizeof(oneGraphic), oneGraphic } },
1522 { CERT_RDN_VISIBLE_STRING, oneW, { sizeof(oneVisible), oneVisible } },
1523 { CERT_RDN_UNIVERSAL_STRING, oneW, { sizeof(oneUniversal), oneUniversal } },
1524 { CERT_RDN_GENERAL_STRING, oneW, { sizeof(oneGeneral), oneGeneral } },
1525 { CERT_RDN_BMP_STRING, oneW, { sizeof(oneBMP), oneBMP } },
1526 { CERT_RDN_UTF8_STRING, oneW, { sizeof(oneUTF8), oneUTF8 } },
1527 { CERT_RDN_BMP_STRING, nihongoURL, { sizeof(nihongoBMP), nihongoBMP } },
1528 { CERT_RDN_UTF8_STRING, nihongoURL, { sizeof(nihongoUTF8), nihongoUTF8 } },
1531 static struct UnicodeExpectedResult unicodeWeirdness[] = {
1532 { CERT_RDN_TELETEX_STRING, nihongoURL, { sizeof(nihongoT61), nihongoT61 } },
1533 { CERT_RDN_GENERAL_STRING, nihongoURL, { sizeof(nihongoGeneral), nihongoGeneral } },
1536 static void test_encodeUnicodeNameValue(DWORD dwEncoding)
1541 CERT_NAME_VALUE value;
1543 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, NULL,
1544 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1545 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1546 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1547 /* Have to have a string of some sort */
1548 value.dwValueType = 0; /* aka CERT_RDN_ANY_TYPE */
1549 value.Value.pbData = NULL;
1550 value.Value.cbData = 0;
1551 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1552 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1553 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1554 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1555 value.dwValueType = CERT_RDN_ENCODED_BLOB;
1556 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1557 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1558 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1559 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1560 value.dwValueType = CERT_RDN_ANY_TYPE;
1561 value.Value.pbData = (LPBYTE)oneW;
1562 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1563 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1564 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1565 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1566 value.Value.cbData = sizeof(oneW);
1567 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1568 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1569 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1570 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1571 /* An encoded string with specified length isn't good enough either */
1572 value.dwValueType = CERT_RDN_ENCODED_BLOB;
1573 value.Value.pbData = oneUniversal;
1574 value.Value.cbData = sizeof(oneUniversal);
1575 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1576 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1577 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1578 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1579 /* More failure checking */
1580 value.Value.cbData = 0;
1581 for (i = 0; i < sizeof(unicodeErrors) / sizeof(unicodeErrors[0]); i++)
1583 value.Value.pbData = (LPBYTE)unicodeErrors[i].str;
1584 value.dwValueType = unicodeErrors[i].valueType;
1585 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1586 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1587 ok(!ret && GetLastError() == unicodeErrors[i].error,
1588 "Value type %ld: expected %08lx, got %08lx\n", value.dwValueType,
1589 unicodeErrors[i].error, GetLastError());
1590 ok(size == unicodeErrors[i].errorIndex,
1591 "Expected error index %ld, got %ld\n", unicodeErrors[i].errorIndex,
1594 /* cbData can be zero if the string is NULL-terminated */
1595 value.Value.cbData = 0;
1596 for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++)
1598 value.Value.pbData = (LPBYTE)unicodeResults[i].str;
1599 value.dwValueType = unicodeResults[i].valueType;
1600 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1601 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1602 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1605 ok(size == unicodeResults[i].encoded.cbData,
1606 "Value type %ld: expected size %ld, got %ld\n",
1607 value.dwValueType, unicodeResults[i].encoded.cbData, size);
1608 ok(!memcmp(unicodeResults[i].encoded.pbData, buf, size),
1609 "Value type %ld: unexpected value\n", value.dwValueType);
1613 /* These "encode," but they do so by truncating each unicode character
1614 * rather than properly encoding it. Kept separate from the proper results,
1615 * because the encoded forms won't decode to their original strings.
1617 for (i = 0; i < sizeof(unicodeWeirdness) / sizeof(unicodeWeirdness[0]); i++)
1619 value.Value.pbData = (LPBYTE)unicodeWeirdness[i].str;
1620 value.dwValueType = unicodeWeirdness[i].valueType;
1621 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1622 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1623 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1626 ok(size == unicodeWeirdness[i].encoded.cbData,
1627 "Value type %ld: expected size %ld, got %ld\n",
1628 value.dwValueType, unicodeWeirdness[i].encoded.cbData, size);
1629 ok(!memcmp(unicodeWeirdness[i].encoded.pbData, buf, size),
1630 "Value type %ld: unexpected value\n", value.dwValueType);
1636 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
1638 if (n <= 0) return 0;
1639 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
1640 return *str1 - *str2;
1643 static void test_decodeUnicodeNameValue(DWORD dwEncoding)
1647 for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++)
1653 ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE,
1654 unicodeResults[i].encoded.pbData, unicodeResults[i].encoded.cbData,
1655 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1656 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1659 PCERT_NAME_VALUE value = (PCERT_NAME_VALUE)buf;
1661 ok(value->dwValueType == unicodeResults[i].valueType,
1662 "Expected value type %ld, got %ld\n", unicodeResults[i].valueType,
1663 value->dwValueType);
1664 ok(!strncmpW((LPWSTR)value->Value.pbData, unicodeResults[i].str,
1665 value->Value.cbData / sizeof(WCHAR)),
1666 "Unexpected decoded value for index %ld (value type %ld)\n", i,
1667 unicodeResults[i].valueType);
1673 struct encodedOctets
1676 const BYTE *encoded;
1679 static const unsigned char bin46[] = { 'h','i',0 };
1680 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1681 static const unsigned char bin48[] = {
1682 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1683 static const unsigned char bin49[] = {
1684 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1685 static const unsigned char bin50[] = { 0 };
1686 static const unsigned char bin51[] = { 0x04,0x00,0 };
1688 static const struct encodedOctets octets[] = {
1694 static void test_encodeOctets(DWORD dwEncoding)
1696 CRYPT_DATA_BLOB blob;
1699 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1705 blob.cbData = strlen((const char*)octets[i].val);
1706 blob.pbData = (BYTE*)octets[i].val;
1707 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1708 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1709 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1713 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1714 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1715 buf[1], octets[i].encoded[1]);
1716 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1717 octets[i].encoded[1] + 1), "Got unexpected value\n");
1723 static void test_decodeOctets(DWORD dwEncoding)
1727 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1733 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1734 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1735 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1736 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1737 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1738 "Expected size >= %d, got %ld\n",
1739 (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1740 ok(buf != NULL, "Expected allocated buffer\n");
1743 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1746 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1747 "Unexpected value\n");
1753 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1758 const BYTE *encoded;
1760 const BYTE *decoded;
1763 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1764 static const unsigned char bin53[] = { 0xff,0xff };
1765 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1766 static const unsigned char bin55[] = { 0xff,0xfe };
1767 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1768 static const unsigned char bin57[] = { 0xfe };
1769 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1771 static const struct encodedBits bits[] = {
1772 /* normal test cases */
1773 { 0, bin52, 2, bin53 },
1774 { 1, bin54, 2, bin55 },
1775 /* strange test case, showing cUnusedBits >= 8 is allowed */
1776 { 9, bin56, 1, bin57 },
1777 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1778 { 17, bin58, 0, NULL },
1781 static void test_encodeBits(DWORD dwEncoding)
1785 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1787 CRYPT_BIT_BLOB blob;
1792 blob.cbData = sizeof(bytesToEncode);
1793 blob.pbData = (BYTE *)bytesToEncode;
1794 blob.cUnusedBits = bits[i].cUnusedBits;
1795 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1796 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1797 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1800 ok(bufSize == bits[i].encoded[1] + 2,
1801 "Got unexpected size %ld, expected %d\n", bufSize,
1802 bits[i].encoded[1] + 2);
1803 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1804 "Unexpected value\n");
1810 static void test_decodeBits(DWORD dwEncoding)
1812 static const BYTE ber[] = "\x03\x02\x01\xff";
1813 static const BYTE berDecoded = 0xfe;
1820 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1822 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1823 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1825 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1828 CRYPT_BIT_BLOB *blob;
1830 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1831 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1832 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1833 blob = (CRYPT_BIT_BLOB *)buf;
1834 ok(blob->cbData == bits[i].cbDecoded,
1835 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1837 if (blob->cbData && bits[i].cbDecoded)
1838 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1839 "Unexpected value\n");
1843 /* special case: check that something that's valid in BER but not in DER
1844 * decodes successfully
1846 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1847 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1848 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1851 CRYPT_BIT_BLOB *blob;
1853 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1854 "Got unexpected size %ld\n", bufSize);
1855 blob = (CRYPT_BIT_BLOB *)buf;
1856 ok(blob->cbData == sizeof(berDecoded),
1857 "Got unexpected length %ld\n", blob->cbData);
1859 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1866 CERT_BASIC_CONSTRAINTS2_INFO info;
1867 const BYTE *encoded;
1870 static const unsigned char bin59[] = { 0x30,0x00 };
1871 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1872 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1873 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1874 static const struct Constraints2 constraints2[] = {
1875 /* empty constraints */
1876 { { FALSE, FALSE, 0}, bin59 },
1878 { { TRUE, FALSE, 0}, bin60 },
1879 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1880 * but that's not the case
1882 { { FALSE, TRUE, 0}, bin61 },
1883 /* can be a CA and has path length constraints set */
1884 { { TRUE, TRUE, 1}, bin62 },
1887 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1888 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1889 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1890 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1891 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1892 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1893 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1894 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1895 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1896 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1898 static void test_encodeBasicConstraints(DWORD dwEncoding)
1900 DWORD i, bufSize = 0;
1901 CERT_BASIC_CONSTRAINTS_INFO info;
1902 CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1903 (LPBYTE)encodedDomainName };
1907 /* First test with the simpler info2 */
1908 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1910 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1911 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1913 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1916 ok(bufSize == constraints2[i].encoded[1] + 2,
1917 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1919 ok(!memcmp(buf, constraints2[i].encoded,
1920 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1924 /* Now test with more complex basic constraints */
1925 info.SubjectType.cbData = 0;
1926 info.fPathLenConstraint = FALSE;
1927 info.cSubtreesConstraint = 0;
1928 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1929 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1930 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1933 ok(bufSize == sizeof(emptyConstraint), "Wrong size %ld\n", bufSize);
1934 ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1935 "Unexpected value\n");
1938 /* None of the certs I examined had any subtree constraint, but I test one
1939 * anyway just in case.
1941 info.cSubtreesConstraint = 1;
1942 info.rgSubtreesConstraint = &nameBlob;
1943 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1944 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1945 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1948 ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %ld\n", bufSize);
1949 ok(!memcmp(buf, constraintWithDomainName,
1950 sizeof(constraintWithDomainName)), "Unexpected value\n");
1953 /* FIXME: test encoding with subject type. */
1956 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1957 static const unsigned char encodedCommonName[] = {
1958 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
1960 static void test_decodeBasicConstraints(DWORD dwEncoding)
1962 static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1964 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1970 /* First test with simpler info2 */
1971 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1973 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1974 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1975 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1976 ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1980 CERT_BASIC_CONSTRAINTS2_INFO *info =
1981 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1983 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1984 "Unexpected value for item %ld\n", i);
1988 /* Check with the order of encoded elements inverted */
1990 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1991 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1993 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1994 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1995 ok(!buf, "Expected buf to be set to NULL\n");
1996 /* Check with a non-DER bool */
1997 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1998 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1999 (BYTE *)&buf, &bufSize);
2000 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2003 CERT_BASIC_CONSTRAINTS2_INFO *info =
2004 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
2006 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
2009 /* Check with a non-basic constraints value */
2010 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2011 (LPBYTE)encodedCommonName, encodedCommonName[1] + 2,
2012 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2013 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2014 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2015 /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
2016 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
2017 emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
2018 (BYTE *)&buf, &bufSize);
2019 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2022 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
2024 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
2025 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
2026 ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
2029 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
2030 constraintWithDomainName, sizeof(constraintWithDomainName),
2031 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2032 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2035 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
2037 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
2038 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
2039 ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
2040 if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
2042 ok(info->rgSubtreesConstraint[0].cbData ==
2043 sizeof(encodedDomainName), "Wrong size %ld\n",
2044 info->rgSubtreesConstraint[0].cbData);
2045 ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
2046 sizeof(encodedDomainName)), "Unexpected value\n");
2052 /* These are terrible public keys of course, I'm just testing encoding */
2053 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
2054 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
2055 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
2056 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
2057 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
2058 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
2059 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
2060 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
2062 struct EncodedRSAPubKey
2064 const BYTE *modulus;
2066 const BYTE *encoded;
2067 size_t decodedModulusLen;
2070 struct EncodedRSAPubKey rsaPubKeys[] = {
2071 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
2072 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
2073 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
2074 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
2077 static void test_encodeRsaPublicKey(DWORD dwEncoding)
2079 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
2080 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
2081 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
2084 DWORD bufSize = 0, i;
2086 /* Try with a bogus blob type */
2088 hdr->bVersion = CUR_BLOB_VERSION;
2090 hdr->aiKeyAlg = CALG_RSA_KEYX;
2091 rsaPubKey->magic = 0x31415352;
2092 rsaPubKey->bitlen = sizeof(modulus1) * 8;
2093 rsaPubKey->pubexp = 65537;
2094 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
2097 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2098 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2100 ok(!ret && GetLastError() == E_INVALIDARG,
2101 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2102 /* Now with a bogus reserved field */
2103 hdr->bType = PUBLICKEYBLOB;
2105 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2106 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2110 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2111 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2112 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2115 /* Now with a bogus blob version */
2118 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2119 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2123 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2124 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2125 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2128 /* And with a bogus alg ID */
2129 hdr->bVersion = CUR_BLOB_VERSION;
2130 hdr->aiKeyAlg = CALG_DES;
2131 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2132 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2136 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2137 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2138 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2141 /* Check a couple of RSA-related OIDs */
2142 hdr->aiKeyAlg = CALG_RSA_KEYX;
2143 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
2144 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2145 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2146 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2147 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
2148 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2149 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2150 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2151 /* Finally, all valid */
2152 hdr->aiKeyAlg = CALG_RSA_KEYX;
2153 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2155 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2156 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
2157 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2158 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2159 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2162 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
2163 "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
2165 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
2166 "Unexpected value\n");
2172 static void test_decodeRsaPublicKey(DWORD dwEncoding)
2179 /* Try with a bad length */
2180 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2181 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
2182 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2183 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2184 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
2185 /* Try with a couple of RSA-related OIDs */
2186 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
2187 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2188 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2189 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2190 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2191 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
2192 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2193 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2194 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2195 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2196 /* Now try success cases */
2197 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2200 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2201 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
2202 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2203 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2206 BLOBHEADER *hdr = (BLOBHEADER *)buf;
2207 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
2209 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
2210 rsaPubKeys[i].decodedModulusLen,
2211 "Wrong size %ld\n", bufSize);
2212 ok(hdr->bType == PUBLICKEYBLOB,
2213 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
2215 ok(hdr->bVersion == CUR_BLOB_VERSION,
2216 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
2217 CUR_BLOB_VERSION, hdr->bVersion);
2218 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
2220 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
2221 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
2222 ok(rsaPubKey->magic == 0x31415352,
2223 "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
2224 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
2225 "Wrong bit len %ld\n", rsaPubKey->bitlen);
2226 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
2228 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2229 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
2230 "Unexpected modulus\n");
2236 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
2237 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
2238 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2240 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
2241 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
2242 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
2243 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2245 static void test_encodeSequenceOfAny(DWORD dwEncoding)
2247 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
2248 CRYPT_SEQUENCE_OF_ANY seq;
2254 /* Encode a homogenous sequence */
2255 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
2257 blobs[i].cbData = ints[i].encoded[1] + 2;
2258 blobs[i].pbData = (BYTE *)ints[i].encoded;
2260 seq.cValue = sizeof(ints) / sizeof(ints[0]);
2261 seq.rgValue = blobs;
2263 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2264 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2265 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2268 ok(bufSize == sizeof(intSequence), "Wrong size %ld\n", bufSize);
2269 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
2272 /* Change the type of the first element in the sequence, and give it
2275 blobs[0].cbData = times[0].encodedTime[1] + 2;
2276 blobs[0].pbData = (BYTE *)times[0].encodedTime;
2277 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2278 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2279 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2282 ok(bufSize == sizeof(mixedSequence), "Wrong size %ld\n", bufSize);
2283 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
2284 "Unexpected value\n");
2289 static void test_decodeSequenceOfAny(DWORD dwEncoding)
2295 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
2296 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2297 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2300 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2303 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2304 "Wrong elements %ld\n", seq->cValue);
2305 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
2307 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
2308 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
2309 seq->rgValue[i].cbData);
2310 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
2311 ints[i].encoded[1] + 2), "Unexpected value\n");
2315 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
2316 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2318 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2321 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2323 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2324 "Wrong elements %ld\n", seq->cValue);
2325 /* Just check the first element since it's all that changed */
2326 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
2327 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
2328 seq->rgValue[0].cbData);
2329 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
2330 times[0].encodedTime[1] + 2), "Unexpected value\n");
2335 struct encodedExtensions
2337 CERT_EXTENSIONS exts;
2338 const BYTE *encoded;
2341 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2342 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2343 static CHAR oid_basic_constraints2[] = szOID_BASIC_CONSTRAINTS2;
2344 static CERT_EXTENSION criticalExt =
2345 { oid_basic_constraints2, TRUE, { 8, crit_ext_data } };
2346 static CERT_EXTENSION nonCriticalExt =
2347 { oid_basic_constraints2, FALSE, { 8, noncrit_ext_data } };
2349 static const BYTE ext0[] = { 0x30,0x00 };
2350 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
2351 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2352 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
2353 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2355 static const struct encodedExtensions exts[] = {
2356 { { 0, NULL }, ext0 },
2357 { { 1, &criticalExt }, ext1 },
2358 { { 1, &nonCriticalExt }, ext2 },
2361 static void test_encodeExtensions(DWORD dwEncoding)
2365 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2371 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
2372 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2373 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2376 ok(bufSize == exts[i].encoded[1] + 2,
2377 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
2378 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
2379 "Unexpected value\n");
2385 static void test_decodeExtensions(DWORD dwEncoding)
2389 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2395 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
2396 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2397 NULL, (BYTE *)&buf, &bufSize);
2398 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2401 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
2404 ok(ext->cExtension == exts[i].exts.cExtension,
2405 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
2407 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
2409 ok(!strcmp(ext->rgExtension[j].pszObjId,
2410 exts[i].exts.rgExtension[j].pszObjId),
2411 "Expected OID %s, got %s\n",
2412 exts[i].exts.rgExtension[j].pszObjId,
2413 ext->rgExtension[j].pszObjId);
2414 ok(!memcmp(ext->rgExtension[j].Value.pbData,
2415 exts[i].exts.rgExtension[j].Value.pbData,
2416 exts[i].exts.rgExtension[j].Value.cbData),
2417 "Unexpected value\n");
2424 /* MS encodes public key info with a NULL if the algorithm identifier's
2425 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
2426 * it encodes them by omitting the algorithm parameters. This latter approach
2427 * seems more correct, so accept either form.
2429 struct encodedPublicKey
2431 CERT_PUBLIC_KEY_INFO info;
2432 const BYTE *encoded;
2433 const BYTE *encodedNoNull;
2434 CERT_PUBLIC_KEY_INFO decoded;
2437 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2439 static const BYTE params[] = { 0x02, 0x01, 0x01 };
2441 static const unsigned char bin64[] = {
2442 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
2443 static const unsigned char bin65[] = {
2444 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
2445 static const unsigned char bin66[] = {
2446 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
2447 static const unsigned char bin67[] = {
2448 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
2449 static const unsigned char bin68[] = {
2450 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
2451 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2452 static const unsigned char bin69[] = {
2453 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
2454 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2455 static const unsigned char bin70[] = {
2456 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2457 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2459 static const unsigned char bin71[] = {
2460 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2461 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2463 static unsigned char bin72[] = { 0x05,0x00};
2465 static CHAR oid_bogus[] = "1.2.3",
2466 oid_rsa[] = szOID_RSA;
2468 static const struct encodedPublicKey pubKeys[] = {
2469 /* with a bogus OID */
2470 { { { oid_bogus, { 0, NULL } }, { 0, NULL, 0 } },
2472 { { oid_bogus, { 2, bin72 } }, { 0, NULL, 0 } } },
2473 /* some normal keys */
2474 { { { oid_rsa, { 0, NULL } }, { 0, NULL, 0} },
2476 { { oid_rsa, { 2, bin72 } }, { 0, NULL, 0 } } },
2477 { { { oid_rsa, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2479 { { oid_rsa, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2480 /* with add'l parameters--note they must be DER-encoded */
2481 { { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2482 (BYTE *)aKey, 0 } },
2484 { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2485 (BYTE *)aKey, 0 } } },
2488 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2492 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2498 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2499 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2501 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2504 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2505 bufSize == pubKeys[i].encodedNoNull[1] + 2,
2506 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2507 pubKeys[i].encodedNoNull[1] + 2, bufSize);
2508 if (bufSize == pubKeys[i].encoded[1] + 2)
2509 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2510 "Unexpected value\n");
2511 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2512 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2513 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2519 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2520 const CERT_PUBLIC_KEY_INFO *got)
2522 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2523 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2524 got->Algorithm.pszObjId);
2525 ok(expected->Algorithm.Parameters.cbData ==
2526 got->Algorithm.Parameters.cbData,
2527 "Expected parameters of %ld bytes, got %ld\n",
2528 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2529 if (expected->Algorithm.Parameters.cbData)
2530 ok(!memcmp(expected->Algorithm.Parameters.pbData,
2531 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2532 "Unexpected algorithm parameters\n");
2533 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2534 "Expected public key of %ld bytes, got %ld\n",
2535 expected->PublicKey.cbData, got->PublicKey.cbData);
2536 if (expected->PublicKey.cbData)
2537 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2538 got->PublicKey.cbData), "Unexpected public key value\n");
2541 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2543 static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2544 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2545 0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2546 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2552 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2554 /* The NULL form decodes to the decoded member */
2555 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2556 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2557 NULL, (BYTE *)&buf, &bufSize);
2558 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2561 comparePublicKeyInfo(&pubKeys[i].decoded,
2562 (CERT_PUBLIC_KEY_INFO *)buf);
2565 /* The non-NULL form decodes to the original */
2566 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2567 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2568 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2569 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2572 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2576 /* Test with bogus (not valid DER) parameters */
2577 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2578 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2579 NULL, (BYTE *)&buf, &bufSize);
2580 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2581 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2584 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2585 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2586 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2587 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2588 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2589 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2590 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2591 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2592 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2593 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2594 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2595 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2596 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2597 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2598 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2599 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2600 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2601 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2602 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2603 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2604 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2605 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2606 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2607 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2608 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2609 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2610 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2611 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2612 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2613 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2614 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2615 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2616 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2617 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2618 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2619 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2620 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2621 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2622 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2624 static const BYTE serialNum[] = { 0x01 };
2626 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2631 CERT_INFO info = { 0 };
2633 /* Test with NULL pvStructInfo */
2634 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2635 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2636 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2637 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2638 /* Test with a V1 cert */
2639 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2640 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2641 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2644 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2645 v1Cert[1] + 2, size);
2646 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2650 info.dwVersion = CERT_V2;
2651 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2652 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2653 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2656 ok(size == sizeof(v2Cert), "Wrong size %ld\n", size);
2657 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2661 info.dwVersion = CERT_V3;
2662 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2663 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2664 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2667 ok(size == sizeof(v3Cert), "Wrong size %ld\n", size);
2668 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2671 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2672 * API doesn't prevent it)
2674 info.dwVersion = CERT_V1;
2675 info.cExtension = 1;
2676 info.rgExtension = &criticalExt;
2677 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2678 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2679 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2682 ok(size == sizeof(v1CertWithConstraints), "Wrong size %ld\n", size);
2683 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2686 /* test v1 cert with a serial number */
2687 info.SerialNumber.cbData = sizeof(serialNum);
2688 info.SerialNumber.pbData = (BYTE *)serialNum;
2689 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2690 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2693 ok(size == sizeof(v1CertWithSerial), "Wrong size %ld\n", size);
2694 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2697 /* Test v1 cert with an issuer name, a subject name, and a serial number */
2698 info.Issuer.cbData = sizeof(encodedCommonName);
2699 info.Issuer.pbData = (BYTE *)encodedCommonName;
2700 info.Subject.cbData = sizeof(encodedCommonName);
2701 info.Subject.pbData = (BYTE *)encodedCommonName;
2702 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2703 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2706 ok(size == sizeof(bigCert), "Wrong size %ld\n", size);
2707 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2710 /* for now, I let more interesting tests be done for each subcomponent,
2711 * rather than retesting them all here.
2715 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2717 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2718 v1CertWithConstraints, v1CertWithSerial };
2723 /* Test with NULL pbEncoded */
2724 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2725 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2726 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2727 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2728 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2729 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2730 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2731 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2732 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2733 * minimum a cert must have a non-zero serial number, an issuer, and a
2736 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2738 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2739 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2740 (BYTE *)&buf, &size);
2741 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2742 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2744 /* Now check with serial number, subject and issuer specified */
2745 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2746 sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2747 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2750 CERT_INFO *info = (CERT_INFO *)buf;
2752 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2753 ok(info->SerialNumber.cbData == 1,
2754 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2755 ok(*info->SerialNumber.pbData == *serialNum,
2756 "Expected serial number %d, got %d\n", *serialNum,
2757 *info->SerialNumber.pbData);
2758 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2759 "Wrong size %ld\n", info->Issuer.cbData);
2760 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2761 "Unexpected issuer\n");
2762 ok(info->Subject.cbData == sizeof(encodedCommonName),
2763 "Wrong size %ld\n", info->Subject.cbData);
2764 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2765 info->Subject.cbData), "Unexpected subject\n");
2770 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2773 static const BYTE signedBigCert[] = {
2774 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2775 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2776 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2777 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2778 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2779 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2780 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2781 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2782 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2783 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2784 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2785 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2787 static void test_encodeCert(DWORD dwEncoding)
2789 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
2790 * also that bigCert is a NULL-terminated string, so don't count its
2791 * last byte (otherwise the signed cert won't decode.)
2793 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2794 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2799 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2800 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2801 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2804 ok(bufSize == sizeof(signedBigCert), "Wrong size %ld\n", bufSize);
2805 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2810 static void test_decodeCert(DWORD dwEncoding)
2816 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2817 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2818 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2821 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2823 ok(info->ToBeSigned.cbData == sizeof(bigCert),
2824 "Wrong cert size %ld\n", info->ToBeSigned.cbData);
2825 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2826 "Unexpected cert\n");
2827 ok(info->Signature.cbData == sizeof(hash),
2828 "Wrong signature size %ld\n", info->Signature.cbData);
2829 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2830 "Unexpected signature\n");
2833 /* A signed cert decodes as a CERT_INFO too */
2834 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, signedBigCert,
2835 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2836 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2839 CERT_INFO *info = (CERT_INFO *)buf;
2841 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2842 ok(info->SerialNumber.cbData == 1,
2843 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2844 ok(*info->SerialNumber.pbData == *serialNum,
2845 "Expected serial number %d, got %d\n", *serialNum,
2846 *info->SerialNumber.pbData);
2847 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2848 "Wrong size %ld\n", info->Issuer.cbData);
2849 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2850 "Unexpected issuer\n");
2851 ok(info->Subject.cbData == sizeof(encodedCommonName),
2852 "Wrong size %ld\n", info->Subject.cbData);
2853 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2854 info->Subject.cbData), "Unexpected subject\n");
2859 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2860 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2861 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2862 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2863 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2865 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2866 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2867 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2868 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2869 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2870 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2871 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2872 0x2e, 0x6f, 0x72, 0x67 };
2873 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2874 CRL_REASON_AFFILIATION_CHANGED;
2876 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2878 CRL_DIST_POINTS_INFO info = { 0 };
2879 CRL_DIST_POINT point = { { 0 } };
2880 CERT_ALT_NAME_ENTRY entry = { 0 };
2885 /* Test with an empty info */
2886 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2887 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2888 ok(!ret && GetLastError() == E_INVALIDARG,
2889 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2890 /* Test with one empty dist point */
2891 info.cDistPoint = 1;
2892 info.rgDistPoint = &point;
2893 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2894 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2897 ok(size == sizeof(emptyDistPoint), "Wrong size %ld\n", size);
2898 ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2901 /* A dist point with an invalid name */
2902 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2903 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2904 U(entry).pwszURL = (LPWSTR)nihongoURL;
2905 U(point.DistPointName).FullName.cAltEntry = 1;
2906 U(point.DistPointName).FullName.rgAltEntry = &entry;
2907 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2908 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2909 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2910 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2911 /* The first invalid character is at index 7 */
2912 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2913 "Expected invalid char at index 7, got %ld\n",
2914 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2915 /* A dist point with (just) a valid name */
2916 U(entry).pwszURL = (LPWSTR)url;
2917 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2918 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2921 ok(size == sizeof(distPointWithUrl), "Wrong size %ld\n", size);
2922 ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2925 /* A dist point with (just) reason flags */
2926 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2927 point.ReasonFlags.cbData = sizeof(crlReason);
2928 point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2929 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2930 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2933 ok(size == sizeof(distPointWithReason), "Wrong size %ld\n", size);
2934 ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2937 /* A dist point with just an issuer */
2938 point.ReasonFlags.cbData = 0;
2939 point.CRLIssuer.cAltEntry = 1;
2940 point.CRLIssuer.rgAltEntry = &entry;
2941 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2942 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2945 ok(size == sizeof(distPointWithIssuer), "Wrong size %ld\n", size);
2946 ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2949 /* A dist point with both a name and an issuer */
2950 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2951 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2952 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2955 ok(size == sizeof(distPointWithUrlAndIssuer),
2956 "Wrong size %ld\n", size);
2957 ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2962 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2967 PCRL_DIST_POINTS_INFO info;
2968 PCRL_DIST_POINT point;
2969 PCERT_ALT_NAME_ENTRY entry;
2971 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2972 emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2973 (BYTE *)&buf, &size);
2976 info = (PCRL_DIST_POINTS_INFO)buf;
2977 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2978 "Wrong size %ld\n", size);
2979 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2981 point = info->rgDistPoint;
2982 ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2983 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2984 point->DistPointName.dwDistPointNameChoice);
2985 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2986 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2989 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2990 distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2991 (BYTE *)&buf, &size);
2994 info = (PCRL_DIST_POINTS_INFO)buf;
2995 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2996 "Wrong size %ld\n", size);
2997 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2999 point = info->rgDistPoint;
3000 ok(point->DistPointName.dwDistPointNameChoice ==
3001 CRL_DIST_POINT_FULL_NAME,
3002 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
3003 point->DistPointName.dwDistPointNameChoice);
3004 ok(U(point->DistPointName).FullName.cAltEntry == 1,
3005 "Expected 1 name entry, got %ld\n",
3006 U(point->DistPointName).FullName.cAltEntry);
3007 entry = U(point->DistPointName).FullName.rgAltEntry;
3008 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
3009 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
3010 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
3011 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
3012 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
3015 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
3016 distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
3017 NULL, (BYTE *)&buf, &size);
3020 info = (PCRL_DIST_POINTS_INFO)buf;
3021 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
3022 "Wrong size %ld\n", size);
3023 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
3025 point = info->rgDistPoint;
3026 ok(point->DistPointName.dwDistPointNameChoice ==
3027 CRL_DIST_POINT_NO_NAME,
3028 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
3029 point->DistPointName.dwDistPointNameChoice);
3030 ok(point->ReasonFlags.cbData == sizeof(crlReason),
3031 "Expected reason length\n");
3032 ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
3033 "Unexpected reason\n");
3034 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
3037 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
3038 distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
3039 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3042 info = (PCRL_DIST_POINTS_INFO)buf;
3043 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
3044 "Wrong size %ld\n", size);
3045 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
3047 point = info->rgDistPoint;
3048 ok(point->DistPointName.dwDistPointNameChoice ==
3049 CRL_DIST_POINT_FULL_NAME,
3050 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
3051 point->DistPointName.dwDistPointNameChoice);
3052 ok(U(point->DistPointName).FullName.cAltEntry == 1,
3053 "Expected 1 name entry, got %ld\n",
3054 U(point->DistPointName).FullName.cAltEntry);
3055 entry = U(point->DistPointName).FullName.rgAltEntry;
3056 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
3057 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
3058 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
3059 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
3060 ok(point->CRLIssuer.cAltEntry == 1,
3061 "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
3062 entry = point->CRLIssuer.rgAltEntry;
3063 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
3064 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
3065 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
3070 static const BYTE badFlagsIDP[] = { 0x30,0x06,0x81,0x01,0xff,0x82,0x01,0xff };
3071 static const BYTE emptyNameIDP[] = { 0x30,0x04,0xa0,0x02,0xa0,0x00 };
3072 static const BYTE urlIDP[] = { 0x30,0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,
3073 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,
3076 static void test_encodeCRLIssuingDistPoint(DWORD dwEncoding)
3081 CRL_ISSUING_DIST_POINT point = { { 0 } };
3082 CERT_ALT_NAME_ENTRY entry;
3084 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, NULL,
3085 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3086 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
3087 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
3088 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3089 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3090 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3093 ok(size == sizeof(emptySequence), "Unexpected size %ld\n", size);
3094 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
3097 /* nonsensical flags */
3098 point.fOnlyContainsUserCerts = TRUE;
3099 point.fOnlyContainsCACerts = TRUE;
3100 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3101 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3102 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3105 ok(size == sizeof(badFlagsIDP), "Unexpected size %ld\n", size);
3106 ok(!memcmp(buf, badFlagsIDP, size), "Unexpected value\n");
3109 /* unimplemented name type */
3110 point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
3111 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_ISSUER_RDN_NAME;
3112 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3113 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3114 ok(!ret && GetLastError() == E_INVALIDARG,
3115 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
3117 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
3118 U(point.DistPointName).FullName.cAltEntry = 0;
3119 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3120 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3121 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3124 ok(size == sizeof(emptyNameIDP), "Unexpected size %ld\n", size);
3125 ok(!memcmp(buf, emptyNameIDP, size), "Unexpected value\n");
3128 /* name with URL entry */
3129 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
3130 U(entry).pwszURL = (LPWSTR)url;
3131 U(point.DistPointName).FullName.cAltEntry = 1;
3132 U(point.DistPointName).FullName.rgAltEntry = &entry;
3133 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3134 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3135 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3138 ok(size == sizeof(urlIDP), "Unexpected size %ld\n", size);
3139 ok(!memcmp(buf, urlIDP, size), "Unexpected value\n");
3144 static void compareAltNameEntry(const CERT_ALT_NAME_ENTRY *expected,
3145 const CERT_ALT_NAME_ENTRY *got)
3147 ok(expected->dwAltNameChoice == got->dwAltNameChoice,
3148 "Expected name choice %ld, got %ld\n", expected->dwAltNameChoice,
3149 got->dwAltNameChoice);
3150 if (expected->dwAltNameChoice == got->dwAltNameChoice)
3152 switch (got->dwAltNameChoice)
3154 case CERT_ALT_NAME_RFC822_NAME:
3155 case CERT_ALT_NAME_DNS_NAME:
3156 case CERT_ALT_NAME_EDI_PARTY_NAME:
3157 case CERT_ALT_NAME_URL:
3158 case CERT_ALT_NAME_REGISTERED_ID:
3159 ok((!U(*expected).pwszURL && !U(*got).pwszURL) ||
3160 !lstrcmpW(U(*expected).pwszURL, U(*got).pwszURL), "Unexpected name\n");
3162 case CERT_ALT_NAME_X400_ADDRESS:
3163 case CERT_ALT_NAME_DIRECTORY_NAME:
3164 case CERT_ALT_NAME_IP_ADDRESS:
3165 ok(U(*got).IPAddress.cbData == U(*expected).IPAddress.cbData,
3166 "Unexpected IP address length %ld\n", U(*got).IPAddress.cbData);
3167 ok(!memcmp(U(*got).IPAddress.pbData, U(*got).IPAddress.pbData,
3168 U(*got).IPAddress.cbData), "Unexpected value\n");
3174 static void compareAltNameInfo(const CERT_ALT_NAME_INFO *expected,
3175 const CERT_ALT_NAME_INFO *got)
3179 ok(expected->cAltEntry == got->cAltEntry, "Expected %ld entries, got %ld\n",
3180 expected->cAltEntry, got->cAltEntry);
3181 for (i = 0; i < min(expected->cAltEntry, got->cAltEntry); i++)
3182 compareAltNameEntry(&expected->rgAltEntry[i], &got->rgAltEntry[i]);
3185 static void compareDistPointName(const CRL_DIST_POINT_NAME *expected,
3186 const CRL_DIST_POINT_NAME *got)
3188 ok(got->dwDistPointNameChoice == expected->dwDistPointNameChoice,
3189 "Unexpected name choice %ld\n", got->dwDistPointNameChoice);
3190 if (got->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
3191 compareAltNameInfo(&(U(*expected).FullName), &(U(*got).FullName));
3194 static void compareCRLIssuingDistPoints(const CRL_ISSUING_DIST_POINT *expected,
3195 const CRL_ISSUING_DIST_POINT *got)
3197 compareDistPointName(&expected->DistPointName, &got->DistPointName);
3198 ok(got->fOnlyContainsUserCerts == expected->fOnlyContainsUserCerts,
3199 "Unexpected fOnlyContainsUserCerts\n");
3200 ok(got->fOnlyContainsCACerts == expected->fOnlyContainsCACerts,
3201 "Unexpected fOnlyContainsCACerts\n");
3202 ok(got->OnlySomeReasonFlags.cbData == expected->OnlySomeReasonFlags.cbData,
3203 "Unexpected reason flags\n");
3204 ok(got->fIndirectCRL == expected->fIndirectCRL,
3205 "Unexpected fIndirectCRL\n");
3208 static void test_decodeCRLIssuingDistPoint(DWORD dwEncoding)
3213 CRL_ISSUING_DIST_POINT point = { { 0 } };
3215 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3216 emptySequence, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3217 (BYTE *)&buf, &size);
3218 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3221 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3224 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3225 badFlagsIDP, badFlagsIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3226 (BYTE *)&buf, &size);
3227 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3230 point.fOnlyContainsUserCerts = point.fOnlyContainsCACerts = TRUE;
3231 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3234 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3235 emptyNameIDP, emptyNameIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3236 (BYTE *)&buf, &size);
3237 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3240 point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
3241 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
3242 U(point.DistPointName).FullName.cAltEntry = 0;
3243 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3246 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3247 urlIDP, urlIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3248 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3251 CERT_ALT_NAME_ENTRY entry;
3253 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
3254 U(entry).pwszURL = (LPWSTR)url;
3255 U(point.DistPointName).FullName.cAltEntry = 1;
3256 U(point.DistPointName).FullName.rgAltEntry = &entry;
3257 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3262 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
3263 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
3265 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
3266 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
3267 0x30, 0x30, 0x30, 0x30, 0x5a };
3268 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
3269 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
3270 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
3271 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
3273 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
3274 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
3275 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
3276 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
3277 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
3278 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
3279 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
3280 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
3281 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
3282 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
3283 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
3284 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
3285 static const BYTE v1CRLWithEntryExt[] = { 0x30,0x5a,0x30,0x02,0x06,0x00,0x30,
3286 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
3287 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
3288 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x2c,0x30,0x2a,0x02,0x01,
3289 0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,
3290 0x30,0x30,0x5a,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,
3291 0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3292 static const BYTE v1CRLWithExt[] = { 0x30,0x5c,0x30,0x02,0x06,0x00,0x30,0x15,
3293 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
3294 0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
3295 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,
3296 0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,
3297 0x30,0x5a,0xa0,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
3298 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3299 static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06,
3300 0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,
3301 0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,
3302 0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,
3303 0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,
3304 0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,
3305 0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3306 static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01,
3307 0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
3308 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,
3309 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,
3310 0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
3311 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,
3312 0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3314 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
3318 static CHAR oid_issuing_dist_point[] = szOID_ISSUING_DIST_POINT;
3320 CRL_INFO info = { 0 };
3321 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
3324 /* Test with a V1 CRL */
3325 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3326 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3327 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3330 ok(size == sizeof(v1CRL), "Wrong size %ld\n", size);
3331 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
3335 info.dwVersion = CRL_V2;
3336 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3337 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3338 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3341 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
3342 v2CRL[1] + 2, size);
3343 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
3346 /* v1 CRL with a name */
3347 info.dwVersion = CRL_V1;
3348 info.Issuer.cbData = sizeof(encodedCommonName);
3349 info.Issuer.pbData = (BYTE *)encodedCommonName;
3350 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3351 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3352 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3355 ok(size == sizeof(v1CRLWithIssuer), "Wrong size %ld\n", size);
3356 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
3359 /* v1 CRL with a name and a NULL entry pointer */
3361 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3362 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3363 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
3364 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
3365 /* now set an empty entry */
3366 info.rgCRLEntry = &entry;
3367 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3368 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3371 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
3372 "Wrong size %ld\n", size);
3373 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
3374 "Got unexpected value\n");
3377 /* an entry with a serial number */
3378 entry.SerialNumber.cbData = sizeof(serialNum);
3379 entry.SerialNumber.pbData = (BYTE *)serialNum;
3380 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3381 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3384 ok(size == sizeof(v1CRLWithIssuerAndEntry),
3385 "Wrong size %ld\n", size);
3386 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
3387 "Got unexpected value\n");
3390 /* an entry with an extension */
3391 entry.cExtension = 1;
3392 entry.rgExtension = &criticalExt;
3393 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3394 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3395 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3398 ok(size == sizeof(v1CRLWithEntryExt), "Wrong size %ld\n", size);
3399 ok(!memcmp(buf, v1CRLWithEntryExt, size), "Got unexpected value\n");
3402 /* a CRL with an extension */
3403 entry.cExtension = 0;
3404 info.cExtension = 1;
3405 info.rgExtension = &criticalExt;
3406 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3407 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3408 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3411 ok(size == sizeof(v1CRLWithExt), "Wrong size %ld\n", size);
3412 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
3415 /* a v2 CRL with an extension, this time non-critical */
3416 info.dwVersion = CRL_V2;
3417 info.rgExtension = &nonCriticalExt;
3418 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3419 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3420 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3423 ok(size == sizeof(v2CRLWithExt), "Wrong size %ld\n", size);
3424 ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n");
3427 /* a v2 CRL with an issuing dist point extension */
3428 ext.pszObjId = oid_issuing_dist_point;
3429 ext.fCritical = TRUE;
3430 ext.Value.cbData = sizeof(urlIDP);
3431 ext.Value.pbData = (LPBYTE)urlIDP;
3432 entry.rgExtension = &ext;
3433 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3434 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3435 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3438 ok(size == sizeof(v2CRLWithIssuingDistPoint), "Wrong size %ld\n", size);
3439 ok(!memcmp(buf, v2CRLWithIssuingDistPoint, size), "Unexpected value\n");
3444 static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01,
3445 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3446 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06,
3447 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
3448 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56,
3449 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
3450 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65,
3451 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
3452 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
3453 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43,
3454 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30,
3455 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33,
3456 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51,
3457 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99,
3458 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31,
3459 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0,
3460 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30,
3461 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30,
3462 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75,
3463 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33,
3464 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30,
3465 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
3466 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06,
3467 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03,
3468 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88,
3469 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd,
3470 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf,
3471 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46,
3472 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f,
3473 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75,
3474 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f,
3475 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82,
3476 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07,
3477 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c,
3480 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
3482 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
3487 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
3489 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3490 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3491 (BYTE *)&buf, &size);
3492 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
3493 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3495 /* at a minimum, a CRL must contain an issuer: */
3496 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3497 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3498 (BYTE *)&buf, &size);
3499 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3502 CRL_INFO *info = (CRL_INFO *)buf;
3504 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3505 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
3507 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3508 "Wrong issuer size %ld\n", info->Issuer.cbData);
3509 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3510 "Unexpected issuer\n");
3513 /* check decoding with an empty CRL entry */
3514 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3515 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
3516 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3517 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
3518 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3519 /* with a real CRL entry */
3520 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3521 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
3522 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3523 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3526 CRL_INFO *info = (CRL_INFO *)buf;
3529 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3530 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3532 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3533 entry = info->rgCRLEntry;
3534 ok(entry->SerialNumber.cbData == 1,
3535 "Expected serial number size 1, got %ld\n",
3536 entry->SerialNumber.cbData);
3537 ok(*entry->SerialNumber.pbData == *serialNum,
3538 "Expected serial number %d, got %d\n", *serialNum,
3539 *entry->SerialNumber.pbData);
3540 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3541 "Wrong issuer size %ld\n", info->Issuer.cbData);
3542 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3543 "Unexpected issuer\n");
3545 /* a real CRL from verisign that has extensions */
3546 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3547 verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG,
3548 NULL, (BYTE *)&buf, &size);
3549 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3552 CRL_INFO *info = (CRL_INFO *)buf;
3555 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3556 ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %ld\n",
3558 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3559 entry = info->rgCRLEntry;
3560 ok(info->cExtension == 2, "Expected 2 extensions, got %ld\n",
3563 /* and finally, with an extension */
3564 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3565 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3566 NULL, (BYTE *)&buf, &size);
3567 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3570 CRL_INFO *info = (CRL_INFO *)buf;
3573 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3574 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3576 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3577 entry = info->rgCRLEntry;
3578 ok(entry->SerialNumber.cbData == 1,
3579 "Expected serial number size 1, got %ld\n",
3580 entry->SerialNumber.cbData);
3581 ok(*entry->SerialNumber.pbData == *serialNum,
3582 "Expected serial number %d, got %d\n", *serialNum,
3583 *entry->SerialNumber.pbData);
3584 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3585 "Wrong issuer size %ld\n", info->Issuer.cbData);
3586 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3587 "Unexpected issuer\n");
3588 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3591 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3592 v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3593 NULL, (BYTE *)&buf, &size);
3594 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3597 CRL_INFO *info = (CRL_INFO *)buf;
3599 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3603 /* And again, with an issuing dist point */
3604 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3605 v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint),
3606 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3607 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3610 CRL_INFO *info = (CRL_INFO *)buf;
3612 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3618 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
3619 szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
3620 static const BYTE encodedUsage[] = {
3621 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
3622 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
3623 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
3625 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
3630 CERT_ENHKEY_USAGE usage;
3632 /* Test with empty usage */
3633 usage.cUsageIdentifier = 0;
3634 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3635 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3636 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3639 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
3640 ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
3643 /* Test with a few usages */
3644 usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
3645 usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
3646 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3647 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3648 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3651 ok(size == sizeof(encodedUsage), "Wrong size %ld\n", size);
3652 ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
3657 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
3663 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3664 emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
3665 (BYTE *)&buf, &size);
3666 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3669 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3671 ok(size >= sizeof(CERT_ENHKEY_USAGE),
3672 "Wrong size %ld\n", size);
3673 ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
3674 usage->cUsageIdentifier);
3677 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3678 encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
3679 (BYTE *)&buf, &size);
3680 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3683 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3686 ok(size >= sizeof(CERT_ENHKEY_USAGE),
3687 "Wrong size %ld\n", size);
3688 ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
3689 "Wrong CRL entries count %ld\n", usage->cUsageIdentifier);
3690 for (i = 0; i < usage->cUsageIdentifier; i++)
3691 ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
3692 "Expected OID %s, got %s\n", keyUsages[i],
3693 usage->rgpszUsageIdentifier[i]);
3698 /* Free *pInfo with HeapFree */
3699 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
3706 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
3708 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
3709 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3710 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3711 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
3713 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3714 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3715 ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
3717 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3718 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3719 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3720 0, NULL, NULL, &size);
3721 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3722 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3723 /* Test with no key */
3724 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3725 0, NULL, NULL, &size);
3726 ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
3728 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
3729 ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
3732 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
3733 NULL, 0, NULL, NULL, &size);
3734 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3735 *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
3738 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
3739 X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
3740 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
3744 /* By default (we passed NULL as the OID) the OID is
3747 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
3748 "Expected %s, got %s\n", szOID_RSA_RSA,
3749 (*pInfo)->Algorithm.pszObjId);
3755 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
3756 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
3757 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
3758 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3759 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3760 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3761 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
3762 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
3763 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3764 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3765 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3766 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3767 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
3768 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
3769 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
3770 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
3771 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
3772 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
3773 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
3774 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
3775 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
3776 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
3777 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
3778 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
3779 0x49, 0xe5, 0xf9, 0x65, 0xf3 };
3781 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
3785 PCCERT_CONTEXT context;
3788 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
3789 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
3790 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
3791 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3794 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3795 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3796 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3797 ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3798 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3799 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3800 ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3802 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3803 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3804 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3806 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3807 CryptDestroyKey(key);
3809 /* Test importing a public key from a certificate context */
3810 context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert,
3811 sizeof(expiredCert));
3812 ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
3816 ok(!strcmp(szOID_RSA_RSA,
3817 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId),
3818 "Expected %s, got %s\n", szOID_RSA_RSA,
3819 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
3820 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING,
3821 &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key);
3822 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3823 CryptDestroyKey(key);
3824 CertFreeCertificateContext(context);
3828 static const char cspName[] = "WineCryptTemp";
3830 static void testPortPublicKeyInfo(void)
3834 PCERT_PUBLIC_KEY_INFO info = NULL;
3836 /* Just in case a previous run failed, delete this thing */
3837 CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3838 CRYPT_DELETEKEYSET);
3839 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3842 testExportPublicKey(csp, &info);
3843 testImportPublicKey(csp, info);
3845 HeapFree(GetProcessHeap(), 0, info);
3846 CryptReleaseContext(csp, 0);
3847 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3848 CRYPT_DELETEKEYSET);
3853 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3854 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3857 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3859 test_encodeInt(encodings[i]);
3860 test_decodeInt(encodings[i]);
3861 test_encodeEnumerated(encodings[i]);
3862 test_decodeEnumerated(encodings[i]);
3863 test_encodeFiletime(encodings[i]);
3864 test_decodeFiletime(encodings[i]);
3865 test_encodeName(encodings[i]);
3866 test_decodeName(encodings[i]);
3867 test_encodeUnicodeName(encodings[i]);
3868 test_decodeUnicodeName(encodings[i]);
3869 test_encodeNameValue(encodings[i]);
3870 test_decodeNameValue(encodings[i]);
3871 test_encodeUnicodeNameValue(encodings[i]);
3872 test_decodeUnicodeNameValue(encodings[i]);
3873 test_encodeAltName(encodings[i]);
3874 test_decodeAltName(encodings[i]);
3875 test_encodeOctets(encodings[i]);
3876 test_decodeOctets(encodings[i]);
3877 test_encodeBits(encodings[i]);
3878 test_decodeBits(encodings[i]);
3879 test_encodeBasicConstraints(encodings[i]);
3880 test_decodeBasicConstraints(encodings[i]);
3881 test_encodeRsaPublicKey(encodings[i]);
3882 test_decodeRsaPublicKey(encodings[i]);
3883 test_encodeSequenceOfAny(encodings[i]);
3884 test_decodeSequenceOfAny(encodings[i]);
3885 test_encodeExtensions(encodings[i]);
3886 test_decodeExtensions(encodings[i]);
3887 test_encodePublicKeyInfo(encodings[i]);
3888 test_decodePublicKeyInfo(encodings[i]);
3889 test_encodeCertToBeSigned(encodings[i]);
3890 test_decodeCertToBeSigned(encodings[i]);
3891 test_encodeCert(encodings[i]);
3892 test_decodeCert(encodings[i]);
3893 test_encodeCRLDistPoints(encodings[i]);
3894 test_decodeCRLDistPoints(encodings[i]);
3895 test_encodeCRLIssuingDistPoint(encodings[i]);
3896 test_decodeCRLIssuingDistPoint(encodings[i]);
3897 test_encodeCRLToBeSigned(encodings[i]);
3898 test_decodeCRLToBeSigned(encodings[i]);
3899 test_encodeEnhancedKeyUsage(encodings[i]);
3900 test_decodeEnhancedKeyUsage(encodings[i]);
3902 testPortPublicKeyInfo();