crypt32/tests: Don't use sizeof in ok() to avoid printf format warnings.
[wine.git] / dlls / crypt32 / tests / encode.c
blobf587bbd5d19bd37bec30ae1d595ecc3476f29bce
1 /*
2 * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
4 * Copyright 2005 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
27 #include "wine/test.h"
29 struct encodedInt
31 int val;
32 const BYTE *encoded;
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[] = {
44 { 1, bin1 },
45 { 127, bin2 },
46 { 128, bin3 },
47 { 256, bin4 },
48 { -128, bin5 },
49 { -129, bin6 },
50 { 0xbaddf00d, bin7 },
53 struct encodedBigInt
55 const BYTE *val;
56 const BYTE *encoded;
57 const BYTE *decoded;
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)
86 DWORD bufSize = 0;
87 int i;
88 BOOL ret;
89 CRYPT_INTEGER_BLOB blob;
90 BYTE *buf = NULL;
92 /* CryptEncodeObjectEx with NULL bufSize crashes..
93 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
94 NULL);
96 /* check bogus encoding */
97 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
98 &bufSize);
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
102 * NTSTATUS.
104 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
105 &bufSize);
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());
117 if (buf)
119 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
120 buf[0]);
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);
125 LocalFree(buf);
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());
136 if (buf)
138 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
139 buf[0]);
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);
144 LocalFree(buf);
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());
160 if (buf)
162 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
163 buf[0]);
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");
169 LocalFree(buf);
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());
183 if (buf)
185 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
186 buf[0]);
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");
192 LocalFree(buf);
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 };
203 BYTE *buf = NULL;
204 DWORD bufSize = 0;
205 int i;
206 BOOL ret;
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,
219 &bufSize);
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,
238 &bufSize);
239 ok(ret && GetLastError() == NOERROR,
240 "Expected success and NOERROR, got %ld\n", GetLastError());
241 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
242 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
243 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
244 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
245 ok(bufSize == sizeof(int), "Wrong size %ld\n", bufSize);
246 ok(buf != NULL, "Expected allocated buffer\n");
247 if (buf)
249 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
250 ints[i].val, *(int *)buf);
251 LocalFree(buf);
254 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
256 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
257 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
258 &bufSize);
259 ok(ret && GetLastError() == NOERROR,
260 "Expected success and NOERROR, got %ld\n", GetLastError());
261 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
262 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
263 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
264 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
265 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %ld\n", bufSize);
266 ok(buf != NULL, "Expected allocated buffer\n");
267 if (buf)
269 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
271 ok(blob->cbData == strlen((const char*)bigInts[i].decoded),
272 "Expected len %d, got %ld\n", lstrlenA((const char*)bigInts[i].decoded),
273 blob->cbData);
274 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
275 "Unexpected value\n");
276 LocalFree(buf);
279 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
281 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
282 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
283 &bufSize);
284 ok(ret && GetLastError() == NOERROR,
285 "Expected success and NOERROR, got %ld\n", GetLastError());
286 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
287 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
288 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
289 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
290 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %ld\n", bufSize);
291 ok(buf != NULL, "Expected allocated buffer\n");
292 if (buf)
294 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
296 ok(blob->cbData == strlen((const char*)bigUInts[i].val),
297 "Expected len %d, got %ld\n", lstrlenA((const char*)bigUInts[i].val),
298 blob->cbData);
299 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
300 "Unexpected value\n");
301 LocalFree(buf);
304 /* Decode the value 1 with long-form length */
305 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
306 sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
307 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
308 if (buf)
310 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
311 LocalFree(buf);
313 /* Try to decode some bogus large items */
314 /* The buffer size is smaller than the encoded length, so this should fail
315 * with CRYPT_E_ASN1_EOD if it's being decoded.
316 * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
317 * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
318 * So this test unfortunately isn't useful.
319 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
320 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
321 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
322 "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
324 /* This will try to decode the buffer and overflow it, check that it's
325 * caught.
327 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
328 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
329 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
330 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
333 static const BYTE bin18[] = {0x0a,0x01,0x01};
334 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80};
336 /* These are always encoded unsigned, and aren't constrained to be any
337 * particular value
339 static const struct encodedInt enums[] = {
340 { 1, bin18 },
341 { -128, bin19 },
344 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
345 * X509_ENUMERATED.
347 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
348 szOID_CRL_REASON_CODE };
350 static void test_encodeEnumerated(DWORD dwEncoding)
352 DWORD i, j;
354 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
356 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
358 BOOL ret;
359 BYTE *buf = NULL;
360 DWORD bufSize = 0;
362 ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
363 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
364 &bufSize);
365 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
366 if (buf)
368 ok(buf[0] == 0xa,
369 "Got unexpected type %d for enumerated (expected 0xa)\n",
370 buf[0]);
371 ok(buf[1] == enums[j].encoded[1],
372 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
373 ok(!memcmp(buf + 1, enums[j].encoded + 1,
374 enums[j].encoded[1] + 1),
375 "Encoded value of 0x%08x didn't match expected\n",
376 enums[j].val);
377 LocalFree(buf);
383 static void test_decodeEnumerated(DWORD dwEncoding)
385 DWORD i, j;
387 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
389 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
391 BOOL ret;
392 DWORD bufSize = sizeof(int);
393 int val;
395 ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
396 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
397 (BYTE *)&val, &bufSize);
398 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
399 ok(bufSize == sizeof(int),
400 "Got unexpected size %ld for enumerated\n", bufSize);
401 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
402 val, enums[j].val);
407 struct encodedFiletime
409 SYSTEMTIME sysTime;
410 const BYTE *encodedTime;
413 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
414 const struct encodedFiletime *time)
416 FILETIME ft = { 0 };
417 BYTE *buf = NULL;
418 DWORD bufSize = 0;
419 BOOL ret;
421 ret = SystemTimeToFileTime(&time->sysTime, &ft);
422 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
423 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
424 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
425 /* years other than 1950-2050 are not allowed for encodings other than
426 * X509_CHOICE_OF_TIME.
428 if (structType == X509_CHOICE_OF_TIME ||
429 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
431 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
432 GetLastError());
433 ok(buf != NULL, "Expected an allocated buffer\n");
434 if (buf)
436 ok(buf[0] == time->encodedTime[0],
437 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
438 buf[0]);
439 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
440 time->encodedTime[1], bufSize);
441 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
442 "Got unexpected value for time encoding\n");
443 LocalFree(buf);
446 else
447 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
448 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
451 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
452 const struct encodedFiletime *time)
454 FILETIME ft1 = { 0 }, ft2 = { 0 };
455 DWORD size = sizeof(ft2);
456 BOOL ret;
458 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
459 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
460 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
461 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
462 /* years other than 1950-2050 are not allowed for encodings other than
463 * X509_CHOICE_OF_TIME.
465 if (structType == X509_CHOICE_OF_TIME ||
466 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
468 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
469 GetLastError());
470 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
471 "Got unexpected value for time decoding\n");
473 else
474 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
475 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
478 static const BYTE bin20[] = {
479 0x17,0x0d,'0','5','0','6','0','6','1','6','1','0','0','0','Z'};
480 static const BYTE bin21[] = {
481 0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
482 static const BYTE bin22[] = {
483 0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
485 static const struct encodedFiletime times[] = {
486 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 },
487 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 },
488 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 },
491 static void test_encodeFiletime(DWORD dwEncoding)
493 DWORD i;
495 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
497 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
498 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
499 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
503 static const BYTE bin23[] = {
504 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','0','0','0','Z'};
505 static const BYTE bin24[] = {
506 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','9','9','9','Z'};
507 static const BYTE bin25[] = {
508 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','+','0','1','0','0'};
509 static const BYTE bin26[] = {
510 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','0','0'};
511 static const BYTE bin27[] = {
512 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','1','5'};
513 static const BYTE bin28[] = {
514 0x18,0x0a,'2','1','4','5','0','6','0','6','1','6'};
515 static const BYTE bin29[] = {
516 0x17,0x0a,'4','5','0','6','0','6','1','6','1','0'};
517 static const BYTE bin30[] = {
518 0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z'};
519 static const BYTE bin31[] = {
520 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1'};
521 static const BYTE bin32[] = {
522 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1'};
523 static const BYTE bin33[] = {
524 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0'};
525 static const BYTE bin34[] = {
526 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0'};
527 static const BYTE bin35[] = {
528 0x17,0x08, '4','5','0','6','0','6','1','6'};
529 static const BYTE bin36[] = {
530 0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z'};
531 static const BYTE bin37[] = {
532 0x18,0x04, '2','1','4','5'};
533 static const BYTE bin38[] = {
534 0x18,0x08, '2','1','4','5','0','6','0','6'};
536 static void test_decodeFiletime(DWORD dwEncoding)
538 static const struct encodedFiletime otherTimes[] = {
539 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin23 },
540 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 },
541 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, bin25 },
542 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, bin26 },
543 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, bin27 },
544 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, bin28 },
545 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin29 },
546 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin30 },
547 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin31 },
548 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin32 },
549 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin33 },
550 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin34 },
552 /* An oddball case that succeeds in Windows, but doesn't seem correct
553 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
555 static const unsigned char *bogusTimes[] = {
556 /* oddly, this succeeds on Windows, with year 2765
557 "\x18" "\x0f" "21r50606161000Z",
559 bin35,
560 bin36,
561 bin37,
562 bin38,
564 DWORD i, size;
565 FILETIME ft1 = { 0 }, ft2 = { 0 };
566 BOOL ret;
568 /* Check bogus length with non-NULL buffer */
569 ret = SystemTimeToFileTime(&times[0].sysTime, &ft1);
570 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
571 size = 1;
572 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
573 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
574 ok(!ret && GetLastError() == ERROR_MORE_DATA,
575 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
576 /* Normal tests */
577 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
579 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
580 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
581 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
583 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
585 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
586 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
587 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
589 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
591 size = sizeof(ft1);
592 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
593 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
594 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
595 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
599 static const char commonName[] = "Juan Lang";
600 static const char surName[] = "Lang";
602 static const BYTE emptySequence[] = { 0x30, 0 };
603 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
604 static const BYTE twoRDNs[] = {
605 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
606 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
607 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
609 static const BYTE us[] = { 0x55, 0x53 };
610 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
611 0x74, 0x61 };
612 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
613 0x6f, 0x6c, 0x69, 0x73 };
614 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
615 0x76, 0x65, 0x72, 0x73 };
616 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
617 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
618 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
619 0x73, 0x74 };
620 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
621 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
623 #define _blob_of(arr) { sizeof(arr), (LPBYTE)arr }
624 const CERT_RDN_ATTR rdnAttrs[] = {
625 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
626 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
627 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
628 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
629 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
630 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
631 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
633 const CERT_RDN_ATTR decodedRdnAttrs[] = {
634 { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, _blob_of(us) },
635 { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, _blob_of(localhostAttr) },
636 { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, _blob_of(minnesota) },
637 { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, _blob_of(minneapolis) },
638 { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, _blob_of(codeweavers) },
639 { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, _blob_of(wine) },
640 { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
642 #undef _blob_of
644 static const BYTE encodedRDNAttrs[] = {
645 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
646 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
647 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
648 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
649 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
650 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
651 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
652 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
653 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
654 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
657 static void test_encodeName(DWORD dwEncoding)
659 CERT_RDN_ATTR attrs[2];
660 CERT_RDN rdn;
661 CERT_NAME_INFO info;
662 BYTE *buf = NULL;
663 DWORD size = 0;
664 BOOL ret;
666 /* Test with NULL pvStructInfo */
667 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
668 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
669 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
670 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
671 /* Test with empty CERT_NAME_INFO */
672 info.cRDN = 0;
673 info.rgRDN = NULL;
674 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
675 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
676 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
677 if (buf)
679 ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
680 "Got unexpected encoding for empty name\n");
681 LocalFree(buf);
683 /* Test with bogus CERT_RDN */
684 info.cRDN = 1;
685 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
686 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
687 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
688 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
689 /* Test with empty CERT_RDN */
690 rdn.cRDNAttr = 0;
691 rdn.rgRDNAttr = NULL;
692 info.cRDN = 1;
693 info.rgRDN = &rdn;
694 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
695 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
696 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
697 if (buf)
699 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
700 "Got unexpected encoding for empty RDN array\n");
701 LocalFree(buf);
703 /* Test with bogus attr array */
704 rdn.cRDNAttr = 1;
705 rdn.rgRDNAttr = NULL;
706 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
707 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
708 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
709 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
710 /* oddly, a bogus OID is accepted by Windows XP; not testing.
711 attrs[0].pszObjId = "bogus";
712 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
713 attrs[0].Value.cbData = sizeof(commonName);
714 attrs[0].Value.pbData = (BYTE *)commonName;
715 rdn.cRDNAttr = 1;
716 rdn.rgRDNAttr = attrs;
717 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
718 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
719 ok(!ret, "Expected failure, got success\n");
721 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
722 * the encoded attributes to be swapped.
724 attrs[0].pszObjId = szOID_COMMON_NAME;
725 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
726 attrs[0].Value.cbData = sizeof(commonName);
727 attrs[0].Value.pbData = (BYTE *)commonName;
728 attrs[1].pszObjId = szOID_SUR_NAME;
729 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
730 attrs[1].Value.cbData = sizeof(surName);
731 attrs[1].Value.pbData = (BYTE *)surName;
732 rdn.cRDNAttr = 2;
733 rdn.rgRDNAttr = attrs;
734 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
735 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
736 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
737 if (buf)
739 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
740 "Got unexpected encoding for two RDN array\n");
741 LocalFree(buf);
743 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
744 rdn.cRDNAttr = 1;
745 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
746 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
747 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
748 ok(!ret && GetLastError() == E_INVALIDARG,
749 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
750 /* Test a more complex name */
751 rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
752 rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
753 info.cRDN = 1;
754 info.rgRDN = &rdn;
755 buf = NULL;
756 size = 0;
757 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
758 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
759 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
760 if (ret)
762 ok(size == sizeof(encodedRDNAttrs), "Wrong size %ld\n", size);
763 ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
764 LocalFree(buf);
768 static void compareNameValues(const CERT_NAME_VALUE *expected,
769 const CERT_NAME_VALUE *got)
771 ok(got->dwValueType == expected->dwValueType,
772 "Expected string type %ld, got %ld\n", expected->dwValueType,
773 got->dwValueType);
774 ok(got->Value.cbData == expected->Value.cbData,
775 "Unexpected data size, got %ld, expected %ld\n", got->Value.cbData,
776 expected->Value.cbData);
777 if (got->Value.cbData && got->Value.pbData)
778 ok(!memcmp(got->Value.pbData, expected->Value.pbData,
779 min(got->Value.cbData, expected->Value.cbData)), "Unexpected value\n");
782 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
783 const CERT_RDN_ATTR *got)
785 if (expected->pszObjId && strlen(expected->pszObjId))
787 ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
788 expected->pszObjId);
789 if (got->pszObjId)
791 ok(!strcmp(got->pszObjId, expected->pszObjId),
792 "Got unexpected OID %s, expected %s\n", got->pszObjId,
793 expected->pszObjId);
796 compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType,
797 (const CERT_NAME_VALUE *)&got->dwValueType);
800 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
802 ok(got->cRDNAttr == expected->cRDNAttr,
803 "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
804 if (got->cRDNAttr)
806 DWORD i;
808 for (i = 0; i < got->cRDNAttr; i++)
809 compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
813 static void compareNames(const CERT_NAME_INFO *expected,
814 const CERT_NAME_INFO *got)
816 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
817 expected->cRDN, got->cRDN);
818 if (got->cRDN)
820 DWORD i;
822 for (i = 0; i < got->cRDN; i++)
823 compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
827 static void test_decodeName(DWORD dwEncoding)
829 BYTE *buf = NULL;
830 DWORD bufSize = 0;
831 BOOL ret;
832 CERT_RDN rdn;
833 CERT_NAME_INFO info = { 1, &rdn };
835 /* test empty name */
836 bufSize = 0;
837 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
838 emptySequence[1] + 2,
839 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
840 (BYTE *)&buf, &bufSize);
841 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
842 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
843 * decoder works the same way, so only test the count.
845 if (buf)
847 ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %ld\n", bufSize);
848 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
849 "Expected 0 RDNs in empty info, got %ld\n",
850 ((CERT_NAME_INFO *)buf)->cRDN);
851 LocalFree(buf);
853 /* test empty RDN */
854 bufSize = 0;
855 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
856 emptyRDNs[1] + 2,
857 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
858 (BYTE *)&buf, &bufSize);
859 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
860 if (buf)
862 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
864 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
865 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
866 "Got unexpected value for empty RDN\n");
867 LocalFree(buf);
869 /* test two RDN attrs */
870 bufSize = 0;
871 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
872 twoRDNs[1] + 2,
873 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
874 (BYTE *)&buf, &bufSize);
875 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
876 if (buf)
878 CERT_RDN_ATTR attrs[] = {
879 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
880 (BYTE *)surName } },
881 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
882 (BYTE *)commonName } },
885 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
886 rdn.rgRDNAttr = attrs;
887 compareNames(&info, (CERT_NAME_INFO *)buf);
888 LocalFree(buf);
890 /* And, a slightly more complicated name */
891 buf = NULL;
892 bufSize = 0;
893 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
894 sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
895 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
896 if (ret)
898 rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
899 rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
900 compareNames(&info, (CERT_NAME_INFO *)buf);
901 LocalFree(buf);
905 struct EncodedNameValue
907 CERT_NAME_VALUE value;
908 const BYTE *encoded;
911 static const char bogusIA5[] = "\x80";
912 static const char bogusPrintable[] = "~";
913 static const char bogusNumeric[] = "A";
914 static const char bogusT61[] = "\xff";
915 static const BYTE bin39[] = { 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
916 0x67,0x00 };
917 static const BYTE bin40[] = { 0x16,0x05,0x4c,0x61,0x6e,0x67,0x00 };
918 static const BYTE bin41[] = { 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
919 0x67,0x00 };
920 static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
921 static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
922 static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
923 static const BYTE bin45[] = { 0x14,0x02,0xff,0x00 };
925 struct EncodedNameValue nameValues[] = {
926 { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
927 bin39 },
928 { { CERT_RDN_IA5_STRING, { sizeof(surName), (BYTE *)surName } }, bin40 },
929 { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } }, bin41 },
930 /* The following tests succeed under Windows, but really should fail,
931 * they contain characters that are illegal for the encoding. I'm
932 * including them to justify my lazy encoding.
934 { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42 },
935 { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable),
936 (BYTE *)bogusPrintable } }, bin43 },
937 { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
938 bin44 },
939 { { CERT_RDN_T61_STRING, { sizeof(bogusT61), (BYTE *)bogusT61 } }, bin45 },
943 static void test_encodeNameValue(DWORD dwEncoding)
945 BYTE *buf = NULL;
946 DWORD size = 0, i;
947 BOOL ret;
949 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
951 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE,
952 &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
953 &size);
954 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
955 if (buf)
957 ok(size == nameValues[i].encoded[1] + 2,
958 "Expected size %d, got %ld\n", nameValues[i].encoded[1] + 2, size);
959 ok(!memcmp(buf, nameValues[i].encoded, size),
960 "Got unexpected encoding\n");
961 LocalFree(buf);
966 static void test_decodeNameValue(DWORD dwEncoding)
968 int i;
969 BYTE *buf = NULL;
970 DWORD bufSize = 0;
971 BOOL ret;
973 for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
975 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE,
976 nameValues[i].encoded, nameValues[i].encoded[1] + 2,
977 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
978 (BYTE *)&buf, &bufSize);
979 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
980 if (buf)
982 compareNameValues(&nameValues[i].value,
983 (const CERT_NAME_VALUE *)buf);
984 LocalFree(buf);
989 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
990 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
991 'h','q','.','o','r','g',0 };
992 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
993 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
994 0x6f, 0x72, 0x67 };
995 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
996 0x575b, 0 };
997 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
998 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
999 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1000 static const BYTE localhost[] = { 127, 0, 0, 1 };
1001 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1002 0x01 };
1004 static void test_encodeAltName(DWORD dwEncoding)
1006 CERT_ALT_NAME_INFO info = { 0 };
1007 CERT_ALT_NAME_ENTRY entry = { 0 };
1008 BYTE *buf = NULL;
1009 DWORD size = 0;
1010 BOOL ret;
1012 /* Test with empty info */
1013 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1014 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1015 if (buf)
1017 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
1018 ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1019 LocalFree(buf);
1021 /* Test with an empty entry */
1022 info.cAltEntry = 1;
1023 info.rgAltEntry = &entry;
1024 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1025 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1026 ok(!ret && GetLastError() == E_INVALIDARG,
1027 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1028 /* Test with an empty pointer */
1029 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1030 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1031 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1032 if (buf)
1034 ok(size == sizeof(emptyURL), "Wrong size %ld\n", size);
1035 ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1036 LocalFree(buf);
1038 /* Test with a real URL */
1039 U(entry).pwszURL = (LPWSTR)url;
1040 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1041 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1042 if (buf)
1044 ok(size == sizeof(encodedURL), "Wrong size %ld\n", size);
1045 ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1046 LocalFree(buf);
1048 /* Now with the URL containing an invalid IA5 char */
1049 U(entry).pwszURL = (LPWSTR)nihongoURL;
1050 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1051 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1052 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1053 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1054 /* The first invalid character is at index 7 */
1055 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1056 "Expected invalid char at index 7, got %ld\n",
1057 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1058 /* Now with the URL missing a scheme */
1059 U(entry).pwszURL = (LPWSTR)dnsName;
1060 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1061 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1062 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1063 if (buf)
1065 /* This succeeds, but it shouldn't, so don't worry about conforming */
1066 LocalFree(buf);
1068 /* Now with a DNS name */
1069 entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1070 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1071 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1072 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1073 if (buf)
1075 ok(size == sizeof(encodedDnsName), "Wrong size %ld\n", size);
1076 ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1077 LocalFree(buf);
1079 /* Test with an IP address */
1080 entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1081 U(entry).IPAddress.cbData = sizeof(localhost);
1082 U(entry).IPAddress.pbData = (LPBYTE)localhost;
1083 ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1084 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1085 if (buf)
1087 ok(size == sizeof(encodedIPAddr), "Wrong size %ld\n", size);
1088 ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1089 LocalFree(buf);
1093 static void test_decodeAltName(DWORD dwEncoding)
1095 static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1096 0x00, 0x00, 0x01 };
1097 static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1098 0x01 };
1099 BOOL ret;
1100 BYTE *buf = NULL;
1101 DWORD bufSize = 0;
1102 CERT_ALT_NAME_INFO *info;
1104 /* Test some bogus ones first */
1105 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1106 unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1107 NULL, (BYTE *)&buf, &bufSize);
1108 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1109 "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1110 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1111 bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1112 &bufSize);
1113 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1114 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1115 /* Now expected cases */
1116 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1117 emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1118 &bufSize);
1119 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1120 if (buf)
1122 info = (CERT_ALT_NAME_INFO *)buf;
1124 ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1125 info->cAltEntry);
1126 LocalFree(buf);
1128 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1129 emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1130 &bufSize);
1131 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1132 if (buf)
1134 info = (CERT_ALT_NAME_INFO *)buf;
1136 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1137 info->cAltEntry);
1138 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1139 "Expected CERT_ALT_NAME_URL, got %ld\n",
1140 info->rgAltEntry[0].dwAltNameChoice);
1141 ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1142 "Expected empty URL\n");
1143 LocalFree(buf);
1145 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1146 encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1147 &bufSize);
1148 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1149 if (buf)
1151 info = (CERT_ALT_NAME_INFO *)buf;
1153 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1154 info->cAltEntry);
1155 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1156 "Expected CERT_ALT_NAME_URL, got %ld\n",
1157 info->rgAltEntry[0].dwAltNameChoice);
1158 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1159 LocalFree(buf);
1161 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1162 encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1163 &bufSize);
1164 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1165 if (buf)
1167 info = (CERT_ALT_NAME_INFO *)buf;
1169 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1170 info->cAltEntry);
1171 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1172 "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1173 info->rgAltEntry[0].dwAltNameChoice);
1174 ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1175 "Unexpected DNS name\n");
1176 LocalFree(buf);
1178 ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1179 encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1180 &bufSize);
1181 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1182 if (buf)
1184 info = (CERT_ALT_NAME_INFO *)buf;
1186 ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1187 info->cAltEntry);
1188 ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1189 "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1190 info->rgAltEntry[0].dwAltNameChoice);
1191 ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1192 "Unexpected IP address length %ld\n",
1193 U(info->rgAltEntry[0]).IPAddress.cbData);
1194 ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1195 sizeof(localhost)), "Unexpected IP address value\n");
1196 LocalFree(buf);
1200 struct encodedOctets
1202 const BYTE *val;
1203 const BYTE *encoded;
1206 static const unsigned char bin46[] = { 'h','i',0 };
1207 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1208 static const unsigned char bin48[] = {
1209 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1210 static const unsigned char bin49[] = {
1211 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1212 static const unsigned char bin50[] = { 0 };
1213 static const unsigned char bin51[] = { 0x04,0x00,0 };
1215 static const struct encodedOctets octets[] = {
1216 { bin46, bin47 },
1217 { bin48, bin49 },
1218 { bin50, bin51 },
1221 static void test_encodeOctets(DWORD dwEncoding)
1223 CRYPT_DATA_BLOB blob;
1224 DWORD i;
1226 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1228 BYTE *buf = NULL;
1229 BOOL ret;
1230 DWORD bufSize = 0;
1232 blob.cbData = strlen((const char*)octets[i].val);
1233 blob.pbData = (BYTE*)octets[i].val;
1234 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1235 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1236 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1237 if (buf)
1239 ok(buf[0] == 4,
1240 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1241 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1242 buf[1], octets[i].encoded[1]);
1243 ok(!memcmp(buf + 1, octets[i].encoded + 1,
1244 octets[i].encoded[1] + 1), "Got unexpected value\n");
1245 LocalFree(buf);
1250 static void test_decodeOctets(DWORD dwEncoding)
1252 DWORD i;
1254 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1256 BYTE *buf = NULL;
1257 BOOL ret;
1258 DWORD bufSize = 0;
1260 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1261 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1262 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1263 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1264 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1265 "Expected size >= %d, got %ld\n",
1266 (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1267 ok(buf != NULL, "Expected allocated buffer\n");
1268 if (buf)
1270 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1272 if (blob->cbData)
1273 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1274 "Unexpected value\n");
1275 LocalFree(buf);
1280 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1282 struct encodedBits
1284 DWORD cUnusedBits;
1285 const BYTE *encoded;
1286 DWORD cbDecoded;
1287 const BYTE *decoded;
1290 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1291 static const unsigned char bin53[] = { 0xff,0xff };
1292 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1293 static const unsigned char bin55[] = { 0xff,0xfe };
1294 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1295 static const unsigned char bin57[] = { 0xfe };
1296 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1298 static const struct encodedBits bits[] = {
1299 /* normal test cases */
1300 { 0, bin52, 2, bin53 },
1301 { 1, bin54, 2, bin55 },
1302 /* strange test case, showing cUnusedBits >= 8 is allowed */
1303 { 9, bin56, 1, bin57 },
1304 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1305 { 17, bin58, 0, NULL },
1308 static void test_encodeBits(DWORD dwEncoding)
1310 DWORD i;
1312 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1314 CRYPT_BIT_BLOB blob;
1315 BOOL ret;
1316 BYTE *buf = NULL;
1317 DWORD bufSize = 0;
1319 blob.cbData = sizeof(bytesToEncode);
1320 blob.pbData = (BYTE *)bytesToEncode;
1321 blob.cUnusedBits = bits[i].cUnusedBits;
1322 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1323 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1324 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1325 if (buf)
1327 ok(bufSize == bits[i].encoded[1] + 2,
1328 "Got unexpected size %ld, expected %d\n", bufSize,
1329 bits[i].encoded[1] + 2);
1330 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1331 "Unexpected value\n");
1332 LocalFree(buf);
1337 static void test_decodeBits(DWORD dwEncoding)
1339 static const BYTE ber[] = "\x03\x02\x01\xff";
1340 static const BYTE berDecoded = 0xfe;
1341 DWORD i;
1342 BOOL ret;
1343 BYTE *buf = NULL;
1344 DWORD bufSize = 0;
1346 /* normal cases */
1347 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1349 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1350 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1351 &bufSize);
1352 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1353 if (buf)
1355 CRYPT_BIT_BLOB *blob;
1357 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1358 "Got unexpected size %ld, expected >= %ld\n", bufSize,
1359 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1360 blob = (CRYPT_BIT_BLOB *)buf;
1361 ok(blob->cbData == bits[i].cbDecoded,
1362 "Got unexpected length %ld, expected %ld\n", blob->cbData,
1363 bits[i].cbDecoded);
1364 if (blob->cbData && bits[i].cbDecoded)
1365 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1366 "Unexpected value\n");
1367 LocalFree(buf);
1370 /* special case: check that something that's valid in BER but not in DER
1371 * decodes successfully
1373 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1374 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1375 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1376 if (buf)
1378 CRYPT_BIT_BLOB *blob;
1380 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1381 "Got unexpected size %ld\n", bufSize);
1382 blob = (CRYPT_BIT_BLOB *)buf;
1383 ok(blob->cbData == sizeof(berDecoded),
1384 "Got unexpected length %ld\n", blob->cbData);
1385 if (blob->cbData)
1386 ok(*blob->pbData == berDecoded, "Unexpected value\n");
1387 LocalFree(buf);
1391 struct Constraints2
1393 CERT_BASIC_CONSTRAINTS2_INFO info;
1394 const BYTE *encoded;
1397 static const unsigned char bin59[] = { 0x30,0x00 };
1398 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1399 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1400 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1401 static const struct Constraints2 constraints2[] = {
1402 /* empty constraints */
1403 { { FALSE, FALSE, 0}, bin59 },
1404 /* can be a CA */
1405 { { TRUE, FALSE, 0}, bin60 },
1406 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1407 * but that's not the case
1409 { { FALSE, TRUE, 0}, bin61 },
1410 /* can be a CA and has path length constraints set */
1411 { { TRUE, TRUE, 1}, bin62 },
1414 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1415 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1416 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1417 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1418 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1419 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1420 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1421 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1422 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1423 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1425 static void test_encodeBasicConstraints(DWORD dwEncoding)
1427 DWORD i, bufSize = 0;
1428 CERT_BASIC_CONSTRAINTS_INFO info;
1429 CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1430 (LPBYTE)encodedDomainName };
1431 BOOL ret;
1432 BYTE *buf = NULL;
1434 /* First test with the simpler info2 */
1435 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1437 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1438 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1439 &bufSize);
1440 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1441 if (buf)
1443 ok(bufSize == constraints2[i].encoded[1] + 2,
1444 "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1445 bufSize);
1446 ok(!memcmp(buf, constraints2[i].encoded,
1447 constraints2[i].encoded[1] + 2), "Unexpected value\n");
1448 LocalFree(buf);
1451 /* Now test with more complex basic constraints */
1452 info.SubjectType.cbData = 0;
1453 info.fPathLenConstraint = FALSE;
1454 info.cSubtreesConstraint = 0;
1455 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1456 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1457 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1458 if (buf)
1460 ok(bufSize == sizeof(emptyConstraint), "Wrong size %ld\n", bufSize);
1461 ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1462 "Unexpected value\n");
1463 LocalFree(buf);
1465 /* None of the certs I examined had any subtree constraint, but I test one
1466 * anyway just in case.
1468 info.cSubtreesConstraint = 1;
1469 info.rgSubtreesConstraint = &nameBlob;
1470 ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1471 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1472 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1473 if (buf)
1475 ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %ld\n", bufSize);
1476 ok(!memcmp(buf, constraintWithDomainName,
1477 sizeof(constraintWithDomainName)), "Unexpected value\n");
1478 LocalFree(buf);
1480 /* FIXME: test encoding with subject type. */
1483 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1484 static const unsigned char encodedCommonName[] = {
1485 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
1487 static void test_decodeBasicConstraints(DWORD dwEncoding)
1489 static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1490 0xff };
1491 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1492 DWORD i;
1493 BOOL ret;
1494 BYTE *buf = NULL;
1495 DWORD bufSize = 0;
1497 /* First test with simpler info2 */
1498 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1500 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1501 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1502 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1503 ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1504 GetLastError());
1505 if (buf)
1507 CERT_BASIC_CONSTRAINTS2_INFO *info =
1508 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1510 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1511 "Unexpected value for item %ld\n", i);
1512 LocalFree(buf);
1515 /* Check with the order of encoded elements inverted */
1516 buf = (PBYTE)1;
1517 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1518 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1519 &bufSize);
1520 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1521 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1522 ok(!buf, "Expected buf to be set to NULL\n");
1523 /* Check with a non-DER bool */
1524 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1525 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1526 (BYTE *)&buf, &bufSize);
1527 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1528 if (buf)
1530 CERT_BASIC_CONSTRAINTS2_INFO *info =
1531 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1533 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1534 LocalFree(buf);
1536 /* Check with a non-basic constraints value */
1537 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1538 (LPBYTE)encodedCommonName, encodedCommonName[1] + 2,
1539 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1540 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1541 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1542 /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
1543 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1544 emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
1545 (BYTE *)&buf, &bufSize);
1546 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1547 if (buf)
1549 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1551 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1552 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1553 ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
1554 LocalFree(buf);
1556 ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1557 constraintWithDomainName, sizeof(constraintWithDomainName),
1558 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1559 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1560 if (buf)
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 == 1, "Expected a subtree constraint\n");
1567 if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
1569 ok(info->rgSubtreesConstraint[0].cbData ==
1570 sizeof(encodedDomainName), "Wrong size %ld\n",
1571 info->rgSubtreesConstraint[0].cbData);
1572 ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
1573 sizeof(encodedDomainName)), "Unexpected value\n");
1575 LocalFree(buf);
1579 /* These are terrible public keys of course, I'm just testing encoding */
1580 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1581 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1582 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1583 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1584 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1585 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1586 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1587 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1589 struct EncodedRSAPubKey
1591 const BYTE *modulus;
1592 size_t modulusLen;
1593 const BYTE *encoded;
1594 size_t decodedModulusLen;
1597 struct EncodedRSAPubKey rsaPubKeys[] = {
1598 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1599 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1600 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1601 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1604 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1606 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1607 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1608 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1609 BOOL ret;
1610 BYTE *buf = NULL;
1611 DWORD bufSize = 0, i;
1613 /* Try with a bogus blob type */
1614 hdr->bType = 2;
1615 hdr->bVersion = CUR_BLOB_VERSION;
1616 hdr->reserved = 0;
1617 hdr->aiKeyAlg = CALG_RSA_KEYX;
1618 rsaPubKey->magic = 0x31415352;
1619 rsaPubKey->bitlen = sizeof(modulus1) * 8;
1620 rsaPubKey->pubexp = 65537;
1621 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1622 sizeof(modulus1));
1624 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1625 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1626 &bufSize);
1627 ok(!ret && GetLastError() == E_INVALIDARG,
1628 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1629 /* Now with a bogus reserved field */
1630 hdr->bType = PUBLICKEYBLOB;
1631 hdr->reserved = 1;
1632 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1633 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1634 &bufSize);
1635 if (buf)
1637 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1638 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1639 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1640 LocalFree(buf);
1642 /* Now with a bogus blob version */
1643 hdr->reserved = 0;
1644 hdr->bVersion = 0;
1645 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1646 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1647 &bufSize);
1648 if (buf)
1650 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1651 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1652 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1653 LocalFree(buf);
1655 /* And with a bogus alg ID */
1656 hdr->bVersion = CUR_BLOB_VERSION;
1657 hdr->aiKeyAlg = CALG_DES;
1658 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1659 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1660 &bufSize);
1661 if (buf)
1663 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1664 "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1665 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1666 LocalFree(buf);
1668 /* Check a couple of RSA-related OIDs */
1669 hdr->aiKeyAlg = CALG_RSA_KEYX;
1670 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1671 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1672 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1673 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1674 ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1675 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1676 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1677 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1678 /* Finally, all valid */
1679 hdr->aiKeyAlg = CALG_RSA_KEYX;
1680 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1682 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1683 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1684 ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1685 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1686 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1687 if (buf)
1689 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1690 "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1691 bufSize);
1692 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1693 "Unexpected value\n");
1694 LocalFree(buf);
1699 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1701 DWORD i;
1702 LPBYTE buf = NULL;
1703 DWORD bufSize = 0;
1704 BOOL ret;
1706 /* Try with a bad length */
1707 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1708 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1709 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1710 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1711 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1712 /* Try with a couple of RSA-related OIDs */
1713 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1714 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1715 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1716 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1717 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1718 ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1719 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1720 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1721 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1722 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1723 /* Now try success cases */
1724 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1726 bufSize = 0;
1727 ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1728 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1729 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1730 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1731 if (buf)
1733 BLOBHEADER *hdr = (BLOBHEADER *)buf;
1734 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1736 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1737 rsaPubKeys[i].decodedModulusLen,
1738 "Wrong size %ld\n", bufSize);
1739 ok(hdr->bType == PUBLICKEYBLOB,
1740 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1741 hdr->bType);
1742 ok(hdr->bVersion == CUR_BLOB_VERSION,
1743 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1744 CUR_BLOB_VERSION, hdr->bVersion);
1745 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1746 hdr->reserved);
1747 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1748 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1749 ok(rsaPubKey->magic == 0x31415352,
1750 "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1751 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1752 "Wrong bit len %ld\n", rsaPubKey->bitlen);
1753 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1754 rsaPubKey->pubexp);
1755 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1756 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1757 "Unexpected modulus\n");
1758 LocalFree(buf);
1763 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1764 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1765 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1767 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1768 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1769 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1770 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1772 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1774 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1775 CRYPT_SEQUENCE_OF_ANY seq;
1776 DWORD i;
1777 BOOL ret;
1778 BYTE *buf = NULL;
1779 DWORD bufSize = 0;
1781 /* Encode a homogenous sequence */
1782 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1784 blobs[i].cbData = ints[i].encoded[1] + 2;
1785 blobs[i].pbData = (BYTE *)ints[i].encoded;
1787 seq.cValue = sizeof(ints) / sizeof(ints[0]);
1788 seq.rgValue = blobs;
1790 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1791 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1792 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1793 if (buf)
1795 ok(bufSize == sizeof(intSequence), "Wrong size %ld\n", bufSize);
1796 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1797 LocalFree(buf);
1799 /* Change the type of the first element in the sequence, and give it
1800 * another go
1802 blobs[0].cbData = times[0].encodedTime[1] + 2;
1803 blobs[0].pbData = (BYTE *)times[0].encodedTime;
1804 ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1805 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1806 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1807 if (buf)
1809 ok(bufSize == sizeof(mixedSequence), "Wrong size %ld\n", bufSize);
1810 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1811 "Unexpected value\n");
1812 LocalFree(buf);
1816 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1818 BOOL ret;
1819 BYTE *buf = NULL;
1820 DWORD bufSize = 0;
1822 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1823 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1824 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1825 if (buf)
1827 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1828 DWORD i;
1830 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1831 "Wrong elements %ld\n", seq->cValue);
1832 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1834 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1835 "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1836 seq->rgValue[i].cbData);
1837 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1838 ints[i].encoded[1] + 2), "Unexpected value\n");
1840 LocalFree(buf);
1842 ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1843 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1844 &bufSize);
1845 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1846 if (buf)
1848 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1850 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1851 "Wrong elements %ld\n", seq->cValue);
1852 /* Just check the first element since it's all that changed */
1853 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1854 "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1855 seq->rgValue[0].cbData);
1856 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1857 times[0].encodedTime[1] + 2), "Unexpected value\n");
1858 LocalFree(buf);
1862 struct encodedExtensions
1864 CERT_EXTENSIONS exts;
1865 const BYTE *encoded;
1868 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1869 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1871 static CERT_EXTENSION criticalExt =
1872 { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1873 static CERT_EXTENSION nonCriticalExt =
1874 { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1876 static const BYTE ext0[] = { 0x30,0x00 };
1877 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1878 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1879 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1880 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1882 static const struct encodedExtensions exts[] = {
1883 { { 0, NULL }, ext0 },
1884 { { 1, &criticalExt }, ext1 },
1885 { { 1, &nonCriticalExt }, ext2 },
1888 static void test_encodeExtensions(DWORD dwEncoding)
1890 DWORD i;
1892 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1894 BOOL ret;
1895 BYTE *buf = NULL;
1896 DWORD bufSize = 0;
1898 ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1899 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1900 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1901 if (buf)
1903 ok(bufSize == exts[i].encoded[1] + 2,
1904 "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1905 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1906 "Unexpected value\n");
1907 LocalFree(buf);
1912 static void test_decodeExtensions(DWORD dwEncoding)
1914 DWORD i;
1916 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1918 BOOL ret;
1919 BYTE *buf = NULL;
1920 DWORD bufSize = 0;
1922 ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1923 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1924 NULL, (BYTE *)&buf, &bufSize);
1925 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1926 if (buf)
1928 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1929 DWORD j;
1931 ok(ext->cExtension == exts[i].exts.cExtension,
1932 "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1933 ext->cExtension);
1934 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1936 ok(!strcmp(ext->rgExtension[j].pszObjId,
1937 exts[i].exts.rgExtension[j].pszObjId),
1938 "Expected OID %s, got %s\n",
1939 exts[i].exts.rgExtension[j].pszObjId,
1940 ext->rgExtension[j].pszObjId);
1941 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1942 exts[i].exts.rgExtension[j].Value.pbData,
1943 exts[i].exts.rgExtension[j].Value.cbData),
1944 "Unexpected value\n");
1946 LocalFree(buf);
1951 /* MS encodes public key info with a NULL if the algorithm identifier's
1952 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
1953 * it encodes them by omitting the algorithm parameters. This latter approach
1954 * seems more correct, so accept either form.
1956 struct encodedPublicKey
1958 CERT_PUBLIC_KEY_INFO info;
1959 const BYTE *encoded;
1960 const BYTE *encodedNoNull;
1961 CERT_PUBLIC_KEY_INFO decoded;
1964 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1965 0xe, 0xf };
1966 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1968 static const unsigned char bin64[] = {
1969 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
1970 static const unsigned char bin65[] = {
1971 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
1972 static const unsigned char bin66[] = {
1973 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
1974 static const unsigned char bin67[] = {
1975 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
1976 static const unsigned char bin68[] = {
1977 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1978 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
1979 static const unsigned char bin69[] = {
1980 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
1981 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
1982 static const unsigned char bin70[] = {
1983 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1984 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1985 0x0f};
1986 static const unsigned char bin71[] = {
1987 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1988 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1989 0x0f};
1990 static unsigned char bin72[] = { 0x05,0x00};
1992 static const struct encodedPublicKey pubKeys[] = {
1993 /* with a bogus OID */
1994 { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1995 bin64, bin65,
1996 { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
1997 /* some normal keys */
1998 { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1999 bin66, bin67,
2000 { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
2001 { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2002 bin68, bin69,
2003 { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2004 /* with add'l parameters--note they must be DER-encoded */
2005 { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2006 (BYTE *)aKey, 0 } },
2007 bin70, bin71,
2008 { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2009 (BYTE *)aKey, 0 } } },
2012 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2014 DWORD i;
2016 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2018 BOOL ret;
2019 BYTE *buf = NULL;
2020 DWORD bufSize = 0;
2022 ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2023 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2024 &bufSize);
2025 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2026 if (buf)
2028 ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2029 bufSize == pubKeys[i].encodedNoNull[1] + 2,
2030 "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2031 pubKeys[i].encodedNoNull[1] + 2, bufSize);
2032 if (bufSize == pubKeys[i].encoded[1] + 2)
2033 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2034 "Unexpected value\n");
2035 else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2036 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2037 pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2038 LocalFree(buf);
2043 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2044 const CERT_PUBLIC_KEY_INFO *got)
2046 ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2047 "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2048 got->Algorithm.pszObjId);
2049 ok(expected->Algorithm.Parameters.cbData ==
2050 got->Algorithm.Parameters.cbData,
2051 "Expected parameters of %ld bytes, got %ld\n",
2052 expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2053 if (expected->Algorithm.Parameters.cbData)
2054 ok(!memcmp(expected->Algorithm.Parameters.pbData,
2055 got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2056 "Unexpected algorithm parameters\n");
2057 ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2058 "Expected public key of %ld bytes, got %ld\n",
2059 expected->PublicKey.cbData, got->PublicKey.cbData);
2060 if (expected->PublicKey.cbData)
2061 ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2062 got->PublicKey.cbData), "Unexpected public key value\n");
2065 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2067 static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2068 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2069 0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2070 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2071 DWORD i;
2072 BOOL ret;
2073 BYTE *buf = NULL;
2074 DWORD bufSize = 0;
2076 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2078 /* The NULL form decodes to the decoded member */
2079 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2080 pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2081 NULL, (BYTE *)&buf, &bufSize);
2082 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2083 if (buf)
2085 comparePublicKeyInfo(&pubKeys[i].decoded,
2086 (CERT_PUBLIC_KEY_INFO *)buf);
2087 LocalFree(buf);
2089 /* The non-NULL form decodes to the original */
2090 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2091 pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2092 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2093 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2094 if (buf)
2096 comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2097 LocalFree(buf);
2100 /* Test with bogus (not valid DER) parameters */
2101 ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2102 bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2103 NULL, (BYTE *)&buf, &bufSize);
2104 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2105 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2108 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2109 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2110 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2111 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2112 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2113 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2114 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2115 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2116 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2117 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2118 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2119 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2120 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2121 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2122 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2123 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2124 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2125 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2126 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2127 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2128 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2129 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2130 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2131 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2132 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2133 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2134 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2135 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2136 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2137 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2138 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2139 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2140 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2141 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2142 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2143 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2144 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2145 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2146 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2148 static const BYTE serialNum[] = { 0x01 };
2150 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2152 BOOL ret;
2153 BYTE *buf = NULL;
2154 DWORD size = 0;
2155 CERT_INFO info = { 0 };
2157 /* Test with NULL pvStructInfo */
2158 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2159 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2160 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2161 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2162 /* Test with a V1 cert */
2163 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2164 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2165 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2166 if (buf)
2168 ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2169 v1Cert[1] + 2, size);
2170 ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2171 LocalFree(buf);
2173 /* Test v2 cert */
2174 info.dwVersion = CERT_V2;
2175 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2176 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2177 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2178 if (buf)
2180 ok(size == sizeof(v2Cert), "Wrong size %ld\n", size);
2181 ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2182 LocalFree(buf);
2184 /* Test v3 cert */
2185 info.dwVersion = CERT_V3;
2186 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2187 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2188 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2189 if (buf)
2191 ok(size == sizeof(v3Cert), "Wrong size %ld\n", size);
2192 ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2193 LocalFree(buf);
2195 /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2196 * API doesn't prevent it)
2198 info.dwVersion = CERT_V1;
2199 info.cExtension = 1;
2200 info.rgExtension = &criticalExt;
2201 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2202 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2203 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2204 if (buf)
2206 ok(size == sizeof(v1CertWithConstraints), "Wrong size %ld\n", size);
2207 ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2208 LocalFree(buf);
2210 /* test v1 cert with a serial number */
2211 info.SerialNumber.cbData = sizeof(serialNum);
2212 info.SerialNumber.pbData = (BYTE *)serialNum;
2213 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2214 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2215 if (buf)
2217 ok(size == sizeof(v1CertWithSerial), "Wrong size %ld\n", size);
2218 ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2219 LocalFree(buf);
2221 /* Test v1 cert with an issuer name, a subject name, and a serial number */
2222 info.Issuer.cbData = sizeof(encodedCommonName);
2223 info.Issuer.pbData = (BYTE *)encodedCommonName;
2224 info.Subject.cbData = sizeof(encodedCommonName);
2225 info.Subject.pbData = (BYTE *)encodedCommonName;
2226 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2227 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2228 if (buf)
2230 ok(size == sizeof(bigCert), "Wrong size %ld\n", size);
2231 ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2232 LocalFree(buf);
2234 /* for now, I let more interesting tests be done for each subcomponent,
2235 * rather than retesting them all here.
2239 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2241 static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2242 v1CertWithConstraints, v1CertWithSerial };
2243 BOOL ret;
2244 BYTE *buf = NULL;
2245 DWORD size = 0, i;
2247 /* Test with NULL pbEncoded */
2248 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2249 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2250 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2251 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2252 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2253 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2254 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2255 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2256 /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2257 * minimum a cert must have a non-zero serial number, an issuer, and a
2258 * subject.
2260 for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2262 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2263 corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2264 (BYTE *)&buf, &size);
2265 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2266 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2268 /* Now check with serial number, subject and issuer specified */
2269 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2270 sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2271 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2272 if (buf)
2274 CERT_INFO *info = (CERT_INFO *)buf;
2276 ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2277 ok(info->SerialNumber.cbData == 1,
2278 "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2279 ok(*info->SerialNumber.pbData == *serialNum,
2280 "Expected serial number %d, got %d\n", *serialNum,
2281 *info->SerialNumber.pbData);
2282 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2283 "Wrong size %ld\n", info->Issuer.cbData);
2284 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2285 "Unexpected issuer\n");
2286 ok(info->Subject.cbData == sizeof(encodedCommonName),
2287 "Wrong size %ld\n", info->Subject.cbData);
2288 ok(!memcmp(info->Subject.pbData, encodedCommonName,
2289 info->Subject.cbData), "Unexpected subject\n");
2290 LocalFree(buf);
2294 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2295 0xe, 0xf };
2297 static const BYTE signedBigCert[] = {
2298 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2299 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2300 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2301 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2302 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2303 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2304 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2305 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2306 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2307 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2308 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2309 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2311 static void test_encodeCert(DWORD dwEncoding)
2313 /* Note the SignatureAlgorithm must match that in the encoded cert. Note
2314 * also that bigCert is a NULL-terminated string, so don't count its
2315 * last byte (otherwise the signed cert won't decode.)
2317 CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2318 { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2319 BOOL ret;
2320 BYTE *buf = NULL;
2321 DWORD bufSize = 0;
2323 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2324 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2325 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2326 if (buf)
2328 ok(bufSize == sizeof(signedBigCert), "Wrong size %ld\n", bufSize);
2329 ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2330 LocalFree(buf);
2334 static void test_decodeCert(DWORD dwEncoding)
2336 BOOL ret;
2337 BYTE *buf = NULL;
2338 DWORD size = 0;
2340 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2341 sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2342 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2343 if (buf)
2345 CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2347 ok(info->ToBeSigned.cbData == sizeof(bigCert),
2348 "Wrong cert size %ld\n", info->ToBeSigned.cbData);
2349 ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2350 "Unexpected cert\n");
2351 ok(info->Signature.cbData == sizeof(hash),
2352 "Wrong signature size %ld\n", info->Signature.cbData);
2353 ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2354 "Unexpected signature\n");
2355 LocalFree(buf);
2359 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2360 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2361 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2362 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2363 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2364 0x00, 0x03 };
2365 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2366 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2367 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2368 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2369 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2370 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2371 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2372 0x2e, 0x6f, 0x72, 0x67 };
2373 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2374 CRL_REASON_AFFILIATION_CHANGED;
2376 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2378 CRL_DIST_POINTS_INFO info = { 0 };
2379 CRL_DIST_POINT point = { { 0 } };
2380 CERT_ALT_NAME_ENTRY entry = { 0 };
2381 BOOL ret;
2382 BYTE *buf = NULL;
2383 DWORD size = 0;
2385 /* Test with an empty info */
2386 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2387 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2388 ok(!ret && GetLastError() == E_INVALIDARG,
2389 "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2390 /* Test with one empty dist point */
2391 info.cDistPoint = 1;
2392 info.rgDistPoint = &point;
2393 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2394 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2395 if (buf)
2397 ok(size == sizeof(emptyDistPoint), "Wrong size %ld\n", size);
2398 ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2399 LocalFree(buf);
2401 /* A dist point with an invalid name */
2402 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2403 entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2404 U(entry).pwszURL = (LPWSTR)nihongoURL;
2405 U(point.DistPointName).FullName.cAltEntry = 1;
2406 U(point.DistPointName).FullName.rgAltEntry = &entry;
2407 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2408 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2409 ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2410 "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2411 /* The first invalid character is at index 7 */
2412 ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2413 "Expected invalid char at index 7, got %ld\n",
2414 GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2415 /* A dist point with (just) a valid name */
2416 U(entry).pwszURL = (LPWSTR)url;
2417 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2418 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2419 if (buf)
2421 ok(size == sizeof(distPointWithUrl), "Wrong size %ld\n", size);
2422 ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2423 LocalFree(buf);
2425 /* A dist point with (just) reason flags */
2426 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2427 point.ReasonFlags.cbData = sizeof(crlReason);
2428 point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2429 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2430 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2431 if (buf)
2433 ok(size == sizeof(distPointWithReason), "Wrong size %ld\n", size);
2434 ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2435 LocalFree(buf);
2437 /* A dist point with just an issuer */
2438 point.ReasonFlags.cbData = 0;
2439 point.CRLIssuer.cAltEntry = 1;
2440 point.CRLIssuer.rgAltEntry = &entry;
2441 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2442 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2443 if (buf)
2445 ok(size == sizeof(distPointWithIssuer), "Wrong size %ld\n", size);
2446 ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2447 LocalFree(buf);
2449 /* A dist point with both a name and an issuer */
2450 point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2451 ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2452 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2453 if (buf)
2455 ok(size == sizeof(distPointWithUrlAndIssuer),
2456 "Wrong size %ld\n", size);
2457 ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2458 LocalFree(buf);
2462 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2464 BOOL ret;
2465 BYTE *buf = NULL;
2466 DWORD size = 0;
2467 PCRL_DIST_POINTS_INFO info;
2468 PCRL_DIST_POINT point;
2469 PCERT_ALT_NAME_ENTRY entry;
2471 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2472 emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2473 (BYTE *)&buf, &size);
2474 if (ret)
2476 info = (PCRL_DIST_POINTS_INFO)buf;
2477 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2478 "Wrong size %ld\n", size);
2479 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2480 info->cDistPoint);
2481 point = info->rgDistPoint;
2482 ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2483 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2484 point->DistPointName.dwDistPointNameChoice);
2485 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2486 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2487 LocalFree(buf);
2489 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2490 distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2491 (BYTE *)&buf, &size);
2492 if (ret)
2494 info = (PCRL_DIST_POINTS_INFO)buf;
2495 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2496 "Wrong size %ld\n", size);
2497 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2498 info->cDistPoint);
2499 point = info->rgDistPoint;
2500 ok(point->DistPointName.dwDistPointNameChoice ==
2501 CRL_DIST_POINT_FULL_NAME,
2502 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2503 point->DistPointName.dwDistPointNameChoice);
2504 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2505 "Expected 1 name entry, got %ld\n",
2506 U(point->DistPointName).FullName.cAltEntry);
2507 entry = U(point->DistPointName).FullName.rgAltEntry;
2508 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2509 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2510 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2511 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2512 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2513 LocalFree(buf);
2515 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2516 distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2517 NULL, (BYTE *)&buf, &size);
2518 if (ret)
2520 info = (PCRL_DIST_POINTS_INFO)buf;
2521 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2522 "Wrong size %ld\n", size);
2523 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2524 info->cDistPoint);
2525 point = info->rgDistPoint;
2526 ok(point->DistPointName.dwDistPointNameChoice ==
2527 CRL_DIST_POINT_NO_NAME,
2528 "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2529 point->DistPointName.dwDistPointNameChoice);
2530 ok(point->ReasonFlags.cbData == sizeof(crlReason),
2531 "Expected reason length\n");
2532 ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2533 "Unexpected reason\n");
2534 ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2535 LocalFree(buf);
2537 ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2538 distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2539 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2540 if (ret)
2542 info = (PCRL_DIST_POINTS_INFO)buf;
2543 ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2544 "Wrong size %ld\n", size);
2545 ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2546 info->cDistPoint);
2547 point = info->rgDistPoint;
2548 ok(point->DistPointName.dwDistPointNameChoice ==
2549 CRL_DIST_POINT_FULL_NAME,
2550 "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2551 point->DistPointName.dwDistPointNameChoice);
2552 ok(U(point->DistPointName).FullName.cAltEntry == 1,
2553 "Expected 1 name entry, got %ld\n",
2554 U(point->DistPointName).FullName.cAltEntry);
2555 entry = U(point->DistPointName).FullName.rgAltEntry;
2556 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2557 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2558 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2559 ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2560 ok(point->CRLIssuer.cAltEntry == 1,
2561 "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2562 entry = point->CRLIssuer.rgAltEntry;
2563 ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2564 "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2565 ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2566 LocalFree(buf);
2570 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2571 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2572 0x30, 0x5a };
2573 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2574 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2575 0x30, 0x30, 0x30, 0x30, 0x5a };
2576 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2577 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2578 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2579 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2580 0x5a };
2581 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2582 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2583 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2584 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2585 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2586 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2587 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2588 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2589 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2590 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2591 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2592 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2593 static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
2594 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2595 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
2596 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2597 0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2598 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
2599 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2600 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2601 static const BYTE v2CRLWithExt[] = { 0x30, 0x5a, 0x02, 0x01, 0x01, 0x30, 0x02,
2602 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2603 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2604 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2605 0x30, 0x30, 0x5a, 0x30, 0x29, 0x30, 0x27, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31,
2606 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2607 0x5a, 0x30, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30,
2608 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2611 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2613 BOOL ret;
2614 BYTE *buf = NULL;
2615 DWORD size = 0;
2616 CRL_INFO info = { 0 };
2617 CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2619 /* Test with a V1 CRL */
2620 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2621 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2622 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2623 if (buf)
2625 ok(size == sizeof(v1CRL), "Wrong size %ld\n", size);
2626 ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2627 LocalFree(buf);
2629 /* Test v2 CRL */
2630 info.dwVersion = CRL_V2;
2631 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2632 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2633 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2634 if (buf)
2636 ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2637 v2CRL[1] + 2, size);
2638 ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2639 LocalFree(buf);
2641 /* v1 CRL with a name */
2642 info.dwVersion = CRL_V1;
2643 info.Issuer.cbData = sizeof(encodedCommonName);
2644 info.Issuer.pbData = (BYTE *)encodedCommonName;
2645 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2646 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2647 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2648 if (buf)
2650 ok(size == sizeof(v1CRLWithIssuer), "Wrong size %ld\n", size);
2651 ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2652 LocalFree(buf);
2654 /* v1 CRL with a name and a NULL entry pointer */
2655 info.cCRLEntry = 1;
2656 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2657 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2658 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2659 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2660 /* now set an empty entry */
2661 info.rgCRLEntry = &entry;
2662 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2663 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2664 if (buf)
2666 ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2667 "Wrong size %ld\n", size);
2668 ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2669 "Got unexpected value\n");
2670 LocalFree(buf);
2672 /* an entry with a serial number */
2673 entry.SerialNumber.cbData = sizeof(serialNum);
2674 entry.SerialNumber.pbData = (BYTE *)serialNum;
2675 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2676 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2677 if (buf)
2679 ok(size == sizeof(v1CRLWithIssuerAndEntry),
2680 "Wrong size %ld\n", size);
2681 ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2682 "Got unexpected value\n");
2683 LocalFree(buf);
2685 /* an entry with an extension */
2686 entry.cExtension = 1;
2687 entry.rgExtension = &criticalExt;
2688 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2689 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2690 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2691 if (buf)
2693 ok(size == sizeof(v1CRLWithExt), "Wrong size %ld\n", size);
2694 ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2695 LocalFree(buf);
2697 /* a v2 CRL with an extension, this time non-critical */
2698 info.dwVersion = CRL_V2;
2699 entry.rgExtension = &nonCriticalExt;
2700 ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2701 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2702 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2703 if (buf)
2705 ok(size == sizeof(v2CRLWithExt), "Wrong size %ld\n", size);
2706 ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n");
2707 LocalFree(buf);
2711 static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01,
2712 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
2713 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06,
2714 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
2715 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56,
2716 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
2717 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65,
2718 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
2719 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
2720 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43,
2721 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30,
2722 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33,
2723 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51,
2724 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99,
2725 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31,
2726 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0,
2727 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30,
2728 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30,
2729 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75,
2730 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33,
2731 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30,
2732 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
2733 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06,
2734 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03,
2735 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88,
2736 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd,
2737 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf,
2738 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46,
2739 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f,
2740 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75,
2741 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f,
2742 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82,
2743 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07,
2744 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c,
2745 0xcd };
2747 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
2749 static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
2750 BOOL ret;
2751 BYTE *buf = NULL;
2752 DWORD size = 0, i;
2754 for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
2756 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2757 corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2758 (BYTE *)&buf, &size);
2759 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2760 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2762 /* at a minimum, a CRL must contain an issuer: */
2763 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2764 v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2765 (BYTE *)&buf, &size);
2766 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2767 if (buf)
2769 CRL_INFO *info = (CRL_INFO *)buf;
2771 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
2772 ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
2773 info->cCRLEntry);
2774 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2775 "Wrong issuer size %ld\n", info->Issuer.cbData);
2776 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2777 "Unexpected issuer\n");
2778 LocalFree(buf);
2780 /* check decoding with an empty CRL entry */
2781 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2782 v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
2783 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2784 todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2785 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2786 /* with a real CRL entry */
2787 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2788 v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
2789 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2790 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2791 if (buf)
2793 CRL_INFO *info = (CRL_INFO *)buf;
2794 CRL_ENTRY *entry;
2796 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
2797 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2798 info->cCRLEntry);
2799 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2800 entry = info->rgCRLEntry;
2801 ok(entry->SerialNumber.cbData == 1,
2802 "Expected serial number size 1, got %ld\n",
2803 entry->SerialNumber.cbData);
2804 ok(*entry->SerialNumber.pbData == *serialNum,
2805 "Expected serial number %d, got %d\n", *serialNum,
2806 *entry->SerialNumber.pbData);
2807 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2808 "Wrong issuer size %ld\n", info->Issuer.cbData);
2809 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2810 "Unexpected issuer\n");
2812 /* a real CRL from verisign that has extensions */
2813 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2814 verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG,
2815 NULL, (BYTE *)&buf, &size);
2816 todo_wine ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2817 if (buf)
2819 CRL_INFO *info = (CRL_INFO *)buf;
2820 CRL_ENTRY *entry;
2822 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
2823 ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %ld\n",
2824 info->cCRLEntry);
2825 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2826 entry = info->rgCRLEntry;
2827 ok(info->cExtension == 2, "Expected 2 extensions, got %ld\n",
2828 info->cExtension);
2830 /* and finally, with an extension */
2831 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2832 v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2833 NULL, (BYTE *)&buf, &size);
2834 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2835 if (buf)
2837 CRL_INFO *info = (CRL_INFO *)buf;
2838 CRL_ENTRY *entry;
2840 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
2841 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2842 info->cCRLEntry);
2843 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2844 entry = info->rgCRLEntry;
2845 ok(entry->SerialNumber.cbData == 1,
2846 "Expected serial number size 1, got %ld\n",
2847 entry->SerialNumber.cbData);
2848 ok(*entry->SerialNumber.pbData == *serialNum,
2849 "Expected serial number %d, got %d\n", *serialNum,
2850 *entry->SerialNumber.pbData);
2851 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2852 "Wrong issuer size %ld\n", info->Issuer.cbData);
2853 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2854 "Unexpected issuer\n");
2855 /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2856 * bug, or am I missing something?
2858 ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2859 info->cExtension);
2861 ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2862 v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2863 NULL, (BYTE *)&buf, &size);
2864 if (buf)
2866 CRL_INFO *info = (CRL_INFO *)buf;
2867 CRL_ENTRY *entry;
2869 ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
2870 ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2871 info->cCRLEntry);
2872 ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2873 entry = info->rgCRLEntry;
2874 ok(entry->SerialNumber.cbData == 1,
2875 "Expected serial number size 1, got %ld\n",
2876 entry->SerialNumber.cbData);
2877 ok(*entry->SerialNumber.pbData == *serialNum,
2878 "Expected serial number %d, got %d\n", *serialNum,
2879 *entry->SerialNumber.pbData);
2880 ok(info->Issuer.cbData == sizeof(encodedCommonName),
2881 "Wrong issuer size %ld\n", info->Issuer.cbData);
2882 ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2883 "Unexpected issuer\n");
2884 /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2885 * bug, or am I missing something?
2887 ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2888 info->cExtension);
2889 LocalFree(buf);
2893 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
2894 szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
2895 static const BYTE encodedUsage[] = {
2896 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
2897 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
2898 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
2900 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
2902 BOOL ret;
2903 BYTE *buf = NULL;
2904 DWORD size = 0;
2905 CERT_ENHKEY_USAGE usage;
2907 /* Test with empty usage */
2908 usage.cUsageIdentifier = 0;
2909 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
2910 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2911 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2912 if (buf)
2914 ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
2915 ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
2916 LocalFree(buf);
2918 /* Test with a few usages */
2919 usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
2920 usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
2921 ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
2922 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2923 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2924 if (buf)
2926 ok(size == sizeof(encodedUsage), "Wrong size %ld\n", size);
2927 ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
2928 LocalFree(buf);
2932 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
2934 BOOL ret;
2935 LPBYTE buf = NULL;
2936 DWORD size = 0;
2938 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
2939 emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
2940 (BYTE *)&buf, &size);
2941 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2942 if (buf)
2944 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
2946 ok(size >= sizeof(CERT_ENHKEY_USAGE),
2947 "Wrong size %ld\n", size);
2948 ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
2949 usage->cUsageIdentifier);
2950 LocalFree(buf);
2952 ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
2953 encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
2954 (BYTE *)&buf, &size);
2955 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2956 if (buf)
2958 CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
2959 DWORD i;
2961 ok(size >= sizeof(CERT_ENHKEY_USAGE),
2962 "Wrong size %ld\n", size);
2963 ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
2964 "Wrong CRL entries count %ld\n", usage->cUsageIdentifier);
2965 for (i = 0; i < usage->cUsageIdentifier; i++)
2966 ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
2967 "Expected OID %s, got %s\n", keyUsages[i],
2968 usage->rgpszUsageIdentifier[i]);
2969 LocalFree(buf);
2973 /* Free *pInfo with HeapFree */
2974 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
2976 BOOL ret;
2977 DWORD size = 0;
2978 HCRYPTKEY key;
2980 /* This crashes
2981 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
2983 ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
2984 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2985 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2986 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
2987 &size);
2988 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2989 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2990 ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
2991 NULL, &size);
2992 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2993 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2994 ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2995 0, NULL, NULL, &size);
2996 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2997 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2998 /* Test with no key */
2999 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3000 0, NULL, NULL, &size);
3001 ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
3002 GetLastError());
3003 ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
3004 ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
3005 if (ret)
3007 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
3008 NULL, 0, NULL, NULL, &size);
3009 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3010 *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
3011 if (*pInfo)
3013 ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
3014 X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
3015 ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
3016 GetLastError());
3017 if (ret)
3019 /* By default (we passed NULL as the OID) the OID is
3020 * szOID_RSA_RSA.
3022 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
3023 "Expected %s, got %s\n", szOID_RSA_RSA,
3024 (*pInfo)->Algorithm.pszObjId);
3030 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
3031 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
3032 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
3033 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3034 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3035 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3036 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
3037 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
3038 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3039 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3040 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3041 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3042 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
3043 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
3044 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
3045 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
3046 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
3047 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
3048 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
3049 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
3050 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
3051 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
3052 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
3053 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
3054 0x49, 0xe5, 0xf9, 0x65, 0xf3 };
3056 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
3058 BOOL ret;
3059 HCRYPTKEY key;
3060 PCCERT_CONTEXT context;
3062 /* These crash
3063 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
3064 ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
3065 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
3066 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3067 NULL);
3069 ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3070 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3071 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3072 ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3073 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3074 "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3075 ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3076 &key);
3077 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3078 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3079 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3080 &key);
3081 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3082 CryptDestroyKey(key);
3084 /* Test importing a public key from a certificate context */
3085 context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert,
3086 sizeof(expiredCert));
3087 ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
3088 GetLastError());
3089 if (context)
3091 ok(!strcmp(szOID_RSA_RSA,
3092 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId),
3093 "Expected %s, got %s\n", szOID_RSA_RSA,
3094 context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
3095 ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING,
3096 &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key);
3097 ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3098 CryptDestroyKey(key);
3099 CertFreeCertificateContext(context);
3103 static const char cspName[] = "WineCryptTemp";
3105 static void testPortPublicKeyInfo(void)
3107 HCRYPTPROV csp;
3108 BOOL ret;
3109 PCERT_PUBLIC_KEY_INFO info = NULL;
3111 /* Just in case a previous run failed, delete this thing */
3112 CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3113 CRYPT_DELETEKEYSET);
3114 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3115 CRYPT_NEWKEYSET);
3117 testExportPublicKey(csp, &info);
3118 testImportPublicKey(csp, info);
3120 HeapFree(GetProcessHeap(), 0, info);
3121 CryptReleaseContext(csp, 0);
3122 ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3123 CRYPT_DELETEKEYSET);
3126 START_TEST(encode)
3128 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3129 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3130 DWORD i;
3132 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3134 test_encodeInt(encodings[i]);
3135 test_decodeInt(encodings[i]);
3136 test_encodeEnumerated(encodings[i]);
3137 test_decodeEnumerated(encodings[i]);
3138 test_encodeFiletime(encodings[i]);
3139 test_decodeFiletime(encodings[i]);
3140 test_encodeName(encodings[i]);
3141 test_decodeName(encodings[i]);
3142 test_encodeNameValue(encodings[i]);
3143 test_decodeNameValue(encodings[i]);
3144 test_encodeAltName(encodings[i]);
3145 test_decodeAltName(encodings[i]);
3146 test_encodeOctets(encodings[i]);
3147 test_decodeOctets(encodings[i]);
3148 test_encodeBits(encodings[i]);
3149 test_decodeBits(encodings[i]);
3150 test_encodeBasicConstraints(encodings[i]);
3151 test_decodeBasicConstraints(encodings[i]);
3152 test_encodeRsaPublicKey(encodings[i]);
3153 test_decodeRsaPublicKey(encodings[i]);
3154 test_encodeSequenceOfAny(encodings[i]);
3155 test_decodeSequenceOfAny(encodings[i]);
3156 test_encodeExtensions(encodings[i]);
3157 test_decodeExtensions(encodings[i]);
3158 test_encodePublicKeyInfo(encodings[i]);
3159 test_decodePublicKeyInfo(encodings[i]);
3160 test_encodeCertToBeSigned(encodings[i]);
3161 test_decodeCertToBeSigned(encodings[i]);
3162 test_encodeCert(encodings[i]);
3163 test_decodeCert(encodings[i]);
3164 test_encodeCRLDistPoints(encodings[i]);
3165 test_decodeCRLDistPoints(encodings[i]);
3166 test_encodeCRLToBeSigned(encodings[i]);
3167 test_decodeCRLToBeSigned(encodings[i]);
3168 test_encodeEnhancedKeyUsage(encodings[i]);
3169 test_decodeEnhancedKeyUsage(encodings[i]);
3171 testPortPublicKeyInfo();