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