2 * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
4 * Copyright 2005 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/test.h"
35 static const struct encodedInt ints[] = {
37 { 127, { 2, 1, 0x7f } },
38 { 128, { 2, 2, 0x00, 0x80 } },
39 { 256, { 2, 2, 0x01, 0x00 } },
40 { -128, { 2, 1, 0x80 } },
41 { -129, { 2, 2, 0xff, 0x7f } },
42 { 0xbaddf00d, { 2, 4, 0xba, 0xdd, 0xf0, 0x0d } },
45 static void test_encodeint(DWORD dwEncoding)
51 /* CryptEncodeObjectEx with NULL bufSize crashes..
52 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
55 /* check bogus encoding */
56 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
58 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
59 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
60 /* check with NULL integer buffer. Windows XP incorrectly returns an
63 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
65 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
66 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
67 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
71 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
72 NULL, NULL, &bufSize);
73 ok(ret, "Expected success, got %ld\n", GetLastError());
74 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
75 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
76 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
79 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
81 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
82 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
88 static void test_decodeint(DWORD dwEncoding)
90 static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
91 static const char testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
97 /* CryptDecodeObjectEx with NULL bufSize crashes..
98 ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
99 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
101 /* check bogus encoding */
102 ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
103 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
104 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
105 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
106 /* check with NULL integer buffer */
107 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
109 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
110 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
111 /* check with a valid, but too large, integer */
112 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
113 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
114 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
115 "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
116 /* check with a DER-encoded string */
117 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
118 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
119 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
120 "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
121 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
123 /* When the output buffer is NULL, this always succeeds */
124 SetLastError(0xdeadbeef);
125 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
126 (BYTE *)&ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
128 ok(ret && GetLastError() == NOERROR,
129 "Expected success and NOERROR, got %ld\n", GetLastError());
130 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
131 (BYTE *)&ints[i].encoded, ints[i].encoded[1] + 2,
132 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
133 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
134 ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
136 ok(buf != NULL, "Expected allocated buffer\n");
139 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
140 ints[i].val, *(int *)buf);
146 struct encodedFiletime
152 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
153 const struct encodedFiletime *time)
160 ret = SystemTimeToFileTime(&time->sysTime, &ft);
161 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
162 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
163 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
164 /* years other than 1950-2050 are not allowed for encodings other than
165 * X509_CHOICE_OF_TIME.
167 if (structType == X509_CHOICE_OF_TIME ||
168 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
170 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
172 ok(buf != NULL, "Expected an allocated buffer\n");
175 ok(buf[0] == time->encodedTime[0],
176 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
178 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
179 time->encodedTime[1], bufSize);
180 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
181 "Got unexpected value for time encoding\n");
186 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
187 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
190 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
191 const struct encodedFiletime *time)
193 FILETIME ft1 = { 0 }, ft2 = { 0 };
194 DWORD size = sizeof(ft2);
197 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
198 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
199 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
200 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
201 /* years other than 1950-2050 are not allowed for encodings other than
202 * X509_CHOICE_OF_TIME.
204 if (structType == X509_CHOICE_OF_TIME ||
205 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
207 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
209 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
210 "Got unexpected value for time decoding\n");
213 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
214 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
217 static const struct encodedFiletime times[] = {
218 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
219 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
220 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
223 static void test_encodeFiletime(DWORD dwEncoding)
227 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
229 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
230 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
231 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
235 static void test_decodeFiletime(DWORD dwEncoding)
237 static const struct encodedFiletime otherTimes[] = {
238 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x13" "19450606161000.000Z" },
239 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
240 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, "\x18" "\x13" "19450606161000+0100" },
241 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, "\x18" "\x13" "19450606161000-0100" },
242 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, "\x18" "\x13" "19450606161000-0115" },
243 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, "\x18" "\x0a" "2145060616" },
244 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0a" "4506061610" },
245 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0b" "4506061610Z" },
246 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0d" "4506061610+01" },
247 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0d" "4506061610-01" },
248 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0f" "4506061610+0100" },
249 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0f" "4506061610-0100" },
251 /* An oddball case that succeeds in Windows, but doesn't seem correct
252 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
254 static const char *bogusTimes[] = {
255 /* oddly, this succeeds on Windows, with year 2765
256 "\x18" "\x0f" "21r50606161000Z",
258 "\x17" "\x08" "45060616",
259 "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
260 "\x18" "\x04" "2145",
261 "\x18" "\x08" "21450606",
264 FILETIME ft1 = { 0 }, ft2 = { 0 };
267 /* Check bogus length with non-NULL buffer */
268 ret = SystemTimeToFileTime(×[0].sysTime, &ft1);
269 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
271 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
272 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
273 ok(!ret && GetLastError() == ERROR_MORE_DATA,
274 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
276 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
278 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
279 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
280 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
282 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
284 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
285 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
286 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
288 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
291 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
292 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
293 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
294 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
304 static const char commonName[] = "Juan Lang";
305 static const char surName[] = "Lang";
306 static const char bogusIA5[] = "\x80";
307 static const char bogusPrintable[] = "~";
308 static const char bogusNumeric[] = "A";
309 static const struct EncodedName names[] = {
310 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
311 { sizeof(commonName), (BYTE *)commonName } },
312 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0aJuan Lang" },
313 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
314 { sizeof(commonName), (BYTE *)commonName } },
315 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x16\x0aJuan Lang" },
316 { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
317 { sizeof(surName), (BYTE *)surName } },
318 "\x30\x10\x31\x0e\x30\x0c\x06\x03\x55\x04\x04\x16\x05Lang" },
319 { { NULL, CERT_RDN_PRINTABLE_STRING,
320 { sizeof(commonName), (BYTE *)commonName } },
321 "\x30\x12\x31\x10\x30\x0e\x06\x00\x13\x0aJuan Lang" },
322 /* The following test isn't a very good one, because it doesn't encode any
323 * Japanese characters. I'm leaving it out for now.
324 { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
325 { sizeof(commonName), (BYTE *)commonName } },
326 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
328 /* The following tests succeed under Windows, but really should fail,
329 * they contain characters that are illegal for the encoding. I'm
330 * including them to justify my lazy encoding.
332 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
333 { sizeof(bogusIA5), (BYTE *)bogusIA5 } },
334 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x16\x02\x80" },
335 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
336 { sizeof(bogusPrintable), (BYTE *)bogusPrintable } },
337 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13\x02\x7e" },
338 { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
339 { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
340 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x12\x02\x41" },
343 static const BYTE emptyName[] = { 0x30, 0 };
344 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
345 static const BYTE twoRDNs[] = "\x30\x23\x31\x21\x30\x0c\x06\x03\x55\x04\x04"
346 "\x13\x05\x4c\x61\x6e\x67\x00\x30\x11\x06\x03\x55\x04\x03"
347 "\x13\x0a\x4a\x75\x61\x6e\x20\x4c\x61\x6e\x67";
349 static void test_encodeName(DWORD dwEncoding)
351 CERT_RDN_ATTR attrs[2];
358 /* Test with NULL pvStructInfo */
359 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
360 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
361 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
362 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
363 /* Test with empty CERT_NAME_INFO */
366 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
367 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
368 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
371 ok(!memcmp(buf, emptyName, sizeof(emptyName)),
372 "Got unexpected encoding for empty name\n");
375 /* Test with bogus CERT_RDN */
377 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
378 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
379 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
380 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
381 /* Test with empty CERT_RDN */
383 rdn.rgRDNAttr = NULL;
386 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
387 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
388 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
391 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
392 "Got unexpected encoding for empty RDN array\n");
395 /* Test with bogus attr array */
397 rdn.rgRDNAttr = NULL;
398 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
399 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
400 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
401 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
402 /* oddly, a bogus OID is accepted by Windows XP; not testing.
403 attrs[0].pszObjId = "bogus";
404 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
405 attrs[0].Value.cbData = sizeof(commonName);
406 attrs[0].Value.pbData = (BYTE *)commonName;
408 rdn.rgRDNAttr = attrs;
409 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
410 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
411 ok(!ret, "Expected failure, got success\n");
413 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
414 * the encoded attributes to be swapped.
416 attrs[0].pszObjId = szOID_COMMON_NAME;
417 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
418 attrs[0].Value.cbData = sizeof(commonName);
419 attrs[0].Value.pbData = (BYTE *)commonName;
420 attrs[1].pszObjId = szOID_SUR_NAME;
421 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
422 attrs[1].Value.cbData = sizeof(surName);
423 attrs[1].Value.pbData = (BYTE *)surName;
425 rdn.rgRDNAttr = attrs;
426 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
427 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
428 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
431 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
432 "Got unexpected encoding for two RDN array\n");
435 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
437 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
438 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
439 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
440 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
441 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
442 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
445 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
446 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
447 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
448 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
451 ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
452 names[i].encoded[1] + 2, size);
453 ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
454 "Got unexpected encoding\n");
460 static void compareNames(const CERT_NAME_INFO *expected,
461 const CERT_NAME_INFO *got)
463 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
464 expected->cRDN, got->cRDN);
467 ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
468 "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
469 got->rgRDN[0].cRDNAttr);
470 if (expected->rgRDN[0].cRDNAttr)
472 if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
473 strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
475 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
476 "Expected OID %s, got NULL\n",
477 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
478 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
479 ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
480 expected->rgRDN[0].rgRDNAttr[0].pszObjId),
481 "Got unexpected OID %s, expected %s\n",
482 got->rgRDN[0].rgRDNAttr[0].pszObjId,
483 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
485 ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
486 expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
487 "Unexpected data size, got %ld, expected %ld\n",
488 got->rgRDN[0].rgRDNAttr[0].Value.cbData,
489 expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
490 if (expected->rgRDN[0].rgRDNAttr[0].Value.pbData)
491 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
492 expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
493 expected->rgRDN[0].rgRDNAttr[0].Value.cbData),
494 "Unexpected value\n");
499 static void test_decodeName(DWORD dwEncoding)
506 CERT_NAME_INFO info = { 1, &rdn };
508 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
510 /* When the output buffer is NULL, this always succeeds */
511 SetLastError(0xdeadbeef);
512 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
513 names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
514 ok(ret && GetLastError() == NOERROR,
515 "Expected success and NOERROR, got %08lx\n", GetLastError());
516 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
517 names[i].encoded[1] + 2,
518 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
519 (BYTE *)&buf, &bufSize);
520 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
522 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
525 compareNames((CERT_NAME_INFO *)buf, &info);
529 /* test empty name */
531 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
533 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
534 (BYTE *)&buf, &bufSize);
535 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
536 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
537 * decoder works the same way, so only test the count.
541 ok(bufSize == sizeof(CERT_NAME_INFO),
542 "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
543 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
544 "Expected 0 RDNs in empty info, got %ld\n",
545 ((CERT_NAME_INFO *)buf)->cRDN);
550 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
552 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
553 (BYTE *)&buf, &bufSize);
554 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
557 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
559 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
560 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
561 "Got unexpected value for empty RDN\n");
564 /* test two RDN attrs */
566 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
568 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
569 (BYTE *)&buf, &bufSize);
570 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
573 CERT_RDN_ATTR attrs[] = {
574 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
576 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
577 (BYTE *)commonName } },
580 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
581 rdn.rgRDNAttr = attrs;
582 compareNames((CERT_NAME_INFO *)buf, &info);
587 static void test_registerOIDFunction(void)
589 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
592 /* oddly, this succeeds under WinXP; the function name key is merely
593 * omitted. This may be a side effect of the registry code, I don't know.
594 * I don't check it because I doubt anyone would depend on it.
595 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
596 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
598 /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
599 * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
601 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
603 ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
604 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
605 "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
606 /* This has no effect, but "succeeds" on XP */
607 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
608 "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
609 ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
610 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
611 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
612 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
613 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
614 "1.2.3.4.5.6.7.8.9.10");
615 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
616 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
617 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
618 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
619 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
620 "1.2.3.4.5.6.7.8.9.10");
621 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
622 /* This has no effect */
623 ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
624 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
625 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
626 /* Check with bogus encoding type: */
627 ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
628 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
629 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
630 /* This is written with value 3 verbatim. Thus, the encoding type isn't
631 * (for now) treated as a mask.
633 ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
634 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
635 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
636 ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
637 "1.2.3.4.5.6.7.8.9.10");
638 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
643 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
644 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
647 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
649 test_encodeint(encodings[i]);
650 test_decodeint(encodings[i]);
651 test_encodeFiletime(encodings[i]);
652 test_decodeFiletime(encodings[i]);
653 test_encodeName(encodings[i]);
654 test_decodeName(encodings[i]);
656 test_registerOIDFunction();