Moved the audio driver configuration to HKCU\Software\Wine\Drivers and
[wine] / dlls / crypt32 / tests / encode.c
1 /*
2  * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
3  *
4  * Copyright 2005 Juan Lang
5  *
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.
10  *
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.
15  *
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
19  */
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
26
27 #include "wine/test.h"
28
29 struct encodedInt
30 {
31     int val;
32     BYTE *encoded;
33 };
34
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" },
43 };
44
45 struct encodedBigInt
46 {
47     BYTE *val;
48     BYTE *encoded;
49     BYTE *decoded;
50 };
51
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" },
59 };
60
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 },
67 };
68
69 static void test_encodeInt(DWORD dwEncoding)
70 {
71     DWORD bufSize = 0;
72     int i;
73     BOOL ret;
74     CRYPT_INTEGER_BLOB blob;
75     BYTE *buf = NULL;
76
77     /* CryptEncodeObjectEx with NULL bufSize crashes..
78     ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
79      NULL);
80      */
81     /* check bogus encoding */
82     ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
83      &bufSize);
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
87      * NTSTATUS.
88      */
89     ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
90      &bufSize);
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++)
94     {
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());
102         if (buf)
103         {
104             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
105              buf[0]);
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);
108             LocalFree(buf);
109         }
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());
119         if (buf)
120         {
121             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
122              buf[0]);
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);
127             LocalFree(buf);
128         }
129     }
130     /* encode a couple bigger ints, just to show it's little-endian and leading
131      * sign bytes are dropped
132      */
133     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
134     {
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());
143         if (buf)
144         {
145             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
146              buf[0]);
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");
152             LocalFree(buf);
153         }
154     }
155     /* and, encode some uints */
156     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
157     {
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());
166         if (buf)
167         {
168             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
169              buf[0]);
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");
175             LocalFree(buf);
176         }
177     }
178 }
179
180 static void test_decodeInt(DWORD dwEncoding)
181 {
182     static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
183     static const char testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
184     BYTE *buf = NULL;
185     DWORD bufSize = 0;
186     int i;
187     BOOL ret;
188
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);
192      */
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,
200      &bufSize);
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++)
214     {
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,
219          &bufSize);
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),
227          bufSize);
228         ok(buf != NULL, "Expected allocated buffer\n");
229         if (buf)
230         {
231             ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
232              ints[i].val, *(int *)buf);
233             LocalFree(buf);
234         }
235     }
236     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
237     {
238         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
239          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
240          &bufSize);
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),
249          bufSize);
250         ok(buf != NULL, "Expected allocated buffer\n");
251         if (buf)
252         {
253             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
254
255             ok(blob->cbData == strlen(bigInts[i].decoded),
256              "Expected len %d, got %ld\n", strlen(bigInts[i].decoded),
257              blob->cbData);
258             ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
259              "Unexpected value\n");
260             LocalFree(buf);
261         }
262     }
263     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
264     {
265         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
266          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
267          &bufSize);
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),
276          bufSize);
277         ok(buf != NULL, "Expected allocated buffer\n");
278         if (buf)
279         {
280             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
281
282             ok(blob->cbData == strlen(bigUInts[i].val),
283              "Expected len %d, got %ld\n", strlen(bigUInts[i].val),
284              blob->cbData);
285             ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
286              "Unexpected value\n");
287             LocalFree(buf);
288         }
289     }
290 }
291
292 /* These are always encoded unsigned, and aren't constrained to be any
293  * particular value
294  */
295 static const struct encodedInt enums[] = {
296  { 1,    "\x0a\x01\x01" },
297  { -128, "\x0a\x05\x00\xff\xff\xff\x80" },
298 };
299
300 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
301  * X509_ENUMERATED.
302  */
303 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
304  szOID_CRL_REASON_CODE };
305
306 static void test_encodeEnumerated(DWORD dwEncoding)
307 {
308     DWORD i, j;
309
310     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
311     {
312         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
313         {
314             BOOL ret;
315             BYTE *buf = NULL;
316             DWORD bufSize = 0;
317
318             ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
319              &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
320              &bufSize);
321             ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
322             if (buf)
323             {
324                 ok(buf[0] == 0xa,
325                  "Got unexpected type %d for enumerated (expected 0xa)\n",
326                  buf[0]);
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",
332                  enums[j].val);
333                 LocalFree(buf);
334             }
335         }
336     }
337 }
338
339 static void test_decodeEnumerated(DWORD dwEncoding)
340 {
341     DWORD i, j;
342
343     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
344     {
345         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
346         {
347             BOOL ret;
348             DWORD bufSize = sizeof(int);
349             int val;
350
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",
359              val, enums[j].val);
360         }
361     }
362 }
363
364 struct encodedFiletime
365 {
366     SYSTEMTIME sysTime;
367     const BYTE *encodedTime;
368 };
369
370 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
371  const struct encodedFiletime *time)
372 {
373     FILETIME ft = { 0 };
374     BYTE *buf = NULL;
375     DWORD bufSize = 0;
376     BOOL ret;
377
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.
384      */
385     if (structType == X509_CHOICE_OF_TIME ||
386      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
387     {
388         ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
389          GetLastError());
390         ok(buf != NULL, "Expected an allocated buffer\n");
391         if (buf)
392         {
393             ok(buf[0] == time->encodedTime[0],
394              "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
395              buf[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");
400             LocalFree(buf);
401         }
402     }
403     else
404         ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
405          "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
406 }
407
408 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
409  const struct encodedFiletime *time)
410 {
411     FILETIME ft1 = { 0 }, ft2 = { 0 };
412     DWORD size = sizeof(ft2);
413     BOOL ret;
414
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.
421      */
422     if (structType == X509_CHOICE_OF_TIME ||
423      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
424     {
425         ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
426          GetLastError());
427         ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
428          "Got unexpected value for time decoding\n");
429     }
430     else
431         ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
432          "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
433 }
434
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" },
439 };
440
441 static void test_encodeFiletime(DWORD dwEncoding)
442 {
443     DWORD i;
444
445     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
446     {
447         testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
448         testTimeEncoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
449         testTimeEncoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
450     }
451 }
452
453 static void test_decodeFiletime(DWORD dwEncoding)
454 {
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" },
468     };
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" },
471      */
472     static const char *bogusTimes[] = {
473      /* oddly, this succeeds on Windows, with year 2765
474      "\x18" "\x0f" "21r50606161000Z",
475       */
476      "\x17" "\x08" "45060616",
477      "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
478      "\x18" "\x04" "2145",
479      "\x18" "\x08" "21450606",
480     };
481     DWORD i, size;
482     FILETIME ft1 = { 0 }, ft2 = { 0 };
483     BOOL ret;
484
485     /* Check bogus length with non-NULL buffer */
486     ret = SystemTimeToFileTime(&times[0].sysTime, &ft1);
487     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
488     size = 1;
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());
493     /* Normal tests */
494     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
495     {
496         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
497         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
498         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
499     }
500     for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
501     {
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]);
505     }
506     for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
507     {
508         size = sizeof(ft1);
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());
513     }
514 }
515
516 struct EncodedName
517 {
518     CERT_RDN_ATTR attr;
519     BYTE *encoded;
520 };
521
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" },
545  */
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.
549   */
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" },
559 };
560
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";
566
567 static void test_encodeName(DWORD dwEncoding)
568 {
569     CERT_RDN_ATTR attrs[2];
570     CERT_RDN rdn;
571     CERT_NAME_INFO info;
572     BYTE *buf = NULL;
573     DWORD size = 0, i;
574     BOOL ret;
575
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 */
582     info.cRDN = 0;
583     info.rgRDN = NULL;
584     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
585      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
586     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
587     if (buf)
588     {
589         ok(!memcmp(buf, emptyName, sizeof(emptyName)),
590          "Got unexpected encoding for empty name\n");
591         LocalFree(buf);
592     }
593     /* Test with bogus CERT_RDN */
594     info.cRDN = 1;
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 */
600     rdn.cRDNAttr = 0;
601     rdn.rgRDNAttr = NULL;
602     info.cRDN = 1;
603     info.rgRDN = &rdn;
604     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
605      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
606     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
607     if (buf)
608     {
609         ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
610          "Got unexpected encoding for empty RDN array\n");
611         LocalFree(buf);
612     }
613     /* Test with bogus attr array */
614     rdn.cRDNAttr = 1;
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;
625     rdn.cRDNAttr = 1;
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");
630      */
631     /* Check with two CERT_RDN_ATTRs.  Note DER encoding forces the order of
632      * the encoded attributes to be swapped.
633      */
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;
642     rdn.cRDNAttr = 2;
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());
647     if (buf)
648     {
649         ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
650          "Got unexpected encoding for two RDN array\n");
651         LocalFree(buf);
652     }
653     /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
654     rdn.cRDNAttr = 1;
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++)
661     {
662         rdn.cRDNAttr = 1;
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());
667         if (buf)
668         {
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");
673             LocalFree(buf);
674         }
675     }
676 }
677
678 static void compareNames(const CERT_NAME_INFO *expected,
679  const CERT_NAME_INFO *got)
680 {
681     ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
682      expected->cRDN, got->cRDN);
683     if (expected->cRDN)
684     {
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)
689         {
690             if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
691              strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
692             {
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);
702             }
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");
713         }
714     }
715 }
716
717 static void test_decodeName(DWORD dwEncoding)
718 {
719     int i;
720     BYTE *buf = NULL;
721     DWORD bufSize = 0;
722     BOOL ret;
723     CERT_RDN rdn;
724     CERT_NAME_INFO info = { 1, &rdn };
725
726     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
727     {
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());
739         rdn.cRDNAttr = 1;
740         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
741         if (buf)
742         {
743             compareNames((CERT_NAME_INFO *)buf, &info);
744             LocalFree(buf);
745         }
746     }
747     /* test empty name */
748     bufSize = 0;
749     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
750      emptyName[1] + 2,
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.
756      */
757     if (buf)
758     {
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);
764         LocalFree(buf);
765     }
766     /* test empty RDN */
767     bufSize = 0;
768     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
769      emptyRDNs[1] + 2,
770      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
771      (BYTE *)&buf, &bufSize);
772     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
773     if (buf)
774     {
775         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
776
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");
780         LocalFree(buf);
781     }
782     /* test two RDN attrs */
783     bufSize = 0;
784     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
785      twoRDNs[1] + 2,
786      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
787      (BYTE *)&buf, &bufSize);
788     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
789     if (buf)
790     {
791         CERT_RDN_ATTR attrs[] = {
792          { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
793           (BYTE *)surName } },
794          { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
795           (BYTE *)commonName } },
796         };
797
798         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
799         rdn.rgRDNAttr = attrs;
800         compareNames((CERT_NAME_INFO *)buf, &info);
801         LocalFree(buf);
802     }
803 }
804
805 struct encodedOctets
806 {
807     BYTE *val;
808     BYTE *encoded;
809 };
810
811 static const struct encodedOctets octets[] = {
812     { "hi", "\x04\x02hi" },
813     { "somelong\xffstring", "\x04\x0fsomelong\xffstring" },
814     { "", "\x04\x00" },
815 };
816
817 static void test_encodeOctets(DWORD dwEncoding)
818 {
819     CRYPT_DATA_BLOB blob;
820     DWORD i;
821
822     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
823     {
824         BYTE *buf = NULL;
825         BOOL ret;
826         DWORD bufSize = 0;
827
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());
833         if (buf)
834         {
835             ok(buf[0] == 4,
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");
841             LocalFree(buf);
842         }
843     }
844 }
845
846 static void test_decodeOctets(DWORD dwEncoding)
847 {
848     DWORD i;
849
850     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
851     {
852         BYTE *buf = NULL;
853         BOOL ret;
854         DWORD bufSize = 0;
855
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");
864         if (buf)
865         {
866             CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
867
868             if (blob->cbData)
869                 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
870                  "Unexpected value\n");
871             LocalFree(buf);
872         }
873     }
874 }
875
876 static const BYTE bytesToEncode[] = { 0xff, 0xff };
877
878 struct encodedBits
879 {
880     DWORD cUnusedBits;
881     BYTE *encoded;
882     DWORD cbDecoded;
883     BYTE *decoded;
884 };
885
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 },
893 };
894
895 static void test_encodeBits(DWORD dwEncoding)
896 {
897     DWORD i;
898
899     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
900     {
901         CRYPT_BIT_BLOB blob;
902         BOOL ret;
903         BYTE *buf = NULL;
904         DWORD bufSize = 0;
905
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());
912         if (buf)
913         {
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");
919             LocalFree(buf);
920         }
921     }
922 }
923
924 static void test_decodeBits(DWORD dwEncoding)
925 {
926     static const BYTE ber[] = "\x03\x02\x01\xff";
927     static const BYTE berDecoded = 0xfe;
928     DWORD i;
929     BOOL ret;
930     BYTE *buf = NULL;
931     DWORD bufSize = 0;
932
933     /* normal cases */
934     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
935     {
936         ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
937          bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
938          &bufSize);
939         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
940         if (buf)
941         {
942             CRYPT_BIT_BLOB *blob;
943
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,
950              bits[i].cbDecoded);
951             if (blob->cbData && bits[i].cbDecoded)
952                 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
953                  "Unexpected value\n");
954             LocalFree(buf);
955         }
956     }
957     /* special case: check that something that's valid in BER but not in DER
958      * decodes successfully
959      */
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());
963     if (buf)
964     {
965         CRYPT_BIT_BLOB *blob;
966
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,
973          sizeof(berDecoded));
974         if (blob->cbData)
975             ok(*blob->pbData == berDecoded, "Unexpected value\n");
976         LocalFree(buf);
977     }
978 }
979
980 static void test_registerOIDFunction(void)
981 {
982     static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
983     BOOL ret;
984
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);
990      */
991     /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
992      * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
993      */
994     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
995      NULL);
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.
1025      */
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());
1032 }
1033
1034 START_TEST(encode)
1035 {
1036     static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
1037      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
1038     DWORD i;
1039
1040     for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
1041     {
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]);
1054     }
1055     test_registerOIDFunction();
1056 }