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[] = {
36 { 1, "\x02\x01\x01" },
37 { 127, "\x02\x01\x7f" },
38 { 128, "\x02\x02\x00\x80" },
39 { 256, "\x02\x02\x01\x00" },
40 { -128, "\x02\x01\x80" },
41 { -129, "\x02\x02\xff\x7f" },
42 { 0xbaddf00d, "\x02\x04\xba\xdd\xf0\x0d" },
52 static const struct encodedBigInt bigInts[] = {
53 { "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08",
54 "\x02\x0a\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff",
55 "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08" },
56 { "\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff\xff",
57 "\x02\x09\xff\x01\x02\x03\x04\x05\x06\x07\x08",
58 "\x08\x07\x06\x05\x04\x03\x02\x01\xff" },
61 /* Decoded is the same as original, so don't bother storing a separate copy */
62 static const struct encodedBigInt bigUInts[] = {
63 { "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08",
64 "\x02\x0a\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff", NULL },
65 { "\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff\xff",
66 "\x02\x0c\x00\xff\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08", NULL },
69 static void test_encodeInt(DWORD dwEncoding)
74 CRYPT_INTEGER_BLOB blob;
77 /* CryptEncodeObjectEx with NULL bufSize crashes..
78 ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
81 /* check bogus encoding */
82 ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
84 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
85 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
86 /* check with NULL integer buffer. Windows XP incorrectly returns an
89 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
91 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
92 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
93 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
95 /* encode as normal integer */
96 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
97 NULL, NULL, &bufSize);
98 ok(ret, "Expected success, got %ld\n", GetLastError());
99 ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
100 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
101 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
104 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
106 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
107 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
110 /* encode as multibyte integer */
111 blob.cbData = sizeof(ints[i].val);
112 blob.pbData = (BYTE *)&ints[i].val;
113 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
114 0, NULL, NULL, &bufSize);
115 ok(ret, "Expected success, got %ld\n", GetLastError());
116 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
117 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
118 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
121 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
123 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
124 buf[1], ints[i].encoded[1]);
125 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
126 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
130 /* encode a couple bigger ints, just to show it's little-endian and leading
131 * sign bytes are dropped
133 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
135 blob.cbData = strlen(bigInts[i].val);
136 blob.pbData = (BYTE *)bigInts[i].val;
137 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
138 0, NULL, NULL, &bufSize);
139 ok(ret, "Expected success, got %ld\n", GetLastError());
140 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
141 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
142 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
145 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
147 ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
148 buf[1], bigInts[i].encoded[1]);
149 ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
150 bigInts[i].encoded[1] + 1),
151 "Encoded value didn't match expected\n");
155 /* and, encode some uints */
156 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
158 blob.cbData = strlen(bigUInts[i].val);
159 blob.pbData = (BYTE *)bigUInts[i].val;
160 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
161 0, NULL, NULL, &bufSize);
162 ok(ret, "Expected success, got %ld\n", GetLastError());
163 ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
164 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
165 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
168 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
170 ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
171 buf[1], bigUInts[i].encoded[1]);
172 ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
173 bigUInts[i].encoded[1] + 1),
174 "Encoded value didn't match expected\n");
180 static void test_decodeInt(DWORD dwEncoding)
182 static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
183 static const char testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
189 /* CryptDecodeObjectEx with NULL bufSize crashes..
190 ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
191 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
193 /* check bogus encoding */
194 ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
195 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
196 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
197 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
198 /* check with NULL integer buffer */
199 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
201 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
202 "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
203 /* check with a valid, but too large, integer */
204 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
205 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
206 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
207 "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
208 /* check with a DER-encoded string */
209 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
210 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
211 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
212 "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
213 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
215 /* When the output buffer is NULL, this always succeeds */
216 SetLastError(0xdeadbeef);
217 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
218 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
220 ok(ret && GetLastError() == NOERROR,
221 "Expected success and NOERROR, got %ld\n", GetLastError());
222 ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
223 (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
224 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
225 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
226 ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
228 ok(buf != NULL, "Expected allocated buffer\n");
231 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
232 ints[i].val, *(int *)buf);
236 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
238 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
239 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
241 ok(ret && GetLastError() == NOERROR,
242 "Expected success and NOERROR, got %ld\n", GetLastError());
243 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
244 (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
245 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
246 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
247 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
248 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
250 ok(buf != NULL, "Expected allocated buffer\n");
253 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
255 ok(blob->cbData == strlen(bigInts[i].decoded),
256 "Expected len %d, got %ld\n", strlen(bigInts[i].decoded),
258 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
259 "Unexpected value\n");
263 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
265 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
266 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
268 ok(ret && GetLastError() == NOERROR,
269 "Expected success and NOERROR, got %ld\n", GetLastError());
270 ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
271 (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
272 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
273 ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
274 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
275 "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
277 ok(buf != NULL, "Expected allocated buffer\n");
280 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
282 ok(blob->cbData == strlen(bigUInts[i].val),
283 "Expected len %d, got %ld\n", strlen(bigUInts[i].val),
285 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
286 "Unexpected value\n");
292 /* These are always encoded unsigned, and aren't constrained to be any
295 static const struct encodedInt enums[] = {
296 { 1, "\x0a\x01\x01" },
297 { -128, "\x0a\x05\x00\xff\xff\xff\x80" },
300 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
303 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
304 szOID_CRL_REASON_CODE };
306 static void test_encodeEnumerated(DWORD dwEncoding)
310 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
312 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
318 ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
319 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
321 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
325 "Got unexpected type %d for enumerated (expected 0xa)\n",
327 ok(buf[1] == enums[j].encoded[1],
328 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
329 ok(!memcmp(buf + 1, enums[j].encoded + 1,
330 enums[j].encoded[1] + 1),
331 "Encoded value of 0x%08x didn't match expected\n",
339 static void test_decodeEnumerated(DWORD dwEncoding)
343 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
345 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
348 DWORD bufSize = sizeof(int);
351 ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
352 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
353 (BYTE *)&val, &bufSize);
354 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
355 ok(bufSize == sizeof(int),
356 "Got unexpected size %ld for enumerated (expected %d)\n",
357 bufSize, sizeof(int));
358 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
364 struct encodedFiletime
367 const BYTE *encodedTime;
370 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
371 const struct encodedFiletime *time)
378 ret = SystemTimeToFileTime(&time->sysTime, &ft);
379 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
380 ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
381 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
382 /* years other than 1950-2050 are not allowed for encodings other than
383 * X509_CHOICE_OF_TIME.
385 if (structType == X509_CHOICE_OF_TIME ||
386 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
388 ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
390 ok(buf != NULL, "Expected an allocated buffer\n");
393 ok(buf[0] == time->encodedTime[0],
394 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
396 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
397 time->encodedTime[1], bufSize);
398 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
399 "Got unexpected value for time encoding\n");
404 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
405 "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
408 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
409 const struct encodedFiletime *time)
411 FILETIME ft1 = { 0 }, ft2 = { 0 };
412 DWORD size = sizeof(ft2);
415 ret = SystemTimeToFileTime(&time->sysTime, &ft1);
416 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
417 ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
418 time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
419 /* years other than 1950-2050 are not allowed for encodings other than
420 * X509_CHOICE_OF_TIME.
422 if (structType == X509_CHOICE_OF_TIME ||
423 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
425 ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
427 ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
428 "Got unexpected value for time decoding\n");
431 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
432 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
435 static const struct encodedFiletime times[] = {
436 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
437 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
438 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
441 static void test_encodeFiletime(DWORD dwEncoding)
445 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
447 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
448 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
449 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
453 static void test_decodeFiletime(DWORD dwEncoding)
455 static const struct encodedFiletime otherTimes[] = {
456 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x13" "19450606161000.000Z" },
457 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
458 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, "\x18" "\x13" "19450606161000+0100" },
459 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, "\x18" "\x13" "19450606161000-0100" },
460 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, "\x18" "\x13" "19450606161000-0115" },
461 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, "\x18" "\x0a" "2145060616" },
462 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0a" "4506061610" },
463 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0b" "4506061610Z" },
464 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0d" "4506061610+01" },
465 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0d" "4506061610-01" },
466 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, "\x17" "\x0f" "4506061610+0100" },
467 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, "\x17" "\x0f" "4506061610-0100" },
469 /* An oddball case that succeeds in Windows, but doesn't seem correct
470 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
472 static const char *bogusTimes[] = {
473 /* oddly, this succeeds on Windows, with year 2765
474 "\x18" "\x0f" "21r50606161000Z",
476 "\x17" "\x08" "45060616",
477 "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
478 "\x18" "\x04" "2145",
479 "\x18" "\x08" "21450606",
482 FILETIME ft1 = { 0 }, ft2 = { 0 };
485 /* Check bogus length with non-NULL buffer */
486 ret = SystemTimeToFileTime(×[0].sysTime, &ft1);
487 ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
489 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
490 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
491 ok(!ret && GetLastError() == ERROR_MORE_DATA,
492 "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
494 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
496 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
497 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
498 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
500 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
502 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
503 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
504 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
506 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
509 ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
510 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
511 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
512 "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
522 static const char commonName[] = "Juan Lang";
523 static const char surName[] = "Lang";
524 static const char bogusIA5[] = "\x80";
525 static const char bogusPrintable[] = "~";
526 static const char bogusNumeric[] = "A";
527 static const struct EncodedName names[] = {
528 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
529 { sizeof(commonName), (BYTE *)commonName } },
530 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0aJuan Lang" },
531 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
532 { sizeof(commonName), (BYTE *)commonName } },
533 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x16\x0aJuan Lang" },
534 { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
535 { sizeof(surName), (BYTE *)surName } },
536 "\x30\x10\x31\x0e\x30\x0c\x06\x03\x55\x04\x04\x16\x05Lang" },
537 { { NULL, CERT_RDN_PRINTABLE_STRING,
538 { sizeof(commonName), (BYTE *)commonName } },
539 "\x30\x12\x31\x10\x30\x0e\x06\x00\x13\x0aJuan Lang" },
540 /* The following test isn't a very good one, because it doesn't encode any
541 * Japanese characters. I'm leaving it out for now.
542 { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
543 { sizeof(commonName), (BYTE *)commonName } },
544 "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
546 /* The following tests succeed under Windows, but really should fail,
547 * they contain characters that are illegal for the encoding. I'm
548 * including them to justify my lazy encoding.
550 { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
551 { sizeof(bogusIA5), (BYTE *)bogusIA5 } },
552 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x16\x02\x80" },
553 { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
554 { sizeof(bogusPrintable), (BYTE *)bogusPrintable } },
555 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13\x02\x7e" },
556 { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
557 { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
558 "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x12\x02\x41" },
561 static const BYTE emptyName[] = { 0x30, 0 };
562 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
563 static const BYTE twoRDNs[] = "\x30\x23\x31\x21\x30\x0c\x06\x03\x55\x04\x04"
564 "\x13\x05\x4c\x61\x6e\x67\x00\x30\x11\x06\x03\x55\x04\x03"
565 "\x13\x0a\x4a\x75\x61\x6e\x20\x4c\x61\x6e\x67";
567 static void test_encodeName(DWORD dwEncoding)
569 CERT_RDN_ATTR attrs[2];
576 /* Test with NULL pvStructInfo */
577 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
578 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
579 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
580 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
581 /* Test with empty CERT_NAME_INFO */
584 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
585 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
586 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
589 ok(!memcmp(buf, emptyName, sizeof(emptyName)),
590 "Got unexpected encoding for empty name\n");
593 /* Test with bogus CERT_RDN */
595 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
596 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
597 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
598 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
599 /* Test with empty CERT_RDN */
601 rdn.rgRDNAttr = NULL;
604 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
605 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
606 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
609 ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
610 "Got unexpected encoding for empty RDN array\n");
613 /* Test with bogus attr array */
615 rdn.rgRDNAttr = NULL;
616 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
617 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
618 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
619 "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
620 /* oddly, a bogus OID is accepted by Windows XP; not testing.
621 attrs[0].pszObjId = "bogus";
622 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
623 attrs[0].Value.cbData = sizeof(commonName);
624 attrs[0].Value.pbData = (BYTE *)commonName;
626 rdn.rgRDNAttr = attrs;
627 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
628 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
629 ok(!ret, "Expected failure, got success\n");
631 /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
632 * the encoded attributes to be swapped.
634 attrs[0].pszObjId = szOID_COMMON_NAME;
635 attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
636 attrs[0].Value.cbData = sizeof(commonName);
637 attrs[0].Value.pbData = (BYTE *)commonName;
638 attrs[1].pszObjId = szOID_SUR_NAME;
639 attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
640 attrs[1].Value.cbData = sizeof(surName);
641 attrs[1].Value.pbData = (BYTE *)surName;
643 rdn.rgRDNAttr = attrs;
644 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
645 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
646 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
649 ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
650 "Got unexpected encoding for two RDN array\n");
653 /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
655 attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
656 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
657 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
658 ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
659 "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
660 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
663 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
664 ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
665 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
666 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
669 ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
670 names[i].encoded[1] + 2, size);
671 ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
672 "Got unexpected encoding\n");
678 static void compareNames(const CERT_NAME_INFO *expected,
679 const CERT_NAME_INFO *got)
681 ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
682 expected->cRDN, got->cRDN);
685 ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
686 "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
687 got->rgRDN[0].cRDNAttr);
688 if (expected->rgRDN[0].cRDNAttr)
690 if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
691 strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
693 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
694 "Expected OID %s, got NULL\n",
695 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
696 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
697 ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
698 expected->rgRDN[0].rgRDNAttr[0].pszObjId),
699 "Got unexpected OID %s, expected %s\n",
700 got->rgRDN[0].rgRDNAttr[0].pszObjId,
701 expected->rgRDN[0].rgRDNAttr[0].pszObjId);
703 ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
704 expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
705 "Unexpected data size, got %ld, expected %ld\n",
706 got->rgRDN[0].rgRDNAttr[0].Value.cbData,
707 expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
708 if (expected->rgRDN[0].rgRDNAttr[0].Value.pbData)
709 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
710 expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
711 expected->rgRDN[0].rgRDNAttr[0].Value.cbData),
712 "Unexpected value\n");
717 static void test_decodeName(DWORD dwEncoding)
724 CERT_NAME_INFO info = { 1, &rdn };
726 for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
728 /* When the output buffer is NULL, this always succeeds */
729 SetLastError(0xdeadbeef);
730 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
731 names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
732 ok(ret && GetLastError() == NOERROR,
733 "Expected success and NOERROR, got %08lx\n", GetLastError());
734 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
735 names[i].encoded[1] + 2,
736 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
737 (BYTE *)&buf, &bufSize);
738 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
740 rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
743 compareNames((CERT_NAME_INFO *)buf, &info);
747 /* test empty name */
749 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
751 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
752 (BYTE *)&buf, &bufSize);
753 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
754 /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
755 * decoder works the same way, so only test the count.
759 ok(bufSize == sizeof(CERT_NAME_INFO),
760 "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
761 ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
762 "Expected 0 RDNs in empty info, got %ld\n",
763 ((CERT_NAME_INFO *)buf)->cRDN);
768 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
770 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
771 (BYTE *)&buf, &bufSize);
772 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
775 CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
777 ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
778 info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
779 "Got unexpected value for empty RDN\n");
782 /* test two RDN attrs */
784 ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
786 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
787 (BYTE *)&buf, &bufSize);
788 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
791 CERT_RDN_ATTR attrs[] = {
792 { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
794 { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
795 (BYTE *)commonName } },
798 rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
799 rdn.rgRDNAttr = attrs;
800 compareNames((CERT_NAME_INFO *)buf, &info);
811 static const struct encodedOctets octets[] = {
812 { "hi", "\x04\x02hi" },
813 { "somelong\xffstring", "\x04\x0fsomelong\xffstring" },
817 static void test_encodeOctets(DWORD dwEncoding)
819 CRYPT_DATA_BLOB blob;
822 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
828 blob.cbData = strlen(octets[i].val);
829 blob.pbData = (BYTE *)octets[i].val;
830 ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
831 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
832 ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
836 "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
837 ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
838 buf[1], octets[i].encoded[1]);
839 ok(!memcmp(buf + 1, octets[i].encoded + 1,
840 octets[i].encoded[1] + 1), "Got unexpected value\n");
846 static void test_decodeOctets(DWORD dwEncoding)
850 for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
856 ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
857 (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
858 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
859 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
860 ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
861 "Expected size >= %d, got %ld\n",
862 sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
863 ok(buf != NULL, "Expected allocated buffer\n");
866 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
869 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
870 "Unexpected value\n");
876 static const BYTE bytesToEncode[] = { 0xff, 0xff };
886 static const struct encodedBits bits[] = {
887 /* normal test case */
888 { 1, "\x03\x03\x01\xff\xfe", 2, "\xff\xfe" },
889 /* strange test case, showing cUnusedBits >= 8 is allowed */
890 { 9, "\x03\x02\x01\xfe", 1, "\xfe" },
891 /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
892 { 17, "\x03\x01\x00", 0, NULL },
895 static void test_encodeBits(DWORD dwEncoding)
899 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
906 blob.cbData = sizeof(bytesToEncode);
907 blob.pbData = (BYTE *)bytesToEncode;
908 blob.cUnusedBits = bits[i].cUnusedBits;
909 ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
910 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
911 ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
914 ok(bufSize == bits[i].encoded[1] + 2,
915 "Got unexpected size %ld, expected %d\n", bufSize,
916 bits[i].encoded[1] + 2);
917 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
918 "Unexpected value\n");
924 static void test_decodeBits(DWORD dwEncoding)
926 static const BYTE ber[] = "\x03\x02\x01\xff";
927 static const BYTE berDecoded = 0xfe;
934 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
936 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
937 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
939 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
942 CRYPT_BIT_BLOB *blob;
944 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
945 "Got unexpected size %ld, expected >= %ld\n", bufSize,
946 sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
947 blob = (CRYPT_BIT_BLOB *)buf;
948 ok(blob->cbData == bits[i].cbDecoded,
949 "Got unexpected length %ld, expected %ld\n", blob->cbData,
951 if (blob->cbData && bits[i].cbDecoded)
952 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
953 "Unexpected value\n");
957 /* special case: check that something that's valid in BER but not in DER
958 * decodes successfully
960 ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
961 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
962 ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
965 CRYPT_BIT_BLOB *blob;
967 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
968 "Got unexpected size %ld, expected >= %d\n", bufSize,
969 sizeof(CRYPT_BIT_BLOB) + berDecoded);
970 blob = (CRYPT_BIT_BLOB *)buf;
971 ok(blob->cbData == sizeof(berDecoded),
972 "Got unexpected length %ld, expected %d\n", blob->cbData,
975 ok(*blob->pbData == berDecoded, "Unexpected value\n");
980 static void test_registerOIDFunction(void)
982 static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
985 /* oddly, this succeeds under WinXP; the function name key is merely
986 * omitted. This may be a side effect of the registry code, I don't know.
987 * I don't check it because I doubt anyone would depend on it.
988 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
989 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
991 /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
992 * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
994 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
996 ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
997 HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
998 "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
999 /* This has no effect, but "succeeds" on XP */
1000 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
1001 "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
1002 ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
1003 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1004 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1005 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1006 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1007 "1.2.3.4.5.6.7.8.9.10");
1008 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1009 ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
1010 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1011 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1012 ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
1013 "1.2.3.4.5.6.7.8.9.10");
1014 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1015 /* This has no effect */
1016 ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
1017 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1018 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1019 /* Check with bogus encoding type: */
1020 ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
1021 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1022 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1023 /* This is written with value 3 verbatim. Thus, the encoding type isn't
1024 * (for now) treated as a mask.
1026 ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
1027 "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1028 ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1029 ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
1030 "1.2.3.4.5.6.7.8.9.10");
1031 ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1036 static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
1037 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
1040 for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
1042 test_encodeInt(encodings[i]);
1043 test_decodeInt(encodings[i]);
1044 test_encodeEnumerated(encodings[i]);
1045 test_decodeEnumerated(encodings[i]);
1046 test_encodeFiletime(encodings[i]);
1047 test_decodeFiletime(encodings[i]);
1048 test_encodeName(encodings[i]);
1049 test_decodeName(encodings[i]);
1050 test_encodeOctets(encodings[i]);
1051 test_decodeOctets(encodings[i]);
1052 test_encodeBits(encodings[i]);
1053 test_decodeBits(encodings[i]);
1055 test_registerOIDFunction();