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};
36 static const BYTE bin2[] = {0x02,0x01,0x7f};
37 static const BYTE bin3[] = {0x02,0x02,0x00,0x80};
38 static const BYTE bin4[] = {0x02,0x02,0x01,0x00};
39 static const BYTE bin5[] = {0x02,0x01,0x80};
40 static const BYTE bin6[] = {0x02,0x02,0xff,0x7f};
41 static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d};
43 static const struct encodedInt ints[] = {
60 static const BYTE bin8[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
61 static const BYTE bin9[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
62 static const BYTE bin10[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
64 static const BYTE bin11[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
65 static const BYTE bin12[] = {0x02,0x09,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
66 static const BYTE bin13[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0};
68 static const struct encodedBigInt bigInts[] = {
69 { bin8, bin9, bin10 },
70 { bin11, bin12, bin13 },
73 static const BYTE bin14[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
74 static const BYTE bin15[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
75 static const BYTE bin16[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
76 static const BYTE bin17[] = {0x02,0x0c,0x00,0xff,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
78 /* Decoded is the same as original, so don't bother storing a separate copy */
79 static const struct encodedBigInt bigUInts[] = {
80 { bin14, bin15, NULL },
81 { bin16, bin17, NULL },
84 static void test_encodeInt(DWORD dwEncoding)
89 CRYPT_INTEGER_BLOB blob;
92 /* CryptEncodeObjectEx with NULL bufSize crashes..
93 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
96 /* check bogus encoding */
97 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
99 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
100 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
101 /* check with NULL integer buffer. Windows XP incorrectly returns an
104 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
106 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
107 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
108 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
110 /* encode as normal integer */
111 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
112 NULL, NULL, &bufSize);
113 ok(ret, "Expected success, got %ld\n", GetLastError());
114 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
115 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
116 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
119 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
121 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
122 buf[1], ints[i].encoded[1]);
123 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
124 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
127 /* encode as multibyte integer */
128 blob.cbData = sizeof(ints[i].val);
129 blob.pbData = (BYTE *)&ints[i].val;
130 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
131 0, NULL, NULL, &bufSize);
132 ok(ret, "Expected success, got %ld\n", GetLastError());
133 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
134 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
135 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
138 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
140 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
141 buf[1], ints[i].encoded[1]);
142 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
143 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
147 /* encode a couple bigger ints, just to show it's little-endian and leading
148 * sign bytes are dropped
150 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
152 blob.cbData = strlen((const char*)bigInts[i].val);
153 blob.pbData = (BYTE *)bigInts[i].val;
154 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
155 0, NULL, NULL, &bufSize);
156 ok(ret, "Expected success, got %ld\n", GetLastError());
157 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
158 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
159 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
162 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
164 ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
165 buf[1], bigInts[i].encoded[1]);
166 ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
167 bigInts[i].encoded[1] + 1),
168 "Encoded value didn't match expected\n");
172 /* and, encode some uints */
173 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
175 blob.cbData = strlen((const char*)bigUInts[i].val);
176 blob.pbData = (BYTE*)bigUInts[i].val;
177 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
178 0, NULL, NULL, &bufSize);
179 ok(ret, "Expected success, got %ld\n", GetLastError());
180 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
181 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
182 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
185 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
187 ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
188 buf[1], bigUInts[i].encoded[1]);
189 ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
190 bigUInts[i].encoded[1] + 1),
191 "Encoded value didn't match expected\n");
197 static void test_decodeInt(DWORD dwEncoding)
199 static const BYTE bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
200 static const BYTE testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
201 static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
202 static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
208 /* CryptDecodeObjectEx with NULL bufSize crashes..
209 ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
210 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
212 /* check bogus encoding */
213 ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
214 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
215 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
216 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
217 /* check with NULL integer buffer */
218 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
220 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
221 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
222 /* check with a valid, but too large, integer */
223 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
224 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
225 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
226 "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
227 /* check with a DER-encoded string */
228 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
229 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
230 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
231 "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
232 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
234 /* When the output buffer is NULL, this always succeeds */
235 SetLastError(0xdeadbeef);
236 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
237 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
239 ok(ret && GetLastError() == NOERROR,
240 "Expected success and NOERROR, got %ld\n", GetLastError());
241 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
242 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
243 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
244 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
245 ok(bufSize == sizeof(int), "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};
339 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80};
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'};
486 static const BYTE bin21[] = {
487 0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
488 static const BYTE bin22[] = {
489 0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
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'};
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'};
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'};
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'};
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'};
519 static const BYTE bin28[] = {
520 0x18,0x0a,'2','1','4','5','0','6','0','6','1','6'};
521 static const BYTE bin29[] = {
522 0x17,0x0a,'4','5','0','6','0','6','1','6','1','0'};
523 static const BYTE bin30[] = {
524 0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z'};
525 static const BYTE bin31[] = {
526 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1'};
527 static const BYTE bin32[] = {
528 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1'};
529 static const BYTE bin33[] = {
530 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0'};
531 static const BYTE bin34[] = {
532 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0'};
533 static const BYTE bin35[] = {
534 0x17,0x08, '4','5','0','6','0','6','1','6'};
535 static const BYTE bin36[] = {
536 0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z'};
537 static const BYTE bin37[] = {
538 0x18,0x04, '2','1','4','5'};
539 static const BYTE bin38[] = {
540 0x18,0x08, '2','1','4','5','0','6','0','6'};
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 emptySequence[] = { 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, emptySequence, sizeof(emptySequence)),
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, emptySequence,
925 emptySequence[1] + 2,
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 emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
994 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
995 'h','q','.','o','r','g',0 };
996 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
997 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
999 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
1001 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1002 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1003 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1004 static const BYTE localhost[] = { 127, 0, 0, 1 };
1005 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1008 static void test_encodeAltName(DWORD dwEncoding)
1010 CERT_ALT_NAME_INFO info = { 0 };
1011 CERT_ALT_NAME_ENTRY entry = { 0 };
1016 /* Test with empty info */
1017 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1018 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1021 ok(size == sizeof(emptySequence), "Expected size %d, got %ld\n",
1022 sizeof(emptySequence), size);
1023 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1026 /* Test with an empty entry */
1028 info.rgAltEntry = &entry;
1029 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1030 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1031 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1032 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1034 /* Test with an empty pointer */
1035 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1036 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1037 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1040 ok(size == sizeof(emptyURL), "Expected size %d, got %ld\n",
1041 sizeof(emptyURL), size);
1042 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1045 /* Test with a real URL */
1046 U(entry).pwszURL = (LPWSTR)url;
1047 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1048 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1051 ok(size == sizeof(encodedURL), "Expected size %d, got %ld\n",
1052 sizeof(encodedURL), size);
1053 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1056 /* Now with the URL containing an invalid IA5 char */
1057 U(entry).pwszURL = (LPWSTR)nihongoURL;
1058 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1059 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1060 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1061 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1062 /* The first invalid character is at index 7 */
1063 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1064 "Expected invalid char at index 7, got %ld\n",
1065 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1066 /* Now with the URL missing a scheme */
1067 U(entry).pwszURL = (LPWSTR)dnsName;
1068 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1069 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1070 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1073 /* This succeeds, but it shouldn't, so don't worry about conforming */
1076 /* Now with a DNS name */
1077 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1078 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1079 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1080 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1083 ok(size == sizeof(encodedDnsName), "Expected size %d, got %ld\n",
1084 sizeof(encodedDnsName), size);
1085 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1088 /* Test with an IP address */
1089 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1090 U(entry).IPAddress.cbData = sizeof(localhost);
1091 U(entry).IPAddress.pbData = (LPBYTE)localhost;
1092 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1093 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1096 ok(size == sizeof(encodedIPAddr), "Expected size %d, got %ld\n",
1097 sizeof(encodedIPAddr), size);
1098 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1103 static void test_decodeAltName(DWORD dwEncoding)
1105 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1107 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1112 CERT_ALT_NAME_INFO *info;
1114 /* Test some bogus ones first */
1115 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1116 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1117 NULL, (BYTE *)&buf, &bufSize);
1118 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1119 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1120 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1121 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1123 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1124 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1125 /* Now expected cases */
1126 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1127 emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1129 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1132 info = (CERT_ALT_NAME_INFO *)buf;
1134 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1138 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1139 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1141 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1144 info = (CERT_ALT_NAME_INFO *)buf;
1146 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1148 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1149 "Expected CERT_ALT_NAME_URL, got %ld\n",
1150 info->rgAltEntry[0].dwAltNameChoice);
1151 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1152 "Expected empty URL\n");
1155 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1156 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1158 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1161 info = (CERT_ALT_NAME_INFO *)buf;
1163 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1165 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1166 "Expected CERT_ALT_NAME_URL, got %ld\n",
1167 info->rgAltEntry[0].dwAltNameChoice);
1168 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1171 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1172 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1174 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1177 info = (CERT_ALT_NAME_INFO *)buf;
1179 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1181 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1182 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1183 info->rgAltEntry[0].dwAltNameChoice);
1184 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1185 "Unexpected DNS name\n");
1188 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1189 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1191 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1194 info = (CERT_ALT_NAME_INFO *)buf;
1196 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1198 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1199 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1200 info->rgAltEntry[0].dwAltNameChoice);
1201 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1202 "Unexpected IP address length %ld\n",
1203 U(info->rgAltEntry[0]).IPAddress.cbData);
1204 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1205 sizeof(localhost)), "Unexpected IP address value\n");
1210 struct encodedOctets
1213 const BYTE *encoded;
1216 static const unsigned char bin46[] = { 'h','i',0 };
1217 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1218 static const unsigned char bin48[] = {
1219 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1220 static const unsigned char bin49[] = {
1221 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1222 static const unsigned char bin50[] = { 0 };
1223 static const unsigned char bin51[] = { 0x04,0x00,0 };
1225 static const struct encodedOctets octets[] = {
1231 static void test_encodeOctets(DWORD dwEncoding)
1233 CRYPT_DATA_BLOB blob;
1236 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1242 blob.cbData = strlen((const char*)octets[i].val);
1243 blob.pbData = (BYTE*)octets[i].val;
1244 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1245 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1246 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1250 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1251 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1252 buf[1], octets[i].encoded[1]);
1253 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1254 octets[i].encoded[1] + 1), "Got unexpected value\n");
1260 static void test_decodeOctets(DWORD dwEncoding)
1264 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1270 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1271 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1272 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1273 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1274 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1275 "Expected size >= %d, got %ld\n",
1276 sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1277 ok(buf != NULL, "Expected allocated buffer\n");
1280 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1283 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1284 "Unexpected value\n");
1290 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1295 const BYTE *encoded;
1297 const BYTE *decoded;
1300 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1301 static const unsigned char bin53[] = { 0xff,0xff };
1302 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1303 static const unsigned char bin55[] = { 0xff,0xfe };
1304 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1305 static const unsigned char bin57[] = { 0xfe };
1306 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1308 static const struct encodedBits bits[] = {
1309 /* normal test cases */
1310 { 0, bin52, 2, bin53 },
1311 { 1, bin54, 2, bin55 },
1312 /* strange test case, showing cUnusedBits >= 8 is allowed */
1313 { 9, bin56, 1, bin57 },
1314 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1315 { 17, bin58, 0, NULL },
1318 static void test_encodeBits(DWORD dwEncoding)
1322 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1324 CRYPT_BIT_BLOB blob;
1329 blob.cbData = sizeof(bytesToEncode);
1330 blob.pbData = (BYTE *)bytesToEncode;
1331 blob.cUnusedBits = bits[i].cUnusedBits;
1332 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1333 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1334 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1337 ok(bufSize == bits[i].encoded[1] + 2,
1338 "Got unexpected size %ld, expected %d\n", bufSize,
1339 bits[i].encoded[1] + 2);
1340 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1341 "Unexpected value\n");
1347 static void test_decodeBits(DWORD dwEncoding)
1349 static const BYTE ber[] = "\x03\x02\x01\xff";
1350 static const BYTE berDecoded = 0xfe;
1357 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1359 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1360 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1362 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1365 CRYPT_BIT_BLOB *blob;
1367 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1368 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1369 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1370 blob = (CRYPT_BIT_BLOB *)buf;
1371 ok(blob->cbData == bits[i].cbDecoded,
1372 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1374 if (blob->cbData && bits[i].cbDecoded)
1375 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1376 "Unexpected value\n");
1380 /* special case: check that something that's valid in BER but not in DER
1381 * decodes successfully
1383 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1384 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1385 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1388 CRYPT_BIT_BLOB *blob;
1390 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1391 "Got unexpected size %ld, expected >= %d\n", bufSize,
1392 sizeof(CRYPT_BIT_BLOB) + berDecoded);
1393 blob = (CRYPT_BIT_BLOB *)buf;
1394 ok(blob->cbData == sizeof(berDecoded),
1395 "Got unexpected length %ld, expected %d\n", blob->cbData,
1396 sizeof(berDecoded));
1398 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1405 CERT_BASIC_CONSTRAINTS2_INFO info;
1406 const BYTE *encoded;
1409 static const unsigned char bin59[] = { 0x30,0x00 };
1410 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1411 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1412 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1413 static const struct Constraints2 constraints2[] = {
1414 /* empty constraints */
1415 { { FALSE, FALSE, 0}, bin59 },
1417 { { TRUE, FALSE, 0}, bin60 },
1418 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1419 * but that's not the case
1421 { { FALSE, TRUE, 0}, bin61 },
1422 /* can be a CA and has path length constraints set */
1423 { { TRUE, TRUE, 1}, bin62 },
1426 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1427 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1428 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1429 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1430 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1431 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1432 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1433 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1434 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1435 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1437 static void test_encodeBasicConstraints(DWORD dwEncoding)
1439 DWORD i, bufSize = 0;
1440 CERT_BASIC_CONSTRAINTS_INFO info;
1441 CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1442 (LPBYTE)encodedDomainName };
1446 /* First test with the simpler info2 */
1447 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1449 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1450 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1452 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1455 ok(bufSize == constraints2[i].encoded[1] + 2,
1456 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1458 ok(!memcmp(buf, constraints2[i].encoded,
1459 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1463 /* Now test with more complex basic constraints */
1464 info.SubjectType.cbData = 0;
1465 info.fPathLenConstraint = FALSE;
1466 info.cSubtreesConstraint = 0;
1467 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1468 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1469 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1472 ok(bufSize == sizeof(emptyConstraint), "Expected %d bytes, got %ld\n",
1473 sizeof(emptyConstraint), bufSize);
1474 ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1475 "Unexpected value\n");
1478 /* None of the certs I examined had any subtree constraint, but I test one
1479 * anyway just in case.
1481 info.cSubtreesConstraint = 1;
1482 info.rgSubtreesConstraint = &nameBlob;
1483 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1484 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1485 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1488 ok(bufSize == sizeof(constraintWithDomainName),
1489 "Expected %d bytes, got %ld\n", sizeof(constraintWithDomainName),
1491 ok(!memcmp(buf, constraintWithDomainName,
1492 sizeof(constraintWithDomainName)), "Unexpected value\n");
1495 /* FIXME: test encoding with subject type. */
1498 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1500 static void test_decodeBasicConstraints(DWORD dwEncoding)
1502 static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1504 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1510 /* First test with simpler info2 */
1511 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1513 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1514 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1515 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1516 ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1520 CERT_BASIC_CONSTRAINTS2_INFO *info =
1521 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1523 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1524 "Unexpected value for item %ld\n", i);
1528 /* Check with the order of encoded elements inverted */
1530 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1531 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1533 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1534 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1535 ok(!buf, "Expected buf to be set to NULL\n");
1536 /* Check with a non-DER bool */
1537 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1538 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1539 (BYTE *)&buf, &bufSize);
1540 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1543 CERT_BASIC_CONSTRAINTS2_INFO *info =
1544 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1546 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1549 /* Check with a non-basic constraints value */
1550 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1551 names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1552 (BYTE *)&buf, &bufSize);
1553 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1554 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1555 /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
1556 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1557 emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
1558 (BYTE *)&buf, &bufSize);
1559 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1562 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1564 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1565 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1566 ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
1569 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1570 constraintWithDomainName, sizeof(constraintWithDomainName),
1571 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1572 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1575 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1577 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1578 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1579 ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
1580 if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
1582 ok(info->rgSubtreesConstraint[0].cbData ==
1583 sizeof(encodedDomainName), "Expected %d bytes, got %ld\n",
1584 sizeof(encodedDomainName), info->rgSubtreesConstraint[0].cbData);
1585 ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
1586 sizeof(encodedDomainName)), "Unexpected value\n");
1592 /* These are terrible public keys of course, I'm just testing encoding */
1593 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1594 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1595 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1596 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1597 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1598 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1599 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1600 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1602 struct EncodedRSAPubKey
1604 const BYTE *modulus;
1606 const BYTE *encoded;
1607 size_t decodedModulusLen;
1610 struct EncodedRSAPubKey rsaPubKeys[] = {
1611 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1612 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1613 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1614 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1617 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1619 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1620 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1621 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1624 DWORD bufSize = 0, i;
1626 /* Try with a bogus blob type */
1628 hdr->bVersion = CUR_BLOB_VERSION;
1630 hdr->aiKeyAlg = CALG_RSA_KEYX;
1631 rsaPubKey->magic = 0x31415352;
1632 rsaPubKey->bitlen = sizeof(modulus1) * 8;
1633 rsaPubKey->pubexp = 65537;
1634 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1637 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1638 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1640 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1641 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1643 /* Now with a bogus reserved field */
1644 hdr->bType = PUBLICKEYBLOB;
1646 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1647 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1651 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1652 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1653 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1656 /* Now with a bogus blob version */
1659 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1660 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1664 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1665 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1666 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1669 /* And with a bogus alg ID */
1670 hdr->bVersion = CUR_BLOB_VERSION;
1671 hdr->aiKeyAlg = CALG_DES;
1672 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1673 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1677 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1678 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1679 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1682 /* Check a couple of RSA-related OIDs */
1683 hdr->aiKeyAlg = CALG_RSA_KEYX;
1684 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1685 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1686 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1687 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1688 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1689 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1690 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1691 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1692 /* Finally, all valid */
1693 hdr->aiKeyAlg = CALG_RSA_KEYX;
1694 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1696 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1697 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1698 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1699 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1700 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1703 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1704 "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1706 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1707 "Unexpected value\n");
1713 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1720 /* Try with a bad length */
1721 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1722 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1723 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1724 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1725 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1726 /* Try with a couple of RSA-related OIDs */
1727 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1728 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1729 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1730 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1731 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1732 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1733 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1734 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1735 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1736 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1737 /* Now try success cases */
1738 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1741 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1742 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1743 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1744 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1747 BLOBHEADER *hdr = (BLOBHEADER *)buf;
1748 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1750 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1751 rsaPubKeys[i].decodedModulusLen,
1752 "Expected size at least %d, got %ld\n",
1753 sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1754 rsaPubKeys[i].decodedModulusLen, bufSize);
1755 ok(hdr->bType == PUBLICKEYBLOB,
1756 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1758 ok(hdr->bVersion == CUR_BLOB_VERSION,
1759 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1760 CUR_BLOB_VERSION, hdr->bVersion);
1761 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1763 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1764 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1765 ok(rsaPubKey->magic == 0x31415352,
1766 "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1767 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1768 "Expected bit len %d, got %ld\n",
1769 rsaPubKeys[i].decodedModulusLen * 8, rsaPubKey->bitlen);
1770 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1772 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1773 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1774 "Unexpected modulus\n");
1780 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1781 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1782 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1784 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1785 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1786 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1787 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1789 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1791 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1792 CRYPT_SEQUENCE_OF_ANY seq;
1798 /* Encode a homogenous sequence */
1799 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1801 blobs[i].cbData = ints[i].encoded[1] + 2;
1802 blobs[i].pbData = (BYTE *)ints[i].encoded;
1804 seq.cValue = sizeof(ints) / sizeof(ints[0]);
1805 seq.rgValue = blobs;
1807 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1808 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1809 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1812 ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1813 sizeof(intSequence), bufSize);
1814 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1817 /* Change the type of the first element in the sequence, and give it
1820 blobs[0].cbData = times[0].encodedTime[1] + 2;
1821 blobs[0].pbData = (BYTE *)times[0].encodedTime;
1822 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1823 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1824 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1827 ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1828 sizeof(mixedSequence), bufSize);
1829 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1830 "Unexpected value\n");
1835 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1841 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1842 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1843 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1846 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1849 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1850 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1852 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1854 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1855 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1856 seq->rgValue[i].cbData);
1857 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1858 ints[i].encoded[1] + 2), "Unexpected value\n");
1862 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1863 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1865 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1868 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1870 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1871 "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1873 /* Just check the first element since it's all that changed */
1874 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1875 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1876 seq->rgValue[0].cbData);
1877 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1878 times[0].encodedTime[1] + 2), "Unexpected value\n");
1883 struct encodedExtensions
1885 CERT_EXTENSIONS exts;
1886 const BYTE *encoded;
1889 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1890 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1892 static CERT_EXTENSION criticalExt =
1893 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1894 static CERT_EXTENSION nonCriticalExt =
1895 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1897 static const BYTE ext0[] = { 0x30,0x00 };
1898 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1899 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1900 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1901 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1903 static const struct encodedExtensions exts[] = {
1904 { { 0, NULL }, ext0 },
1905 { { 1, &criticalExt }, ext1 },
1906 { { 1, &nonCriticalExt }, ext2 },
1909 static void test_encodeExtensions(DWORD dwEncoding)
1913 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1919 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1920 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1921 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1924 ok(bufSize == exts[i].encoded[1] + 2,
1925 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1926 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1927 "Unexpected value\n");
1933 static void test_decodeExtensions(DWORD dwEncoding)
1937 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1943 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1944 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1945 NULL, (BYTE *)&buf, &bufSize);
1946 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1949 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1952 ok(ext->cExtension == exts[i].exts.cExtension,
1953 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1955 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1957 ok(!strcmp(ext->rgExtension[j].pszObjId,
1958 exts[i].exts.rgExtension[j].pszObjId),
1959 "Expected OID %s, got %s\n",
1960 exts[i].exts.rgExtension[j].pszObjId,
1961 ext->rgExtension[j].pszObjId);
1962 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1963 exts[i].exts.rgExtension[j].Value.pbData,
1964 exts[i].exts.rgExtension[j].Value.cbData),
1965 "Unexpected value\n");
1972 /* MS encodes public key info with a NULL if the algorithm identifier's
1973 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
1974 * it encodes them by omitting the algorithm parameters. This latter approach
1975 * seems more correct, so accept either form.
1977 struct encodedPublicKey
1979 CERT_PUBLIC_KEY_INFO info;
1980 const BYTE *encoded;
1981 const BYTE *encodedNoNull;
1982 CERT_PUBLIC_KEY_INFO decoded;
1985 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1987 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1989 static const unsigned char bin64[] = {
1990 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
1991 static const unsigned char bin65[] = {
1992 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
1993 static const unsigned char bin66[] = {
1994 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
1995 static const unsigned char bin67[] = {
1996 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
1997 static const unsigned char bin68[] = {
1998 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1999 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2000 static const unsigned char bin69[] = {
2001 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
2002 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2003 static const unsigned char bin70[] = {
2004 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2005 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2007 static const unsigned char bin71[] = {
2008 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2009 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2011 static unsigned char bin72[] = { 0x05,0x00};
2013 static const struct encodedPublicKey pubKeys[] = {
2014 /* with a bogus OID */
2015 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
2017 { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
2018 /* some normal keys */
2019 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
2021 { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
2022 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2024 { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2025 /* with add'l parameters--note they must be DER-encoded */
2026 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2027 (BYTE *)aKey, 0 } },
2029 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2030 (BYTE *)aKey, 0 } } },
2033 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2037 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2043 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2044 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2046 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2049 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2050 bufSize == pubKeys[i].encodedNoNull[1] + 2,
2051 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2052 pubKeys[i].encodedNoNull[1] + 2, bufSize);
2053 if (bufSize == pubKeys[i].encoded[1] + 2)
2054 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2055 "Unexpected value\n");
2056 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2057 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2058 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2064 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2065 const CERT_PUBLIC_KEY_INFO *got)
2067 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2068 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2069 got->Algorithm.pszObjId);
2070 ok(expected->Algorithm.Parameters.cbData ==
2071 got->Algorithm.Parameters.cbData,
2072 "Expected parameters of %ld bytes, got %ld\n",
2073 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2074 if (expected->Algorithm.Parameters.cbData)
2075 ok(!memcmp(expected->Algorithm.Parameters.pbData,
2076 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2077 "Unexpected algorithm parameters\n");
2078 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2079 "Expected public key of %ld bytes, got %ld\n",
2080 expected->PublicKey.cbData, got->PublicKey.cbData);
2081 if (expected->PublicKey.cbData)
2082 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2083 got->PublicKey.cbData), "Unexpected public key value\n");
2086 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2088 static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2089 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2090 0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2091 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2097 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2099 /* The NULL form decodes to the decoded member */
2100 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2101 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2102 NULL, (BYTE *)&buf, &bufSize);
2103 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2106 comparePublicKeyInfo(&pubKeys[i].decoded,
2107 (CERT_PUBLIC_KEY_INFO *)buf);
2110 /* The non-NULL form decodes to the original */
2111 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2112 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2113 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2114 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2117 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2121 /* Test with bogus (not valid DER) parameters */
2122 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2123 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2124 NULL, (BYTE *)&buf, &bufSize);
2125 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2126 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2129 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2130 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2131 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2132 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2133 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2134 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2135 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2136 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2137 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2138 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2139 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2140 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2141 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2142 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2143 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2144 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2145 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2146 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2147 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2148 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2149 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2150 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2151 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2152 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2153 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2154 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2155 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2156 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2157 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2158 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2159 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2160 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2161 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2162 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2163 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2164 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2165 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2166 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2167 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2169 /* This is the encoded form of the printable string "Juan Lang" */
2170 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
2171 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
2172 0x61, 0x6e, 0x67, 0x00 };
2173 static const BYTE serialNum[] = { 0x01 };
2175 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2180 CERT_INFO info = { 0 };
2182 /* Test with NULL pvStructInfo */
2183 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2184 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2185 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2186 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2187 /* Test with a V1 cert */
2188 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2189 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2190 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2193 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2194 v1Cert[1] + 2, size);
2195 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2199 info.dwVersion = CERT_V2;
2200 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2201 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2202 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2205 ok(size == sizeof(v2Cert), "Expected size %d, got %ld\n",
2206 sizeof(v2Cert), size);
2207 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2211 info.dwVersion = CERT_V3;
2212 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2213 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2214 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2217 ok(size == sizeof(v3Cert), "Expected size %d, got %ld\n",
2218 sizeof(v3Cert), size);
2219 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2222 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2223 * API doesn't prevent it)
2225 info.dwVersion = CERT_V1;
2226 info.cExtension = 1;
2227 info.rgExtension = &criticalExt;
2228 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2229 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2230 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2233 ok(size == sizeof(v1CertWithConstraints), "Expected size %d, got %ld\n",
2234 sizeof(v1CertWithConstraints), size);
2235 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2238 /* test v1 cert with a serial number */
2239 info.SerialNumber.cbData = sizeof(serialNum);
2240 info.SerialNumber.pbData = (BYTE *)serialNum;
2241 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2242 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2245 ok(size == sizeof(v1CertWithSerial), "Expected size %d, got %ld\n",
2246 sizeof(v1CertWithSerial), size);
2247 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2250 /* Test v1 cert with an issuer name, a subject name, and a serial number */
2251 info.Issuer.cbData = sizeof(encodedCommonName);
2252 info.Issuer.pbData = (BYTE *)encodedCommonName;
2253 info.Subject.cbData = sizeof(encodedCommonName);
2254 info.Subject.pbData = (BYTE *)encodedCommonName;
2255 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2256 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2259 ok(size == sizeof(bigCert), "Expected size %d, got %ld\n",
2260 sizeof(bigCert), size);
2261 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2264 /* for now, I let more interesting tests be done for each subcomponent,
2265 * rather than retesting them all here.
2269 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2271 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2272 v1CertWithConstraints, v1CertWithSerial };
2277 /* Test with NULL pbEncoded */
2278 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2279 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2280 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2281 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2282 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2283 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2284 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2285 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2286 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2287 * minimum a cert must have a non-zero serial number, an issuer, and a
2290 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2292 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2293 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2294 (BYTE *)&buf, &size);
2295 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2296 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2298 /* Now check with serial number, subject and issuer specified */
2299 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2300 sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2301 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2304 CERT_INFO *info = (CERT_INFO *)buf;
2306 ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
2307 sizeof(CERT_INFO), size);
2308 ok(info->SerialNumber.cbData == 1,
2309 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2310 ok(*info->SerialNumber.pbData == *serialNum,
2311 "Expected serial number %d, got %d\n", *serialNum,
2312 *info->SerialNumber.pbData);
2313 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2314 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2315 info->Issuer.cbData);
2316 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2317 "Unexpected issuer\n");
2318 ok(info->Subject.cbData == sizeof(encodedCommonName),
2319 "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
2320 info->Subject.cbData);
2321 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2322 info->Subject.cbData), "Unexpected subject\n");
2327 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2330 static const BYTE signedBigCert[] = {
2331 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2332 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2333 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2334 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2335 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2336 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2337 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2338 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2339 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2340 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2341 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2342 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2344 static void test_encodeCert(DWORD dwEncoding)
2346 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
2347 * also that bigCert is a NULL-terminated string, so don't count its
2348 * last byte (otherwise the signed cert won't decode.)
2350 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2351 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2356 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2357 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2358 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2361 ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
2362 sizeof(signedBigCert), bufSize);
2363 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2368 static void test_decodeCert(DWORD dwEncoding)
2374 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2375 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2376 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2379 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2381 ok(info->ToBeSigned.cbData == sizeof(bigCert),
2382 "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert),
2383 info->ToBeSigned.cbData);
2384 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2385 "Unexpected cert\n");
2386 ok(info->Signature.cbData == sizeof(hash),
2387 "Expected signature size %d, got %ld\n", sizeof(hash),
2388 info->Signature.cbData);
2389 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2390 "Unexpected signature\n");
2395 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2396 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2397 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2398 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2399 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2401 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2402 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2403 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2404 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2405 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2406 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2407 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2408 0x2e, 0x6f, 0x72, 0x67 };
2409 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2410 CRL_REASON_AFFILIATION_CHANGED;
2412 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2414 CRL_DIST_POINTS_INFO info = { 0 };
2415 CRL_DIST_POINT point = { { 0 } };
2416 CERT_ALT_NAME_ENTRY entry = { 0 };
2421 /* Test with an empty info */
2422 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2423 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2424 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
2425 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
2427 /* Test with one empty dist point */
2428 info.cDistPoint = 1;
2429 info.rgDistPoint = &point;
2430 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2431 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2434 ok(size == sizeof(emptyDistPoint), "Expected size %d, got %ld\n",
2435 sizeof(emptyDistPoint), size);
2436 ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2439 /* A dist point with an invalid name */
2440 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2441 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2442 U(entry).pwszURL = (LPWSTR)nihongoURL;
2443 U(point.DistPointName).FullName.cAltEntry = 1;
2444 U(point.DistPointName).FullName.rgAltEntry = &entry;
2445 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2446 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2447 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2448 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2449 /* The first invalid character is at index 7 */
2450 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2451 "Expected invalid char at index 7, got %ld\n",
2452 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2453 /* A dist point with (just) a valid name */
2454 U(entry).pwszURL = (LPWSTR)url;
2455 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2456 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2459 ok(size == sizeof(distPointWithUrl), "Expected size %d, got %ld\n",
2460 sizeof(distPointWithUrl), size);
2461 ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2464 /* A dist point with (just) reason flags */
2465 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2466 point.ReasonFlags.cbData = sizeof(crlReason);
2467 point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2468 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2469 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2472 ok(size == sizeof(distPointWithReason), "Expected size %d, got %ld\n",
2473 sizeof(distPointWithReason), size);
2474 ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2477 /* A dist point with just an issuer */
2478 point.ReasonFlags.cbData = 0;
2479 point.CRLIssuer.cAltEntry = 1;
2480 point.CRLIssuer.rgAltEntry = &entry;
2481 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2482 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2485 ok(size == sizeof(distPointWithIssuer), "Expected size %d, got %ld\n",
2486 sizeof(distPointWithIssuer), size);
2487 ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2490 /* A dist point with both a name and an issuer */
2491 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2492 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2493 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2496 ok(size == sizeof(distPointWithUrlAndIssuer),
2497 "Expected size %d, got %ld\n", sizeof(distPointWithUrlAndIssuer),
2499 ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2504 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2509 PCRL_DIST_POINTS_INFO info;
2510 PCRL_DIST_POINT point;
2511 PCERT_ALT_NAME_ENTRY entry;
2513 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2514 emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2515 (BYTE *)&buf, &size);
2518 info = (PCRL_DIST_POINTS_INFO)buf;
2519 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2520 "Expected size at least %d, got %ld\n",
2521 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2522 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2524 point = info->rgDistPoint;
2525 ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2526 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2527 point->DistPointName.dwDistPointNameChoice);
2528 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2529 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2532 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2533 distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2534 (BYTE *)&buf, &size);
2537 info = (PCRL_DIST_POINTS_INFO)buf;
2538 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2539 "Expected size at least %d, got %ld\n",
2540 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2541 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2543 point = info->rgDistPoint;
2544 ok(point->DistPointName.dwDistPointNameChoice ==
2545 CRL_DIST_POINT_FULL_NAME,
2546 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2547 point->DistPointName.dwDistPointNameChoice);
2548 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2549 "Expected 1 name entry, got %ld\n",
2550 U(point->DistPointName).FullName.cAltEntry);
2551 entry = U(point->DistPointName).FullName.rgAltEntry;
2552 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2553 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2554 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2555 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2556 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2559 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2560 distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2561 NULL, (BYTE *)&buf, &size);
2564 info = (PCRL_DIST_POINTS_INFO)buf;
2565 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2566 "Expected size at least %d, got %ld\n",
2567 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2568 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2570 point = info->rgDistPoint;
2571 ok(point->DistPointName.dwDistPointNameChoice ==
2572 CRL_DIST_POINT_NO_NAME,
2573 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2574 point->DistPointName.dwDistPointNameChoice);
2575 ok(point->ReasonFlags.cbData == sizeof(crlReason),
2576 "Expected reason length\n");
2577 ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2578 "Unexpected reason\n");
2579 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2582 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2583 distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2584 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2587 info = (PCRL_DIST_POINTS_INFO)buf;
2588 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2589 "Expected size at least %d, got %ld\n",
2590 sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2591 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2593 point = info->rgDistPoint;
2594 ok(point->DistPointName.dwDistPointNameChoice ==
2595 CRL_DIST_POINT_FULL_NAME,
2596 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2597 point->DistPointName.dwDistPointNameChoice);
2598 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2599 "Expected 1 name entry, got %ld\n",
2600 U(point->DistPointName).FullName.cAltEntry);
2601 entry = U(point->DistPointName).FullName.rgAltEntry;
2602 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2603 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2604 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2605 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2606 ok(point->CRLIssuer.cAltEntry == 1,
2607 "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2608 entry = point->CRLIssuer.rgAltEntry;
2609 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2610 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2611 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2616 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2617 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2619 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2620 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2621 0x30, 0x30, 0x30, 0x30, 0x5a };
2622 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2623 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2624 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2625 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2627 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2628 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2629 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2630 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2631 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2632 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2633 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2634 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2635 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2636 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2637 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2638 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2639 static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
2640 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2641 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
2642 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2643 0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2644 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
2645 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2646 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2648 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2653 CRL_INFO info = { 0 };
2654 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2656 /* Test with a V1 CRL */
2657 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2658 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2659 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2662 ok(size == sizeof(v1CRL), "Expected size %d, got %ld\n",
2663 sizeof(v1CRL), size);
2664 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2668 info.dwVersion = CRL_V2;
2669 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2670 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2671 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2674 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2675 v2CRL[1] + 2, size);
2676 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2679 /* v1 CRL with a name */
2680 info.dwVersion = CRL_V1;
2681 info.Issuer.cbData = sizeof(encodedCommonName);
2682 info.Issuer.pbData = (BYTE *)encodedCommonName;
2683 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2684 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2685 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2688 ok(size == sizeof(v1CRLWithIssuer), "Expected size %d, got %ld\n",
2689 sizeof(v1CRLWithIssuer), size);
2690 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2693 /* v1 CRL with a name and a NULL entry pointer */
2695 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2696 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2697 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2698 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2699 /* now set an empty entry */
2700 info.rgCRLEntry = &entry;
2701 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2702 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2705 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2706 "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEmptyEntry),
2708 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2709 "Got unexpected value\n");
2712 /* an entry with a serial number */
2713 entry.SerialNumber.cbData = sizeof(serialNum);
2714 entry.SerialNumber.pbData = (BYTE *)serialNum;
2715 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2716 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2719 ok(size == sizeof(v1CRLWithIssuerAndEntry),
2720 "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEntry), size);
2721 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2722 "Got unexpected value\n");
2725 /* and finally, an entry with an extension */
2726 entry.cExtension = 1;
2727 entry.rgExtension = &criticalExt;
2728 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2729 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2730 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2733 ok(size == sizeof(v1CRLWithExt), "Expected size %d, got %ld\n",
2734 sizeof(v1CRLWithExt), size);
2735 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2740 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
2742 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
2747 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
2749 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2750 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2751 (BYTE *)&buf, &size);
2752 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2753 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2755 /* at a minimum, a CRL must contain an issuer: */
2756 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2757 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2758 (BYTE *)&buf, &size);
2759 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2762 CRL_INFO *info = (CRL_INFO *)buf;
2764 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2765 sizeof(CRL_INFO), size);
2766 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
2768 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2769 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2770 info->Issuer.cbData);
2771 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2772 "Unexpected issuer\n");
2775 /* check decoding with an empty CRL entry */
2776 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2777 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
2778 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2779 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2780 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2781 /* with a real CRL entry */
2782 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2783 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
2784 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2785 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2788 CRL_INFO *info = (CRL_INFO *)buf;
2791 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2792 sizeof(CRL_INFO), size);
2793 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2795 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2796 entry = info->rgCRLEntry;
2797 ok(entry->SerialNumber.cbData == 1,
2798 "Expected serial number size 1, got %ld\n",
2799 entry->SerialNumber.cbData);
2800 ok(*entry->SerialNumber.pbData == *serialNum,
2801 "Expected serial number %d, got %d\n", *serialNum,
2802 *entry->SerialNumber.pbData);
2803 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2804 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2805 info->Issuer.cbData);
2806 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2807 "Unexpected issuer\n");
2809 /* and finally, with an extension */
2810 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2811 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2812 NULL, (BYTE *)&buf, &size);
2813 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2816 CRL_INFO *info = (CRL_INFO *)buf;
2819 ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2820 sizeof(CRL_INFO), size);
2821 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2823 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2824 entry = info->rgCRLEntry;
2825 ok(entry->SerialNumber.cbData == 1,
2826 "Expected serial number size 1, got %ld\n",
2827 entry->SerialNumber.cbData);
2828 ok(*entry->SerialNumber.pbData == *serialNum,
2829 "Expected serial number %d, got %d\n", *serialNum,
2830 *entry->SerialNumber.pbData);
2831 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2832 "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2833 info->Issuer.cbData);
2834 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2835 "Unexpected issuer\n");
2836 /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2837 * bug, or am I missing something?
2839 ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2844 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
2845 szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
2846 static const BYTE encodedUsage[] = {
2847 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
2848 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
2849 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
2851 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
2856 CERT_ENHKEY_USAGE usage;
2858 /* Test with empty usage */
2859 usage.cUsageIdentifier = 0;
2860 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
2861 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2862 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2865 ok(size == sizeof(emptySequence), "Expected size %d, got %ld\n",
2866 sizeof(emptySequence), size);
2867 ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
2870 /* Test with a few usages */
2871 usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
2872 usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
2873 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
2874 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2875 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2878 ok(size == sizeof(encodedUsage), "Expected size %d, got %ld\n",
2879 sizeof(encodedUsage), size);
2880 ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
2885 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
2891 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
2892 emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
2893 (BYTE *)&buf, &size);
2894 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2897 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
2899 ok(size >= sizeof(CERT_ENHKEY_USAGE),
2900 "Expected size at least %d, got %ld\n", sizeof(CERT_ENHKEY_USAGE),
2902 ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
2903 usage->cUsageIdentifier);
2906 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
2907 encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
2908 (BYTE *)&buf, &size);
2909 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2912 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
2915 ok(size >= sizeof(CERT_ENHKEY_USAGE),
2916 "Expected size at least %d, got %ld\n", sizeof(CERT_ENHKEY_USAGE),
2918 ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
2919 "Expected %d CRL entries, got %ld\n",
2920 sizeof(keyUsages) / sizeof(keyUsages[0]),
2921 usage->cUsageIdentifier);
2922 for (i = 0; i < usage->cUsageIdentifier; i++)
2923 ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
2924 "Expected OID %s, got %s\n", keyUsages[i],
2925 usage->rgpszUsageIdentifier[i]);
2930 /* Free *pInfo with HeapFree */
2931 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
2938 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
2940 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
2941 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2942 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2943 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
2945 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2946 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2947 ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
2949 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2950 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2951 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2952 0, NULL, NULL, &size);
2953 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2954 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2955 /* Test with no key */
2956 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2957 0, NULL, NULL, &size);
2958 ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
2960 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
2961 ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
2964 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
2965 NULL, 0, NULL, NULL, &size);
2966 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2967 *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
2970 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
2971 X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
2972 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
2976 /* By default (we passed NULL as the OID) the OID is
2979 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
2980 "Expected %s, got %s\n", szOID_RSA_RSA,
2981 (*pInfo)->Algorithm.pszObjId);
2987 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
2993 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
2994 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
2995 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
2996 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2999 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3000 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3001 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3002 ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3003 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3004 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3005 ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3007 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3008 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3009 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3011 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3012 CryptDestroyKey(key);
3015 static const char cspName[] = "WineCryptTemp";
3017 static void testPortPublicKeyInfo(void)
3021 PCERT_PUBLIC_KEY_INFO info = NULL;
3023 /* Just in case a previous run failed, delete this thing */
3024 CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3025 CRYPT_DELETEKEYSET);
3026 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3029 testExportPublicKey(csp, &info);
3030 testImportPublicKey(csp, info);
3032 HeapFree(GetProcessHeap(), 0, info);
3033 CryptReleaseContext(csp, 0);
3034 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3035 CRYPT_DELETEKEYSET);
3040 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3041 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3044 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3046 test_encodeInt(encodings[i]);
3047 test_decodeInt(encodings[i]);
3048 test_encodeEnumerated(encodings[i]);
3049 test_decodeEnumerated(encodings[i]);
3050 test_encodeFiletime(encodings[i]);
3051 test_decodeFiletime(encodings[i]);
3052 test_encodeName(encodings[i]);
3053 test_decodeName(encodings[i]);
3054 test_encodeAltName(encodings[i]);
3055 test_decodeAltName(encodings[i]);
3056 test_encodeOctets(encodings[i]);
3057 test_decodeOctets(encodings[i]);
3058 test_encodeBits(encodings[i]);
3059 test_decodeBits(encodings[i]);
3060 test_encodeBasicConstraints(encodings[i]);
3061 test_decodeBasicConstraints(encodings[i]);
3062 test_encodeRsaPublicKey(encodings[i]);
3063 test_decodeRsaPublicKey(encodings[i]);
3064 test_encodeSequenceOfAny(encodings[i]);
3065 test_decodeSequenceOfAny(encodings[i]);
3066 test_encodeExtensions(encodings[i]);
3067 test_decodeExtensions(encodings[i]);
3068 test_encodePublicKeyInfo(encodings[i]);
3069 test_decodePublicKeyInfo(encodings[i]);
3070 test_encodeCertToBeSigned(encodings[i]);
3071 test_decodeCertToBeSigned(encodings[i]);
3072 test_encodeCert(encodings[i]);
3073 test_decodeCert(encodings[i]);
3074 test_encodeCRLDistPoints(encodings[i]);
3075 test_decodeCRLDistPoints(encodings[i]);
3076 test_encodeCRLToBeSigned(encodings[i]);
3077 test_decodeCRLToBeSigned(encodings[i]);
3078 test_encodeEnhancedKeyUsage(encodings[i]);
3079 test_decodeEnhancedKeyUsage(encodings[i]);
3081 testPortPublicKeyInfo();