Implemented memory cert stores.
[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     const 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     const BYTE *val;
48     const BYTE *encoded;
49     const 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(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
107              buf[1], ints[i].encoded[1]);
108             ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
109              "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
110             LocalFree(buf);
111         }
112         /* encode as multibyte integer */
113         blob.cbData = sizeof(ints[i].val);
114         blob.pbData = (BYTE *)&ints[i].val;
115         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
116          0, NULL, NULL, &bufSize);
117         ok(ret, "Expected success, got %ld\n", GetLastError());
118         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
119          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
120         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
121         if (buf)
122         {
123             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
124              buf[0]);
125             ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
126              buf[1], ints[i].encoded[1]);
127             ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
128              "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
129             LocalFree(buf);
130         }
131     }
132     /* encode a couple bigger ints, just to show it's little-endian and leading
133      * sign bytes are dropped
134      */
135     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
136     {
137         blob.cbData = strlen(bigInts[i].val);
138         blob.pbData = (BYTE *)bigInts[i].val;
139         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
140          0, NULL, NULL, &bufSize);
141         ok(ret, "Expected success, got %ld\n", GetLastError());
142         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
143          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
144         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
145         if (buf)
146         {
147             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
148              buf[0]);
149             ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
150              buf[1], bigInts[i].encoded[1]);
151             ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
152              bigInts[i].encoded[1] + 1),
153              "Encoded value didn't match expected\n");
154             LocalFree(buf);
155         }
156     }
157     /* and, encode some uints */
158     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
159     {
160         blob.cbData = strlen(bigUInts[i].val);
161         blob.pbData = (BYTE *)bigUInts[i].val;
162         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
163          0, NULL, NULL, &bufSize);
164         ok(ret, "Expected success, got %ld\n", GetLastError());
165         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
166          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
167         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
168         if (buf)
169         {
170             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
171              buf[0]);
172             ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
173              buf[1], bigUInts[i].encoded[1]);
174             ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
175              bigUInts[i].encoded[1] + 1),
176              "Encoded value didn't match expected\n");
177             LocalFree(buf);
178         }
179     }
180 }
181
182 static void test_decodeInt(DWORD dwEncoding)
183 {
184     static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
185     static const char testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
186     static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
187     static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
188     BYTE *buf = NULL;
189     DWORD bufSize = 0;
190     int i;
191     BOOL ret;
192
193     /* CryptDecodeObjectEx with NULL bufSize crashes..
194     ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded, 
195      ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
196      */
197     /* check bogus encoding */
198     ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded, 
199      ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
200     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
201      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
202     /* check with NULL integer buffer */
203     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
204      &bufSize);
205     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
206      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
207     /* check with a valid, but too large, integer */
208     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
209      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
210     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
211      "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
212     /* check with a DER-encoded string */
213     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
214      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
215     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
216      "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
217     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
218     {
219         /* When the output buffer is NULL, this always succeeds */
220         SetLastError(0xdeadbeef);
221         ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
222          (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
223          &bufSize);
224         ok(ret && GetLastError() == NOERROR,
225          "Expected success and NOERROR, got %ld\n", GetLastError());
226         ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
227          (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
228          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
229         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
230         ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
231          bufSize);
232         ok(buf != NULL, "Expected allocated buffer\n");
233         if (buf)
234         {
235             ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
236              ints[i].val, *(int *)buf);
237             LocalFree(buf);
238         }
239     }
240     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
241     {
242         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
243          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
244          &bufSize);
245         ok(ret && GetLastError() == NOERROR,
246          "Expected success and NOERROR, got %ld\n", GetLastError());
247         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
248          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
249          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
250         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
251         ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
252          "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
253          bufSize);
254         ok(buf != NULL, "Expected allocated buffer\n");
255         if (buf)
256         {
257             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
258
259             ok(blob->cbData == strlen(bigInts[i].decoded),
260              "Expected len %d, got %ld\n", strlen(bigInts[i].decoded),
261              blob->cbData);
262             ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
263              "Unexpected value\n");
264             LocalFree(buf);
265         }
266     }
267     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
268     {
269         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
270          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
271          &bufSize);
272         ok(ret && GetLastError() == NOERROR,
273          "Expected success and NOERROR, got %ld\n", GetLastError());
274         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
275          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
276          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
277         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
278         ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
279          "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
280          bufSize);
281         ok(buf != NULL, "Expected allocated buffer\n");
282         if (buf)
283         {
284             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
285
286             ok(blob->cbData == strlen(bigUInts[i].val),
287              "Expected len %d, got %ld\n", strlen(bigUInts[i].val),
288              blob->cbData);
289             ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
290              "Unexpected value\n");
291             LocalFree(buf);
292         }
293     }
294     /* Decode the value 1 with long-form length */
295     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
296      sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
297     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
298     if (buf)
299     {
300         ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
301         LocalFree(buf);
302     }
303     /* Try to decode some bogus large items */
304     /* The buffer size is smaller than the encoded length, so this should fail
305      * with CRYPT_E_ASN1_EOD if it's being decoded.
306      * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
307      * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
308      * So this test unfortunately isn't useful.
309     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
310      0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
311     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
312      "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
313      */
314     /* This will try to decode the buffer and overflow it, check that it's
315      * caught.
316      */
317     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
318      0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
319     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
320      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
321 }
322
323 /* These are always encoded unsigned, and aren't constrained to be any
324  * particular value
325  */
326 static const struct encodedInt enums[] = {
327  { 1,    "\x0a\x01\x01" },
328  { -128, "\x0a\x05\x00\xff\xff\xff\x80" },
329 };
330
331 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
332  * X509_ENUMERATED.
333  */
334 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
335  szOID_CRL_REASON_CODE };
336
337 static void test_encodeEnumerated(DWORD dwEncoding)
338 {
339     DWORD i, j;
340
341     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
342     {
343         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
344         {
345             BOOL ret;
346             BYTE *buf = NULL;
347             DWORD bufSize = 0;
348
349             ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
350              &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
351              &bufSize);
352             ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
353             if (buf)
354             {
355                 ok(buf[0] == 0xa,
356                  "Got unexpected type %d for enumerated (expected 0xa)\n",
357                  buf[0]);
358                 ok(buf[1] == enums[j].encoded[1],
359                  "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
360                 ok(!memcmp(buf + 1, enums[j].encoded + 1,
361                  enums[j].encoded[1] + 1),
362                  "Encoded value of 0x%08x didn't match expected\n",
363                  enums[j].val);
364                 LocalFree(buf);
365             }
366         }
367     }
368 }
369
370 static void test_decodeEnumerated(DWORD dwEncoding)
371 {
372     DWORD i, j;
373
374     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
375     {
376         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
377         {
378             BOOL ret;
379             DWORD bufSize = sizeof(int);
380             int val;
381
382             ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
383              enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
384              (BYTE *)&val, &bufSize);
385             ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
386             ok(bufSize == sizeof(int),
387              "Got unexpected size %ld for enumerated (expected %d)\n",
388              bufSize, sizeof(int));
389             ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
390              val, enums[j].val);
391         }
392     }
393 }
394
395 struct encodedFiletime
396 {
397     SYSTEMTIME sysTime;
398     const BYTE *encodedTime;
399 };
400
401 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
402  const struct encodedFiletime *time)
403 {
404     FILETIME ft = { 0 };
405     BYTE *buf = NULL;
406     DWORD bufSize = 0;
407     BOOL ret;
408
409     ret = SystemTimeToFileTime(&time->sysTime, &ft);
410     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
411     ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
412      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
413     /* years other than 1950-2050 are not allowed for encodings other than
414      * X509_CHOICE_OF_TIME.
415      */
416     if (structType == X509_CHOICE_OF_TIME ||
417      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
418     {
419         ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
420          GetLastError());
421         ok(buf != NULL, "Expected an allocated buffer\n");
422         if (buf)
423         {
424             ok(buf[0] == time->encodedTime[0],
425              "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
426              buf[0]);
427             ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
428              time->encodedTime[1], bufSize);
429             ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
430              "Got unexpected value for time encoding\n");
431             LocalFree(buf);
432         }
433     }
434     else
435         ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
436          "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
437 }
438
439 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
440  const struct encodedFiletime *time)
441 {
442     FILETIME ft1 = { 0 }, ft2 = { 0 };
443     DWORD size = sizeof(ft2);
444     BOOL ret;
445
446     ret = SystemTimeToFileTime(&time->sysTime, &ft1);
447     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
448     ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
449      time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
450     /* years other than 1950-2050 are not allowed for encodings other than
451      * X509_CHOICE_OF_TIME.
452      */
453     if (structType == X509_CHOICE_OF_TIME ||
454      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
455     {
456         ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
457          GetLastError());
458         ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
459          "Got unexpected value for time decoding\n");
460     }
461     else
462         ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
463          "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
464 }
465
466 static const struct encodedFiletime times[] = {
467  { { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
468  { { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
469  { { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
470 };
471
472 static void test_encodeFiletime(DWORD dwEncoding)
473 {
474     DWORD i;
475
476     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
477     {
478         testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
479         testTimeEncoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
480         testTimeEncoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
481     }
482 }
483
484 static void test_decodeFiletime(DWORD dwEncoding)
485 {
486     static const struct encodedFiletime otherTimes[] = {
487      { { 1945, 6, 1, 6, 16, 10, 0, 0 },   "\x18" "\x13" "19450606161000.000Z" },
488      { { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
489      { { 1945, 6, 1, 6, 17, 10, 0, 0 },   "\x18" "\x13" "19450606161000+0100" },
490      { { 1945, 6, 1, 6, 15, 10, 0, 0 },   "\x18" "\x13" "19450606161000-0100" },
491      { { 1945, 6, 1, 6, 14, 55, 0, 0 },   "\x18" "\x13" "19450606161000-0115" },
492      { { 2145, 6, 1, 6, 16,  0, 0, 0 },   "\x18" "\x0a" "2145060616" },
493      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   "\x17" "\x0a" "4506061610" },
494      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   "\x17" "\x0b" "4506061610Z" },
495      { { 2045, 6, 1, 6, 17, 10, 0, 0 },   "\x17" "\x0d" "4506061610+01" },
496      { { 2045, 6, 1, 6, 15, 10, 0, 0 },   "\x17" "\x0d" "4506061610-01" },
497      { { 2045, 6, 1, 6, 17, 10, 0, 0 },   "\x17" "\x0f" "4506061610+0100" },
498      { { 2045, 6, 1, 6, 15, 10, 0, 0 },   "\x17" "\x0f" "4506061610-0100" },
499     };
500     /* An oddball case that succeeds in Windows, but doesn't seem correct
501      { { 2145, 6, 1, 2, 11, 31, 0, 0 },   "\x18" "\x13" "21450606161000-9999" },
502      */
503     static const char *bogusTimes[] = {
504      /* oddly, this succeeds on Windows, with year 2765
505      "\x18" "\x0f" "21r50606161000Z",
506       */
507      "\x17" "\x08" "45060616",
508      "\x18" "\x0f" "aaaaaaaaaaaaaaZ",
509      "\x18" "\x04" "2145",
510      "\x18" "\x08" "21450606",
511     };
512     DWORD i, size;
513     FILETIME ft1 = { 0 }, ft2 = { 0 };
514     BOOL ret;
515
516     /* Check bogus length with non-NULL buffer */
517     ret = SystemTimeToFileTime(&times[0].sysTime, &ft1);
518     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
519     size = 1;
520     ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
521      times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
522     ok(!ret && GetLastError() == ERROR_MORE_DATA,
523      "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
524     /* Normal tests */
525     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
526     {
527         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
528         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
529         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
530     }
531     for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
532     {
533         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
534         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
535         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
536     }
537     for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
538     {
539         size = sizeof(ft1);
540         ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
541          bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
542         ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
543          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
544     }
545 }
546
547 struct EncodedName
548 {
549     CERT_RDN_ATTR attr;
550     const BYTE *encoded;
551 };
552
553 static const char commonName[] = "Juan Lang";
554 static const char surName[] = "Lang";
555 static const char bogusIA5[] = "\x80";
556 static const char bogusPrintable[] = "~";
557 static const char bogusNumeric[] = "A";
558 static const struct EncodedName names[] = {
559  { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
560    { sizeof(commonName), (BYTE *)commonName } },
561  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0aJuan Lang" },
562  { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
563    { sizeof(commonName), (BYTE *)commonName } },
564  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x16\x0aJuan Lang" },
565  { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
566    { sizeof(surName), (BYTE *)surName } },
567  "\x30\x10\x31\x0e\x30\x0c\x06\x03\x55\x04\x04\x16\x05Lang" },
568  { { NULL, CERT_RDN_PRINTABLE_STRING,
569    { sizeof(commonName), (BYTE *)commonName } },
570  "\x30\x12\x31\x10\x30\x0e\x06\x00\x13\x0aJuan Lang" },
571 /* The following test isn't a very good one, because it doesn't encode any
572  * Japanese characters.  I'm leaving it out for now.
573  { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
574    { sizeof(commonName), (BYTE *)commonName } },
575  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
576  */
577  /* The following tests succeed under Windows, but really should fail,
578   * they contain characters that are illegal for the encoding.  I'm
579   * including them to justify my lazy encoding.
580   */
581  { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
582    { sizeof(bogusIA5), (BYTE *)bogusIA5 } },
583  "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x16\x02\x80" },
584  { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
585    { sizeof(bogusPrintable), (BYTE *)bogusPrintable } },
586  "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13\x02\x7e" },
587  { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
588    { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
589  "\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x12\x02\x41" },
590 };
591
592 static const BYTE emptyName[] = { 0x30, 0 };
593 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
594 static const BYTE twoRDNs[] = "\x30\x23\x31\x21\x30\x0c\x06\x03\x55\x04\x04"
595  "\x13\x05\x4c\x61\x6e\x67\x00\x30\x11\x06\x03\x55\x04\x03"
596  "\x13\x0a\x4a\x75\x61\x6e\x20\x4c\x61\x6e\x67";
597
598 static void test_encodeName(DWORD dwEncoding)
599 {
600     CERT_RDN_ATTR attrs[2];
601     CERT_RDN rdn;
602     CERT_NAME_INFO info;
603     BYTE *buf = NULL;
604     DWORD size = 0, i;
605     BOOL ret;
606
607     /* Test with NULL pvStructInfo */
608     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
609      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
610     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
611      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
612     /* Test with empty CERT_NAME_INFO */
613     info.cRDN = 0;
614     info.rgRDN = NULL;
615     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
616      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
617     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
618     if (buf)
619     {
620         ok(!memcmp(buf, emptyName, sizeof(emptyName)),
621          "Got unexpected encoding for empty name\n");
622         LocalFree(buf);
623     }
624     /* Test with bogus CERT_RDN */
625     info.cRDN = 1;
626     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
627      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
628     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
629      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
630     /* Test with empty CERT_RDN */
631     rdn.cRDNAttr = 0;
632     rdn.rgRDNAttr = NULL;
633     info.cRDN = 1;
634     info.rgRDN = &rdn;
635     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
636      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
637     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
638     if (buf)
639     {
640         ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
641          "Got unexpected encoding for empty RDN array\n");
642         LocalFree(buf);
643     }
644     /* Test with bogus attr array */
645     rdn.cRDNAttr = 1;
646     rdn.rgRDNAttr = NULL;
647     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
648      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
649     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
650      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
651     /* oddly, a bogus OID is accepted by Windows XP; not testing.
652     attrs[0].pszObjId = "bogus";
653     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
654     attrs[0].Value.cbData = sizeof(commonName);
655     attrs[0].Value.pbData = (BYTE *)commonName;
656     rdn.cRDNAttr = 1;
657     rdn.rgRDNAttr = attrs;
658     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
659      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
660     ok(!ret, "Expected failure, got success\n");
661      */
662     /* Check with two CERT_RDN_ATTRs.  Note DER encoding forces the order of
663      * the encoded attributes to be swapped.
664      */
665     attrs[0].pszObjId = szOID_COMMON_NAME;
666     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
667     attrs[0].Value.cbData = sizeof(commonName);
668     attrs[0].Value.pbData = (BYTE *)commonName;
669     attrs[1].pszObjId = szOID_SUR_NAME;
670     attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
671     attrs[1].Value.cbData = sizeof(surName);
672     attrs[1].Value.pbData = (BYTE *)surName;
673     rdn.cRDNAttr = 2;
674     rdn.rgRDNAttr = attrs;
675     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
676      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
677     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
678     if (buf)
679     {
680         ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
681          "Got unexpected encoding for two RDN array\n");
682         LocalFree(buf);
683     }
684     /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
685     rdn.cRDNAttr = 1;
686     attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
687     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
688      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
689     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
690      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
691     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
692     {
693         rdn.cRDNAttr = 1;
694         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
695         ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
696          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
697         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
698         if (buf)
699         {
700             ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
701              names[i].encoded[1] + 2, size);
702             ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
703              "Got unexpected encoding\n");
704             LocalFree(buf);
705         }
706     }
707 }
708
709 static void compareNames(const CERT_NAME_INFO *expected,
710  const CERT_NAME_INFO *got)
711 {
712     ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
713      expected->cRDN, got->cRDN);
714     if (expected->cRDN)
715     {
716         ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
717          "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
718          got->rgRDN[0].cRDNAttr);
719         if (expected->rgRDN[0].cRDNAttr)
720         {
721             if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
722              strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
723             {
724                 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
725                  "Expected OID %s, got NULL\n",
726                  expected->rgRDN[0].rgRDNAttr[0].pszObjId);
727                 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
728                     ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
729                      expected->rgRDN[0].rgRDNAttr[0].pszObjId),
730                      "Got unexpected OID %s, expected %s\n",
731                      got->rgRDN[0].rgRDNAttr[0].pszObjId,
732                      expected->rgRDN[0].rgRDNAttr[0].pszObjId);
733             }
734             ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
735              expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
736              "Unexpected data size, got %ld, expected %ld\n",
737              got->rgRDN[0].rgRDNAttr[0].Value.cbData,
738              expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
739             if (expected->rgRDN[0].rgRDNAttr[0].Value.pbData)
740                 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
741                  expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
742                  expected->rgRDN[0].rgRDNAttr[0].Value.cbData),
743                  "Unexpected value\n");
744         }
745     }
746 }
747
748 static void test_decodeName(DWORD dwEncoding)
749 {
750     int i;
751     BYTE *buf = NULL;
752     DWORD bufSize = 0;
753     BOOL ret;
754     CERT_RDN rdn;
755     CERT_NAME_INFO info = { 1, &rdn };
756
757     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
758     {
759         /* When the output buffer is NULL, this always succeeds */
760         SetLastError(0xdeadbeef);
761         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
762          names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
763         ok(ret && GetLastError() == NOERROR,
764          "Expected success and NOERROR, got %08lx\n", GetLastError());
765         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
766          names[i].encoded[1] + 2,
767          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
768          (BYTE *)&buf, &bufSize);
769         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
770         rdn.cRDNAttr = 1;
771         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
772         if (buf)
773         {
774             compareNames((CERT_NAME_INFO *)buf, &info);
775             LocalFree(buf);
776         }
777     }
778     /* test empty name */
779     bufSize = 0;
780     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
781      emptyName[1] + 2,
782      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
783      (BYTE *)&buf, &bufSize);
784     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
785     /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL.  My
786      * decoder works the same way, so only test the count.
787      */
788     if (buf)
789     {
790         ok(bufSize == sizeof(CERT_NAME_INFO),
791          "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
792         ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
793          "Expected 0 RDNs in empty info, got %ld\n",
794          ((CERT_NAME_INFO *)buf)->cRDN);
795         LocalFree(buf);
796     }
797     /* test empty RDN */
798     bufSize = 0;
799     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
800      emptyRDNs[1] + 2,
801      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
802      (BYTE *)&buf, &bufSize);
803     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
804     if (buf)
805     {
806         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
807
808         ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
809          info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
810          "Got unexpected value for empty RDN\n");
811         LocalFree(buf);
812     }
813     /* test two RDN attrs */
814     bufSize = 0;
815     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
816      twoRDNs[1] + 2,
817      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
818      (BYTE *)&buf, &bufSize);
819     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
820     if (buf)
821     {
822         CERT_RDN_ATTR attrs[] = {
823          { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
824           (BYTE *)surName } },
825          { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
826           (BYTE *)commonName } },
827         };
828
829         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
830         rdn.rgRDNAttr = attrs;
831         compareNames((CERT_NAME_INFO *)buf, &info);
832         LocalFree(buf);
833     }
834 }
835
836 struct encodedOctets
837 {
838     const BYTE *val;
839     const BYTE *encoded;
840 };
841
842 static const struct encodedOctets octets[] = {
843     { "hi", "\x04\x02hi" },
844     { "somelong\xffstring", "\x04\x0fsomelong\xffstring" },
845     { "", "\x04\x00" },
846 };
847
848 static void test_encodeOctets(DWORD dwEncoding)
849 {
850     CRYPT_DATA_BLOB blob;
851     DWORD i;
852
853     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
854     {
855         BYTE *buf = NULL;
856         BOOL ret;
857         DWORD bufSize = 0;
858
859         blob.cbData = strlen(octets[i].val);
860         blob.pbData = (BYTE *)octets[i].val;
861         ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
862          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
863         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
864         if (buf)
865         {
866             ok(buf[0] == 4,
867              "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
868             ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
869              buf[1], octets[i].encoded[1]);
870             ok(!memcmp(buf + 1, octets[i].encoded + 1,
871              octets[i].encoded[1] + 1), "Got unexpected value\n");
872             LocalFree(buf);
873         }
874     }
875 }
876
877 static void test_decodeOctets(DWORD dwEncoding)
878 {
879     DWORD i;
880
881     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
882     {
883         BYTE *buf = NULL;
884         BOOL ret;
885         DWORD bufSize = 0;
886
887         ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
888          (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
889          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
890         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
891         ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
892          "Expected size >= %d, got %ld\n",
893          sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
894         ok(buf != NULL, "Expected allocated buffer\n");
895         if (buf)
896         {
897             CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
898
899             if (blob->cbData)
900                 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
901                  "Unexpected value\n");
902             LocalFree(buf);
903         }
904     }
905 }
906
907 static const BYTE bytesToEncode[] = { 0xff, 0xff };
908
909 struct encodedBits
910 {
911     DWORD cUnusedBits;
912     const BYTE *encoded;
913     DWORD cbDecoded;
914     const BYTE *decoded;
915 };
916
917 static const struct encodedBits bits[] = {
918     /* normal test cases */
919     { 0, "\x03\x03\x00\xff\xff", 2, "\xff\xff" },
920     { 1, "\x03\x03\x01\xff\xfe", 2, "\xff\xfe" },
921     /* strange test case, showing cUnusedBits >= 8 is allowed */
922     { 9, "\x03\x02\x01\xfe", 1, "\xfe" },
923     /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
924     { 17, "\x03\x01\x00", 0, NULL },
925 };
926
927 static void test_encodeBits(DWORD dwEncoding)
928 {
929     DWORD i;
930
931     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
932     {
933         CRYPT_BIT_BLOB blob;
934         BOOL ret;
935         BYTE *buf = NULL;
936         DWORD bufSize = 0;
937
938         blob.cbData = sizeof(bytesToEncode);
939         blob.pbData = (BYTE *)bytesToEncode;
940         blob.cUnusedBits = bits[i].cUnusedBits;
941         ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
942          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
943         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
944         if (buf)
945         {
946             ok(bufSize == bits[i].encoded[1] + 2,
947              "Got unexpected size %ld, expected %d\n", bufSize,
948              bits[i].encoded[1] + 2);
949             ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
950              "Unexpected value\n");
951             LocalFree(buf);
952         }
953     }
954 }
955
956 static void test_decodeBits(DWORD dwEncoding)
957 {
958     static const BYTE ber[] = "\x03\x02\x01\xff";
959     static const BYTE berDecoded = 0xfe;
960     DWORD i;
961     BOOL ret;
962     BYTE *buf = NULL;
963     DWORD bufSize = 0;
964
965     /* normal cases */
966     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
967     {
968         ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
969          bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
970          &bufSize);
971         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
972         if (buf)
973         {
974             CRYPT_BIT_BLOB *blob;
975
976             ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
977              "Got unexpected size %ld, expected >= %ld\n", bufSize,
978              sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
979             blob = (CRYPT_BIT_BLOB *)buf;
980             ok(blob->cbData == bits[i].cbDecoded,
981              "Got unexpected length %ld, expected %ld\n", blob->cbData,
982              bits[i].cbDecoded);
983             if (blob->cbData && bits[i].cbDecoded)
984                 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
985                  "Unexpected value\n");
986             LocalFree(buf);
987         }
988     }
989     /* special case: check that something that's valid in BER but not in DER
990      * decodes successfully
991      */
992     ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
993      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
994     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
995     if (buf)
996     {
997         CRYPT_BIT_BLOB *blob;
998
999         ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1000          "Got unexpected size %ld, expected >= %d\n", bufSize,
1001          sizeof(CRYPT_BIT_BLOB) + berDecoded);
1002         blob = (CRYPT_BIT_BLOB *)buf;
1003         ok(blob->cbData == sizeof(berDecoded),
1004          "Got unexpected length %ld, expected %d\n", blob->cbData,
1005          sizeof(berDecoded));
1006         if (blob->cbData)
1007             ok(*blob->pbData == berDecoded, "Unexpected value\n");
1008         LocalFree(buf);
1009     }
1010 }
1011
1012 struct Constraints2
1013 {
1014     CERT_BASIC_CONSTRAINTS2_INFO info;
1015     const BYTE *encoded;
1016 };
1017
1018 static const struct Constraints2 constraints2[] = {
1019  /* empty constraints */
1020  { { FALSE, FALSE, 0}, "\x30\x00" },
1021  /* can be a CA */
1022  { { TRUE,  FALSE, 0}, "\x30\x03\x01\x01\xff" },
1023  /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1024   * but that's not the case
1025   */
1026  { { FALSE, TRUE,  0}, "\x30\x03\x02\x01\x00" },
1027  /* can be a CA and has path length constraints set */
1028  { { TRUE,  TRUE,  1}, "\x30\x06\x01\x01\xff\x02\x01\x01" },
1029 };
1030
1031 static void test_encodeBasicConstraints(DWORD dwEncoding)
1032 {
1033     DWORD i;
1034
1035     /* First test with the simpler info2 */
1036     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1037     {
1038         BOOL ret;
1039         BYTE *buf = NULL;
1040         DWORD bufSize = 0;
1041
1042         ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1043          &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1044          &bufSize);
1045         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1046         if (buf)
1047         {
1048             ok(bufSize == constraints2[i].encoded[1] + 2,
1049              "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1050              bufSize);
1051             ok(!memcmp(buf, constraints2[i].encoded,
1052              constraints2[i].encoded[1] + 2), "Unexpected value\n");
1053             LocalFree(buf);
1054         }
1055     }
1056 }
1057
1058 static void test_decodeBasicConstraints(DWORD dwEncoding)
1059 {
1060     static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
1061     static const struct Constraints2 badBool = { { TRUE, TRUE, 1 },
1062      "\x30\x06\x01\x01\x01\x02\x01\x01" };
1063     DWORD i;
1064     BOOL ret;
1065     BYTE *buf = NULL;
1066     DWORD bufSize = 0;
1067
1068     /* First test with simpler info2 */
1069     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1070     {
1071         ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1072          constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1073          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1074         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1075         if (buf)
1076         {
1077             CERT_BASIC_CONSTRAINTS2_INFO *info =
1078              (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1079
1080             ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1081              "Unexpected value\n");
1082             LocalFree(buf);
1083         }
1084     }
1085     /* Check with the order of encoded elements inverted */
1086     buf = (PBYTE)1;
1087     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1088      inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1089      &bufSize);
1090     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1091      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1092     ok(!buf, "Expected buf to be set to NULL\n");
1093     /* Check with a non-DER bool */
1094     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1095      badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1096      (BYTE *)&buf, &bufSize);
1097     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1098     if (buf)
1099     {
1100         CERT_BASIC_CONSTRAINTS2_INFO *info =
1101          (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1102
1103         ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1104         LocalFree(buf);
1105     }
1106     /* Check with a non-basic constraints value */
1107     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1108      names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1109      (BYTE *)&buf, &bufSize);
1110     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1111      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1112 }
1113
1114 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1115  0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1116  0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1117
1118 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1119  0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1120  0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1121  0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1122
1123 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1124 {
1125     CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1126     CRYPT_SEQUENCE_OF_ANY seq;
1127     DWORD i;
1128     BOOL ret;
1129     BYTE *buf = NULL;
1130     DWORD bufSize = 0;
1131
1132     /* Encode a homogenous sequence */
1133     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1134     {
1135         blobs[i].cbData = ints[i].encoded[1] + 2;
1136         blobs[i].pbData = (BYTE *)ints[i].encoded;
1137     }
1138     seq.cValue = sizeof(ints) / sizeof(ints[0]);
1139     seq.rgValue = blobs;
1140
1141     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1142      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1143     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1144     if (buf)
1145     {
1146         ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1147          sizeof(intSequence), bufSize);
1148         ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1149         LocalFree(buf);
1150     }
1151     /* Change the type of the first element in the sequence, and give it
1152      * another go
1153      */
1154     blobs[0].cbData = times[0].encodedTime[1] + 2;
1155     blobs[0].pbData = (BYTE *)times[0].encodedTime;
1156     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1157      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1158     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1159     if (buf)
1160     {
1161         ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1162          sizeof(mixedSequence), bufSize);
1163         ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1164          "Unexpected value\n");
1165         LocalFree(buf);
1166     }
1167 }
1168
1169 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1170 {
1171     BOOL ret;
1172     BYTE *buf = NULL;
1173     DWORD bufSize = 0;
1174
1175     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1176      intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1177     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1178     if (buf)
1179     {
1180         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1181         DWORD i;
1182
1183         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1184          "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1185          seq->cValue);
1186         for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1187         {
1188             ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1189              "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1190              seq->rgValue[i].cbData);
1191             ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1192              ints[i].encoded[1] + 2), "Unexpected value\n");
1193         }
1194         LocalFree(buf);
1195     }
1196     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1197      mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1198      &bufSize);
1199     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1200     if (buf)
1201     {
1202         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1203
1204         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1205          "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1206          seq->cValue);
1207         /* Just check the first element since it's all that changed */
1208         ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1209          "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1210          seq->rgValue[0].cbData);
1211         ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1212          times[0].encodedTime[1] + 2), "Unexpected value\n");
1213         LocalFree(buf);
1214     }
1215 }
1216
1217 struct encodedExtensions
1218 {
1219     CERT_EXTENSIONS exts;
1220     const BYTE *encoded;
1221 };
1222
1223 static CERT_EXTENSION criticalExt =
1224  { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
1225 static CERT_EXTENSION nonCriticalExt =
1226  { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, "\x30\x06\x01\x01\xff\x02\x01\x01" } };
1227
1228 static const struct encodedExtensions exts[] = {
1229  { { 0, NULL }, "\x30\x00" },
1230  { { 1, &criticalExt }, "\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff"
1231   "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
1232  { { 1, &nonCriticalExt }, "\x30\x11\x30\x0f\x06\x03\x55\x1d\x13"
1233   "\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01" },
1234 };
1235
1236 static void test_encodeExtensions(DWORD dwEncoding)
1237 {
1238     DWORD i;
1239
1240     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1241     {
1242         BOOL ret;
1243         BYTE *buf = NULL;
1244         DWORD bufSize = 0;
1245
1246         ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1247          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1248         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1249         if (buf)
1250         {
1251             ok(bufSize == exts[i].encoded[1] + 2,
1252              "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1253             ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1254              "Unexpected value\n");
1255             LocalFree(buf);
1256         }
1257     }
1258 }
1259
1260 static void test_decodeExtensions(DWORD dwEncoding)
1261 {
1262     DWORD i;
1263
1264     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1265     {
1266         BOOL ret;
1267         BYTE *buf = NULL;
1268         DWORD bufSize = 0;
1269
1270         ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1271          exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1272          NULL, (BYTE *)&buf, &bufSize);
1273         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1274         if (buf)
1275         {
1276             CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1277             DWORD j;
1278
1279             ok(ext->cExtension == exts[i].exts.cExtension,
1280              "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1281              ext->cExtension);
1282             for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1283             {
1284                 ok(!strcmp(ext->rgExtension[j].pszObjId,
1285                  exts[i].exts.rgExtension[j].pszObjId),
1286                  "Expected OID %s, got %s\n",
1287                  exts[i].exts.rgExtension[j].pszObjId,
1288                  ext->rgExtension[j].pszObjId);
1289                 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1290                  exts[i].exts.rgExtension[j].Value.pbData,
1291                  exts[i].exts.rgExtension[j].Value.cbData),
1292                  "Unexpected value\n");
1293             }
1294             LocalFree(buf);
1295         }
1296     }
1297 }
1298
1299 /* MS encodes public key info with a NULL if the algorithm identifier's
1300  * parameters are empty.  However, when encoding an algorithm in a CERT_INFO,
1301  * it encodes them by omitting the algorithm parameters.  This latter approach
1302  * seems more correct, so accept either form.
1303  */
1304 struct encodedPublicKey
1305 {
1306     CERT_PUBLIC_KEY_INFO info;
1307     const BYTE *encoded;
1308     const BYTE *encodedNoNull;
1309     CERT_PUBLIC_KEY_INFO decoded;
1310 };
1311
1312 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1313  0xe, 0xf };
1314 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1315
1316 static const struct encodedPublicKey pubKeys[] = {
1317  /* with a bogus OID */
1318  { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1319   "\x30\x0b\x30\x06\x06\x02\x2a\x03\x05\x00\x03\x01\x00",
1320   "\x30\x09\x30\x04\x06\x02\x2a\x03\x03\x01\x00",
1321   { { "1.2.3", { 2, "\x05\x00" } }, { 0, NULL, 0 } } },
1322  /* some normal keys */
1323  { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1324   "\x30\x0f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x01\x00",
1325   "\x30\x0d\x30\x08\x06\x06\x2a\x86\x48\x86\xf7\x0d\x03\x01\x00",
1326   { { szOID_RSA, { 2, "\x05\x00" } }, { 0, NULL, 0 } } },
1327  { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
1328   "\x30\x1f\x30\x0a\x06\x06\x2a\x86\x48\x86\xf7\x0d\x05\x00\x03\x11\x00\x00\x01"
1329   "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1330   "\x30\x1d\x30\x08\x06\x06\x2a\x86\x48\x86\xf7\x0d\x03\x11\x00\x00\x01"
1331   "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
1332   { { szOID_RSA, { 2, "\x05\x00" } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
1333  /* with add'l parameters--note they must be DER-encoded */
1334  { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1335   (BYTE *)aKey, 0 } },
1336   "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01"
1337   "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1338   "\x0f",
1339   "\x30\x20\x30\x0b\x06\x06\x2a\x86\x48\x86\xf7\x0d\x02\x01\x01"
1340   "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1341   "\x0f",
1342   { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1343   (BYTE *)aKey, 0 } } },
1344 };
1345
1346 static void test_encodePublicKeyInfo(DWORD dwEncoding)
1347 {
1348     DWORD i;
1349
1350     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1351     {
1352         BOOL ret;
1353         BYTE *buf = NULL;
1354         DWORD bufSize = 0;
1355
1356         ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1357          &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1358          &bufSize);
1359         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1360         if (buf)
1361         {
1362             ok(bufSize == pubKeys[i].encoded[1] + 2 ||
1363              bufSize == pubKeys[i].encodedNoNull[1] + 2,
1364              "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
1365              pubKeys[i].encodedNoNull[1] + 2, bufSize);
1366             if (bufSize == pubKeys[i].encoded[1] + 2)
1367                 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
1368                  "Unexpected value\n");
1369             else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
1370                 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
1371                  pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
1372             LocalFree(buf);
1373         }
1374     }
1375 }
1376
1377 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
1378  const CERT_PUBLIC_KEY_INFO *got)
1379 {
1380     ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
1381      "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
1382      got->Algorithm.pszObjId);
1383     ok(expected->Algorithm.Parameters.cbData ==
1384      got->Algorithm.Parameters.cbData,
1385      "Expected parameters of %ld bytes, got %ld\n",
1386      expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
1387     if (expected->Algorithm.Parameters.cbData)
1388         ok(!memcmp(expected->Algorithm.Parameters.pbData,
1389          got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
1390          "Unexpected algorithm parameters\n");
1391     ok(expected->PublicKey.cbData == got->PublicKey.cbData,
1392      "Expected public key of %ld bytes, got %ld\n",
1393      expected->PublicKey.cbData, got->PublicKey.cbData);
1394     if (expected->PublicKey.cbData)
1395         ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
1396          got->PublicKey.cbData), "Unexpected public key value\n");
1397 }
1398
1399 static void test_decodePublicKeyInfo(DWORD dwEncoding)
1400 {
1401     static const BYTE bogusPubKeyInfo[] =
1402      "\x30\x22\x30\x0d\x06\x06\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x01\x01"
1403      "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1404      "\x0f";
1405     DWORD i;
1406     BOOL ret;
1407     BYTE *buf = NULL;
1408     DWORD bufSize = 0;
1409
1410     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1411     {
1412         /* The NULL form decodes to the decoded member */
1413         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1414          pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1415          NULL, (BYTE *)&buf, &bufSize);
1416         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1417         if (buf)
1418         {
1419             comparePublicKeyInfo(&pubKeys[i].decoded,
1420              (CERT_PUBLIC_KEY_INFO *)buf);
1421             LocalFree(buf);
1422         }
1423         /* The non-NULL form decodes to the original */
1424         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1425          pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
1426          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1427         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1428         if (buf)
1429         {
1430             comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
1431             LocalFree(buf);
1432         }
1433     }
1434     /* Test with bogus (not valid DER) parameters */
1435     ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1436      bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1437      NULL, (BYTE *)&buf, &bufSize);
1438     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1439      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1440 }
1441
1442 static const BYTE v1Cert[] = "\x30\x33\x02\x00\x30\x02\x06\x00\x30\x22\x18"
1443  "\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x18\x0f\x31"
1444  "\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07\x30\x02\x06"
1445  "\x00\x03\x01\x00";
1446 static const BYTE v2Cert[] = "\x30\x38\xa0\x03\x02\x01\x01\x02\x00\x30\x02\x06"
1447  "\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30"
1448  "\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30"
1449  "\x07\x30\x02\x06\x00\x03\x01\x00";
1450 static const BYTE v3Cert[] = "\x30\x38\xa0\x03\x02\x01\x02\x02\x00\x30\x02\x06"
1451  "\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30"
1452  "\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30"
1453  "\x07\x30\x02\x06\x00\x03\x01\x00";
1454 static const BYTE v1CertWithConstraints[] = "\x30\x4b\x02\x00\x30\x02\x06\x00"
1455  "\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a"
1456  "\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07"
1457  "\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01"
1458  "\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01";
1459 static const BYTE v1CertWithSerial[] = "\x30\x4c\x02\x01\x01\x30\x02\x06\x00"
1460  "\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a"
1461  "\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30\x30\x5a\x30\x07"
1462  "\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14\x30\x12\x06\x03\x55\x1d\x13\x01"
1463  "\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x01";
1464 static const BYTE bigCert[] = "\x30\x7a\x02\x01\x01\x30\x02\x06\x00"
1465  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e\x20\x4c"
1466  "\x61\x6e\x67\x00\x30\x22\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30"
1467  "\x30\x30\x30\x5a\x18\x0f\x31\x36\x30\x31\x30\x31\x30\x31\x30\x30\x30\x30\x30"
1468  "\x30\x5a\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a\x4a\x75\x61\x6e"
1469  "\x20\x4c\x61\x6e\x67\x00\x30\x07\x30\x02\x06\x00\x03\x01\x00\xa3\x16\x30\x14"
1470  "\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01"
1471  "\x01";
1472 /* This is the encoded form of the printable string "Juan Lang" */
1473 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
1474  0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
1475  0x61, 0x6e, 0x67, 0x00 };
1476 static const BYTE serialNum[] = { 0x01 };
1477
1478 static void test_encodeCertToBeSigned(DWORD dwEncoding)
1479 {
1480     BOOL ret;
1481     BYTE *buf = NULL;
1482     DWORD size = 0;
1483     CERT_INFO info = { 0 };
1484
1485     /* Test with NULL pvStructInfo */
1486     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
1487      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1488     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1489      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1490     /* Test with a V1 cert */
1491     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1492      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1493     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1494     if (buf)
1495     {
1496         ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
1497          v1Cert[1] + 2, size);
1498         ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
1499         LocalFree(buf);
1500     }
1501     /* Test v2 cert */
1502     info.dwVersion = CERT_V2;
1503     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1504      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1505     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1506     if (buf)
1507     {
1508         ok(size == v2Cert[1] + 2, "Expected size %d, got %ld\n",
1509          v3Cert[1] + 2, size);
1510         ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
1511         LocalFree(buf);
1512     }
1513     /* Test v3 cert */
1514     info.dwVersion = CERT_V3;
1515     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1516      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1517     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1518     if (buf)
1519     {
1520         ok(size == v3Cert[1] + 2, "Expected size %d, got %ld\n",
1521          v3Cert[1] + 2, size);
1522         ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
1523         LocalFree(buf);
1524     }
1525     /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
1526      * API doesn't prevent it)
1527      */
1528     info.dwVersion = CERT_V1;
1529     info.cExtension = 1;
1530     info.rgExtension = &criticalExt;
1531     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1532      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1533     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1534     if (buf)
1535     {
1536         ok(size == v1CertWithConstraints[1] + 2, "Expected size %d, got %ld\n",
1537          v1CertWithConstraints[1] + 2, size);
1538         ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
1539         LocalFree(buf);
1540     }
1541     /* test v1 cert with a serial number */
1542     info.SerialNumber.cbData = sizeof(serialNum);
1543     info.SerialNumber.pbData = (BYTE *)serialNum;
1544     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1545      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1546     if (buf)
1547     {
1548         ok(size == v1CertWithSerial[1] + 2, "Expected size %d, got %ld\n",
1549          v1CertWithSerial[1] + 2, size);
1550         ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
1551         LocalFree(buf);
1552     }
1553     /* Test v1 cert with an issuer name, a subject name, and a serial number */
1554     info.Issuer.cbData = sizeof(encodedCommonName);
1555     info.Issuer.pbData = (BYTE *)encodedCommonName;
1556     info.Subject.cbData = sizeof(encodedCommonName);
1557     info.Subject.pbData = (BYTE *)encodedCommonName;
1558     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
1559      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1560     if (buf)
1561     {
1562         ok(size == bigCert[1] + 2, "Expected size %d, got %ld\n",
1563          bigCert[1] + 2, size);
1564         ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
1565         LocalFree(buf);
1566     }
1567     /* for now, I let more interesting tests be done for each subcomponent,
1568      * rather than retesting them all here.
1569      */
1570 }
1571
1572 static void test_decodeCertToBeSigned(DWORD dwEncoding)
1573 {
1574     static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
1575      v1CertWithConstraints, v1CertWithSerial };
1576     BOOL ret;
1577     BYTE *buf = NULL;
1578     DWORD size = 0, i;
1579
1580     /* Test with NULL pbEncoded */
1581     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
1582      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1583     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1584      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
1585     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
1586      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1587     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1588      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1589     /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
1590      * minimum a cert must have a non-zero serial number, an issuer, and a
1591      * subject.
1592      */
1593     for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
1594     {
1595         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
1596          corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1597          (BYTE *)&buf, &size);
1598         ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1599          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1600     }
1601     /* Now check with serial number, subject and issuer specified */
1602     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
1603      bigCert[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1604     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1605     if (buf)
1606     {
1607         CERT_INFO *info = (CERT_INFO *)buf;
1608
1609         ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
1610          sizeof(CERT_INFO), size);
1611         ok(info->SerialNumber.cbData == 1,
1612          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
1613         ok(*info->SerialNumber.pbData == *serialNum,
1614          "Expected serial number %d, got %d\n", *serialNum,
1615          *info->SerialNumber.pbData);
1616         ok(info->Issuer.cbData == sizeof(encodedCommonName),
1617          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
1618          info->Issuer.cbData);
1619         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
1620          "Unexpected issuer\n");
1621         ok(info->Subject.cbData == sizeof(encodedCommonName),
1622          "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
1623          info->Subject.cbData);
1624         ok(!memcmp(info->Subject.pbData, encodedCommonName,
1625          info->Subject.cbData), "Unexpected subject\n");
1626         LocalFree(buf);
1627     }
1628 }
1629
1630 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1631  0xe, 0xf };
1632
1633 static const BYTE signedBigCert[] = {
1634  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
1635  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
1636  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
1637  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1638  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
1639  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
1640  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
1641  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
1642  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
1643  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
1644  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1645  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
1646
1647 static void test_encodeCert(DWORD dwEncoding)
1648 {
1649     /* Note the SignatureAlgorithm must match that in the encoded cert.  Note
1650      * also that bigCert is a NULL-terminated string, so don't count its
1651      * last byte (otherwise the signed cert won't decode.)
1652      */
1653     CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert) - 1, (BYTE *)bigCert },
1654      { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
1655     BOOL ret;
1656     BYTE *buf = NULL;
1657     DWORD bufSize = 0;
1658
1659     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
1660      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1661     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1662     if (buf)
1663     {
1664         ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
1665          sizeof(signedBigCert), bufSize);
1666         ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
1667         LocalFree(buf);
1668     }
1669 }
1670
1671 static void test_decodeCert(DWORD dwEncoding)
1672 {
1673     BOOL ret;
1674     BYTE *buf = NULL;
1675     DWORD size = 0;
1676
1677     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
1678      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1679     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1680     if (buf)
1681     {
1682         CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
1683
1684         ok(info->ToBeSigned.cbData == sizeof(bigCert) - 1,
1685          "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert) - 1,
1686          info->ToBeSigned.cbData);
1687         ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
1688          "Unexpected cert\n");
1689         ok(info->Signature.cbData == sizeof(hash),
1690          "Expected signature size %d, got %ld\n", sizeof(hash),
1691          info->Signature.cbData);
1692         ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
1693          "Unexpected signature\n");
1694         LocalFree(buf);
1695     }
1696 }
1697
1698 static void test_registerOIDFunction(void)
1699 {
1700     static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
1701     BOOL ret;
1702
1703     /* oddly, this succeeds under WinXP; the function name key is merely
1704      * omitted.  This may be a side effect of the registry code, I don't know.
1705      * I don't check it because I doubt anyone would depend on it.
1706     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
1707      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1708      */
1709     /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
1710      * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
1711      */
1712     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
1713      NULL);
1714     ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
1715      HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
1716      "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
1717     /* This has no effect, but "succeeds" on XP */
1718     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
1719      "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
1720     ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
1721     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1722      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1723     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1724     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
1725      "1.2.3.4.5.6.7.8.9.10");
1726     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1727     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
1728      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1729     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1730     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
1731      "1.2.3.4.5.6.7.8.9.10");
1732     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1733     /* This has no effect */
1734     ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
1735      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1736     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1737     /* Check with bogus encoding type: */
1738     ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
1739      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1740     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1741     /* This is written with value 3 verbatim.  Thus, the encoding type isn't
1742      * (for now) treated as a mask.
1743      */
1744     ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
1745      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
1746     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
1747     ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
1748      "1.2.3.4.5.6.7.8.9.10");
1749     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
1750 }
1751
1752 START_TEST(encode)
1753 {
1754     static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
1755      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
1756     DWORD i;
1757
1758     for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
1759     {
1760         test_encodeInt(encodings[i]);
1761         test_decodeInt(encodings[i]);
1762         test_encodeEnumerated(encodings[i]);
1763         test_decodeEnumerated(encodings[i]);
1764         test_encodeFiletime(encodings[i]);
1765         test_decodeFiletime(encodings[i]);
1766         test_encodeName(encodings[i]);
1767         test_decodeName(encodings[i]);
1768         test_encodeOctets(encodings[i]);
1769         test_decodeOctets(encodings[i]);
1770         test_encodeBits(encodings[i]);
1771         test_decodeBits(encodings[i]);
1772         test_encodeBasicConstraints(encodings[i]);
1773         test_decodeBasicConstraints(encodings[i]);
1774         test_encodeSequenceOfAny(encodings[i]);
1775         test_decodeSequenceOfAny(encodings[i]);
1776         test_encodeExtensions(encodings[i]);
1777         test_decodeExtensions(encodings[i]);
1778         test_encodePublicKeyInfo(encodings[i]);
1779         test_decodePublicKeyInfo(encodings[i]);
1780         test_encodeCertToBeSigned(encodings[i]);
1781         test_decodeCertToBeSigned(encodings[i]);
1782         test_encodeCert(encodings[i]);
1783         test_decodeCert(encodings[i]);
1784     }
1785     test_registerOIDFunction();
1786 }