2 * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
4 * Copyright 2005 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/test.h"
35 static const BYTE bin1[] = {0x02,0x01,0x01,0};
36 static const BYTE bin2[] = {0x02,0x01,0x7f,0};
37 static const BYTE bin3[] = {0x02,0x02,0x00,0x80,0};
38 static const BYTE bin4[] = {0x02,0x02,0x01,0x00,0};
39 static const BYTE bin5[] = {0x02,0x01,0x80,0};
40 static const BYTE bin6[] = {0x02,0x02,0xff,0x7f,0};
41 static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d,0};
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), "Expected size %d, got %ld\n", sizeof(int),
247 ok(buf != NULL, "Expected allocated buffer\n");
250 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
251 ints[i].val, *(int *)buf);
255 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
257 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
258 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
260 ok(ret && GetLastError() == NOERROR,
261 "Expected success and NOERROR, got %ld\n", GetLastError());
262 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
263 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
264 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
265 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
266 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
267 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
269 ok(buf != NULL, "Expected allocated buffer\n");
272 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
274 ok(blob->cbData == strlen((const char*)bigInts[i].decoded),
275 "Expected len %d, got %ld\n", strlen((const char*)bigInts[i].decoded),
277 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
278 "Unexpected value\n");
282 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
284 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
285 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
287 ok(ret && GetLastError() == NOERROR,
288 "Expected success and NOERROR, got %ld\n", GetLastError());
289 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
290 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
291 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
292 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
293 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
294 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
296 ok(buf != NULL, "Expected allocated buffer\n");
299 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
301 ok(blob->cbData == strlen((const char*)bigUInts[i].val),
302 "Expected len %d, got %ld\n", strlen((const char*)bigUInts[i].val),
304 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
305 "Unexpected value\n");
309 /* Decode the value 1 with long-form length */
310 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
311 sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
312 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
315 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
318 /* Try to decode some bogus large items */
319 /* The buffer size is smaller than the encoded length, so this should fail
320 * with CRYPT_E_ASN1_EOD if it's being decoded.
321 * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
322 * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
323 * So this test unfortunately isn't useful.
324 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
325 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
326 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
327 "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
329 /* This will try to decode the buffer and overflow it, check that it's
332 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
333 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
334 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
335 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
338 static const BYTE bin18[] = {0x0a,0x01,0x01,0};
339 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80,0};
341 /* These are always encoded unsigned, and aren't constrained to be any
344 static const struct encodedInt enums[] = {
349 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
352 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
353 szOID_CRL_REASON_CODE };
355 static void test_encodeEnumerated(DWORD dwEncoding)
359 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
361 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
367 ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
368 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
370 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
374 "Got unexpected type %d for enumerated (expected 0xa)\n",
376 ok(buf[1] == enums[j].encoded[1],
377 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
378 ok(!memcmp(buf + 1, enums[j].encoded + 1,
379 enums[j].encoded[1] + 1),
380 "Encoded value of 0x%08x didn't match expected\n",
388 static void test_decodeEnumerated(DWORD dwEncoding)
392 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
394 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
397 DWORD bufSize = sizeof(int);
400 ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
401 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
402 (BYTE *)&val, &bufSize);
403 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
404 ok(bufSize == sizeof(int),
405 "Got unexpected size %ld for enumerated (expected %d)\n",
406 bufSize, sizeof(int));
407 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
413 struct encodedFiletime
416 const BYTE *encodedTime;
419 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
420 const struct encodedFiletime *time)
427 ret = SystemTimeToFileTime(&time->sysTime, &ft);
428 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
429 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
430 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
431 /* years other than 1950-2050 are not allowed for encodings other than
432 * X509_CHOICE_OF_TIME.
434 if (structType == X509_CHOICE_OF_TIME ||
435 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
437 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
439 ok(buf != NULL, "Expected an allocated buffer\n");
442 ok(buf[0] == time->encodedTime[0],
443 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
445 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
446 time->encodedTime[1], bufSize);
447 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
448 "Got unexpected value for time encoding\n");
453 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
454 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
457 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
458 const struct encodedFiletime *time)
460 FILETIME ft1 = { 0 }, ft2 = { 0 };
461 DWORD size = sizeof(ft2);
464 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
465 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
466 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
467 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
468 /* years other than 1950-2050 are not allowed for encodings other than
469 * X509_CHOICE_OF_TIME.
471 if (structType == X509_CHOICE_OF_TIME ||
472 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
474 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
476 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
477 "Got unexpected value for time decoding\n");
480 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
481 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
484 static const BYTE bin20[] = {
485 0x17,0x0d,'0','5','0','6','0','6','1','6','1','0','0','0','Z',0};
486 static const BYTE bin21[] = {
487 0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z',0};
488 static const BYTE bin22[] = {
489 0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z',0};
491 static const struct encodedFiletime times[] = {
492 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 },
493 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 },
494 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 },
497 static void test_encodeFiletime(DWORD dwEncoding)
501 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
503 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
504 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
505 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
509 static const BYTE bin23[] = {
510 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','0','0','0','Z',0};
511 static const BYTE bin24[] = {
512 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','9','9','9','Z',0};
513 static const BYTE bin25[] = {
514 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','+','0','1','0','0',0};
515 static const BYTE bin26[] = {
516 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','0','0',0};
517 static const BYTE bin27[] = {
518 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','1','5',0};
519 static const BYTE bin28[] = {
520 0x18,0x0a,'2','1','4','5','0','6','0','6','1','6',0};
521 static const BYTE bin29[] = {
522 0x17,0x0a,'4','5','0','6','0','6','1','6','1','0',0};
523 static const BYTE bin30[] = {
524 0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z',0};
525 static const BYTE bin31[] = {
526 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1',0};
527 static const BYTE bin32[] = {
528 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1',0};
529 static const BYTE bin33[] = {
530 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0',0};
531 static const BYTE bin34[] = {
532 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0',0};
533 static const BYTE bin35[] = {
534 0x17,0x08, '4','5','0','6','0','6','1','6',0};
535 static const BYTE bin36[] = {
536 0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z',0};
537 static const BYTE bin37[] = {
538 0x18,0x04, '2','1','4','5',0};
539 static const BYTE bin38[] = {
540 0x18,0x08, '2','1','4','5','0','6','0','6',0};
542 static void test_decodeFiletime(DWORD dwEncoding)
544 static const struct encodedFiletime otherTimes[] = {
545 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin23 },
546 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 },
547 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, bin25 },
548 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, bin26 },
549 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, bin27 },
550 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, bin28 },
551 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin29 },
552 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin30 },
553 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin31 },
554 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin32 },
555 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin33 },
556 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin34 },
558 /* An oddball case that succeeds in Windows, but doesn't seem correct
559 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
561 static const unsigned char *bogusTimes[] = {
562 /* oddly, this succeeds on Windows, with year 2765
563 "\x18" "\x0f" "21r50606161000Z",
571 FILETIME ft1 = { 0 }, ft2 = { 0 };
574 /* Check bogus length with non-NULL buffer */
575 ret = SystemTimeToFileTime(×[0].sysTime, &ft1);
576 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
578 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
579 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
580 ok(!ret && GetLastError() == ERROR_MORE_DATA,
581 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
583 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
585 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
586 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
587 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
589 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
591 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
592 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
593 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
595 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
598 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
599 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
600 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
601 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
611 static const char commonName[] = "Juan Lang";
612 static const char surName[] = "Lang";
613 static const char bogusIA5[] = "\x80";
614 static const char bogusPrintable[] = "~";
615 static const char bogusNumeric[] = "A";
616 static const unsigned char bin39[] = {
617 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
618 static const unsigned char bin40[] = {
619 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x16,0x0a,'J','u','a','n',' ','L','a','n','g',0};
620 static const unsigned char bin41[] = {
621 0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x16,0x05,'L','a','n','g',0};
622 static const unsigned char bin42[] = {
623 0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x00,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
624 static const unsigned char bin43[] = {
625 0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x16,0x02,0x80,0};
626 static const unsigned char bin44[] = {
627 0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x13,0x02,0x7e,0};
628 static const unsigned char bin45[] = {
629 0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x12,0x02,0x41,0};
630 static const struct EncodedName names[] = {
631 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
632 { sizeof(commonName), (BYTE *)commonName } }, bin39 },
633 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
634 { sizeof(commonName), (BYTE *)commonName } }, bin40 },
635 { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
636 { sizeof(surName), (BYTE *)surName } }, bin41 },
637 { { NULL, CERT_RDN_PRINTABLE_STRING,
638 { sizeof(commonName), (BYTE *)commonName } }, bin42 },
639 /* The following test isn't a very good one, because it doesn't encode any
640 * Japanese characters. I'm leaving it out for now.
641 { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
642 { sizeof(commonName), (BYTE *)commonName } },
643 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
645 /* The following tests succeed under Windows, but really should fail,
646 * they contain characters that are illegal for the encoding. I'm
647 * including them to justify my lazy encoding.
649 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
650 { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin43 },
651 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
652 { sizeof(bogusPrintable), (BYTE *)bogusPrintable } }, bin44 },
653 { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
654 { sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, bin45 },
657 static const BYTE emptyName[] = { 0x30, 0 };
658 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
659 static const BYTE twoRDNs[] = {
660 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
661 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
662 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
664 static const BYTE us[] = { 0x55, 0x53 };
665 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
667 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
668 0x6f, 0x6c, 0x69, 0x73 };
669 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
670 0x76, 0x65, 0x72, 0x73 };
671 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
672 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
673 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
675 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
676 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
678 #define _blob_of(arr) { sizeof(arr), (LPBYTE)arr }
679 const CERT_RDN_ATTR rdnAttrs[] = {
680 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
681 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
682 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
683 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
684 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
685 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
686 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
688 const CERT_RDN_ATTR decodedRdnAttrs[] = {
689 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
690 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
691 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
692 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
693 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
694 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
695 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
699 static const BYTE encodedRDNAttrs[] = {
700 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
701 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
702 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
703 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
704 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
705 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
706 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
707 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
708 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
709 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
712 static void test_encodeName(DWORD dwEncoding)
714 CERT_RDN_ATTR attrs[2];
721 /* Test with NULL pvStructInfo */
722 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
723 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
724 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
725 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
726 /* Test with empty CERT_NAME_INFO */
729 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
730 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
731 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
734 ok(!memcmp(buf, emptyName, sizeof(emptyName)),
735 "Got unexpected encoding for empty name\n");
738 /* Test with bogus CERT_RDN */
740 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
741 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
742 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
743 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
744 /* Test with empty CERT_RDN */
746 rdn.rgRDNAttr = NULL;
749 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
750 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
751 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
754 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
755 "Got unexpected encoding for empty RDN array\n");
758 /* Test with bogus attr array */
760 rdn.rgRDNAttr = NULL;
761 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
762 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
763 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
764 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
765 /* oddly, a bogus OID is accepted by Windows XP; not testing.
766 attrs[0].pszObjId = "bogus";
767 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
768 attrs[0].Value.cbData = sizeof(commonName);
769 attrs[0].Value.pbData = (BYTE *)commonName;
771 rdn.rgRDNAttr = attrs;
772 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
773 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
774 ok(!ret, "Expected failure, got success\n");
776 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
777 * the encoded attributes to be swapped.
779 attrs[0].pszObjId = szOID_COMMON_NAME;
780 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
781 attrs[0].Value.cbData = sizeof(commonName);
782 attrs[0].Value.pbData = (BYTE *)commonName;
783 attrs[1].pszObjId = szOID_SUR_NAME;
784 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
785 attrs[1].Value.cbData = sizeof(surName);
786 attrs[1].Value.pbData = (BYTE *)surName;
788 rdn.rgRDNAttr = attrs;
789 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
790 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
791 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
794 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
795 "Got unexpected encoding for two RDN array\n");
798 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
800 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
801 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
802 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
803 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
804 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
805 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
808 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
809 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
810 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
811 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
814 ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
815 names[i].encoded[1] + 2, size);
816 ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
817 "Got unexpected encoding\n");
821 /* Test a more complex name */
822 rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
823 rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
828 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
829 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
830 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
833 ok(size == sizeof(encodedRDNAttrs), "Expected size %d, got %ld\n",
834 sizeof(encodedRDNAttrs), size);
835 ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
840 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
841 const CERT_RDN_ATTR *got)
843 if (expected->pszObjId && strlen(expected->pszObjId))
845 ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
849 ok(!strcmp(got->pszObjId, expected->pszObjId),
850 "Got unexpected OID %s, expected %s\n", got->pszObjId,
854 ok(got->dwValueType == expected->dwValueType,
855 "Expected string type %ld, got %ld\n", expected->dwValueType,
857 ok(got->Value.cbData == expected->Value.cbData,
858 "Unexpected data size, got %ld, expected %ld\n", got->Value.cbData,
859 expected->Value.cbData);
860 if (got->Value.cbData && got->Value.pbData)
861 ok(!memcmp(got->Value.pbData, expected->Value.pbData,
862 min(got->Value.cbData, expected->Value.cbData)), "Unexpected value\n");
865 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
867 ok(got->cRDNAttr == expected->cRDNAttr,
868 "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
873 for (i = 0; i < got->cRDNAttr; i++)
874 compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
878 static void compareNames(const CERT_NAME_INFO *expected,
879 const CERT_NAME_INFO *got)
881 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
882 expected->cRDN, got->cRDN);
887 for (i = 0; i < got->cRDN; i++)
888 compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
892 static void test_decodeName(DWORD dwEncoding)
899 CERT_NAME_INFO info = { 1, &rdn };
901 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
903 /* When the output buffer is NULL, this always succeeds */
904 SetLastError(0xdeadbeef);
905 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
906 names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
907 ok(ret && GetLastError() == NOERROR,
908 "Expected success and NOERROR, got %08lx\n", GetLastError());
909 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
910 names[i].encoded[1] + 2,
911 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
912 (BYTE *)&buf, &bufSize);
913 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
915 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
918 compareNames(&info, (CERT_NAME_INFO *)buf);
922 /* test empty name */
924 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
926 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
927 (BYTE *)&buf, &bufSize);
928 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
929 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
930 * decoder works the same way, so only test the count.
934 ok(bufSize == sizeof(CERT_NAME_INFO),
935 "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
936 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
937 "Expected 0 RDNs in empty info, got %ld\n",
938 ((CERT_NAME_INFO *)buf)->cRDN);
943 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
945 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
946 (BYTE *)&buf, &bufSize);
947 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
950 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
952 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
953 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
954 "Got unexpected value for empty RDN\n");
957 /* test two RDN attrs */
959 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
961 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
962 (BYTE *)&buf, &bufSize);
963 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
966 CERT_RDN_ATTR attrs[] = {
967 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
969 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
970 (BYTE *)commonName } },
973 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
974 rdn.rgRDNAttr = attrs;
975 compareNames(&info, (CERT_NAME_INFO *)buf);
978 /* And, a slightly more complicated name */
981 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
982 sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
983 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
986 rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
987 rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
988 compareNames(&info, (CERT_NAME_INFO *)buf);
993 static const BYTE emptyAltName[] = { 0x30, 0x00 };
994 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
995 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
996 'h','q','.','o','r','g',0 };
997 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
998 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
1000 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
1002 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1003 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1004 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1005 static const BYTE localhost[] = { 127, 0, 0, 1 };
1006 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1009 static void test_encodeAltName(DWORD dwEncoding)
1011 CERT_ALT_NAME_INFO info = { 0 };
1012 CERT_ALT_NAME_ENTRY entry = { 0 };
1017 /* Test with empty info */
1018 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1019 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1022 ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n",
1023 sizeof(emptyAltName), size);
1024 ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n");
1027 /* Test with an empty entry */
1029 info.rgAltEntry = &entry;
1030 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1031 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1032 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1033 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1035 /* Test with an empty pointer */
1036 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1037 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1038 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1041 ok(size == sizeof(emptyURL), "Expected size %d, got %ld\n",
1042 sizeof(emptyURL), size);
1043 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1046 /* Test with a real URL */
1047 U(entry).pwszURL = (LPWSTR)url;
1048 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1049 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1052 ok(size == sizeof(encodedURL), "Expected size %d, got %ld\n",
1053 sizeof(encodedURL), size);
1054 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1057 /* Now with the URL containing an invalid IA5 char */
1058 U(entry).pwszURL = (LPWSTR)nihongoURL;
1059 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1060 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1061 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1062 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1063 /* The first invalid character is at index 7 */
1064 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1065 "Expected invalid char at index 7, got %ld\n",
1066 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1067 /* Now with the URL missing a scheme */
1068 U(entry).pwszURL = (LPWSTR)dnsName;
1069 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1070 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1071 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1074 /* This succeeds, but it shouldn't, so don't worry about conforming */
1077 /* Now with a DNS name */
1078 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1079 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1080 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1081 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1084 ok(size == sizeof(encodedDnsName), "Expected size %d, got %ld\n",
1085 sizeof(encodedDnsName), size);
1086 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1089 /* Test with an IP address */
1090 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1091 U(entry).IPAddress.cbData = sizeof(localhost);
1092 U(entry).IPAddress.pbData = (LPBYTE)localhost;
1093 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1094 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1097 ok(size == sizeof(encodedIPAddr), "Expected size %d, got %ld\n",
1098 sizeof(encodedIPAddr), size);
1099 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1104 static void test_decodeAltName(DWORD dwEncoding)
1106 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1108 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1113 CERT_ALT_NAME_INFO *info;
1115 /* Test some bogus ones first */
1116 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1117 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1118 NULL, (BYTE *)&buf, &bufSize);
1119 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1120 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1121 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1122 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1124 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1125 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1126 /* Now expected cases */
1127 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName,
1128 emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1130 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1133 info = (CERT_ALT_NAME_INFO *)buf;
1135 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1139 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1140 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1142 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1145 info = (CERT_ALT_NAME_INFO *)buf;
1147 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1149 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1150 "Expected CERT_ALT_NAME_URL, got %ld\n",
1151 info->rgAltEntry[0].dwAltNameChoice);
1152 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1153 "Expected empty URL\n");
1156 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1157 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1159 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1162 info = (CERT_ALT_NAME_INFO *)buf;
1164 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1166 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1167 "Expected CERT_ALT_NAME_URL, got %ld\n",
1168 info->rgAltEntry[0].dwAltNameChoice);
1169 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1172 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1173 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1175 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1178 info = (CERT_ALT_NAME_INFO *)buf;
1180 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1182 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1183 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1184 info->rgAltEntry[0].dwAltNameChoice);
1185 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1186 "Unexpected DNS name\n");
1189 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1190 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1192 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1195 info = (CERT_ALT_NAME_INFO *)buf;
1197 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1199 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1200 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1201 info->rgAltEntry[0].dwAltNameChoice);
1202 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1203 "Unexpected IP address length %ld\n",
1204 U(info->rgAltEntry[0]).IPAddress.cbData);
1205 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1206 sizeof(localhost)), "Unexpected IP address value\n");
1211 struct encodedOctets
1214 const BYTE *encoded;
1217 static const unsigned char bin46[] = { 'h','i',0 };
1218 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1219 static const unsigned char bin48[] = {
1220 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1221 static const unsigned char bin49[] = {
1222 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1223 static const unsigned char bin50[] = { 0 };
1224 static const unsigned char bin51[] = { 0x04,0x00,0 };
1226 static const struct encodedOctets octets[] = {
1232 static void test_encodeOctets(DWORD dwEncoding)
1234 CRYPT_DATA_BLOB blob;
1237 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1243 blob.cbData = strlen((const char*)octets[i].val);
1244 blob.pbData = (BYTE*)octets[i].val;
1245 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1246 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1247 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1251 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1252 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1253 buf[1], octets[i].encoded[1]);
1254 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1255 octets[i].encoded[1] + 1), "Got unexpected value\n");
1261 static void test_decodeOctets(DWORD dwEncoding)
1265 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1271 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1272 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1273 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1274 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1275 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1276 "Expected size >= %d, got %ld\n",
1277 sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1278 ok(buf != NULL, "Expected allocated buffer\n");
1281 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1284 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1285 "Unexpected value\n");
1291 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1296 const BYTE *encoded;
1298 const BYTE *decoded;
1301 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff,0 };
1302 static const unsigned char bin53[] = { 0xff,0xff,0 };
1303 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe,0 };
1304 static const unsigned char bin55[] = { 0xff,0xfe,0 };
1305 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe,0 };
1306 static const unsigned char bin57[] = { 0xfe,0 };
1307 static const unsigned char bin58[] = { 0x03,0x01,0x00,0 };
1309 static const struct encodedBits bits[] = {
1310 /* normal test cases */
1311 { 0, bin52, 2, bin53 },
1312 { 1, bin54, 2, bin55 },
1313 /* strange test case, showing cUnusedBits >= 8 is allowed */
1314 { 9, bin56, 1, bin57 },
1315 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1316 { 17, bin58, 0, NULL },
1319 static void test_encodeBits(DWORD dwEncoding)
1323 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1325 CRYPT_BIT_BLOB blob;
1330 blob.cbData = sizeof(bytesToEncode);
1331 blob.pbData = (BYTE *)bytesToEncode;
1332 blob.cUnusedBits = bits[i].cUnusedBits;
1333 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1334 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1335 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1338 ok(bufSize == bits[i].encoded[1] + 2,
1339 "Got unexpected size %ld, expected %d\n", bufSize,
1340 bits[i].encoded[1] + 2);
1341 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1342 "Unexpected value\n");
1348 static void test_decodeBits(DWORD dwEncoding)
1350 static const BYTE ber[] = "\x03\x02\x01\xff";
1351 static const BYTE berDecoded = 0xfe;
1358 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1360 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1361 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1363 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1366 CRYPT_BIT_BLOB *blob;
1368 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1369 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1370 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1371 blob = (CRYPT_BIT_BLOB *)buf;
1372 ok(blob->cbData == bits[i].cbDecoded,
1373 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1375 if (blob->cbData && bits[i].cbDecoded)
1376 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1377 "Unexpected value\n");
1381 /* special case: check that something that's valid in BER but not in DER
1382 * decodes successfully
1384 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1385 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1386 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1389 CRYPT_BIT_BLOB *blob;
1391 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1392 "Got unexpected size %ld, expected >= %d\n", bufSize,
1393 sizeof(CRYPT_BIT_BLOB) + berDecoded);
1394 blob = (CRYPT_BIT_BLOB *)buf;
1395 ok(blob->cbData == sizeof(berDecoded),
1396 "Got unexpected length %ld, expected %d\n", blob->cbData,
1397 sizeof(berDecoded));
1399 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1406 CERT_BASIC_CONSTRAINTS2_INFO info;
1407 const BYTE *encoded;
1410 static const unsigned char bin59[] = { 0x30,0x00,0 };
1411 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff,0 };
1412 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00,0 };
1413 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0 };
1414 static const struct Constraints2 constraints2[] = {
1415 /* empty constraints */
1416 { { FALSE, FALSE, 0}, bin59 },
1418 { { TRUE, FALSE, 0}, bin60 },
1419 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1420 * but that's not the case
1422 { { FALSE, TRUE, 0}, bin61 },
1423 /* can be a CA and has path length constraints set */
1424 { { TRUE, TRUE, 1}, bin62 },
1427 static void test_encodeBasicConstraints(DWORD dwEncoding)
1431 /* First test with the simpler info2 */
1432 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1438 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1439 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1441 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1444 ok(bufSize == constraints2[i].encoded[1] + 2,
1445 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1447 ok(!memcmp(buf, constraints2[i].encoded,
1448 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1454 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01,0 };
1456 static void test_decodeBasicConstraints(DWORD dwEncoding)
1458 static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
1459 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1465 /* First test with simpler info2 */
1466 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1468 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1469 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1470 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1471 ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1475 CERT_BASIC_CONSTRAINTS2_INFO *info =
1476 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1478 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1479 "Unexpected value for item %ld\n", i);
1483 /* Check with the order of encoded elements inverted */
1485 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1486 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1488 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1489 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1490 ok(!buf, "Expected buf to be set to NULL\n");
1491 /* Check with a non-DER bool */
1492 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1493 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1494 (BYTE *)&buf, &bufSize);
1495 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1498 CERT_BASIC_CONSTRAINTS2_INFO *info =
1499 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1501 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1504 /* Check with a non-basic constraints value */
1505 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1506 names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1507 (BYTE *)&buf, &bufSize);
1508 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1509 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1512 /* These are terrible public keys of course, I'm just testing encoding */
1513 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1514 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1515 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1516 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1517 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1518 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1519 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1520 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1522 struct EncodedRSAPubKey
1524 const BYTE *modulus;
1526 const BYTE *encoded;
1527 size_t decodedModulusLen;
1530 struct EncodedRSAPubKey rsaPubKeys[] = {
1531 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1532 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1533 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1534 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1537 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1539 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1540 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1541 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1544 DWORD bufSize = 0, i;
1546 /* Try with a bogus blob type */
1548 hdr->bVersion = CUR_BLOB_VERSION;
1550 hdr->aiKeyAlg = CALG_RSA_KEYX;
1551 rsaPubKey->magic = 0x31415352;
1552 rsaPubKey->bitlen = sizeof(modulus1) * 8;
1553 rsaPubKey->pubexp = 65537;
1554 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1557 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1558 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1560 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1561 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1563 /* Now with a bogus reserved field */
1564 hdr->bType = PUBLICKEYBLOB;
1566 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1567 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1571 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1572 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1573 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1576 /* Now with a bogus blob version */
1579 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1580 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1584 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1585 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1586 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1589 /* And with a bogus alg ID */
1590 hdr->bVersion = CUR_BLOB_VERSION;
1591 hdr->aiKeyAlg = CALG_DES;
1592 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1593 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1597 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1598 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1599 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1602 /* Check a couple of RSA-related OIDs */
1603 hdr->aiKeyAlg = CALG_RSA_KEYX;
1604 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1605 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1606 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1607 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1608 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1609 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1610 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1611 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1612 /* Finally, all valid */
1613 hdr->aiKeyAlg = CALG_RSA_KEYX;
1614 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1616 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1617 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1618 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1619 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1620 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1623 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1624 "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1626 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1627 "Unexpected value\n");
1633 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1640 /* Try with a bad length */
1641 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1642 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1643 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1644 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1645 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1646 /* Try with a couple of RSA-related OIDs */
1647 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1648 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1649 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1650 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1651 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1652 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1653 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1654 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1655 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1656 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1657 /* Now try success cases */
1658 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1661 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1662 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1663 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1664 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1667 BLOBHEADER *hdr = (BLOBHEADER *)buf;
1668 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1670 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1671 rsaPubKeys[i].decodedModulusLen,
1672 "Expected size at least %d, got %ld\n",
1673 sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1674 rsaPubKeys[i].decodedModulusLen, bufSize);
1675 ok(hdr->bType == PUBLICKEYBLOB,
1676 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1678 ok(hdr->bVersion == CUR_BLOB_VERSION,
1679 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1680 CUR_BLOB_VERSION, hdr->bVersion);
1681 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1683 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1684 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1685 ok(rsaPubKey->magic == 0x31415352,
1686 "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1687 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1688 "Expected bit len %d, got %ld\n",
1689 rsaPubKeys[i].decodedModulusLen * 8, rsaPubKey->bitlen);
1690 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1692 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1693 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1694 "Unexpected modulus\n");
1700 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1701 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1702 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1704 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1705 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1706 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1707 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1709 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1711 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1712 CRYPT_SEQUENCE_OF_ANY seq;
1718 /* Encode a homogenous sequence */
1719 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1721 blobs[i].cbData = ints[i].encoded[1] + 2;
1722 blobs[i].pbData = (BYTE *)ints[i].encoded;
1724 seq.cValue = sizeof(ints) / sizeof(ints[0]);
1725 seq.rgValue = blobs;
1727 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1728 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1729 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1732 ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1733 sizeof(intSequence), bufSize);
1734 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1737 /* Change the type of the first element in the sequence, and give it
1740 blobs[0].cbData = times[0].encodedTime[1] + 2;
1741 blobs[0].pbData = (BYTE *)times[0].encodedTime;
1742 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1743 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1744 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1747 ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1748 sizeof(mixedSequence), bufSize);
1749 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1750 "Unexpected value\n");
1755 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1761 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1762 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1763 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1766 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1769 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1770 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1772 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1774 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1775 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1776 seq->rgValue[i].cbData);
1777 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1778 ints[i].encoded[1] + 2), "Unexpected value\n");
1782 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1783 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1785 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1788 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1790 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1791 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1793 /* Just check the first element since it's all that changed */
1794 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1795 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1796 seq->rgValue[0].cbData);
1797 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1798 times[0].encodedTime[1] + 2), "Unexpected value\n");
1803 struct encodedExtensions
1805 CERT_EXTENSIONS exts;
1806 const BYTE *encoded;
1809 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1810 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1812 static CERT_EXTENSION criticalExt =
1813 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1814 static CERT_EXTENSION nonCriticalExt =
1815 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1817 static const BYTE ext0[] = { 0x30,0x00 };
1818 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1819 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1820 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1821 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1823 static const struct encodedExtensions exts[] = {
1824 { { 0, NULL }, ext0 },
1825 { { 1, &criticalExt }, ext1 },
1826 { { 1, &nonCriticalExt }, ext2 },
1829 static void test_encodeExtensions(DWORD dwEncoding)
1833 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1839 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1840 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1841 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1844 ok(bufSize == exts[i].encoded[1] + 2,
1845 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1846 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1847 "Unexpected value\n");
1853 static void test_decodeExtensions(DWORD dwEncoding)
1857 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1863 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1864 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1865 NULL, (BYTE *)&buf, &bufSize);
1866 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1869 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1872 ok(ext->cExtension == exts[i].exts.cExtension,
1873 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1875 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1877 ok(!strcmp(ext->rgExtension[j].pszObjId,
1878 exts[i].exts.rgExtension[j].pszObjId),
1879 "Expected OID %s, got %s\n",
1880 exts[i].exts.rgExtension[j].pszObjId,
1881 ext->rgExtension[j].pszObjId);
1882 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1883 exts[i].exts.rgExtension[j].Value.pbData,
1884 exts[i].exts.rgExtension[j].Value.cbData),
1885 "Unexpected value\n");
1892 /* MS encodes public key info with a NULL if the algorithm identifier's
1893 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
1894 * it encodes them by omitting the algorithm parameters. This latter approach
1895 * seems more correct, so accept either form.
1897 struct encodedPublicKey
1899 CERT_PUBLIC_KEY_INFO info;
1900 const BYTE *encoded;
1901 const BYTE *encodedNoNull;
1902 CERT_PUBLIC_KEY_INFO decoded;
1905 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1907 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1909 static const unsigned char bin64[] = {
1910 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00,0};
1911 static const unsigned char bin65[] = {
1912 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00,0};
1913 static const unsigned char bin66[] = {
1914 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00,0};
1915 static const unsigned char bin67[] = {
1916 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00,0};
1917 static const unsigned char bin68[] = {
1918 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1919 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0};
1920 static const unsigned char bin69[] = {
1921 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
1922 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0};
1923 static const unsigned char bin70[] = {
1924 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1925 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1927 static const unsigned char bin71[] = {
1928 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1929 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1931 static unsigned char bin72[] = { 0x05,0x00,0};
1933 static const struct encodedPublicKey pubKeys[] = {
1934 /* with a bogus OID */
1935 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1937 { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
1938 /* some normal keys */
1939 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1941 { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
1942 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
1944 { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
1945 /* with add'l parameters--note they must be DER-encoded */
1946 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1947 (BYTE *)aKey, 0 } },
1949 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1950 (BYTE *)aKey, 0 } } },
1953 static void test_encodePublicKeyInfo(DWORD dwEncoding)
1957 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1963 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1964 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1966 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1969 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
1970 bufSize == pubKeys[i].encodedNoNull[1] + 2,
1971 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
1972 pubKeys[i].encodedNoNull[1] + 2, bufSize);
1973 if (bufSize == pubKeys[i].encoded[1] + 2)
1974 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
1975 "Unexpected value\n");
1976 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
1977 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
1978 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
1984 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
1985 const CERT_PUBLIC_KEY_INFO *got)
1987 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
1988 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
1989 got->Algorithm.pszObjId);
1990 ok(expected->Algorithm.Parameters.cbData ==
1991 got->Algorithm.Parameters.cbData,
1992 "Expected parameters of %ld bytes, got %ld\n",
1993 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
1994 if (expected->Algorithm.Parameters.cbData)
1995 ok(!memcmp(expected->Algorithm.Parameters.pbData,
1996 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
1997 "Unexpected algorithm parameters\n");
1998 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
1999 "Expected public key of %ld bytes, got %ld\n",
2000 expected->PublicKey.cbData, got->PublicKey.cbData);
2001 if (expected->PublicKey.cbData)
2002 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2003 got->PublicKey.cbData), "Unexpected public key value\n");
2006 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2008 static const BYTE bogusPubKeyInfo[] =
2009 "\x30\x22\x30\x0d\x06\x06\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x01\x01"
2010 "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
2017 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2019 /* The NULL form decodes to the decoded member */
2020 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2021 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2022 NULL, (BYTE *)&buf, &bufSize);
2023 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2026 comparePublicKeyInfo(&pubKeys[i].decoded,
2027 (CERT_PUBLIC_KEY_INFO *)buf);
2030 /* The non-NULL form decodes to the original */
2031 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2032 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2033 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2034 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2037 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2041 /* Test with bogus (not valid DER) parameters */
2042 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2043 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2044 NULL, (BYTE *)&buf, &bufSize);
2045 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2046 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2049 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2050 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2051 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2052 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2053 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2054 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2055 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2056 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2057 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2058 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2059 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2060 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2061 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2062 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2063 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2064 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2065 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2066 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2067 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2068 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2069 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2070 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2071 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2072 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2073 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2074 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2075 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2076 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2077 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2078 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2079 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2080 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2081 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2082 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2083 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2084 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2085 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2086 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2087 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2089 /* This is the encoded form of the printable string "Juan Lang" */
2090 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
2091 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
2092 0x61, 0x6e, 0x67, 0x00 };
2093 static const BYTE serialNum[] = { 0x01 };
2095 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2100 CERT_INFO info = { 0 };
2102 /* Test with NULL pvStructInfo */
2103 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2104 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2105 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2106 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2107 /* Test with a V1 cert */
2108 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2109 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2110 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2113 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2114 v1Cert[1] + 2, size);
2115 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2119 info.dwVersion = CERT_V2;
2120 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2121 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2122 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2125 ok(size == sizeof(v2Cert), "Expected size %d, got %ld\n",
2126 sizeof(v2Cert), size);
2127 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2131 info.dwVersion = CERT_V3;
2132 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2133 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2134 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2137 ok(size == sizeof(v3Cert), "Expected size %d, got %ld\n",
2138 sizeof(v3Cert), size);
2139 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2142 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2143 * API doesn't prevent it)
2145 info.dwVersion = CERT_V1;
2146 info.cExtension = 1;
2147 info.rgExtension = &criticalExt;
2148 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2149 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2150 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2153 ok(size == sizeof(v1CertWithConstraints), "Expected size %d, got %ld\n",
2154 sizeof(v1CertWithConstraints), size);
2155 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2158 /* test v1 cert with a serial number */
2159 info.SerialNumber.cbData = sizeof(serialNum);
2160 info.SerialNumber.pbData = (BYTE *)serialNum;
2161 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2162 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2165 ok(size == sizeof(v1CertWithSerial), "Expected size %d, got %ld\n",
2166 sizeof(v1CertWithSerial), size);
2167 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2170 /* Test v1 cert with an issuer name, a subject name, and a serial number */
2171 info.Issuer.cbData = sizeof(encodedCommonName);
2172 info.Issuer.pbData = (BYTE *)encodedCommonName;
2173 info.Subject.cbData = sizeof(encodedCommonName);
2174 info.Subject.pbData = (BYTE *)encodedCommonName;
2175 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2176 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2179 ok(size == sizeof(bigCert), "Expected size %d, got %ld\n",
2180 sizeof(bigCert), size);
2181 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2184 /* for now, I let more interesting tests be done for each subcomponent,
2185 * rather than retesting them all here.
2189 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2191 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2192 v1CertWithConstraints, v1CertWithSerial };
2197 /* Test with NULL pbEncoded */
2198 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2199 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2200 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2201 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2202 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2203 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2204 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2205 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2206 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2207 * minimum a cert must have a non-zero serial number, an issuer, and a
2210 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2212 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2213 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2214 (BYTE *)&buf, &size);
2215 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2216 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2218 /* Now check with serial number, subject and issuer specified */
2219 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2220 sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2221 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2224 CERT_INFO *info = (CERT_INFO *)buf;
2226 ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
2227 sizeof(CERT_INFO), size);
2228 ok(info->SerialNumber.cbData == 1,
2229 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2230 ok(*info->SerialNumber.pbData == *serialNum,
2231 "Expected serial number %d, got %d\n", *serialNum,
2232 *info->SerialNumber.pbData);
2233 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2234 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2235 info->Issuer.cbData);
2236 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2237 "Unexpected issuer\n");
2238 ok(info->Subject.cbData == sizeof(encodedCommonName),
2239 "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
2240 info->Subject.cbData);
2241 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2242 info->Subject.cbData), "Unexpected subject\n");
2247 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2250 static const BYTE signedBigCert[] = {
2251 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2252 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2253 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2254 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2255 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2256 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2257 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2258 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2259 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2260 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2261 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2262 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2264 static void test_encodeCert(DWORD dwEncoding)
2266 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
2267 * also that bigCert is a NULL-terminated string, so don't count its
2268 * last byte (otherwise the signed cert won't decode.)
2270 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2271 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2276 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2277 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2278 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2281 ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
2282 sizeof(signedBigCert), bufSize);
2283 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2288 static void test_decodeCert(DWORD dwEncoding)
2294 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2295 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2296 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2299 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2301 ok(info->ToBeSigned.cbData == sizeof(bigCert),
2302 "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert),
2303 info->ToBeSigned.cbData);
2304 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2305 "Unexpected cert\n");
2306 ok(info->Signature.cbData == sizeof(hash),
2307 "Expected signature size %d, got %ld\n", sizeof(hash),
2308 info->Signature.cbData);
2309 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2310 "Unexpected signature\n");
2315 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2316 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2317 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2318 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2319 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2321 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2322 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2323 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2324 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2325 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2326 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2327 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2328 0x2e, 0x6f, 0x72, 0x67 };
2329 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2330 CRL_REASON_AFFILIATION_CHANGED;
2332 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2334 CRL_DIST_POINTS_INFO info = { 0 };
2335 CRL_DIST_POINT point = { { 0 } };
2336 CERT_ALT_NAME_ENTRY entry = { 0 };
2341 /* Test with an empty info */
2342 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2343 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2344 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
2345 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
2347 /* Test with one empty dist point */
2348 info.cDistPoint = 1;
2349 info.rgDistPoint = &point;
2350 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2351 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2354 ok(size == sizeof(emptyDistPoint), "Expected size %d, got %ld\n",
2355 sizeof(emptyDistPoint), size);
2356 ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2359 /* A dist point with an invalid name */
2360 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2361 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2362 U(entry).pwszURL = (LPWSTR)nihongoURL;
2363 U(point.DistPointName).FullName.cAltEntry = 1;
2364 U(point.DistPointName).FullName.rgAltEntry = &entry;
2365 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2366 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2367 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2368 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2369 /* The first invalid character is at index 7 */
2370 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2371 "Expected invalid char at index 7, got %ld\n",
2372 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2373 /* A dist point with (just) a valid name */
2374 U(entry).pwszURL = (LPWSTR)url;
2375 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2376 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2379 ok(size == sizeof(distPointWithUrl), "Expected size %d, got %ld\n",
2380 sizeof(distPointWithUrl), size);
2381 ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2384 /* A dist point with (just) reason flags */
2385 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2386 point.ReasonFlags.cbData = sizeof(crlReason);
2387 point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2388 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2389 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2392 ok(size == sizeof(distPointWithReason), "Expected size %d, got %ld\n",
2393 sizeof(distPointWithReason), size);
2394 ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2397 /* A dist point with just an issuer */
2398 point.ReasonFlags.cbData = 0;
2399 point.CRLIssuer.cAltEntry = 1;
2400 point.CRLIssuer.rgAltEntry = &entry;
2401 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2402 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2405 ok(size == sizeof(distPointWithIssuer), "Expected size %d, got %ld\n",
2406 sizeof(distPointWithIssuer), size);
2407 ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2410 /* A dist point with both a name and an issuer */
2411 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2412 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2413 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2416 ok(size == sizeof(distPointWithUrlAndIssuer),
2417 "Expected size %d, got %ld\n", sizeof(distPointWithUrlAndIssuer),
2419 ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2424 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2429 PCRL_DIST_POINTS_INFO info;
2430 PCRL_DIST_POINT point;
2431 PCERT_ALT_NAME_ENTRY entry;
2433 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2434 emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2435 (BYTE *)&buf, &size);
2438 info = (PCRL_DIST_POINTS_INFO)buf;
2439 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2440 "Expected size at least %d, got %ld\n",
2441 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2442 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2444 point = info->rgDistPoint;
2445 ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2446 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2447 point->DistPointName.dwDistPointNameChoice);
2448 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2449 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2452 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2453 distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2454 (BYTE *)&buf, &size);
2457 info = (PCRL_DIST_POINTS_INFO)buf;
2458 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2459 "Expected size at least %d, got %ld\n",
2460 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2461 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2463 point = info->rgDistPoint;
2464 ok(point->DistPointName.dwDistPointNameChoice ==
2465 CRL_DIST_POINT_FULL_NAME,
2466 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2467 point->DistPointName.dwDistPointNameChoice);
2468 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2469 "Expected 1 name entry, got %ld\n",
2470 U(point->DistPointName).FullName.cAltEntry);
2471 entry = U(point->DistPointName).FullName.rgAltEntry;
2472 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2473 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2474 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2475 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2476 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2479 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2480 distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2481 NULL, (BYTE *)&buf, &size);
2484 info = (PCRL_DIST_POINTS_INFO)buf;
2485 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2486 "Expected size at least %d, got %ld\n",
2487 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2488 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2490 point = info->rgDistPoint;
2491 ok(point->DistPointName.dwDistPointNameChoice ==
2492 CRL_DIST_POINT_NO_NAME,
2493 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2494 point->DistPointName.dwDistPointNameChoice);
2495 ok(point->ReasonFlags.cbData == sizeof(crlReason),
2496 "Expected reason length\n");
2497 ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2498 "Unexpected reason\n");
2499 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2502 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2503 distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2504 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2507 info = (PCRL_DIST_POINTS_INFO)buf;
2508 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2509 "Expected size at least %d, got %ld\n",
2510 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2511 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2513 point = info->rgDistPoint;
2514 ok(point->DistPointName.dwDistPointNameChoice ==
2515 CRL_DIST_POINT_FULL_NAME,
2516 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2517 point->DistPointName.dwDistPointNameChoice);
2518 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2519 "Expected 1 name entry, got %ld\n",
2520 U(point->DistPointName).FullName.cAltEntry);
2521 entry = U(point->DistPointName).FullName.rgAltEntry;
2522 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2523 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2524 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2525 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2526 ok(point->CRLIssuer.cAltEntry == 1,
2527 "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2528 entry = point->CRLIssuer.rgAltEntry;
2529 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2530 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2531 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2536 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2537 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2539 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2540 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2541 0x30, 0x30, 0x30, 0x30, 0x5a };
2542 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2543 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2544 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2545 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2547 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2548 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2549 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2550 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2551 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2552 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2553 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2554 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2555 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2556 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2557 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2558 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2559 static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
2560 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2561 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
2562 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2563 0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2564 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
2565 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2566 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2568 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2573 CRL_INFO info = { 0 };
2574 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2576 /* Test with a V1 CRL */
2577 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2578 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2579 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2582 ok(size == sizeof(v1CRL), "Expected size %d, got %ld\n",
2583 sizeof(v1CRL), size);
2584 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2588 info.dwVersion = CRL_V2;
2589 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2590 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2591 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2594 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2595 v2CRL[1] + 2, size);
2596 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2599 /* v1 CRL with a name */
2600 info.dwVersion = CRL_V1;
2601 info.Issuer.cbData = sizeof(encodedCommonName);
2602 info.Issuer.pbData = (BYTE *)encodedCommonName;
2603 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2604 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2605 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2608 ok(size == sizeof(v1CRLWithIssuer), "Expected size %d, got %ld\n",
2609 sizeof(v1CRLWithIssuer), size);
2610 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2613 /* v1 CRL with a name and a NULL entry pointer */
2615 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2616 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2617 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2618 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2619 /* now set an empty entry */
2620 info.rgCRLEntry = &entry;
2621 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2622 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2625 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2626 "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEmptyEntry),
2628 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2629 "Got unexpected value\n");
2632 /* an entry with a serial number */
2633 entry.SerialNumber.cbData = sizeof(serialNum);
2634 entry.SerialNumber.pbData = (BYTE *)serialNum;
2635 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2636 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2639 ok(size == sizeof(v1CRLWithIssuerAndEntry),
2640 "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEntry), size);
2641 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2642 "Got unexpected value\n");
2645 /* and finally, an entry with an extension */
2646 entry.cExtension = 1;
2647 entry.rgExtension = &criticalExt;
2648 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2649 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2650 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2653 ok(size == sizeof(v1CRLWithExt), "Expected size %d, got %ld\n",
2654 sizeof(v1CRLWithExt), size);
2655 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2660 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
2662 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
2667 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
2669 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2670 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2671 (BYTE *)&buf, &size);
2672 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2673 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2675 /* at a minimum, a CRL must contain an issuer: */
2676 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2677 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2678 (BYTE *)&buf, &size);
2679 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2682 CRL_INFO *info = (CRL_INFO *)buf;
2684 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2685 sizeof(CRL_INFO), size);
2686 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
2688 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2689 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2690 info->Issuer.cbData);
2691 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2692 "Unexpected issuer\n");
2695 /* check decoding with an empty CRL entry */
2696 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2697 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
2698 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2699 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2700 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2701 /* with a real CRL entry */
2702 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2703 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
2704 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2705 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2708 CRL_INFO *info = (CRL_INFO *)buf;
2711 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2712 sizeof(CRL_INFO), size);
2713 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2715 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2716 entry = info->rgCRLEntry;
2717 ok(entry->SerialNumber.cbData == 1,
2718 "Expected serial number size 1, got %ld\n",
2719 entry->SerialNumber.cbData);
2720 ok(*entry->SerialNumber.pbData == *serialNum,
2721 "Expected serial number %d, got %d\n", *serialNum,
2722 *entry->SerialNumber.pbData);
2723 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2724 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2725 info->Issuer.cbData);
2726 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2727 "Unexpected issuer\n");
2729 /* and finally, with an extension */
2730 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2731 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2732 NULL, (BYTE *)&buf, &size);
2733 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2736 CRL_INFO *info = (CRL_INFO *)buf;
2739 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2740 sizeof(CRL_INFO), size);
2741 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2743 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2744 entry = info->rgCRLEntry;
2745 ok(entry->SerialNumber.cbData == 1,
2746 "Expected serial number size 1, got %ld\n",
2747 entry->SerialNumber.cbData);
2748 ok(*entry->SerialNumber.pbData == *serialNum,
2749 "Expected serial number %d, got %d\n", *serialNum,
2750 *entry->SerialNumber.pbData);
2751 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2752 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2753 info->Issuer.cbData);
2754 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2755 "Unexpected issuer\n");
2756 /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2757 * bug, or am I missing something?
2759 ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2764 /* Free *pInfo with HeapFree */
2765 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
2772 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
2774 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
2775 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2776 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2777 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
2779 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2780 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2781 ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
2783 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2784 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2785 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2786 0, NULL, NULL, &size);
2787 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2788 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2789 /* Test with no key */
2790 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2791 0, NULL, NULL, &size);
2792 ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
2794 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
2795 ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
2798 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
2799 NULL, 0, NULL, NULL, &size);
2800 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2801 *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
2804 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
2805 X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
2806 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
2810 /* By default (we passed NULL as the OID) the OID is
2813 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
2814 "Expected %s, got %s\n", szOID_RSA_RSA,
2815 (*pInfo)->Algorithm.pszObjId);
2821 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
2827 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
2828 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
2829 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
2830 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2833 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
2834 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2835 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2836 ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
2837 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2838 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2839 ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
2841 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2842 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2843 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2845 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2846 CryptDestroyKey(key);
2849 static const char cspName[] = "WineCryptTemp";
2851 static void testPortPublicKeyInfo(void)
2855 PCERT_PUBLIC_KEY_INFO info = NULL;
2857 /* Just in case a previous run failed, delete this thing */
2858 CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2859 CRYPT_DELETEKEYSET);
2860 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2863 testExportPublicKey(csp, &info);
2864 testImportPublicKey(csp, info);
2866 HeapFree(GetProcessHeap(), 0, info);
2867 CryptReleaseContext(csp, 0);
2868 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2869 CRYPT_DELETEKEYSET);
2874 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
2875 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
2878 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
2880 test_encodeInt(encodings[i]);
2881 test_decodeInt(encodings[i]);
2882 test_encodeEnumerated(encodings[i]);
2883 test_decodeEnumerated(encodings[i]);
2884 test_encodeFiletime(encodings[i]);
2885 test_decodeFiletime(encodings[i]);
2886 test_encodeName(encodings[i]);
2887 test_decodeName(encodings[i]);
2888 test_encodeAltName(encodings[i]);
2889 test_decodeAltName(encodings[i]);
2890 test_encodeOctets(encodings[i]);
2891 test_decodeOctets(encodings[i]);
2892 test_encodeBits(encodings[i]);
2893 test_decodeBits(encodings[i]);
2894 test_encodeBasicConstraints(encodings[i]);
2895 test_decodeBasicConstraints(encodings[i]);
2896 test_encodeRsaPublicKey(encodings[i]);
2897 test_decodeRsaPublicKey(encodings[i]);
2898 test_encodeSequenceOfAny(encodings[i]);
2899 test_decodeSequenceOfAny(encodings[i]);
2900 test_encodeExtensions(encodings[i]);
2901 test_decodeExtensions(encodings[i]);
2902 test_encodePublicKeyInfo(encodings[i]);
2903 test_decodePublicKeyInfo(encodings[i]);
2904 test_encodeCertToBeSigned(encodings[i]);
2905 test_decodeCertToBeSigned(encodings[i]);
2906 test_encodeCert(encodings[i]);
2907 test_decodeCert(encodings[i]);
2908 test_encodeCRLDistPoints(encodings[i]);
2909 test_decodeCRLDistPoints(encodings[i]);
2910 test_encodeCRLToBeSigned(encodings[i]);
2911 test_decodeCRLToBeSigned(encodings[i]);
2913 testPortPublicKeyInfo();