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 _blob_of(arr) { sizeof(arr), (LPBYTE)arr }
630 const CERT_RDN_ATTR rdnAttrs[] = {
631 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
632 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
633 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
634 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
635 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
636 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
637 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
639 const CERT_RDN_ATTR decodedRdnAttrs[] = {
640 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
641 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
642 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
643 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
644 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
645 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
646 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
650 static const BYTE encodedRDNAttrs[] = {
651 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
652 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
653 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
654 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
655 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
656 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
657 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
658 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
659 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
660 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
663 static void test_encodeName(DWORD dwEncoding)
665 CERT_RDN_ATTR attrs[2];
668 static CHAR oid_common_name[] = szOID_COMMON_NAME,
669 oid_sur_name[] = szOID_SUR_NAME;
674 /* Test with NULL pvStructInfo */
675 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
676 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
677 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
678 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
679 /* Test with empty CERT_NAME_INFO */
682 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
683 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
684 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
687 ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
688 "Got unexpected encoding for empty name\n");
691 /* Test with bogus CERT_RDN */
693 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
694 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
695 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
696 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
697 /* Test with empty CERT_RDN */
699 rdn.rgRDNAttr = NULL;
702 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
703 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
704 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
707 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
708 "Got unexpected encoding for empty RDN array\n");
711 /* Test with bogus attr array */
713 rdn.rgRDNAttr = NULL;
714 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
715 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
716 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
717 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
718 /* oddly, a bogus OID is accepted by Windows XP; not testing.
719 attrs[0].pszObjId = "bogus";
720 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
721 attrs[0].Value.cbData = sizeof(commonName);
722 attrs[0].Value.pbData = (BYTE *)commonName;
724 rdn.rgRDNAttr = attrs;
725 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
726 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
727 ok(!ret, "Expected failure, got success\n");
729 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
730 * the encoded attributes to be swapped.
732 attrs[0].pszObjId = oid_common_name;
733 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
734 attrs[0].Value.cbData = sizeof(commonName);
735 attrs[0].Value.pbData = (BYTE *)commonName;
736 attrs[1].pszObjId = oid_sur_name;
737 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
738 attrs[1].Value.cbData = sizeof(surName);
739 attrs[1].Value.pbData = (BYTE *)surName;
741 rdn.rgRDNAttr = attrs;
742 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
743 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
744 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
747 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
748 "Got unexpected encoding for two RDN array\n");
751 /* A name can be "encoded" with previously encoded RDN attrs. */
752 attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB;
753 attrs[0].Value.pbData = (LPBYTE)twoRDNs;
754 attrs[0].Value.cbData = sizeof(twoRDNs);
756 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
757 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
758 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
761 ok(size == sizeof(encodedTwoRDNs), "Unexpected size %ld\n", size);
762 ok(!memcmp(buf, encodedTwoRDNs, size),
763 "Unexpected value for re-endoded two RDN array\n");
766 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
768 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
769 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
770 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
771 ok(!ret && GetLastError() == E_INVALIDARG,
772 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
773 /* Test a more complex name */
774 rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
775 rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
780 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
781 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
782 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
785 ok(size == sizeof(encodedRDNAttrs), "Wrong size %ld\n", size);
786 ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
791 static void compareNameValues(const CERT_NAME_VALUE *expected,
792 const CERT_NAME_VALUE *got)
794 ok(got->dwValueType == expected->dwValueType,
795 "Expected string type %ld, got %ld\n", expected->dwValueType,
797 ok(got->Value.cbData == expected->Value.cbData,
798 "String type %ld: unexpected data size, got %ld, expected %ld\n",
799 expected->dwValueType, got->Value.cbData, expected->Value.cbData);
800 if (got->Value.cbData && got->Value.pbData)
801 ok(!memcmp(got->Value.pbData, expected->Value.pbData,
802 min(got->Value.cbData, expected->Value.cbData)),
803 "String type %ld: unexpected value\n", expected->dwValueType);
806 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
807 const CERT_RDN_ATTR *got)
809 if (expected->pszObjId && strlen(expected->pszObjId))
811 ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
815 ok(!strcmp(got->pszObjId, expected->pszObjId),
816 "Got unexpected OID %s, expected %s\n", got->pszObjId,
820 compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType,
821 (const CERT_NAME_VALUE *)&got->dwValueType);
824 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
826 ok(got->cRDNAttr == expected->cRDNAttr,
827 "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
832 for (i = 0; i < got->cRDNAttr; i++)
833 compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
837 static void compareNames(const CERT_NAME_INFO *expected,
838 const CERT_NAME_INFO *got)
840 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
841 expected->cRDN, got->cRDN);
846 for (i = 0; i < got->cRDN; i++)
847 compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
851 static void test_decodeName(DWORD dwEncoding)
857 CERT_NAME_INFO info = { 1, &rdn };
859 /* test empty name */
861 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
862 emptySequence[1] + 2,
863 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
864 (BYTE *)&buf, &bufSize);
865 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
866 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
867 * decoder works the same way, so only test the count.
871 ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %ld\n", bufSize);
872 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
873 "Expected 0 RDNs in empty info, got %ld\n",
874 ((CERT_NAME_INFO *)buf)->cRDN);
879 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
881 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
882 (BYTE *)&buf, &bufSize);
883 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
886 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
888 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
889 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
890 "Got unexpected value for empty RDN\n");
893 /* test two RDN attrs */
895 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
897 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
898 (BYTE *)&buf, &bufSize);
899 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
902 CERT_RDN_ATTR attrs[] = {
903 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
905 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
906 (BYTE *)commonName } },
909 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
910 rdn.rgRDNAttr = attrs;
911 compareNames(&info, (CERT_NAME_INFO *)buf);
914 /* And, a slightly more complicated name */
917 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
918 sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
919 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
922 rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
923 rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
924 compareNames(&info, (CERT_NAME_INFO *)buf);
929 struct EncodedNameValue
931 CERT_NAME_VALUE value;
936 static const char bogusIA5[] = "\x80";
937 static const char bogusPrintable[] = "~";
938 static const char bogusNumeric[] = "A";
939 static WCHAR commonNameW[] = { 'J','u','a','n',' ','L','a','n','g',0 };
940 static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
941 static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
942 static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
943 static BYTE octetCommonNameValue[] = {
944 0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
945 static BYTE numericCommonNameValue[] = {
946 0x12,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
947 static BYTE printableCommonNameValue[] = {
948 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
949 static BYTE t61CommonNameValue[] = {
950 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
951 static BYTE videotexCommonNameValue[] = {
952 0x15,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
953 static BYTE ia5CommonNameValue[] = {
954 0x16,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
955 static BYTE graphicCommonNameValue[] = {
956 0x19,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
957 static BYTE visibleCommonNameValue[] = {
958 0x1a,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
959 static BYTE generalCommonNameValue[] = {
960 0x1b,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
961 static BYTE bmpCommonNameValue[] = {
962 0x1e,0x14,0x00,0x4a,0x00,0x75,0x00,0x61,0x00,0x6e,0x00,0x20,0x00,0x4c,0x00,
963 0x61,0x00,0x6e,0x00,0x67,0x00,0x00 };
964 static BYTE utf8CommonNameValue[] = {
965 0x0c,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
967 static struct EncodedNameValue nameValues[] = {
968 { { CERT_RDN_OCTET_STRING, { sizeof(commonName), (BYTE *)commonName } },
969 octetCommonNameValue, sizeof(octetCommonNameValue) },
970 { { CERT_RDN_NUMERIC_STRING, { sizeof(commonName), (BYTE *)commonName } },
971 numericCommonNameValue, sizeof(numericCommonNameValue) },
972 { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
973 printableCommonNameValue, sizeof(printableCommonNameValue) },
974 { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } },
975 t61CommonNameValue, sizeof(t61CommonNameValue) },
976 { { CERT_RDN_VIDEOTEX_STRING, { sizeof(commonName), (BYTE *)commonName } },
977 videotexCommonNameValue, sizeof(videotexCommonNameValue) },
978 { { CERT_RDN_IA5_STRING, { sizeof(commonName), (BYTE *)commonName } },
979 ia5CommonNameValue, sizeof(ia5CommonNameValue) },
980 { { CERT_RDN_GRAPHIC_STRING, { sizeof(commonName), (BYTE *)commonName } },
981 graphicCommonNameValue, sizeof(graphicCommonNameValue) },
982 { { CERT_RDN_VISIBLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
983 visibleCommonNameValue, sizeof(visibleCommonNameValue) },
984 { { CERT_RDN_GENERAL_STRING, { sizeof(commonName), (BYTE *)commonName } },
985 generalCommonNameValue, sizeof(generalCommonNameValue) },
986 { { CERT_RDN_BMP_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } },
987 bmpCommonNameValue, sizeof(bmpCommonNameValue) },
988 { { CERT_RDN_UTF8_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } },
989 utf8CommonNameValue, sizeof(utf8CommonNameValue) },
990 /* The following tests succeed under Windows, but really should fail,
991 * they contain characters that are illegal for the encoding. I'm
992 * including them to justify my lazy encoding.
994 { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42,
996 { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable),
997 (BYTE *)bogusPrintable } }, bin43, sizeof(bin43) },
998 { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
999 bin44, sizeof(bin44) },
1002 static void test_encodeNameValue(DWORD dwEncoding)
1007 CERT_NAME_VALUE value = { 0, { 0, NULL } };
1009 value.dwValueType = 14;
1010 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value,
1011 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1012 ok(!ret && GetLastError() == CRYPT_E_ASN1_CHOICE,
1013 "Expected CRYPT_E_ASN1_CHOICE, got %08lx\n", GetLastError());
1014 value.dwValueType = CERT_RDN_ENCODED_BLOB;
1015 value.Value.pbData = printableCommonNameValue;
1016 value.Value.cbData = sizeof(printableCommonNameValue);
1017 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value,
1018 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1019 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1022 ok(size == sizeof(printableCommonNameValue), "Unexpected size %ld\n",
1024 ok(!memcmp(buf, printableCommonNameValue, size),
1025 "Unexpected encoding\n");
1028 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
1030 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE,
1031 &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1033 ok(ret, "Type %ld: CryptEncodeObjectEx failed: %08lx\n",
1034 nameValues[i].value.dwValueType, GetLastError());
1037 ok(size == nameValues[i].encodedSize,
1038 "Expected size %ld, got %ld\n", nameValues[i].encodedSize, size);
1039 ok(!memcmp(buf, nameValues[i].encoded, size),
1040 "Got unexpected encoding\n");
1046 static void test_decodeNameValue(DWORD dwEncoding)
1053 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
1055 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE,
1056 nameValues[i].encoded, nameValues[i].encoded[1] + 2,
1057 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1058 (BYTE *)&buf, &bufSize);
1059 ok(ret, "Value type %ld: CryptDecodeObjectEx failed: %08lx\n",
1060 nameValues[i].value.dwValueType, GetLastError());
1063 compareNameValues(&nameValues[i].value,
1064 (const CERT_NAME_VALUE *)buf);
1070 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
1071 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
1072 'h','q','.','o','r','g',0 };
1073 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
1074 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
1076 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
1078 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1079 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1080 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1081 static const BYTE localhost[] = { 127, 0, 0, 1 };
1082 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1085 static void test_encodeAltName(DWORD dwEncoding)
1087 CERT_ALT_NAME_INFO info = { 0 };
1088 CERT_ALT_NAME_ENTRY entry = { 0 };
1093 /* Test with empty info */
1094 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1095 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1098 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
1099 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1102 /* Test with an empty entry */
1104 info.rgAltEntry = &entry;
1105 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1106 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1107 ok(!ret && GetLastError() == E_INVALIDARG,
1108 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1109 /* Test with an empty pointer */
1110 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1111 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1112 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1115 ok(size == sizeof(emptyURL), "Wrong size %ld\n", size);
1116 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1119 /* Test with a real URL */
1120 U(entry).pwszURL = (LPWSTR)url;
1121 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1122 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1125 ok(size == sizeof(encodedURL), "Wrong size %ld\n", size);
1126 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1129 /* Now with the URL containing an invalid IA5 char */
1130 U(entry).pwszURL = (LPWSTR)nihongoURL;
1131 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1132 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1133 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1134 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1135 /* The first invalid character is at index 7 */
1136 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1137 "Expected invalid char at index 7, got %ld\n",
1138 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1139 /* Now with the URL missing a scheme */
1140 U(entry).pwszURL = (LPWSTR)dnsName;
1141 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1142 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1143 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1146 /* This succeeds, but it shouldn't, so don't worry about conforming */
1149 /* Now with a DNS name */
1150 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1151 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1152 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1153 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1156 ok(size == sizeof(encodedDnsName), "Wrong size %ld\n", size);
1157 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1160 /* Test with an IP address */
1161 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1162 U(entry).IPAddress.cbData = sizeof(localhost);
1163 U(entry).IPAddress.pbData = (LPBYTE)localhost;
1164 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1165 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1168 ok(size == sizeof(encodedIPAddr), "Wrong size %ld\n", size);
1169 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1174 static void test_decodeAltName(DWORD dwEncoding)
1176 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1178 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1183 CERT_ALT_NAME_INFO *info;
1185 /* Test some bogus ones first */
1186 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1187 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1188 NULL, (BYTE *)&buf, &bufSize);
1189 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1190 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1191 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1192 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1194 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1195 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1196 /* Now expected cases */
1197 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1198 emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1200 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1203 info = (CERT_ALT_NAME_INFO *)buf;
1205 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1209 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1210 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1212 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1215 info = (CERT_ALT_NAME_INFO *)buf;
1217 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1219 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1220 "Expected CERT_ALT_NAME_URL, got %ld\n",
1221 info->rgAltEntry[0].dwAltNameChoice);
1222 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1223 "Expected empty URL\n");
1226 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1227 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1229 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1232 info = (CERT_ALT_NAME_INFO *)buf;
1234 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1236 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1237 "Expected CERT_ALT_NAME_URL, got %ld\n",
1238 info->rgAltEntry[0].dwAltNameChoice);
1239 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1242 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1243 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1245 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1248 info = (CERT_ALT_NAME_INFO *)buf;
1250 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1252 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1253 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1254 info->rgAltEntry[0].dwAltNameChoice);
1255 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1256 "Unexpected DNS name\n");
1259 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1260 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1262 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1265 info = (CERT_ALT_NAME_INFO *)buf;
1267 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1269 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1270 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1271 info->rgAltEntry[0].dwAltNameChoice);
1272 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1273 "Unexpected IP address length %ld\n",
1274 U(info->rgAltEntry[0]).IPAddress.cbData);
1275 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1276 sizeof(localhost)), "Unexpected IP address value\n");
1281 struct UnicodeExpectedError
1289 static const WCHAR oneW[] = { '1',0 };
1290 static const WCHAR aW[] = { 'a',0 };
1291 static const WCHAR quoteW[] = { '"', 0 };
1293 static struct UnicodeExpectedError unicodeErrors[] = {
1294 { CERT_RDN_ANY_TYPE, oneW, 0, CRYPT_E_NOT_CHAR_STRING },
1295 { CERT_RDN_ENCODED_BLOB, oneW, 0, CRYPT_E_NOT_CHAR_STRING },
1296 { CERT_RDN_OCTET_STRING, oneW, 0, CRYPT_E_NOT_CHAR_STRING },
1297 { 14, oneW, 0, CRYPT_E_ASN1_CHOICE },
1298 { CERT_RDN_NUMERIC_STRING, aW, 0, CRYPT_E_INVALID_NUMERIC_STRING },
1299 { CERT_RDN_PRINTABLE_STRING, quoteW, 0, CRYPT_E_INVALID_PRINTABLE_STRING },
1300 { CERT_RDN_IA5_STRING, nihongoURL, 7, CRYPT_E_INVALID_IA5_STRING },
1303 struct UnicodeExpectedResult
1307 CRYPT_DATA_BLOB encoded;
1310 static BYTE oneNumeric[] = { 0x12, 0x01, 0x31 };
1311 static BYTE onePrintable[] = { 0x13, 0x01, 0x31 };
1312 static BYTE oneTeletex[] = { 0x14, 0x01, 0x31 };
1313 static BYTE oneVideotex[] = { 0x15, 0x01, 0x31 };
1314 static BYTE oneIA5[] = { 0x16, 0x01, 0x31 };
1315 static BYTE oneGraphic[] = { 0x19, 0x01, 0x31 };
1316 static BYTE oneVisible[] = { 0x1a, 0x01, 0x31 };
1317 static BYTE oneUniversal[] = { 0x1c, 0x04, 0x00, 0x00, 0x00, 0x31 };
1318 static BYTE oneGeneral[] = { 0x1b, 0x01, 0x31 };
1319 static BYTE oneBMP[] = { 0x1e, 0x02, 0x00, 0x31 };
1320 static BYTE oneUTF8[] = { 0x0c, 0x01, 0x31 };
1321 static BYTE nihongoT61[] = { 0x14,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,
1323 static BYTE nihongoGeneral[] = { 0x1b,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
1325 static BYTE nihongoBMP[] = { 0x1e,0x12,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,
1326 0x00,0x3a,0x00,0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b };
1327 static BYTE nihongoUTF8[] = { 0x0c,0x0d,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
1328 0xe2,0x89,0xaf,0xe5,0x9d,0x9b };
1330 static struct UnicodeExpectedResult unicodeResults[] = {
1331 { CERT_RDN_NUMERIC_STRING, oneW, { sizeof(oneNumeric), oneNumeric } },
1332 { CERT_RDN_PRINTABLE_STRING, oneW, { sizeof(onePrintable), onePrintable } },
1333 { CERT_RDN_TELETEX_STRING, oneW, { sizeof(oneTeletex), oneTeletex } },
1334 { CERT_RDN_VIDEOTEX_STRING, oneW, { sizeof(oneVideotex), oneVideotex } },
1335 { CERT_RDN_IA5_STRING, oneW, { sizeof(oneIA5), oneIA5 } },
1336 { CERT_RDN_GRAPHIC_STRING, oneW, { sizeof(oneGraphic), oneGraphic } },
1337 { CERT_RDN_VISIBLE_STRING, oneW, { sizeof(oneVisible), oneVisible } },
1338 { CERT_RDN_UNIVERSAL_STRING, oneW, { sizeof(oneUniversal), oneUniversal } },
1339 { CERT_RDN_GENERAL_STRING, oneW, { sizeof(oneGeneral), oneGeneral } },
1340 { CERT_RDN_BMP_STRING, oneW, { sizeof(oneBMP), oneBMP } },
1341 { CERT_RDN_UTF8_STRING, oneW, { sizeof(oneUTF8), oneUTF8 } },
1342 { CERT_RDN_BMP_STRING, nihongoURL, { sizeof(nihongoBMP), nihongoBMP } },
1343 { CERT_RDN_UTF8_STRING, nihongoURL, { sizeof(nihongoUTF8), nihongoUTF8 } },
1346 static struct UnicodeExpectedResult unicodeWeirdness[] = {
1347 { CERT_RDN_TELETEX_STRING, nihongoURL, { sizeof(nihongoT61), nihongoT61 } },
1348 { CERT_RDN_GENERAL_STRING, nihongoURL, { sizeof(nihongoGeneral), nihongoGeneral } },
1351 static void test_encodeUnicodeNameValue(DWORD dwEncoding)
1356 CERT_NAME_VALUE value;
1358 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, NULL,
1359 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1360 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1361 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1362 /* Have to have a string of some sort */
1363 value.dwValueType = 0; /* aka CERT_RDN_ANY_TYPE */
1364 value.Value.pbData = NULL;
1365 value.Value.cbData = 0;
1366 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1367 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1368 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1369 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1370 value.dwValueType = CERT_RDN_ENCODED_BLOB;
1371 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1372 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1373 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1374 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1375 value.dwValueType = CERT_RDN_ANY_TYPE;
1376 value.Value.pbData = (LPBYTE)oneW;
1377 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1378 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1379 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1380 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1381 value.Value.cbData = sizeof(oneW);
1382 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1383 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1384 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1385 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1386 /* An encoded string with specified length isn't good enough either */
1387 value.dwValueType = CERT_RDN_ENCODED_BLOB;
1388 value.Value.pbData = oneUniversal;
1389 value.Value.cbData = sizeof(oneUniversal);
1390 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1391 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1392 ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1393 "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1394 /* More failure checking */
1395 value.Value.cbData = 0;
1396 for (i = 0; i < sizeof(unicodeErrors) / sizeof(unicodeErrors[0]); i++)
1398 value.Value.pbData = (LPBYTE)unicodeErrors[i].str;
1399 value.dwValueType = unicodeErrors[i].valueType;
1400 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1401 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1402 ok(!ret && GetLastError() == unicodeErrors[i].error,
1403 "Value type %ld: expected %08lx, got %08lx\n", value.dwValueType,
1404 unicodeErrors[i].error, GetLastError());
1405 ok(size == unicodeErrors[i].errorIndex,
1406 "Expected error index %ld, got %ld\n", unicodeErrors[i].errorIndex,
1409 /* cbData can be zero if the string is NULL-terminated */
1410 value.Value.cbData = 0;
1411 for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++)
1413 value.Value.pbData = (LPBYTE)unicodeResults[i].str;
1414 value.dwValueType = unicodeResults[i].valueType;
1415 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1416 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1417 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1420 ok(size == unicodeResults[i].encoded.cbData,
1421 "Value type %ld: expected size %ld, got %ld\n",
1422 value.dwValueType, unicodeResults[i].encoded.cbData, size);
1423 ok(!memcmp(unicodeResults[i].encoded.pbData, buf, size),
1424 "Value type %ld: unexpected value\n", value.dwValueType);
1428 /* These "encode," but they do so by truncating each unicode character
1429 * rather than properly encoding it. Kept separate from the proper results,
1430 * because the encoded forms won't decode to their original strings.
1432 for (i = 0; i < sizeof(unicodeWeirdness) / sizeof(unicodeWeirdness[0]); i++)
1434 value.Value.pbData = (LPBYTE)unicodeWeirdness[i].str;
1435 value.dwValueType = unicodeWeirdness[i].valueType;
1436 ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1437 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1438 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1441 ok(size == unicodeWeirdness[i].encoded.cbData,
1442 "Value type %ld: expected size %ld, got %ld\n",
1443 value.dwValueType, unicodeWeirdness[i].encoded.cbData, size);
1444 ok(!memcmp(unicodeWeirdness[i].encoded.pbData, buf, size),
1445 "Value type %ld: unexpected value\n", value.dwValueType);
1451 static void test_decodeUnicodeNameValue(DWORD dwEncoding)
1455 for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++)
1461 ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE,
1462 unicodeResults[i].encoded.pbData, unicodeResults[i].encoded.cbData,
1463 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1464 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1467 PCERT_NAME_VALUE value = (PCERT_NAME_VALUE)buf;
1469 ok(value->dwValueType == unicodeResults[i].valueType,
1470 "Expected value type %ld, got %ld\n", unicodeResults[i].valueType,
1471 value->dwValueType);
1472 ok(!lstrcmpW((LPWSTR)value->Value.pbData, unicodeResults[i].str),
1473 "Unexpected decoded value for index %ld (value type %ld)\n", i,
1474 unicodeResults[i].valueType);
1480 struct encodedOctets
1483 const BYTE *encoded;
1486 static const unsigned char bin46[] = { 'h','i',0 };
1487 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1488 static const unsigned char bin48[] = {
1489 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1490 static const unsigned char bin49[] = {
1491 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1492 static const unsigned char bin50[] = { 0 };
1493 static const unsigned char bin51[] = { 0x04,0x00,0 };
1495 static const struct encodedOctets octets[] = {
1501 static void test_encodeOctets(DWORD dwEncoding)
1503 CRYPT_DATA_BLOB blob;
1506 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1512 blob.cbData = strlen((const char*)octets[i].val);
1513 blob.pbData = (BYTE*)octets[i].val;
1514 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1515 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1516 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1520 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1521 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1522 buf[1], octets[i].encoded[1]);
1523 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1524 octets[i].encoded[1] + 1), "Got unexpected value\n");
1530 static void test_decodeOctets(DWORD dwEncoding)
1534 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1540 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1541 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1542 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1543 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1544 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1545 "Expected size >= %d, got %ld\n",
1546 (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1547 ok(buf != NULL, "Expected allocated buffer\n");
1550 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1553 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1554 "Unexpected value\n");
1560 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1565 const BYTE *encoded;
1567 const BYTE *decoded;
1570 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1571 static const unsigned char bin53[] = { 0xff,0xff };
1572 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1573 static const unsigned char bin55[] = { 0xff,0xfe };
1574 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1575 static const unsigned char bin57[] = { 0xfe };
1576 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1578 static const struct encodedBits bits[] = {
1579 /* normal test cases */
1580 { 0, bin52, 2, bin53 },
1581 { 1, bin54, 2, bin55 },
1582 /* strange test case, showing cUnusedBits >= 8 is allowed */
1583 { 9, bin56, 1, bin57 },
1584 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1585 { 17, bin58, 0, NULL },
1588 static void test_encodeBits(DWORD dwEncoding)
1592 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1594 CRYPT_BIT_BLOB blob;
1599 blob.cbData = sizeof(bytesToEncode);
1600 blob.pbData = (BYTE *)bytesToEncode;
1601 blob.cUnusedBits = bits[i].cUnusedBits;
1602 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1603 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1604 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1607 ok(bufSize == bits[i].encoded[1] + 2,
1608 "Got unexpected size %ld, expected %d\n", bufSize,
1609 bits[i].encoded[1] + 2);
1610 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1611 "Unexpected value\n");
1617 static void test_decodeBits(DWORD dwEncoding)
1619 static const BYTE ber[] = "\x03\x02\x01\xff";
1620 static const BYTE berDecoded = 0xfe;
1627 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1629 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1630 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1632 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1635 CRYPT_BIT_BLOB *blob;
1637 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1638 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1639 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1640 blob = (CRYPT_BIT_BLOB *)buf;
1641 ok(blob->cbData == bits[i].cbDecoded,
1642 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1644 if (blob->cbData && bits[i].cbDecoded)
1645 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1646 "Unexpected value\n");
1650 /* special case: check that something that's valid in BER but not in DER
1651 * decodes successfully
1653 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1654 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1655 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1658 CRYPT_BIT_BLOB *blob;
1660 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1661 "Got unexpected size %ld\n", bufSize);
1662 blob = (CRYPT_BIT_BLOB *)buf;
1663 ok(blob->cbData == sizeof(berDecoded),
1664 "Got unexpected length %ld\n", blob->cbData);
1666 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1673 CERT_BASIC_CONSTRAINTS2_INFO info;
1674 const BYTE *encoded;
1677 static const unsigned char bin59[] = { 0x30,0x00 };
1678 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1679 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1680 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1681 static const struct Constraints2 constraints2[] = {
1682 /* empty constraints */
1683 { { FALSE, FALSE, 0}, bin59 },
1685 { { TRUE, FALSE, 0}, bin60 },
1686 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1687 * but that's not the case
1689 { { FALSE, TRUE, 0}, bin61 },
1690 /* can be a CA and has path length constraints set */
1691 { { TRUE, TRUE, 1}, bin62 },
1694 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1695 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1696 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1697 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1698 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1699 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1700 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1701 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1702 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1703 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1705 static void test_encodeBasicConstraints(DWORD dwEncoding)
1707 DWORD i, bufSize = 0;
1708 CERT_BASIC_CONSTRAINTS_INFO info;
1709 CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1710 (LPBYTE)encodedDomainName };
1714 /* First test with the simpler info2 */
1715 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1717 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1718 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1720 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1723 ok(bufSize == constraints2[i].encoded[1] + 2,
1724 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1726 ok(!memcmp(buf, constraints2[i].encoded,
1727 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1731 /* Now test with more complex basic constraints */
1732 info.SubjectType.cbData = 0;
1733 info.fPathLenConstraint = FALSE;
1734 info.cSubtreesConstraint = 0;
1735 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1736 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1737 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1740 ok(bufSize == sizeof(emptyConstraint), "Wrong size %ld\n", bufSize);
1741 ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1742 "Unexpected value\n");
1745 /* None of the certs I examined had any subtree constraint, but I test one
1746 * anyway just in case.
1748 info.cSubtreesConstraint = 1;
1749 info.rgSubtreesConstraint = &nameBlob;
1750 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1751 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1752 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1755 ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %ld\n", bufSize);
1756 ok(!memcmp(buf, constraintWithDomainName,
1757 sizeof(constraintWithDomainName)), "Unexpected value\n");
1760 /* FIXME: test encoding with subject type. */
1763 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1764 static const unsigned char encodedCommonName[] = {
1765 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
1767 static void test_decodeBasicConstraints(DWORD dwEncoding)
1769 static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1771 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1777 /* First test with simpler info2 */
1778 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1780 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1781 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1782 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1783 ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1787 CERT_BASIC_CONSTRAINTS2_INFO *info =
1788 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1790 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1791 "Unexpected value for item %ld\n", i);
1795 /* Check with the order of encoded elements inverted */
1797 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1798 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1800 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1801 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1802 ok(!buf, "Expected buf to be set to NULL\n");
1803 /* Check with a non-DER bool */
1804 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1805 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1806 (BYTE *)&buf, &bufSize);
1807 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1810 CERT_BASIC_CONSTRAINTS2_INFO *info =
1811 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1813 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1816 /* Check with a non-basic constraints value */
1817 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1818 (LPBYTE)encodedCommonName, encodedCommonName[1] + 2,
1819 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1820 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1821 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1822 /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
1823 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1824 emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
1825 (BYTE *)&buf, &bufSize);
1826 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1829 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1831 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1832 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1833 ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
1836 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1837 constraintWithDomainName, sizeof(constraintWithDomainName),
1838 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1839 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1842 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1844 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1845 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1846 ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
1847 if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
1849 ok(info->rgSubtreesConstraint[0].cbData ==
1850 sizeof(encodedDomainName), "Wrong size %ld\n",
1851 info->rgSubtreesConstraint[0].cbData);
1852 ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
1853 sizeof(encodedDomainName)), "Unexpected value\n");
1859 /* These are terrible public keys of course, I'm just testing encoding */
1860 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1861 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1862 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1863 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1864 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1865 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1866 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1867 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1869 struct EncodedRSAPubKey
1871 const BYTE *modulus;
1873 const BYTE *encoded;
1874 size_t decodedModulusLen;
1877 struct EncodedRSAPubKey rsaPubKeys[] = {
1878 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1879 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1880 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1881 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1884 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1886 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1887 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1888 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1891 DWORD bufSize = 0, i;
1893 /* Try with a bogus blob type */
1895 hdr->bVersion = CUR_BLOB_VERSION;
1897 hdr->aiKeyAlg = CALG_RSA_KEYX;
1898 rsaPubKey->magic = 0x31415352;
1899 rsaPubKey->bitlen = sizeof(modulus1) * 8;
1900 rsaPubKey->pubexp = 65537;
1901 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1904 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1905 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1907 ok(!ret && GetLastError() == E_INVALIDARG,
1908 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1909 /* Now with a bogus reserved field */
1910 hdr->bType = PUBLICKEYBLOB;
1912 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1913 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1917 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1918 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1919 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1922 /* Now with a bogus blob version */
1925 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1926 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1930 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1931 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1932 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1935 /* And with a bogus alg ID */
1936 hdr->bVersion = CUR_BLOB_VERSION;
1937 hdr->aiKeyAlg = CALG_DES;
1938 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1939 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1943 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1944 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1945 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1948 /* Check a couple of RSA-related OIDs */
1949 hdr->aiKeyAlg = CALG_RSA_KEYX;
1950 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1951 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1952 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1953 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1954 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1955 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1956 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1957 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1958 /* Finally, all valid */
1959 hdr->aiKeyAlg = CALG_RSA_KEYX;
1960 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1962 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1963 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1964 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1965 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1966 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1969 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1970 "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1972 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1973 "Unexpected value\n");
1979 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1986 /* Try with a bad length */
1987 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1988 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1989 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1990 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1991 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1992 /* Try with a couple of RSA-related OIDs */
1993 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1994 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1995 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1996 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1997 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1998 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1999 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2000 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2001 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2002 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2003 /* Now try success cases */
2004 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2007 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2008 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
2009 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2010 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2013 BLOBHEADER *hdr = (BLOBHEADER *)buf;
2014 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
2016 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
2017 rsaPubKeys[i].decodedModulusLen,
2018 "Wrong size %ld\n", bufSize);
2019 ok(hdr->bType == PUBLICKEYBLOB,
2020 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
2022 ok(hdr->bVersion == CUR_BLOB_VERSION,
2023 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
2024 CUR_BLOB_VERSION, hdr->bVersion);
2025 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
2027 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
2028 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
2029 ok(rsaPubKey->magic == 0x31415352,
2030 "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
2031 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
2032 "Wrong bit len %ld\n", rsaPubKey->bitlen);
2033 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
2035 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2036 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
2037 "Unexpected modulus\n");
2043 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
2044 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
2045 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2047 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
2048 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
2049 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
2050 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2052 static void test_encodeSequenceOfAny(DWORD dwEncoding)
2054 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
2055 CRYPT_SEQUENCE_OF_ANY seq;
2061 /* Encode a homogenous sequence */
2062 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
2064 blobs[i].cbData = ints[i].encoded[1] + 2;
2065 blobs[i].pbData = (BYTE *)ints[i].encoded;
2067 seq.cValue = sizeof(ints) / sizeof(ints[0]);
2068 seq.rgValue = blobs;
2070 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2071 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2072 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2075 ok(bufSize == sizeof(intSequence), "Wrong size %ld\n", bufSize);
2076 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
2079 /* Change the type of the first element in the sequence, and give it
2082 blobs[0].cbData = times[0].encodedTime[1] + 2;
2083 blobs[0].pbData = (BYTE *)times[0].encodedTime;
2084 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2085 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2086 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2089 ok(bufSize == sizeof(mixedSequence), "Wrong size %ld\n", bufSize);
2090 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
2091 "Unexpected value\n");
2096 static void test_decodeSequenceOfAny(DWORD dwEncoding)
2102 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
2103 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2104 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2107 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2110 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2111 "Wrong elements %ld\n", seq->cValue);
2112 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
2114 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
2115 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
2116 seq->rgValue[i].cbData);
2117 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
2118 ints[i].encoded[1] + 2), "Unexpected value\n");
2122 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
2123 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2125 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2128 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2130 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2131 "Wrong elements %ld\n", seq->cValue);
2132 /* Just check the first element since it's all that changed */
2133 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
2134 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
2135 seq->rgValue[0].cbData);
2136 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
2137 times[0].encodedTime[1] + 2), "Unexpected value\n");
2142 struct encodedExtensions
2144 CERT_EXTENSIONS exts;
2145 const BYTE *encoded;
2148 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2149 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2151 static CERT_EXTENSION criticalExt =
2152 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
2153 static CERT_EXTENSION nonCriticalExt =
2154 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
2156 static const BYTE ext0[] = { 0x30,0x00 };
2157 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
2158 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2159 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
2160 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2162 static const struct encodedExtensions exts[] = {
2163 { { 0, NULL }, ext0 },
2164 { { 1, &criticalExt }, ext1 },
2165 { { 1, &nonCriticalExt }, ext2 },
2168 static void test_encodeExtensions(DWORD dwEncoding)
2172 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2178 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
2179 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2180 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2183 ok(bufSize == exts[i].encoded[1] + 2,
2184 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
2185 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
2186 "Unexpected value\n");
2192 static void test_decodeExtensions(DWORD dwEncoding)
2196 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2202 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
2203 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2204 NULL, (BYTE *)&buf, &bufSize);
2205 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2208 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
2211 ok(ext->cExtension == exts[i].exts.cExtension,
2212 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
2214 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
2216 ok(!strcmp(ext->rgExtension[j].pszObjId,
2217 exts[i].exts.rgExtension[j].pszObjId),
2218 "Expected OID %s, got %s\n",
2219 exts[i].exts.rgExtension[j].pszObjId,
2220 ext->rgExtension[j].pszObjId);
2221 ok(!memcmp(ext->rgExtension[j].Value.pbData,
2222 exts[i].exts.rgExtension[j].Value.pbData,
2223 exts[i].exts.rgExtension[j].Value.cbData),
2224 "Unexpected value\n");
2231 /* MS encodes public key info with a NULL if the algorithm identifier's
2232 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
2233 * it encodes them by omitting the algorithm parameters. This latter approach
2234 * seems more correct, so accept either form.
2236 struct encodedPublicKey
2238 CERT_PUBLIC_KEY_INFO info;
2239 const BYTE *encoded;
2240 const BYTE *encodedNoNull;
2241 CERT_PUBLIC_KEY_INFO decoded;
2244 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2246 static const BYTE params[] = { 0x02, 0x01, 0x01 };
2248 static const unsigned char bin64[] = {
2249 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
2250 static const unsigned char bin65[] = {
2251 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
2252 static const unsigned char bin66[] = {
2253 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
2254 static const unsigned char bin67[] = {
2255 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
2256 static const unsigned char bin68[] = {
2257 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
2258 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2259 static const unsigned char bin69[] = {
2260 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
2261 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2262 static const unsigned char bin70[] = {
2263 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2264 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2266 static const unsigned char bin71[] = {
2267 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2268 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2270 static unsigned char bin72[] = { 0x05,0x00};
2272 static const struct encodedPublicKey pubKeys[] = {
2273 /* with a bogus OID */
2274 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
2276 { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
2277 /* some normal keys */
2278 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
2280 { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
2281 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2283 { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2284 /* with add'l parameters--note they must be DER-encoded */
2285 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2286 (BYTE *)aKey, 0 } },
2288 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2289 (BYTE *)aKey, 0 } } },
2292 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2296 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2302 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2303 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2305 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2308 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2309 bufSize == pubKeys[i].encodedNoNull[1] + 2,
2310 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2311 pubKeys[i].encodedNoNull[1] + 2, bufSize);
2312 if (bufSize == pubKeys[i].encoded[1] + 2)
2313 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2314 "Unexpected value\n");
2315 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2316 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2317 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2323 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2324 const CERT_PUBLIC_KEY_INFO *got)
2326 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2327 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2328 got->Algorithm.pszObjId);
2329 ok(expected->Algorithm.Parameters.cbData ==
2330 got->Algorithm.Parameters.cbData,
2331 "Expected parameters of %ld bytes, got %ld\n",
2332 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2333 if (expected->Algorithm.Parameters.cbData)
2334 ok(!memcmp(expected->Algorithm.Parameters.pbData,
2335 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2336 "Unexpected algorithm parameters\n");
2337 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2338 "Expected public key of %ld bytes, got %ld\n",
2339 expected->PublicKey.cbData, got->PublicKey.cbData);
2340 if (expected->PublicKey.cbData)
2341 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2342 got->PublicKey.cbData), "Unexpected public key value\n");
2345 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2347 static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2348 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2349 0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2350 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2356 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2358 /* The NULL form decodes to the decoded member */
2359 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2360 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2361 NULL, (BYTE *)&buf, &bufSize);
2362 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2365 comparePublicKeyInfo(&pubKeys[i].decoded,
2366 (CERT_PUBLIC_KEY_INFO *)buf);
2369 /* The non-NULL form decodes to the original */
2370 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2371 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2372 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2373 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2376 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2380 /* Test with bogus (not valid DER) parameters */
2381 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2382 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2383 NULL, (BYTE *)&buf, &bufSize);
2384 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2385 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2388 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2389 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2390 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2391 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2392 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2393 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2394 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2395 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2396 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2397 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2398 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2399 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2400 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2401 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2402 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2403 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2404 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2405 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2406 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2407 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2408 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2409 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2410 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2411 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2412 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2413 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2414 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2415 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2416 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2417 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2418 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2419 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2420 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2421 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2422 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2423 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2424 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2425 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2426 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2428 static const BYTE serialNum[] = { 0x01 };
2430 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2435 CERT_INFO info = { 0 };
2437 /* Test with NULL pvStructInfo */
2438 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2439 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2440 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2441 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2442 /* Test with a V1 cert */
2443 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2444 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2445 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2448 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2449 v1Cert[1] + 2, size);
2450 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2454 info.dwVersion = CERT_V2;
2455 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2456 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2457 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2460 ok(size == sizeof(v2Cert), "Wrong size %ld\n", size);
2461 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2465 info.dwVersion = CERT_V3;
2466 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2467 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2468 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2471 ok(size == sizeof(v3Cert), "Wrong size %ld\n", size);
2472 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2475 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2476 * API doesn't prevent it)
2478 info.dwVersion = CERT_V1;
2479 info.cExtension = 1;
2480 info.rgExtension = &criticalExt;
2481 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2482 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2483 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2486 ok(size == sizeof(v1CertWithConstraints), "Wrong size %ld\n", size);
2487 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2490 /* test v1 cert with a serial number */
2491 info.SerialNumber.cbData = sizeof(serialNum);
2492 info.SerialNumber.pbData = (BYTE *)serialNum;
2493 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2494 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2497 ok(size == sizeof(v1CertWithSerial), "Wrong size %ld\n", size);
2498 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2501 /* Test v1 cert with an issuer name, a subject name, and a serial number */
2502 info.Issuer.cbData = sizeof(encodedCommonName);
2503 info.Issuer.pbData = (BYTE *)encodedCommonName;
2504 info.Subject.cbData = sizeof(encodedCommonName);
2505 info.Subject.pbData = (BYTE *)encodedCommonName;
2506 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2507 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2510 ok(size == sizeof(bigCert), "Wrong size %ld\n", size);
2511 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2514 /* for now, I let more interesting tests be done for each subcomponent,
2515 * rather than retesting them all here.
2519 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2521 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2522 v1CertWithConstraints, v1CertWithSerial };
2527 /* Test with NULL pbEncoded */
2528 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2529 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2530 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2531 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2532 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2533 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2534 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2535 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2536 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2537 * minimum a cert must have a non-zero serial number, an issuer, and a
2540 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2542 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2543 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2544 (BYTE *)&buf, &size);
2545 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2546 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2548 /* Now check with serial number, subject and issuer specified */
2549 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2550 sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2551 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2554 CERT_INFO *info = (CERT_INFO *)buf;
2556 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2557 ok(info->SerialNumber.cbData == 1,
2558 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2559 ok(*info->SerialNumber.pbData == *serialNum,
2560 "Expected serial number %d, got %d\n", *serialNum,
2561 *info->SerialNumber.pbData);
2562 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2563 "Wrong size %ld\n", info->Issuer.cbData);
2564 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2565 "Unexpected issuer\n");
2566 ok(info->Subject.cbData == sizeof(encodedCommonName),
2567 "Wrong size %ld\n", info->Subject.cbData);
2568 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2569 info->Subject.cbData), "Unexpected subject\n");
2574 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2577 static const BYTE signedBigCert[] = {
2578 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2579 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2580 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2581 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2582 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2583 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2584 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2585 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2586 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2587 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2588 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2589 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2591 static void test_encodeCert(DWORD dwEncoding)
2593 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
2594 * also that bigCert is a NULL-terminated string, so don't count its
2595 * last byte (otherwise the signed cert won't decode.)
2597 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2598 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2603 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2604 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2605 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2608 ok(bufSize == sizeof(signedBigCert), "Wrong size %ld\n", bufSize);
2609 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2614 static void test_decodeCert(DWORD dwEncoding)
2620 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2621 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2622 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2625 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2627 ok(info->ToBeSigned.cbData == sizeof(bigCert),
2628 "Wrong cert size %ld\n", info->ToBeSigned.cbData);
2629 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2630 "Unexpected cert\n");
2631 ok(info->Signature.cbData == sizeof(hash),
2632 "Wrong signature size %ld\n", info->Signature.cbData);
2633 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2634 "Unexpected signature\n");
2637 /* A signed cert decodes as a CERT_INFO too */
2638 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, signedBigCert,
2639 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2640 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2643 CERT_INFO *info = (CERT_INFO *)buf;
2645 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2646 ok(info->SerialNumber.cbData == 1,
2647 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2648 ok(*info->SerialNumber.pbData == *serialNum,
2649 "Expected serial number %d, got %d\n", *serialNum,
2650 *info->SerialNumber.pbData);
2651 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2652 "Wrong size %ld\n", info->Issuer.cbData);
2653 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2654 "Unexpected issuer\n");
2655 ok(info->Subject.cbData == sizeof(encodedCommonName),
2656 "Wrong size %ld\n", info->Subject.cbData);
2657 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2658 info->Subject.cbData), "Unexpected subject\n");
2663 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2664 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2665 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2666 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2667 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2669 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2670 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2671 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2672 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2673 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2674 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2675 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2676 0x2e, 0x6f, 0x72, 0x67 };
2677 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2678 CRL_REASON_AFFILIATION_CHANGED;
2680 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2682 CRL_DIST_POINTS_INFO info = { 0 };
2683 CRL_DIST_POINT point = { { 0 } };
2684 CERT_ALT_NAME_ENTRY entry = { 0 };
2689 /* Test with an empty info */
2690 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2691 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2692 ok(!ret && GetLastError() == E_INVALIDARG,
2693 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2694 /* Test with one empty dist point */
2695 info.cDistPoint = 1;
2696 info.rgDistPoint = &point;
2697 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2698 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2701 ok(size == sizeof(emptyDistPoint), "Wrong size %ld\n", size);
2702 ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2705 /* A dist point with an invalid name */
2706 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2707 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2708 U(entry).pwszURL = (LPWSTR)nihongoURL;
2709 U(point.DistPointName).FullName.cAltEntry = 1;
2710 U(point.DistPointName).FullName.rgAltEntry = &entry;
2711 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2712 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2713 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2714 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2715 /* The first invalid character is at index 7 */
2716 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2717 "Expected invalid char at index 7, got %ld\n",
2718 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2719 /* A dist point with (just) a valid name */
2720 U(entry).pwszURL = (LPWSTR)url;
2721 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2722 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2725 ok(size == sizeof(distPointWithUrl), "Wrong size %ld\n", size);
2726 ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2729 /* A dist point with (just) reason flags */
2730 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2731 point.ReasonFlags.cbData = sizeof(crlReason);
2732 point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2733 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2734 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2737 ok(size == sizeof(distPointWithReason), "Wrong size %ld\n", size);
2738 ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2741 /* A dist point with just an issuer */
2742 point.ReasonFlags.cbData = 0;
2743 point.CRLIssuer.cAltEntry = 1;
2744 point.CRLIssuer.rgAltEntry = &entry;
2745 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2746 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2749 ok(size == sizeof(distPointWithIssuer), "Wrong size %ld\n", size);
2750 ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2753 /* A dist point with both a name and an issuer */
2754 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2755 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2756 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2759 ok(size == sizeof(distPointWithUrlAndIssuer),
2760 "Wrong size %ld\n", size);
2761 ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2766 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2771 PCRL_DIST_POINTS_INFO info;
2772 PCRL_DIST_POINT point;
2773 PCERT_ALT_NAME_ENTRY entry;
2775 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2776 emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2777 (BYTE *)&buf, &size);
2780 info = (PCRL_DIST_POINTS_INFO)buf;
2781 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2782 "Wrong size %ld\n", size);
2783 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2785 point = info->rgDistPoint;
2786 ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2787 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2788 point->DistPointName.dwDistPointNameChoice);
2789 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2790 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2793 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2794 distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2795 (BYTE *)&buf, &size);
2798 info = (PCRL_DIST_POINTS_INFO)buf;
2799 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2800 "Wrong size %ld\n", size);
2801 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2803 point = info->rgDistPoint;
2804 ok(point->DistPointName.dwDistPointNameChoice ==
2805 CRL_DIST_POINT_FULL_NAME,
2806 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2807 point->DistPointName.dwDistPointNameChoice);
2808 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2809 "Expected 1 name entry, got %ld\n",
2810 U(point->DistPointName).FullName.cAltEntry);
2811 entry = U(point->DistPointName).FullName.rgAltEntry;
2812 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2813 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2814 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2815 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2816 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2819 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2820 distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2821 NULL, (BYTE *)&buf, &size);
2824 info = (PCRL_DIST_POINTS_INFO)buf;
2825 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2826 "Wrong size %ld\n", size);
2827 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2829 point = info->rgDistPoint;
2830 ok(point->DistPointName.dwDistPointNameChoice ==
2831 CRL_DIST_POINT_NO_NAME,
2832 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2833 point->DistPointName.dwDistPointNameChoice);
2834 ok(point->ReasonFlags.cbData == sizeof(crlReason),
2835 "Expected reason length\n");
2836 ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2837 "Unexpected reason\n");
2838 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2841 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2842 distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2843 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2846 info = (PCRL_DIST_POINTS_INFO)buf;
2847 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2848 "Wrong size %ld\n", size);
2849 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2851 point = info->rgDistPoint;
2852 ok(point->DistPointName.dwDistPointNameChoice ==
2853 CRL_DIST_POINT_FULL_NAME,
2854 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2855 point->DistPointName.dwDistPointNameChoice);
2856 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2857 "Expected 1 name entry, got %ld\n",
2858 U(point->DistPointName).FullName.cAltEntry);
2859 entry = U(point->DistPointName).FullName.rgAltEntry;
2860 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2861 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2862 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2863 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2864 ok(point->CRLIssuer.cAltEntry == 1,
2865 "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2866 entry = point->CRLIssuer.rgAltEntry;
2867 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2868 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2869 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2874 static const BYTE badFlagsIDP[] = { 0x30,0x06,0x81,0x01,0xff,0x82,0x01,0xff };
2875 static const BYTE emptyNameIDP[] = { 0x30,0x04,0xa0,0x02,0xa0,0x00 };
2876 static const BYTE urlIDP[] = { 0x30,0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,
2877 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,
2880 static void test_encodeCRLIssuingDistPoint(DWORD dwEncoding)
2885 CRL_ISSUING_DIST_POINT point = { { 0 } };
2886 CERT_ALT_NAME_ENTRY entry;
2888 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, NULL,
2889 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2890 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2891 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2892 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2893 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2894 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2897 ok(size == sizeof(emptySequence), "Unexpected size %ld\n", size);
2898 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
2901 /* nonsensical flags */
2902 point.fOnlyContainsUserCerts = TRUE;
2903 point.fOnlyContainsCACerts = TRUE;
2904 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2905 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2906 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2909 ok(size == sizeof(badFlagsIDP), "Unexpected size %ld\n", size);
2910 ok(!memcmp(buf, badFlagsIDP, size), "Unexpected value\n");
2913 /* unimplemented name type */
2914 point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
2915 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_ISSUER_RDN_NAME;
2916 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2917 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2918 ok(!ret && GetLastError() == E_INVALIDARG,
2919 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2921 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2922 U(point.DistPointName).FullName.cAltEntry = 0;
2923 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2924 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2925 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2928 ok(size == sizeof(emptyNameIDP), "Unexpected size %ld\n", size);
2929 ok(!memcmp(buf, emptyNameIDP, size), "Unexpected value\n");
2932 /* name with URL entry */
2933 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2934 U(entry).pwszURL = (LPWSTR)url;
2935 U(point.DistPointName).FullName.cAltEntry = 1;
2936 U(point.DistPointName).FullName.rgAltEntry = &entry;
2937 ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2938 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2939 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2942 ok(size == sizeof(urlIDP), "Unexpected size %ld\n", size);
2943 ok(!memcmp(buf, urlIDP, size), "Unexpected value\n");
2948 static void compareAltNameEntry(const CERT_ALT_NAME_ENTRY *expected,
2949 const CERT_ALT_NAME_ENTRY *got)
2951 ok(expected->dwAltNameChoice == got->dwAltNameChoice,
2952 "Expected name choice %ld, got %ld\n", expected->dwAltNameChoice,
2953 got->dwAltNameChoice);
2954 if (expected->dwAltNameChoice == got->dwAltNameChoice)
2956 switch (got->dwAltNameChoice)
2958 case CERT_ALT_NAME_RFC822_NAME:
2959 case CERT_ALT_NAME_DNS_NAME:
2960 case CERT_ALT_NAME_EDI_PARTY_NAME:
2961 case CERT_ALT_NAME_URL:
2962 case CERT_ALT_NAME_REGISTERED_ID:
2963 ok((!U(*expected).pwszURL && !U(*got).pwszURL) ||
2964 !lstrcmpW(U(*expected).pwszURL, U(*got).pwszURL), "Unexpected name\n");
2966 case CERT_ALT_NAME_X400_ADDRESS:
2967 case CERT_ALT_NAME_DIRECTORY_NAME:
2968 case CERT_ALT_NAME_IP_ADDRESS:
2969 ok(U(*got).IPAddress.cbData == U(*expected).IPAddress.cbData,
2970 "Unexpected IP address length %ld\n", U(*got).IPAddress.cbData);
2971 ok(!memcmp(U(*got).IPAddress.pbData, U(*got).IPAddress.pbData,
2972 U(*got).IPAddress.cbData), "Unexpected value\n");
2978 static void compareAltNameInfo(const CERT_ALT_NAME_INFO *expected,
2979 const CERT_ALT_NAME_INFO *got)
2983 ok(expected->cAltEntry == got->cAltEntry, "Expected %ld entries, got %ld\n",
2984 expected->cAltEntry, got->cAltEntry);
2985 for (i = 0; i < min(expected->cAltEntry, got->cAltEntry); i++)
2986 compareAltNameEntry(&expected->rgAltEntry[i], &got->rgAltEntry[i]);
2989 static void compareDistPointName(const CRL_DIST_POINT_NAME *expected,
2990 const CRL_DIST_POINT_NAME *got)
2992 ok(got->dwDistPointNameChoice == expected->dwDistPointNameChoice,
2993 "Unexpected name choice %ld\n", got->dwDistPointNameChoice);
2994 if (got->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
2995 compareAltNameInfo(&(U(*expected).FullName), &(U(*got).FullName));
2998 static void compareCRLIssuingDistPoints(const CRL_ISSUING_DIST_POINT *expected,
2999 const CRL_ISSUING_DIST_POINT *got)
3001 compareDistPointName(&expected->DistPointName, &got->DistPointName);
3002 ok(got->fOnlyContainsUserCerts == expected->fOnlyContainsUserCerts,
3003 "Unexpected fOnlyContainsUserCerts\n");
3004 ok(got->fOnlyContainsCACerts == expected->fOnlyContainsCACerts,
3005 "Unexpected fOnlyContainsCACerts\n");
3006 ok(got->OnlySomeReasonFlags.cbData == expected->OnlySomeReasonFlags.cbData,
3007 "Unexpected reason flags\n");
3008 ok(got->fIndirectCRL == expected->fIndirectCRL,
3009 "Unexpected fIndirectCRL\n");
3012 static void test_decodeCRLIssuingDistPoint(DWORD dwEncoding)
3017 CRL_ISSUING_DIST_POINT point = { { 0 } };
3019 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3020 emptySequence, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3021 (BYTE *)&buf, &size);
3022 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3025 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3028 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3029 badFlagsIDP, badFlagsIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3030 (BYTE *)&buf, &size);
3031 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3034 point.fOnlyContainsUserCerts = point.fOnlyContainsCACerts = TRUE;
3035 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3038 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3039 emptyNameIDP, emptyNameIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3040 (BYTE *)&buf, &size);
3041 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3044 point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
3045 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
3046 U(point.DistPointName).FullName.cAltEntry = 0;
3047 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3050 ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3051 urlIDP, urlIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3052 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3055 CERT_ALT_NAME_ENTRY entry;
3057 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
3058 U(entry).pwszURL = (LPWSTR)url;
3059 U(point.DistPointName).FullName.cAltEntry = 1;
3060 U(point.DistPointName).FullName.rgAltEntry = &entry;
3061 compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3066 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
3067 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
3069 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
3070 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
3071 0x30, 0x30, 0x30, 0x30, 0x5a };
3072 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
3073 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
3074 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
3075 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
3077 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
3078 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
3079 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
3080 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
3081 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
3082 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
3083 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
3084 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
3085 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
3086 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
3087 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
3088 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
3089 static const BYTE v1CRLWithEntryExt[] = { 0x30,0x5a,0x30,0x02,0x06,0x00,0x30,
3090 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
3091 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
3092 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x2c,0x30,0x2a,0x02,0x01,
3093 0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,
3094 0x30,0x30,0x5a,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,
3095 0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3096 static const BYTE v1CRLWithExt[] = { 0x30,0x5c,0x30,0x02,0x06,0x00,0x30,0x15,
3097 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
3098 0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
3099 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,
3100 0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,
3101 0x30,0x5a,0xa0,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
3102 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3103 static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06,
3104 0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,
3105 0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,
3106 0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,
3107 0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,
3108 0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,
3109 0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3110 static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01,
3111 0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
3112 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,
3113 0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,
3114 0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
3115 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,
3116 0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3118 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
3122 static CHAR oid_issuing_dist_point[] = szOID_ISSUING_DIST_POINT;
3124 CRL_INFO info = { 0 };
3125 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
3128 /* Test with a V1 CRL */
3129 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3130 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3131 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3134 ok(size == sizeof(v1CRL), "Wrong size %ld\n", size);
3135 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
3139 info.dwVersion = CRL_V2;
3140 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3141 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3142 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3145 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
3146 v2CRL[1] + 2, size);
3147 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
3150 /* v1 CRL with a name */
3151 info.dwVersion = CRL_V1;
3152 info.Issuer.cbData = sizeof(encodedCommonName);
3153 info.Issuer.pbData = (BYTE *)encodedCommonName;
3154 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3155 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3156 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3159 ok(size == sizeof(v1CRLWithIssuer), "Wrong size %ld\n", size);
3160 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
3163 /* v1 CRL with a name and a NULL entry pointer */
3165 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3166 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3167 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
3168 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
3169 /* now set an empty entry */
3170 info.rgCRLEntry = &entry;
3171 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3172 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3175 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
3176 "Wrong size %ld\n", size);
3177 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
3178 "Got unexpected value\n");
3181 /* an entry with a serial number */
3182 entry.SerialNumber.cbData = sizeof(serialNum);
3183 entry.SerialNumber.pbData = (BYTE *)serialNum;
3184 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3185 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3188 ok(size == sizeof(v1CRLWithIssuerAndEntry),
3189 "Wrong size %ld\n", size);
3190 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
3191 "Got unexpected value\n");
3194 /* an entry with an extension */
3195 entry.cExtension = 1;
3196 entry.rgExtension = &criticalExt;
3197 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3198 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3199 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3202 ok(size == sizeof(v1CRLWithEntryExt), "Wrong size %ld\n", size);
3203 ok(!memcmp(buf, v1CRLWithEntryExt, size), "Got unexpected value\n");
3206 /* a CRL with an extension */
3207 entry.cExtension = 0;
3208 info.cExtension = 1;
3209 info.rgExtension = &criticalExt;
3210 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3211 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3212 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3215 ok(size == sizeof(v1CRLWithExt), "Wrong size %ld\n", size);
3216 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
3219 /* a v2 CRL with an extension, this time non-critical */
3220 info.dwVersion = CRL_V2;
3221 info.rgExtension = &nonCriticalExt;
3222 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3223 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3224 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3227 ok(size == sizeof(v2CRLWithExt), "Wrong size %ld\n", size);
3228 ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n");
3231 /* a v2 CRL with an issuing dist point extension */
3232 ext.pszObjId = oid_issuing_dist_point;
3233 ext.fCritical = TRUE;
3234 ext.Value.cbData = sizeof(urlIDP);
3235 ext.Value.pbData = (LPBYTE)urlIDP;
3236 entry.rgExtension = &ext;
3237 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3238 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3239 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3242 ok(size == sizeof(v2CRLWithIssuingDistPoint), "Wrong size %ld\n", size);
3243 ok(!memcmp(buf, v2CRLWithIssuingDistPoint, size), "Unexpected value\n");
3248 static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01,
3249 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3250 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06,
3251 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
3252 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56,
3253 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
3254 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65,
3255 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
3256 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
3257 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43,
3258 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30,
3259 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33,
3260 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51,
3261 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99,
3262 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31,
3263 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0,
3264 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30,
3265 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30,
3266 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75,
3267 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33,
3268 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30,
3269 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
3270 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06,
3271 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03,
3272 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88,
3273 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd,
3274 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf,
3275 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46,
3276 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f,
3277 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75,
3278 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f,
3279 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82,
3280 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07,
3281 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c,
3284 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
3286 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
3291 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
3293 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3294 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3295 (BYTE *)&buf, &size);
3296 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
3297 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3299 /* at a minimum, a CRL must contain an issuer: */
3300 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3301 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3302 (BYTE *)&buf, &size);
3303 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3306 CRL_INFO *info = (CRL_INFO *)buf;
3308 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3309 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
3311 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3312 "Wrong issuer size %ld\n", info->Issuer.cbData);
3313 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3314 "Unexpected issuer\n");
3317 /* check decoding with an empty CRL entry */
3318 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3319 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
3320 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3321 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
3322 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3323 /* with a real CRL entry */
3324 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3325 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
3326 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3327 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3330 CRL_INFO *info = (CRL_INFO *)buf;
3333 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3334 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3336 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3337 entry = info->rgCRLEntry;
3338 ok(entry->SerialNumber.cbData == 1,
3339 "Expected serial number size 1, got %ld\n",
3340 entry->SerialNumber.cbData);
3341 ok(*entry->SerialNumber.pbData == *serialNum,
3342 "Expected serial number %d, got %d\n", *serialNum,
3343 *entry->SerialNumber.pbData);
3344 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3345 "Wrong issuer size %ld\n", info->Issuer.cbData);
3346 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3347 "Unexpected issuer\n");
3349 /* a real CRL from verisign that has extensions */
3350 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3351 verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG,
3352 NULL, (BYTE *)&buf, &size);
3353 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3356 CRL_INFO *info = (CRL_INFO *)buf;
3359 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3360 ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %ld\n",
3362 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3363 entry = info->rgCRLEntry;
3364 ok(info->cExtension == 2, "Expected 2 extensions, got %ld\n",
3367 /* and finally, with an extension */
3368 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3369 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3370 NULL, (BYTE *)&buf, &size);
3371 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3374 CRL_INFO *info = (CRL_INFO *)buf;
3377 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3378 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3380 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3381 entry = info->rgCRLEntry;
3382 ok(entry->SerialNumber.cbData == 1,
3383 "Expected serial number size 1, got %ld\n",
3384 entry->SerialNumber.cbData);
3385 ok(*entry->SerialNumber.pbData == *serialNum,
3386 "Expected serial number %d, got %d\n", *serialNum,
3387 *entry->SerialNumber.pbData);
3388 ok(info->Issuer.cbData == sizeof(encodedCommonName),
3389 "Wrong issuer size %ld\n", info->Issuer.cbData);
3390 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3391 "Unexpected issuer\n");
3392 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3395 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3396 v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3397 NULL, (BYTE *)&buf, &size);
3398 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3401 CRL_INFO *info = (CRL_INFO *)buf;
3403 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3407 /* And again, with an issuing dist point */
3408 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3409 v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint),
3410 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3411 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3414 CRL_INFO *info = (CRL_INFO *)buf;
3416 ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3422 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
3423 szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
3424 static const BYTE encodedUsage[] = {
3425 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
3426 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
3427 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
3429 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
3434 CERT_ENHKEY_USAGE usage;
3436 /* Test with empty usage */
3437 usage.cUsageIdentifier = 0;
3438 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3439 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3440 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3443 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
3444 ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
3447 /* Test with a few usages */
3448 usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
3449 usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
3450 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3451 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3452 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3455 ok(size == sizeof(encodedUsage), "Wrong size %ld\n", size);
3456 ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
3461 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
3467 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3468 emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
3469 (BYTE *)&buf, &size);
3470 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3473 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3475 ok(size >= sizeof(CERT_ENHKEY_USAGE),
3476 "Wrong size %ld\n", size);
3477 ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
3478 usage->cUsageIdentifier);
3481 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3482 encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
3483 (BYTE *)&buf, &size);
3484 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3487 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3490 ok(size >= sizeof(CERT_ENHKEY_USAGE),
3491 "Wrong size %ld\n", size);
3492 ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
3493 "Wrong CRL entries count %ld\n", usage->cUsageIdentifier);
3494 for (i = 0; i < usage->cUsageIdentifier; i++)
3495 ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
3496 "Expected OID %s, got %s\n", keyUsages[i],
3497 usage->rgpszUsageIdentifier[i]);
3502 /* Free *pInfo with HeapFree */
3503 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
3510 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
3512 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
3513 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3514 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3515 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
3517 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3518 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3519 ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
3521 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3522 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3523 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3524 0, NULL, NULL, &size);
3525 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3526 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3527 /* Test with no key */
3528 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3529 0, NULL, NULL, &size);
3530 ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
3532 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
3533 ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
3536 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
3537 NULL, 0, NULL, NULL, &size);
3538 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3539 *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
3542 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
3543 X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
3544 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
3548 /* By default (we passed NULL as the OID) the OID is
3551 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
3552 "Expected %s, got %s\n", szOID_RSA_RSA,
3553 (*pInfo)->Algorithm.pszObjId);
3559 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
3560 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
3561 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
3562 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3563 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3564 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3565 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
3566 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
3567 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3568 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3569 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3570 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3571 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
3572 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
3573 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
3574 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
3575 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
3576 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
3577 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
3578 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
3579 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
3580 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
3581 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
3582 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
3583 0x49, 0xe5, 0xf9, 0x65, 0xf3 };
3585 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
3589 PCCERT_CONTEXT context;
3592 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
3593 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
3594 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
3595 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3598 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3599 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3600 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3601 ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3602 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3603 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3604 ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3606 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3607 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3608 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3610 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3611 CryptDestroyKey(key);
3613 /* Test importing a public key from a certificate context */
3614 context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert,
3615 sizeof(expiredCert));
3616 ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
3620 ok(!strcmp(szOID_RSA_RSA,
3621 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId),
3622 "Expected %s, got %s\n", szOID_RSA_RSA,
3623 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
3624 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING,
3625 &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key);
3626 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3627 CryptDestroyKey(key);
3628 CertFreeCertificateContext(context);
3632 static const char cspName[] = "WineCryptTemp";
3634 static void testPortPublicKeyInfo(void)
3638 PCERT_PUBLIC_KEY_INFO info = NULL;
3640 /* Just in case a previous run failed, delete this thing */
3641 CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3642 CRYPT_DELETEKEYSET);
3643 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3646 testExportPublicKey(csp, &info);
3647 testImportPublicKey(csp, info);
3649 HeapFree(GetProcessHeap(), 0, info);
3650 CryptReleaseContext(csp, 0);
3651 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3652 CRYPT_DELETEKEYSET);
3657 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3658 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3661 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3663 test_encodeInt(encodings[i]);
3664 test_decodeInt(encodings[i]);
3665 test_encodeEnumerated(encodings[i]);
3666 test_decodeEnumerated(encodings[i]);
3667 test_encodeFiletime(encodings[i]);
3668 test_decodeFiletime(encodings[i]);
3669 test_encodeName(encodings[i]);
3670 test_decodeName(encodings[i]);
3671 test_encodeNameValue(encodings[i]);
3672 test_decodeNameValue(encodings[i]);
3673 test_encodeUnicodeNameValue(encodings[i]);
3674 test_decodeUnicodeNameValue(encodings[i]);
3675 test_encodeAltName(encodings[i]);
3676 test_decodeAltName(encodings[i]);
3677 test_encodeOctets(encodings[i]);
3678 test_decodeOctets(encodings[i]);
3679 test_encodeBits(encodings[i]);
3680 test_decodeBits(encodings[i]);
3681 test_encodeBasicConstraints(encodings[i]);
3682 test_decodeBasicConstraints(encodings[i]);
3683 test_encodeRsaPublicKey(encodings[i]);
3684 test_decodeRsaPublicKey(encodings[i]);
3685 test_encodeSequenceOfAny(encodings[i]);
3686 test_decodeSequenceOfAny(encodings[i]);
3687 test_encodeExtensions(encodings[i]);
3688 test_decodeExtensions(encodings[i]);
3689 test_encodePublicKeyInfo(encodings[i]);
3690 test_decodePublicKeyInfo(encodings[i]);
3691 test_encodeCertToBeSigned(encodings[i]);
3692 test_decodeCertToBeSigned(encodings[i]);
3693 test_encodeCert(encodings[i]);
3694 test_decodeCert(encodings[i]);
3695 test_encodeCRLDistPoints(encodings[i]);
3696 test_decodeCRLDistPoints(encodings[i]);
3697 test_encodeCRLIssuingDistPoint(encodings[i]);
3698 test_decodeCRLIssuingDistPoint(encodings[i]);
3699 test_encodeCRLToBeSigned(encodings[i]);
3700 test_decodeCRLToBeSigned(encodings[i]);
3701 test_encodeEnhancedKeyUsage(encodings[i]);
3702 test_decodeEnhancedKeyUsage(encodings[i]);
3704 testPortPublicKeyInfo();