ole32: Remove unnecessary assert(This) calls.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 BYTE bin1[] = {0x02,0x01,0x01};
36 static const BYTE bin2[] = {0x02,0x01,0x7f};
37 static const BYTE bin3[] = {0x02,0x02,0x00,0x80};
38 static const BYTE bin4[] = {0x02,0x02,0x01,0x00};
39 static const BYTE bin5[] = {0x02,0x01,0x80};
40 static const BYTE bin6[] = {0x02,0x02,0xff,0x7f};
41 static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d};
42
43 static const struct encodedInt ints[] = {
44  { 1,          bin1 },
45  { 127,        bin2 },
46  { 128,        bin3 },
47  { 256,        bin4 },
48  { -128,       bin5 },
49  { -129,       bin6 },
50  { 0xbaddf00d, bin7 },
51 };
52
53 struct encodedBigInt
54 {
55     const BYTE *val;
56     const BYTE *encoded;
57     const BYTE *decoded;
58 };
59
60 static const BYTE bin8[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
61 static const BYTE bin9[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
62 static const BYTE bin10[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
63
64 static const BYTE bin11[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
65 static const BYTE bin12[] = {0x02,0x09,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
66 static const BYTE bin13[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0};
67
68 static const struct encodedBigInt bigInts[] = {
69  { bin8, bin9, bin10 },
70  { bin11, bin12, bin13 },
71 };
72
73 static const BYTE bin14[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
74 static const BYTE bin15[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
75 static const BYTE bin16[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
76 static const BYTE bin17[] = {0x02,0x0c,0x00,0xff,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
77
78 /* Decoded is the same as original, so don't bother storing a separate copy */
79 static const struct encodedBigInt bigUInts[] = {
80  { bin14, bin15, NULL },
81  { bin16, bin17, NULL },
82 };
83
84 static void test_encodeInt(DWORD dwEncoding)
85 {
86     DWORD bufSize = 0;
87     int i;
88     BOOL ret;
89     CRYPT_INTEGER_BLOB blob;
90     BYTE *buf = NULL;
91
92     /* CryptEncodeObjectEx with NULL bufSize crashes..
93     ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
94      NULL);
95      */
96     /* check bogus encoding */
97     ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
98      &bufSize);
99     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
100      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
101     /* check with NULL integer buffer.  Windows XP incorrectly returns an
102      * NTSTATUS.
103      */
104     ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
105      &bufSize);
106     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
107      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
108     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
109     {
110         /* encode as normal integer */
111         ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
112          NULL, NULL, &bufSize);
113         ok(ret, "Expected success, got %ld\n", GetLastError());
114         ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
115          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
116         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
117         if (buf)
118         {
119             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
120              buf[0]);
121             ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
122              buf[1], ints[i].encoded[1]);
123             ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
124              "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
125             LocalFree(buf);
126         }
127         /* encode as multibyte integer */
128         blob.cbData = sizeof(ints[i].val);
129         blob.pbData = (BYTE *)&ints[i].val;
130         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
131          0, NULL, NULL, &bufSize);
132         ok(ret, "Expected success, got %ld\n", GetLastError());
133         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
134          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
135         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
136         if (buf)
137         {
138             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
139              buf[0]);
140             ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
141              buf[1], ints[i].encoded[1]);
142             ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
143              "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
144             LocalFree(buf);
145         }
146     }
147     /* encode a couple bigger ints, just to show it's little-endian and leading
148      * sign bytes are dropped
149      */
150     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
151     {
152         blob.cbData = strlen((const char*)bigInts[i].val);
153         blob.pbData = (BYTE *)bigInts[i].val;
154         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
155          0, NULL, NULL, &bufSize);
156         ok(ret, "Expected success, got %ld\n", GetLastError());
157         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
158          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
159         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
160         if (buf)
161         {
162             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
163              buf[0]);
164             ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
165              buf[1], bigInts[i].encoded[1]);
166             ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
167              bigInts[i].encoded[1] + 1),
168              "Encoded value didn't match expected\n");
169             LocalFree(buf);
170         }
171     }
172     /* and, encode some uints */
173     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
174     {
175         blob.cbData = strlen((const char*)bigUInts[i].val);
176         blob.pbData = (BYTE*)bigUInts[i].val;
177         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
178          0, NULL, NULL, &bufSize);
179         ok(ret, "Expected success, got %ld\n", GetLastError());
180         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
181          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
182         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
183         if (buf)
184         {
185             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
186              buf[0]);
187             ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
188              buf[1], bigUInts[i].encoded[1]);
189             ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
190              bigUInts[i].encoded[1] + 1),
191              "Encoded value didn't match expected\n");
192             LocalFree(buf);
193         }
194     }
195 }
196
197 static void test_decodeInt(DWORD dwEncoding)
198 {
199     static const BYTE bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
200     static const BYTE testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
201     static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
202     static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
203     BYTE *buf = NULL;
204     DWORD bufSize = 0;
205     int i;
206     BOOL ret;
207
208     /* CryptDecodeObjectEx with NULL bufSize crashes..
209     ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded, 
210      ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
211      */
212     /* check bogus encoding */
213     ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded, 
214      ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
215     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
216      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
217     /* check with NULL integer buffer */
218     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
219      &bufSize);
220     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
221      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
222     /* check with a valid, but too large, integer */
223     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
224      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
225     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
226      "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
227     /* check with a DER-encoded string */
228     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
229      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
230     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
231      "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
232     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
233     {
234         /* When the output buffer is NULL, this always succeeds */
235         SetLastError(0xdeadbeef);
236         ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
237          (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
238          &bufSize);
239         ok(ret && GetLastError() == NOERROR,
240          "Expected success and NOERROR, got %ld\n", GetLastError());
241         ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
242          (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
243          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
244         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
245         ok(bufSize == sizeof(int), "Wrong size %ld\n", bufSize);
246         ok(buf != NULL, "Expected allocated buffer\n");
247         if (buf)
248         {
249             ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
250              ints[i].val, *(int *)buf);
251             LocalFree(buf);
252         }
253     }
254     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
255     {
256         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
257          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
258          &bufSize);
259         ok(ret && GetLastError() == NOERROR,
260          "Expected success and NOERROR, got %ld\n", GetLastError());
261         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
262          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
263          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
264         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
265         ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %ld\n", bufSize);
266         ok(buf != NULL, "Expected allocated buffer\n");
267         if (buf)
268         {
269             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
270
271             ok(blob->cbData == strlen((const char*)bigInts[i].decoded),
272              "Expected len %d, got %ld\n", lstrlenA((const char*)bigInts[i].decoded),
273              blob->cbData);
274             ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
275              "Unexpected value\n");
276             LocalFree(buf);
277         }
278     }
279     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
280     {
281         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
282          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
283          &bufSize);
284         ok(ret && GetLastError() == NOERROR,
285          "Expected success and NOERROR, got %ld\n", GetLastError());
286         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
287          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
288          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
289         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
290         ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %ld\n", bufSize);
291         ok(buf != NULL, "Expected allocated buffer\n");
292         if (buf)
293         {
294             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
295
296             ok(blob->cbData == strlen((const char*)bigUInts[i].val),
297              "Expected len %d, got %ld\n", lstrlenA((const char*)bigUInts[i].val),
298              blob->cbData);
299             ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
300              "Unexpected value\n");
301             LocalFree(buf);
302         }
303     }
304     /* Decode the value 1 with long-form length */
305     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
306      sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
307     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
308     if (buf)
309     {
310         ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
311         LocalFree(buf);
312     }
313     /* Try to decode some bogus large items */
314     /* The buffer size is smaller than the encoded length, so this should fail
315      * with CRYPT_E_ASN1_EOD if it's being decoded.
316      * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
317      * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
318      * So this test unfortunately isn't useful.
319     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
320      0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
321     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
322      "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
323      */
324     /* This will try to decode the buffer and overflow it, check that it's
325      * caught.
326      */
327     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
328      0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
329     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
330      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
331 }
332
333 static const BYTE bin18[] = {0x0a,0x01,0x01};
334 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80};
335
336 /* These are always encoded unsigned, and aren't constrained to be any
337  * particular value
338  */
339 static const struct encodedInt enums[] = {
340  { 1,    bin18 },
341  { -128, bin19 },
342 };
343
344 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
345  * X509_ENUMERATED.
346  */
347 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
348  szOID_CRL_REASON_CODE };
349
350 static void test_encodeEnumerated(DWORD dwEncoding)
351 {
352     DWORD i, j;
353
354     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
355     {
356         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
357         {
358             BOOL ret;
359             BYTE *buf = NULL;
360             DWORD bufSize = 0;
361
362             ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
363              &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
364              &bufSize);
365             ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
366             if (buf)
367             {
368                 ok(buf[0] == 0xa,
369                  "Got unexpected type %d for enumerated (expected 0xa)\n",
370                  buf[0]);
371                 ok(buf[1] == enums[j].encoded[1],
372                  "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
373                 ok(!memcmp(buf + 1, enums[j].encoded + 1,
374                  enums[j].encoded[1] + 1),
375                  "Encoded value of 0x%08x didn't match expected\n",
376                  enums[j].val);
377                 LocalFree(buf);
378             }
379         }
380     }
381 }
382
383 static void test_decodeEnumerated(DWORD dwEncoding)
384 {
385     DWORD i, j;
386
387     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
388     {
389         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
390         {
391             BOOL ret;
392             DWORD bufSize = sizeof(int);
393             int val;
394
395             ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
396              enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
397              (BYTE *)&val, &bufSize);
398             ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
399             ok(bufSize == sizeof(int),
400              "Got unexpected size %ld for enumerated\n", bufSize);
401             ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
402              val, enums[j].val);
403         }
404     }
405 }
406
407 struct encodedFiletime
408 {
409     SYSTEMTIME sysTime;
410     const BYTE *encodedTime;
411 };
412
413 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
414  const struct encodedFiletime *time)
415 {
416     FILETIME ft = { 0 };
417     BYTE *buf = NULL;
418     DWORD bufSize = 0;
419     BOOL ret;
420
421     ret = SystemTimeToFileTime(&time->sysTime, &ft);
422     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
423     ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
424      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
425     /* years other than 1950-2050 are not allowed for encodings other than
426      * X509_CHOICE_OF_TIME.
427      */
428     if (structType == X509_CHOICE_OF_TIME ||
429      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
430     {
431         ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
432          GetLastError());
433         ok(buf != NULL, "Expected an allocated buffer\n");
434         if (buf)
435         {
436             ok(buf[0] == time->encodedTime[0],
437              "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
438              buf[0]);
439             ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
440              time->encodedTime[1], bufSize);
441             ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
442              "Got unexpected value for time encoding\n");
443             LocalFree(buf);
444         }
445     }
446     else
447         ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
448          "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
449 }
450
451 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
452  const struct encodedFiletime *time)
453 {
454     FILETIME ft1 = { 0 }, ft2 = { 0 };
455     DWORD size = sizeof(ft2);
456     BOOL ret;
457
458     ret = SystemTimeToFileTime(&time->sysTime, &ft1);
459     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
460     ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
461      time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
462     /* years other than 1950-2050 are not allowed for encodings other than
463      * X509_CHOICE_OF_TIME.
464      */
465     if (structType == X509_CHOICE_OF_TIME ||
466      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
467     {
468         ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
469          GetLastError());
470         ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
471          "Got unexpected value for time decoding\n");
472     }
473     else
474         ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
475          "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
476 }
477
478 static const BYTE bin20[] = {
479     0x17,0x0d,'0','5','0','6','0','6','1','6','1','0','0','0','Z'};
480 static const BYTE bin21[] = {
481     0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
482 static const BYTE bin22[] = {
483     0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z'};
484
485 static const struct encodedFiletime times[] = {
486  { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 },
487  { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 },
488  { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 },
489 };
490
491 static void test_encodeFiletime(DWORD dwEncoding)
492 {
493     DWORD i;
494
495     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
496     {
497         testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
498         testTimeEncoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
499         testTimeEncoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
500     }
501 }
502
503 static const BYTE bin23[] = {
504     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','0','0','0','Z'};
505 static const BYTE bin24[] = {
506     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','9','9','9','Z'};
507 static const BYTE bin25[] = {
508     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','+','0','1','0','0'};
509 static const BYTE bin26[] = {
510     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','0','0'};
511 static const BYTE bin27[] = {
512     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','1','5'};
513 static const BYTE bin28[] = {
514     0x18,0x0a,'2','1','4','5','0','6','0','6','1','6'};
515 static const BYTE bin29[] = {
516     0x17,0x0a,'4','5','0','6','0','6','1','6','1','0'};
517 static const BYTE bin30[] = {
518     0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z'};
519 static const BYTE bin31[] = {
520     0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1'};
521 static const BYTE bin32[] = {
522     0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1'};
523 static const BYTE bin33[] = {
524     0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0'};
525 static const BYTE bin34[] = {
526     0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0'};
527 static const BYTE bin35[] = {
528     0x17,0x08, '4','5','0','6','0','6','1','6'};
529 static const BYTE bin36[] = {
530     0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z'};
531 static const BYTE bin37[] = {
532     0x18,0x04, '2','1','4','5'};
533 static const BYTE bin38[] = {
534     0x18,0x08, '2','1','4','5','0','6','0','6'};
535
536 static void test_decodeFiletime(DWORD dwEncoding)
537 {
538     static const struct encodedFiletime otherTimes[] = {
539      { { 1945, 6, 1, 6, 16, 10, 0, 0 },   bin23 },
540      { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 },
541      { { 1945, 6, 1, 6, 17, 10, 0, 0 },   bin25 },
542      { { 1945, 6, 1, 6, 15, 10, 0, 0 },   bin26 },
543      { { 1945, 6, 1, 6, 14, 55, 0, 0 },   bin27 },
544      { { 2145, 6, 1, 6, 16,  0, 0, 0 },   bin28 },
545      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   bin29 },
546      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   bin30 },
547      { { 2045, 6, 1, 6, 17, 10, 0, 0 },   bin31 },
548      { { 2045, 6, 1, 6, 15, 10, 0, 0 },   bin32 },
549      { { 2045, 6, 1, 6, 17, 10, 0, 0 },   bin33 },
550      { { 2045, 6, 1, 6, 15, 10, 0, 0 },   bin34 },
551     };
552     /* An oddball case that succeeds in Windows, but doesn't seem correct
553      { { 2145, 6, 1, 2, 11, 31, 0, 0 },   "\x18" "\x13" "21450606161000-9999" },
554      */
555     static const unsigned char *bogusTimes[] = {
556      /* oddly, this succeeds on Windows, with year 2765
557      "\x18" "\x0f" "21r50606161000Z",
558       */
559      bin35,
560      bin36,
561      bin37,
562      bin38,
563     };
564     DWORD i, size;
565     FILETIME ft1 = { 0 }, ft2 = { 0 };
566     BOOL ret;
567
568     /* Check bogus length with non-NULL buffer */
569     ret = SystemTimeToFileTime(&times[0].sysTime, &ft1);
570     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
571     size = 1;
572     ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
573      times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
574     ok(!ret && GetLastError() == ERROR_MORE_DATA,
575      "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
576     /* Normal tests */
577     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
578     {
579         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
580         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
581         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
582     }
583     for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
584     {
585         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
586         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
587         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
588     }
589     for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
590     {
591         size = sizeof(ft1);
592         ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
593          bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
594         ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
595          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
596     }
597 }
598
599 static const char commonName[] = "Juan Lang";
600 static const char surName[] = "Lang";
601
602 static const BYTE emptySequence[] = { 0x30, 0 };
603 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
604 static const BYTE twoRDNs[] = {
605     0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
606     0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
607     0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
608
609 static const BYTE us[] = { 0x55, 0x53 };
610 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
611  0x74, 0x61 };
612 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
613  0x6f, 0x6c, 0x69, 0x73 };
614 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
615  0x76, 0x65, 0x72, 0x73 };
616 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
617  0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
618 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
619  0x73, 0x74 };
620 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
621  0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
622
623 #define _blob_of(arr) { sizeof(arr), (LPBYTE)arr }
624 const CERT_RDN_ATTR rdnAttrs[] = {
625  { "2.5.4.6", CERT_RDN_PRINTABLE_STRING,        _blob_of(us) },
626  { "2.5.4.8", CERT_RDN_PRINTABLE_STRING,        _blob_of(minnesota) },
627  { "2.5.4.7", CERT_RDN_PRINTABLE_STRING,        _blob_of(minneapolis) },
628  { "2.5.4.10", CERT_RDN_PRINTABLE_STRING,       _blob_of(codeweavers) },
629  { "2.5.4.11", CERT_RDN_PRINTABLE_STRING,       _blob_of(wine) },
630  { "2.5.4.3", CERT_RDN_PRINTABLE_STRING,        _blob_of(localhostAttr) },
631  { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
632 };
633 const CERT_RDN_ATTR decodedRdnAttrs[] = {
634  { "2.5.4.6", CERT_RDN_PRINTABLE_STRING,        _blob_of(us) },
635  { "2.5.4.3", CERT_RDN_PRINTABLE_STRING,        _blob_of(localhostAttr) },
636  { "2.5.4.8", CERT_RDN_PRINTABLE_STRING,        _blob_of(minnesota) },
637  { "2.5.4.7", CERT_RDN_PRINTABLE_STRING,        _blob_of(minneapolis) },
638  { "2.5.4.10", CERT_RDN_PRINTABLE_STRING,       _blob_of(codeweavers) },
639  { "2.5.4.11", CERT_RDN_PRINTABLE_STRING,       _blob_of(wine) },
640  { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, _blob_of(aric) },
641 };
642 #undef _blob_of
643
644 static const BYTE encodedRDNAttrs[] = {
645 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
646 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
647 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
648 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
649 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
650 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
651 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
652 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
653 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
654 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
655 };
656
657 static void test_encodeName(DWORD dwEncoding)
658 {
659     CERT_RDN_ATTR attrs[2];
660     CERT_RDN rdn;
661     CERT_NAME_INFO info;
662     static CHAR oid_common_name[] = szOID_COMMON_NAME,
663                 oid_sur_name[]    = szOID_SUR_NAME;
664     BYTE *buf = NULL;
665     DWORD size = 0;
666     BOOL ret;
667
668     /* Test with NULL pvStructInfo */
669     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
670      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
671     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
672      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
673     /* Test with empty CERT_NAME_INFO */
674     info.cRDN = 0;
675     info.rgRDN = NULL;
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, emptySequence, sizeof(emptySequence)),
682          "Got unexpected encoding for empty name\n");
683         LocalFree(buf);
684     }
685     /* Test with bogus CERT_RDN */
686     info.cRDN = 1;
687     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
688      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
689     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
690      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
691     /* Test with empty CERT_RDN */
692     rdn.cRDNAttr = 0;
693     rdn.rgRDNAttr = NULL;
694     info.cRDN = 1;
695     info.rgRDN = &rdn;
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(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
702          "Got unexpected encoding for empty RDN array\n");
703         LocalFree(buf);
704     }
705     /* Test with bogus attr array */
706     rdn.cRDNAttr = 1;
707     rdn.rgRDNAttr = NULL;
708     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
709      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
710     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
711      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
712     /* oddly, a bogus OID is accepted by Windows XP; not testing.
713     attrs[0].pszObjId = "bogus";
714     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
715     attrs[0].Value.cbData = sizeof(commonName);
716     attrs[0].Value.pbData = (BYTE *)commonName;
717     rdn.cRDNAttr = 1;
718     rdn.rgRDNAttr = attrs;
719     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
720      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
721     ok(!ret, "Expected failure, got success\n");
722      */
723     /* Check with two CERT_RDN_ATTRs.  Note DER encoding forces the order of
724      * the encoded attributes to be swapped.
725      */
726     attrs[0].pszObjId = oid_common_name;
727     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
728     attrs[0].Value.cbData = sizeof(commonName);
729     attrs[0].Value.pbData = (BYTE *)commonName;
730     attrs[1].pszObjId = oid_sur_name;
731     attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
732     attrs[1].Value.cbData = sizeof(surName);
733     attrs[1].Value.pbData = (BYTE *)surName;
734     rdn.cRDNAttr = 2;
735     rdn.rgRDNAttr = attrs;
736     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
737      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
738     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
739     if (buf)
740     {
741         ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
742          "Got unexpected encoding for two RDN array\n");
743         LocalFree(buf);
744     }
745     /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
746     rdn.cRDNAttr = 1;
747     attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
748     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
749      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
750     ok(!ret && GetLastError() == E_INVALIDARG,
751      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
752     /* Test a more complex name */
753     rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
754     rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
755     info.cRDN = 1;
756     info.rgRDN = &rdn;
757     buf = NULL;
758     size = 0;
759     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
760      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
761     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
762     if (ret)
763     {
764         ok(size == sizeof(encodedRDNAttrs), "Wrong size %ld\n", size);
765         ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
766         LocalFree(buf);
767     }
768 }
769
770 static void compareNameValues(const CERT_NAME_VALUE *expected,
771  const CERT_NAME_VALUE *got)
772 {
773     ok(got->dwValueType == expected->dwValueType,
774      "Expected string type %ld, got %ld\n", expected->dwValueType,
775      got->dwValueType);
776     ok(got->Value.cbData == expected->Value.cbData,
777      "Unexpected data size, got %ld, expected %ld\n", got->Value.cbData,
778      expected->Value.cbData);
779     if (got->Value.cbData && got->Value.pbData)
780         ok(!memcmp(got->Value.pbData, expected->Value.pbData,
781          min(got->Value.cbData, expected->Value.cbData)), "Unexpected value\n");
782 }
783
784 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
785  const CERT_RDN_ATTR *got)
786 {
787     if (expected->pszObjId && strlen(expected->pszObjId))
788     {
789         ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
790          expected->pszObjId);
791         if (got->pszObjId)
792         {
793             ok(!strcmp(got->pszObjId, expected->pszObjId),
794              "Got unexpected OID %s, expected %s\n", got->pszObjId,
795              expected->pszObjId);
796         }
797     }
798     compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType,
799      (const CERT_NAME_VALUE *)&got->dwValueType);
800 }
801
802 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
803 {
804     ok(got->cRDNAttr == expected->cRDNAttr,
805      "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
806     if (got->cRDNAttr)
807     {
808         DWORD i;
809
810         for (i = 0; i < got->cRDNAttr; i++)
811             compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
812     }
813 }
814
815 static void compareNames(const CERT_NAME_INFO *expected,
816  const CERT_NAME_INFO *got)
817 {
818     ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
819      expected->cRDN, got->cRDN);
820     if (got->cRDN)
821     {
822         DWORD i;
823
824         for (i = 0; i < got->cRDN; i++)
825             compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
826     }
827 }
828
829 static void test_decodeName(DWORD dwEncoding)
830 {
831     BYTE *buf = NULL;
832     DWORD bufSize = 0;
833     BOOL ret;
834     CERT_RDN rdn;
835     CERT_NAME_INFO info = { 1, &rdn };
836
837     /* test empty name */
838     bufSize = 0;
839     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
840      emptySequence[1] + 2,
841      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
842      (BYTE *)&buf, &bufSize);
843     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
844     /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL.  My
845      * decoder works the same way, so only test the count.
846      */
847     if (buf)
848     {
849         ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %ld\n", bufSize);
850         ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
851          "Expected 0 RDNs in empty info, got %ld\n",
852          ((CERT_NAME_INFO *)buf)->cRDN);
853         LocalFree(buf);
854     }
855     /* test empty RDN */
856     bufSize = 0;
857     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
858      emptyRDNs[1] + 2,
859      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
860      (BYTE *)&buf, &bufSize);
861     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
862     if (buf)
863     {
864         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
865
866         ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
867          info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
868          "Got unexpected value for empty RDN\n");
869         LocalFree(buf);
870     }
871     /* test two RDN attrs */
872     bufSize = 0;
873     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
874      twoRDNs[1] + 2,
875      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
876      (BYTE *)&buf, &bufSize);
877     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
878     if (buf)
879     {
880         CERT_RDN_ATTR attrs[] = {
881          { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
882           (BYTE *)surName } },
883          { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
884           (BYTE *)commonName } },
885         };
886
887         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
888         rdn.rgRDNAttr = attrs;
889         compareNames(&info, (CERT_NAME_INFO *)buf);
890         LocalFree(buf);
891     }
892     /* And, a slightly more complicated name */
893     buf = NULL;
894     bufSize = 0;
895     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
896      sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
897     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
898     if (ret)
899     {
900         rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
901         rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
902         compareNames(&info, (CERT_NAME_INFO *)buf);
903         LocalFree(buf);
904     }
905 }
906
907 struct EncodedNameValue
908 {
909     CERT_NAME_VALUE value;
910     const BYTE *encoded;
911 };
912
913 static const char bogusIA5[] = "\x80";
914 static const char bogusPrintable[] = "~";
915 static const char bogusNumeric[] = "A";
916 static const char bogusT61[] = "\xff";
917 static const BYTE bin39[] = { 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
918  0x67,0x00 };
919 static const BYTE bin40[] = { 0x16,0x05,0x4c,0x61,0x6e,0x67,0x00 };
920 static const BYTE bin41[] = { 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
921  0x67,0x00 };
922 static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
923 static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
924 static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
925 static const BYTE bin45[] = { 0x14,0x02,0xff,0x00 };
926
927 struct EncodedNameValue nameValues[] = {
928  { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
929      bin39 },
930  { { CERT_RDN_IA5_STRING, { sizeof(surName), (BYTE *)surName } }, bin40 },
931  { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } }, bin41 },
932  /* The following tests succeed under Windows, but really should fail,
933   * they contain characters that are illegal for the encoding.  I'm
934   * including them to justify my lazy encoding.
935   */
936  { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42 },
937  { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable),
938      (BYTE *)bogusPrintable } }, bin43 },
939  { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
940      bin44 },
941  { { CERT_RDN_T61_STRING, { sizeof(bogusT61), (BYTE *)bogusT61 } }, bin45 },
942 };
943
944
945 static void test_encodeNameValue(DWORD dwEncoding)
946 {
947     BYTE *buf = NULL;
948     DWORD size = 0, i;
949     BOOL ret;
950
951     for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
952     {
953         ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE,
954          &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
955          &size);
956         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
957         if (buf)
958         {
959             ok(size == nameValues[i].encoded[1] + 2,
960              "Expected size %d, got %ld\n", nameValues[i].encoded[1] + 2, size);
961             ok(!memcmp(buf, nameValues[i].encoded, size),
962              "Got unexpected encoding\n");
963             LocalFree(buf);
964         }
965     }
966 }
967
968 static void test_decodeNameValue(DWORD dwEncoding)
969 {
970     int i;
971     BYTE *buf = NULL;
972     DWORD bufSize = 0;
973     BOOL ret;
974
975     for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
976     {
977         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE,
978          nameValues[i].encoded, nameValues[i].encoded[1] + 2,
979          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
980          (BYTE *)&buf, &bufSize);
981         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
982         if (buf)
983         {
984             compareNameValues(&nameValues[i].value,
985              (const CERT_NAME_VALUE *)buf);
986             LocalFree(buf);
987         }
988     }
989 }
990
991 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
992 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
993  'h','q','.','o','r','g',0 };
994 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
995  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
996  0x6f, 0x72, 0x67 };
997 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
998  0x575b, 0 };
999 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1000 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1001  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1002 static const BYTE localhost[] = { 127, 0, 0, 1 };
1003 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1004  0x01 };
1005
1006 static void test_encodeAltName(DWORD dwEncoding)
1007 {
1008     CERT_ALT_NAME_INFO info = { 0 };
1009     CERT_ALT_NAME_ENTRY entry = { 0 };
1010     BYTE *buf = NULL;
1011     DWORD size = 0;
1012     BOOL ret;
1013
1014     /* Test with empty info */
1015     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1016      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1017     if (buf)
1018     {
1019         ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
1020         ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1021         LocalFree(buf);
1022     }
1023     /* Test with an empty entry */
1024     info.cAltEntry = 1;
1025     info.rgAltEntry = &entry;
1026     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1027      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1028     ok(!ret && GetLastError() == E_INVALIDARG,
1029      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1030     /* Test with an empty pointer */
1031     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1032     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1033      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1034     if (buf)
1035     {
1036         ok(size == sizeof(emptyURL), "Wrong size %ld\n", size);
1037         ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1038         LocalFree(buf);
1039     }
1040     /* Test with a real URL */
1041     U(entry).pwszURL = (LPWSTR)url;
1042     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1043      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1044     if (buf)
1045     {
1046         ok(size == sizeof(encodedURL), "Wrong size %ld\n", size);
1047         ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1048         LocalFree(buf);
1049     }
1050     /* Now with the URL containing an invalid IA5 char */
1051     U(entry).pwszURL = (LPWSTR)nihongoURL;
1052     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1053      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1054     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1055      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1056     /* The first invalid character is at index 7 */
1057     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1058      "Expected invalid char at index 7, got %ld\n",
1059      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1060     /* Now with the URL missing a scheme */
1061     U(entry).pwszURL = (LPWSTR)dnsName;
1062     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1063      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1064     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1065     if (buf)
1066     {
1067         /* This succeeds, but it shouldn't, so don't worry about conforming */
1068         LocalFree(buf);
1069     }
1070     /* Now with a DNS name */
1071     entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1072     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1073      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1074     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1075     if (buf)
1076     {
1077         ok(size == sizeof(encodedDnsName), "Wrong size %ld\n", size);
1078         ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1079         LocalFree(buf);
1080     }
1081     /* Test with an IP address */
1082     entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1083     U(entry).IPAddress.cbData = sizeof(localhost);
1084     U(entry).IPAddress.pbData = (LPBYTE)localhost;
1085     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1086      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1087     if (buf)
1088     {
1089         ok(size == sizeof(encodedIPAddr), "Wrong size %ld\n", size);
1090         ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1091         LocalFree(buf);
1092     }
1093 }
1094
1095 static void test_decodeAltName(DWORD dwEncoding)
1096 {
1097     static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1098      0x00, 0x00, 0x01 };
1099     static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1100      0x01 };
1101     BOOL ret;
1102     BYTE *buf = NULL;
1103     DWORD bufSize = 0;
1104     CERT_ALT_NAME_INFO *info;
1105
1106     /* Test some bogus ones first */
1107     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1108      unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1109      NULL, (BYTE *)&buf, &bufSize);
1110     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1111      "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1112     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1113      bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1114      &bufSize);
1115     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1116      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1117     /* Now expected cases */
1118     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1119      emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1120      &bufSize);
1121     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1122     if (buf)
1123     {
1124         info = (CERT_ALT_NAME_INFO *)buf;
1125
1126         ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1127          info->cAltEntry);
1128         LocalFree(buf);
1129     }
1130     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1131      emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1132      &bufSize);
1133     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1134     if (buf)
1135     {
1136         info = (CERT_ALT_NAME_INFO *)buf;
1137
1138         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1139          info->cAltEntry);
1140         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1141          "Expected CERT_ALT_NAME_URL, got %ld\n",
1142          info->rgAltEntry[0].dwAltNameChoice);
1143         ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1144          "Expected empty URL\n");
1145         LocalFree(buf);
1146     }
1147     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1148      encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1149      &bufSize);
1150     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1151     if (buf)
1152     {
1153         info = (CERT_ALT_NAME_INFO *)buf;
1154
1155         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1156          info->cAltEntry);
1157         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1158          "Expected CERT_ALT_NAME_URL, got %ld\n",
1159          info->rgAltEntry[0].dwAltNameChoice);
1160         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1161         LocalFree(buf);
1162     }
1163     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1164      encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1165      &bufSize);
1166     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1167     if (buf)
1168     {
1169         info = (CERT_ALT_NAME_INFO *)buf;
1170
1171         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1172          info->cAltEntry);
1173         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1174          "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1175          info->rgAltEntry[0].dwAltNameChoice);
1176         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1177          "Unexpected DNS name\n");
1178         LocalFree(buf);
1179     }
1180     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1181      encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1182      &bufSize);
1183     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1184     if (buf)
1185     {
1186         info = (CERT_ALT_NAME_INFO *)buf;
1187
1188         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1189          info->cAltEntry);
1190         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1191          "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1192          info->rgAltEntry[0].dwAltNameChoice);
1193         ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1194          "Unexpected IP address length %ld\n",
1195           U(info->rgAltEntry[0]).IPAddress.cbData);
1196         ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1197          sizeof(localhost)), "Unexpected IP address value\n");
1198         LocalFree(buf);
1199     }
1200 }
1201
1202 struct encodedOctets
1203 {
1204     const BYTE *val;
1205     const BYTE *encoded;
1206 };
1207
1208 static const unsigned char bin46[] = { 'h','i',0 };
1209 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1210 static const unsigned char bin48[] = {
1211      's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1212 static const unsigned char bin49[] = {
1213      0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1214 static const unsigned char bin50[] = { 0 };
1215 static const unsigned char bin51[] = { 0x04,0x00,0 };
1216
1217 static const struct encodedOctets octets[] = {
1218     { bin46, bin47 },
1219     { bin48, bin49 },
1220     { bin50, bin51 },
1221 };
1222
1223 static void test_encodeOctets(DWORD dwEncoding)
1224 {
1225     CRYPT_DATA_BLOB blob;
1226     DWORD i;
1227
1228     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1229     {
1230         BYTE *buf = NULL;
1231         BOOL ret;
1232         DWORD bufSize = 0;
1233
1234         blob.cbData = strlen((const char*)octets[i].val);
1235         blob.pbData = (BYTE*)octets[i].val;
1236         ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1237          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1238         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1239         if (buf)
1240         {
1241             ok(buf[0] == 4,
1242              "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1243             ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1244              buf[1], octets[i].encoded[1]);
1245             ok(!memcmp(buf + 1, octets[i].encoded + 1,
1246              octets[i].encoded[1] + 1), "Got unexpected value\n");
1247             LocalFree(buf);
1248         }
1249     }
1250 }
1251
1252 static void test_decodeOctets(DWORD dwEncoding)
1253 {
1254     DWORD i;
1255
1256     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1257     {
1258         BYTE *buf = NULL;
1259         BOOL ret;
1260         DWORD bufSize = 0;
1261
1262         ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1263          (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1264          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1265         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1266         ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1267          "Expected size >= %d, got %ld\n",
1268            (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1269         ok(buf != NULL, "Expected allocated buffer\n");
1270         if (buf)
1271         {
1272             CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1273
1274             if (blob->cbData)
1275                 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1276                  "Unexpected value\n");
1277             LocalFree(buf);
1278         }
1279     }
1280 }
1281
1282 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1283
1284 struct encodedBits
1285 {
1286     DWORD cUnusedBits;
1287     const BYTE *encoded;
1288     DWORD cbDecoded;
1289     const BYTE *decoded;
1290 };
1291
1292 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1293 static const unsigned char bin53[] = { 0xff,0xff };
1294 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1295 static const unsigned char bin55[] = { 0xff,0xfe };
1296 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1297 static const unsigned char bin57[] = { 0xfe };
1298 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1299
1300 static const struct encodedBits bits[] = {
1301     /* normal test cases */
1302     { 0, bin52, 2, bin53 },
1303     { 1, bin54, 2, bin55 },
1304     /* strange test case, showing cUnusedBits >= 8 is allowed */
1305     { 9, bin56, 1, bin57 },
1306     /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1307     { 17, bin58, 0, NULL },
1308 };
1309
1310 static void test_encodeBits(DWORD dwEncoding)
1311 {
1312     DWORD i;
1313
1314     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1315     {
1316         CRYPT_BIT_BLOB blob;
1317         BOOL ret;
1318         BYTE *buf = NULL;
1319         DWORD bufSize = 0;
1320
1321         blob.cbData = sizeof(bytesToEncode);
1322         blob.pbData = (BYTE *)bytesToEncode;
1323         blob.cUnusedBits = bits[i].cUnusedBits;
1324         ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1325          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1326         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1327         if (buf)
1328         {
1329             ok(bufSize == bits[i].encoded[1] + 2,
1330              "Got unexpected size %ld, expected %d\n", bufSize,
1331              bits[i].encoded[1] + 2);
1332             ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1333              "Unexpected value\n");
1334             LocalFree(buf);
1335         }
1336     }
1337 }
1338
1339 static void test_decodeBits(DWORD dwEncoding)
1340 {
1341     static const BYTE ber[] = "\x03\x02\x01\xff";
1342     static const BYTE berDecoded = 0xfe;
1343     DWORD i;
1344     BOOL ret;
1345     BYTE *buf = NULL;
1346     DWORD bufSize = 0;
1347
1348     /* normal cases */
1349     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1350     {
1351         ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1352          bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1353          &bufSize);
1354         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1355         if (buf)
1356         {
1357             CRYPT_BIT_BLOB *blob;
1358
1359             ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1360              "Got unexpected size %ld, expected >= %ld\n", bufSize,
1361              sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1362             blob = (CRYPT_BIT_BLOB *)buf;
1363             ok(blob->cbData == bits[i].cbDecoded,
1364              "Got unexpected length %ld, expected %ld\n", blob->cbData,
1365              bits[i].cbDecoded);
1366             if (blob->cbData && bits[i].cbDecoded)
1367                 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1368                  "Unexpected value\n");
1369             LocalFree(buf);
1370         }
1371     }
1372     /* special case: check that something that's valid in BER but not in DER
1373      * decodes successfully
1374      */
1375     ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1376      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1377     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1378     if (buf)
1379     {
1380         CRYPT_BIT_BLOB *blob;
1381
1382         ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1383            "Got unexpected size %ld\n", bufSize);
1384         blob = (CRYPT_BIT_BLOB *)buf;
1385         ok(blob->cbData == sizeof(berDecoded),
1386            "Got unexpected length %ld\n", blob->cbData);
1387         if (blob->cbData)
1388             ok(*blob->pbData == berDecoded, "Unexpected value\n");
1389         LocalFree(buf);
1390     }
1391 }
1392
1393 struct Constraints2
1394 {
1395     CERT_BASIC_CONSTRAINTS2_INFO info;
1396     const BYTE *encoded;
1397 };
1398
1399 static const unsigned char bin59[] = { 0x30,0x00 };
1400 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1401 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1402 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1403 static const struct Constraints2 constraints2[] = {
1404  /* empty constraints */
1405  { { FALSE, FALSE, 0}, bin59 },
1406  /* can be a CA */
1407  { { TRUE,  FALSE, 0}, bin60 },
1408  /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1409   * but that's not the case
1410   */
1411  { { FALSE, TRUE,  0}, bin61 },
1412  /* can be a CA and has path length constraints set */
1413  { { TRUE,  TRUE,  1}, bin62 },
1414 };
1415
1416 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1417 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1418  0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1419  0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1420  0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1421 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1422  0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1423  0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1424  0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1425  0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1426
1427 static void test_encodeBasicConstraints(DWORD dwEncoding)
1428 {
1429     DWORD i, bufSize = 0;
1430     CERT_BASIC_CONSTRAINTS_INFO info;
1431     CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1432      (LPBYTE)encodedDomainName };
1433     BOOL ret;
1434     BYTE *buf = NULL;
1435
1436     /* First test with the simpler info2 */
1437     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1438     {
1439         ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1440          &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1441          &bufSize);
1442         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1443         if (buf)
1444         {
1445             ok(bufSize == constraints2[i].encoded[1] + 2,
1446              "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1447              bufSize);
1448             ok(!memcmp(buf, constraints2[i].encoded,
1449              constraints2[i].encoded[1] + 2), "Unexpected value\n");
1450             LocalFree(buf);
1451         }
1452     }
1453     /* Now test with more complex basic constraints */
1454     info.SubjectType.cbData = 0;
1455     info.fPathLenConstraint = FALSE;
1456     info.cSubtreesConstraint = 0;
1457     ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1458      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1459     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1460     if (buf)
1461     {
1462         ok(bufSize == sizeof(emptyConstraint), "Wrong size %ld\n", bufSize);
1463         ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1464          "Unexpected value\n");
1465         LocalFree(buf);
1466     }
1467     /* None of the certs I examined had any subtree constraint, but I test one
1468      * anyway just in case.
1469      */
1470     info.cSubtreesConstraint = 1;
1471     info.rgSubtreesConstraint = &nameBlob;
1472     ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1473      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1474     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1475     if (buf)
1476     {
1477         ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %ld\n", bufSize);
1478         ok(!memcmp(buf, constraintWithDomainName,
1479          sizeof(constraintWithDomainName)), "Unexpected value\n");
1480         LocalFree(buf);
1481     }
1482     /* FIXME: test encoding with subject type. */
1483 }
1484
1485 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1486 static const unsigned char encodedCommonName[] = {
1487     0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
1488
1489 static void test_decodeBasicConstraints(DWORD dwEncoding)
1490 {
1491     static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1492      0xff };
1493     static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1494     DWORD i;
1495     BOOL ret;
1496     BYTE *buf = NULL;
1497     DWORD bufSize = 0;
1498
1499     /* First test with simpler info2 */
1500     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1501     {
1502         ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1503          constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1504          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1505         ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1506          GetLastError());
1507         if (buf)
1508         {
1509             CERT_BASIC_CONSTRAINTS2_INFO *info =
1510              (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1511
1512             ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1513              "Unexpected value for item %ld\n", i);
1514             LocalFree(buf);
1515         }
1516     }
1517     /* Check with the order of encoded elements inverted */
1518     buf = (PBYTE)1;
1519     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1520      inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1521      &bufSize);
1522     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1523      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1524     ok(!buf, "Expected buf to be set to NULL\n");
1525     /* Check with a non-DER bool */
1526     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1527      badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1528      (BYTE *)&buf, &bufSize);
1529     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1530     if (buf)
1531     {
1532         CERT_BASIC_CONSTRAINTS2_INFO *info =
1533          (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1534
1535         ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1536         LocalFree(buf);
1537     }
1538     /* Check with a non-basic constraints value */
1539     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1540      (LPBYTE)encodedCommonName, encodedCommonName[1] + 2,
1541      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1542     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1543      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1544     /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
1545     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1546      emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
1547      (BYTE *)&buf, &bufSize);
1548     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1549     if (buf)
1550     {
1551         CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1552
1553         ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1554         ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1555         ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
1556         LocalFree(buf);
1557     }
1558     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
1559      constraintWithDomainName, sizeof(constraintWithDomainName),
1560      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1561     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1562     if (buf)
1563     {
1564         CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
1565
1566         ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
1567         ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
1568         ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
1569         if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
1570         {
1571             ok(info->rgSubtreesConstraint[0].cbData ==
1572              sizeof(encodedDomainName), "Wrong size %ld\n",
1573              info->rgSubtreesConstraint[0].cbData);
1574             ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
1575              sizeof(encodedDomainName)), "Unexpected value\n");
1576         }
1577         LocalFree(buf);
1578     }
1579 }
1580
1581 /* These are terrible public keys of course, I'm just testing encoding */
1582 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1583 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1584 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1585 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1586 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1587 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1588 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1589 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1590
1591 struct EncodedRSAPubKey
1592 {
1593     const BYTE *modulus;
1594     size_t modulusLen;
1595     const BYTE *encoded;
1596     size_t decodedModulusLen;
1597 };
1598
1599 struct EncodedRSAPubKey rsaPubKeys[] = {
1600     { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1601     { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1602     { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1603     { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1604 };
1605
1606 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1607 {
1608     BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1609     BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1610     RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1611     BOOL ret;
1612     BYTE *buf = NULL;
1613     DWORD bufSize = 0, i;
1614
1615     /* Try with a bogus blob type */
1616     hdr->bType = 2;
1617     hdr->bVersion = CUR_BLOB_VERSION;
1618     hdr->reserved = 0;
1619     hdr->aiKeyAlg = CALG_RSA_KEYX;
1620     rsaPubKey->magic = 0x31415352;
1621     rsaPubKey->bitlen = sizeof(modulus1) * 8;
1622     rsaPubKey->pubexp = 65537;
1623     memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1624      sizeof(modulus1));
1625
1626     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1627      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1628      &bufSize);
1629     ok(!ret && GetLastError() == E_INVALIDARG,
1630      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1631     /* Now with a bogus reserved field */
1632     hdr->bType = PUBLICKEYBLOB;
1633     hdr->reserved = 1;
1634     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1635      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1636      &bufSize);
1637     if (buf)
1638     {
1639         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1640          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1641         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1642         LocalFree(buf);
1643     }
1644     /* Now with a bogus blob version */
1645     hdr->reserved = 0;
1646     hdr->bVersion = 0;
1647     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1648      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1649      &bufSize);
1650     if (buf)
1651     {
1652         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1653          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1654         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1655         LocalFree(buf);
1656     }
1657     /* And with a bogus alg ID */
1658     hdr->bVersion = CUR_BLOB_VERSION;
1659     hdr->aiKeyAlg = CALG_DES;
1660     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1661      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1662      &bufSize);
1663     if (buf)
1664     {
1665         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1666          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1667         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1668         LocalFree(buf);
1669     }
1670     /* Check a couple of RSA-related OIDs */
1671     hdr->aiKeyAlg = CALG_RSA_KEYX;
1672     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1673      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1674     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1675      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1676     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1677      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1678     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1679      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1680     /* Finally, all valid */
1681     hdr->aiKeyAlg = CALG_RSA_KEYX;
1682     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1683     {
1684         memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1685          rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1686         ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1687          toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1688         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1689         if (buf)
1690         {
1691             ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1692              "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1693              bufSize);
1694             ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1695              "Unexpected value\n");
1696             LocalFree(buf);
1697         }
1698     }
1699 }
1700
1701 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1702 {
1703     DWORD i;
1704     LPBYTE buf = NULL;
1705     DWORD bufSize = 0;
1706     BOOL ret;
1707
1708     /* Try with a bad length */
1709     ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1710      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1711      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1712     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1713      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1714     /* Try with a couple of RSA-related OIDs */
1715     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1716      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1717      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1718     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1719      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1720     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1721      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1722      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1723     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1724      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1725     /* Now try success cases */
1726     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1727     {
1728         bufSize = 0;
1729         ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1730          rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1731          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1732         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1733         if (buf)
1734         {
1735             BLOBHEADER *hdr = (BLOBHEADER *)buf;
1736             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1737
1738             ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1739              rsaPubKeys[i].decodedModulusLen,
1740              "Wrong size %ld\n", bufSize);
1741             ok(hdr->bType == PUBLICKEYBLOB,
1742              "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1743              hdr->bType);
1744             ok(hdr->bVersion == CUR_BLOB_VERSION,
1745              "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1746              CUR_BLOB_VERSION, hdr->bVersion);
1747             ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1748              hdr->reserved);
1749             ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1750              "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1751             ok(rsaPubKey->magic == 0x31415352,
1752              "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1753             ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1754              "Wrong bit len %ld\n", rsaPubKey->bitlen);
1755             ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1756              rsaPubKey->pubexp);
1757             ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1758              rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1759              "Unexpected modulus\n");
1760             LocalFree(buf);
1761         }
1762     }
1763 }
1764
1765 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1766  0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1767  0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1768
1769 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1770  0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1771  0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1772  0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1773
1774 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1775 {
1776     CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1777     CRYPT_SEQUENCE_OF_ANY seq;
1778     DWORD i;
1779     BOOL ret;
1780     BYTE *buf = NULL;
1781     DWORD bufSize = 0;
1782
1783     /* Encode a homogenous sequence */
1784     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1785     {
1786         blobs[i].cbData = ints[i].encoded[1] + 2;
1787         blobs[i].pbData = (BYTE *)ints[i].encoded;
1788     }
1789     seq.cValue = sizeof(ints) / sizeof(ints[0]);
1790     seq.rgValue = blobs;
1791
1792     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1793      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1794     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1795     if (buf)
1796     {
1797         ok(bufSize == sizeof(intSequence), "Wrong size %ld\n", bufSize);
1798         ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1799         LocalFree(buf);
1800     }
1801     /* Change the type of the first element in the sequence, and give it
1802      * another go
1803      */
1804     blobs[0].cbData = times[0].encodedTime[1] + 2;
1805     blobs[0].pbData = (BYTE *)times[0].encodedTime;
1806     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1807      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1808     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1809     if (buf)
1810     {
1811         ok(bufSize == sizeof(mixedSequence), "Wrong size %ld\n", bufSize);
1812         ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1813          "Unexpected value\n");
1814         LocalFree(buf);
1815     }
1816 }
1817
1818 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1819 {
1820     BOOL ret;
1821     BYTE *buf = NULL;
1822     DWORD bufSize = 0;
1823
1824     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1825      intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1826     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1827     if (buf)
1828     {
1829         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1830         DWORD i;
1831
1832         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1833          "Wrong elements %ld\n", seq->cValue);
1834         for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1835         {
1836             ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1837              "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1838              seq->rgValue[i].cbData);
1839             ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1840              ints[i].encoded[1] + 2), "Unexpected value\n");
1841         }
1842         LocalFree(buf);
1843     }
1844     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1845      mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1846      &bufSize);
1847     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1848     if (buf)
1849     {
1850         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1851
1852         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1853          "Wrong elements %ld\n", seq->cValue);
1854         /* Just check the first element since it's all that changed */
1855         ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1856          "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1857          seq->rgValue[0].cbData);
1858         ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1859          times[0].encodedTime[1] + 2), "Unexpected value\n");
1860         LocalFree(buf);
1861     }
1862 }
1863
1864 struct encodedExtensions
1865 {
1866     CERT_EXTENSIONS exts;
1867     const BYTE *encoded;
1868 };
1869
1870 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1871 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1872
1873 static CERT_EXTENSION criticalExt =
1874  { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1875 static CERT_EXTENSION nonCriticalExt =
1876  { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1877
1878 static const BYTE ext0[] = { 0x30,0x00 };
1879 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1880                              0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1881 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1882                              0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1883
1884 static const struct encodedExtensions exts[] = {
1885  { { 0, NULL }, ext0 },
1886  { { 1, &criticalExt }, ext1 },
1887  { { 1, &nonCriticalExt }, ext2 },
1888 };
1889
1890 static void test_encodeExtensions(DWORD dwEncoding)
1891 {
1892     DWORD i;
1893
1894     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1895     {
1896         BOOL ret;
1897         BYTE *buf = NULL;
1898         DWORD bufSize = 0;
1899
1900         ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1901          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1902         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1903         if (buf)
1904         {
1905             ok(bufSize == exts[i].encoded[1] + 2,
1906              "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1907             ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1908              "Unexpected value\n");
1909             LocalFree(buf);
1910         }
1911     }
1912 }
1913
1914 static void test_decodeExtensions(DWORD dwEncoding)
1915 {
1916     DWORD i;
1917
1918     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1919     {
1920         BOOL ret;
1921         BYTE *buf = NULL;
1922         DWORD bufSize = 0;
1923
1924         ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1925          exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1926          NULL, (BYTE *)&buf, &bufSize);
1927         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1928         if (buf)
1929         {
1930             CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1931             DWORD j;
1932
1933             ok(ext->cExtension == exts[i].exts.cExtension,
1934              "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1935              ext->cExtension);
1936             for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1937             {
1938                 ok(!strcmp(ext->rgExtension[j].pszObjId,
1939                  exts[i].exts.rgExtension[j].pszObjId),
1940                  "Expected OID %s, got %s\n",
1941                  exts[i].exts.rgExtension[j].pszObjId,
1942                  ext->rgExtension[j].pszObjId);
1943                 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1944                  exts[i].exts.rgExtension[j].Value.pbData,
1945                  exts[i].exts.rgExtension[j].Value.cbData),
1946                  "Unexpected value\n");
1947             }
1948             LocalFree(buf);
1949         }
1950     }
1951 }
1952
1953 /* MS encodes public key info with a NULL if the algorithm identifier's
1954  * parameters are empty.  However, when encoding an algorithm in a CERT_INFO,
1955  * it encodes them by omitting the algorithm parameters.  This latter approach
1956  * seems more correct, so accept either form.
1957  */
1958 struct encodedPublicKey
1959 {
1960     CERT_PUBLIC_KEY_INFO info;
1961     const BYTE *encoded;
1962     const BYTE *encodedNoNull;
1963     CERT_PUBLIC_KEY_INFO decoded;
1964 };
1965
1966 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1967  0xe, 0xf };
1968 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1969
1970 static const unsigned char bin64[] = {
1971     0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
1972 static const unsigned char bin65[] = {
1973     0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
1974 static const unsigned char bin66[] = {
1975     0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
1976 static const unsigned char bin67[] = {
1977     0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
1978 static const unsigned char bin68[] = {
1979     0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1980     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
1981 static const unsigned char bin69[] = {
1982     0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
1983     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
1984 static const unsigned char bin70[] = {
1985     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1986     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1987     0x0f};
1988 static const unsigned char bin71[] = {
1989     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1990     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1991     0x0f};
1992 static unsigned char bin72[] = { 0x05,0x00};
1993
1994 static const struct encodedPublicKey pubKeys[] = {
1995  /* with a bogus OID */
1996  { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1997   bin64, bin65,
1998   { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
1999  /* some normal keys */
2000  { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
2001   bin66, bin67,
2002   { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
2003  { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2004   bin68, bin69,
2005   { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2006  /* with add'l parameters--note they must be DER-encoded */
2007  { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2008   (BYTE *)aKey, 0 } },
2009   bin70, bin71,
2010   { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2011   (BYTE *)aKey, 0 } } },
2012 };
2013
2014 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2015 {
2016     DWORD i;
2017
2018     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2019     {
2020         BOOL ret;
2021         BYTE *buf = NULL;
2022         DWORD bufSize = 0;
2023
2024         ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2025          &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2026          &bufSize);
2027         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2028         if (buf)
2029         {
2030             ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2031              bufSize == pubKeys[i].encodedNoNull[1] + 2,
2032              "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2033              pubKeys[i].encodedNoNull[1] + 2, bufSize);
2034             if (bufSize == pubKeys[i].encoded[1] + 2)
2035                 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2036                  "Unexpected value\n");
2037             else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2038                 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2039                  pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2040             LocalFree(buf);
2041         }
2042     }
2043 }
2044
2045 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2046  const CERT_PUBLIC_KEY_INFO *got)
2047 {
2048     ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2049      "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2050      got->Algorithm.pszObjId);
2051     ok(expected->Algorithm.Parameters.cbData ==
2052      got->Algorithm.Parameters.cbData,
2053      "Expected parameters of %ld bytes, got %ld\n",
2054      expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2055     if (expected->Algorithm.Parameters.cbData)
2056         ok(!memcmp(expected->Algorithm.Parameters.pbData,
2057          got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2058          "Unexpected algorithm parameters\n");
2059     ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2060      "Expected public key of %ld bytes, got %ld\n",
2061      expected->PublicKey.cbData, got->PublicKey.cbData);
2062     if (expected->PublicKey.cbData)
2063         ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2064          got->PublicKey.cbData), "Unexpected public key value\n");
2065 }
2066
2067 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2068 {
2069     static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2070      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2071      0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2072      0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2073     DWORD i;
2074     BOOL ret;
2075     BYTE *buf = NULL;
2076     DWORD bufSize = 0;
2077
2078     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2079     {
2080         /* The NULL form decodes to the decoded member */
2081         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2082          pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2083          NULL, (BYTE *)&buf, &bufSize);
2084         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2085         if (buf)
2086         {
2087             comparePublicKeyInfo(&pubKeys[i].decoded,
2088              (CERT_PUBLIC_KEY_INFO *)buf);
2089             LocalFree(buf);
2090         }
2091         /* The non-NULL form decodes to the original */
2092         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2093          pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2094          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2095         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2096         if (buf)
2097         {
2098             comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2099             LocalFree(buf);
2100         }
2101     }
2102     /* Test with bogus (not valid DER) parameters */
2103     ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2104      bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2105      NULL, (BYTE *)&buf, &bufSize);
2106     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2107      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2108 }
2109
2110 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2111  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2112  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2113  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2114  0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2115 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2116  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2117  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2118  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2119  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2120 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2121  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2122  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2123  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2124  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2125 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2126  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2127  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2128  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2129  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2130  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2131  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2132 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2133  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2134  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2135  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2136  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2137  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2138  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2139 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2140  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2141  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2142  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2143  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2144  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2145  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2146  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2147  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2148  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2149
2150 static const BYTE serialNum[] = { 0x01 };
2151
2152 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2153 {
2154     BOOL ret;
2155     BYTE *buf = NULL;
2156     DWORD size = 0;
2157     CERT_INFO info = { 0 };
2158
2159     /* Test with NULL pvStructInfo */
2160     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2161      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2162     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2163      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2164     /* Test with a V1 cert */
2165     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2166      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2167     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2168     if (buf)
2169     {
2170         ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2171          v1Cert[1] + 2, size);
2172         ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2173         LocalFree(buf);
2174     }
2175     /* Test v2 cert */
2176     info.dwVersion = CERT_V2;
2177     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2178      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2179     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2180     if (buf)
2181     {
2182         ok(size == sizeof(v2Cert), "Wrong size %ld\n", size);
2183         ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2184         LocalFree(buf);
2185     }
2186     /* Test v3 cert */
2187     info.dwVersion = CERT_V3;
2188     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2189      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2190     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2191     if (buf)
2192     {
2193         ok(size == sizeof(v3Cert), "Wrong size %ld\n", size);
2194         ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2195         LocalFree(buf);
2196     }
2197     /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2198      * API doesn't prevent it)
2199      */
2200     info.dwVersion = CERT_V1;
2201     info.cExtension = 1;
2202     info.rgExtension = &criticalExt;
2203     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2204      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2205     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2206     if (buf)
2207     {
2208         ok(size == sizeof(v1CertWithConstraints), "Wrong size %ld\n", size);
2209         ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2210         LocalFree(buf);
2211     }
2212     /* test v1 cert with a serial number */
2213     info.SerialNumber.cbData = sizeof(serialNum);
2214     info.SerialNumber.pbData = (BYTE *)serialNum;
2215     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2216      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2217     if (buf)
2218     {
2219         ok(size == sizeof(v1CertWithSerial), "Wrong size %ld\n", size);
2220         ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2221         LocalFree(buf);
2222     }
2223     /* Test v1 cert with an issuer name, a subject name, and a serial number */
2224     info.Issuer.cbData = sizeof(encodedCommonName);
2225     info.Issuer.pbData = (BYTE *)encodedCommonName;
2226     info.Subject.cbData = sizeof(encodedCommonName);
2227     info.Subject.pbData = (BYTE *)encodedCommonName;
2228     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2229      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2230     if (buf)
2231     {
2232         ok(size == sizeof(bigCert), "Wrong size %ld\n", size);
2233         ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2234         LocalFree(buf);
2235     }
2236     /* for now, I let more interesting tests be done for each subcomponent,
2237      * rather than retesting them all here.
2238      */
2239 }
2240
2241 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2242 {
2243     static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2244      v1CertWithConstraints, v1CertWithSerial };
2245     BOOL ret;
2246     BYTE *buf = NULL;
2247     DWORD size = 0, i;
2248
2249     /* Test with NULL pbEncoded */
2250     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2251      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2252     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2253      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2254     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2255      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2256     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2257      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2258     /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2259      * minimum a cert must have a non-zero serial number, an issuer, and a
2260      * subject.
2261      */
2262     for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2263     {
2264         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2265          corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2266          (BYTE *)&buf, &size);
2267         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2268          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2269     }
2270     /* Now check with serial number, subject and issuer specified */
2271     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2272      sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2273     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2274     if (buf)
2275     {
2276         CERT_INFO *info = (CERT_INFO *)buf;
2277
2278         ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2279         ok(info->SerialNumber.cbData == 1,
2280          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2281         ok(*info->SerialNumber.pbData == *serialNum,
2282          "Expected serial number %d, got %d\n", *serialNum,
2283          *info->SerialNumber.pbData);
2284         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2285          "Wrong size %ld\n", info->Issuer.cbData);
2286         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2287          "Unexpected issuer\n");
2288         ok(info->Subject.cbData == sizeof(encodedCommonName),
2289          "Wrong size %ld\n", info->Subject.cbData);
2290         ok(!memcmp(info->Subject.pbData, encodedCommonName,
2291          info->Subject.cbData), "Unexpected subject\n");
2292         LocalFree(buf);
2293     }
2294 }
2295
2296 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2297  0xe, 0xf };
2298
2299 static const BYTE signedBigCert[] = {
2300  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2301  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2302  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2303  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2304  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2305  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2306  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2307  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2308  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2309  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2310  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2311  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2312
2313 static void test_encodeCert(DWORD dwEncoding)
2314 {
2315     /* Note the SignatureAlgorithm must match that in the encoded cert.  Note
2316      * also that bigCert is a NULL-terminated string, so don't count its
2317      * last byte (otherwise the signed cert won't decode.)
2318      */
2319     CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2320      { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2321     BOOL ret;
2322     BYTE *buf = NULL;
2323     DWORD bufSize = 0;
2324
2325     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2326      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2327     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2328     if (buf)
2329     {
2330         ok(bufSize == sizeof(signedBigCert), "Wrong size %ld\n", bufSize);
2331         ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2332         LocalFree(buf);
2333     }
2334 }
2335
2336 static void test_decodeCert(DWORD dwEncoding)
2337 {
2338     BOOL ret;
2339     BYTE *buf = NULL;
2340     DWORD size = 0;
2341
2342     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2343      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2344     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2345     if (buf)
2346     {
2347         CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2348
2349         ok(info->ToBeSigned.cbData == sizeof(bigCert),
2350          "Wrong cert size %ld\n", info->ToBeSigned.cbData);
2351         ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2352          "Unexpected cert\n");
2353         ok(info->Signature.cbData == sizeof(hash),
2354          "Wrong signature size %ld\n", info->Signature.cbData);
2355         ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2356          "Unexpected signature\n");
2357         LocalFree(buf);
2358     }
2359     /* A signed cert decodes as a CERT_INFO too */
2360     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, signedBigCert,
2361      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2362     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2363     if (buf)
2364     {
2365         CERT_INFO *info = (CERT_INFO *)buf;
2366
2367         ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2368         ok(info->SerialNumber.cbData == 1,
2369          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2370         ok(*info->SerialNumber.pbData == *serialNum,
2371          "Expected serial number %d, got %d\n", *serialNum,
2372          *info->SerialNumber.pbData);
2373         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2374          "Wrong size %ld\n", info->Issuer.cbData);
2375         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2376          "Unexpected issuer\n");
2377         ok(info->Subject.cbData == sizeof(encodedCommonName),
2378          "Wrong size %ld\n", info->Subject.cbData);
2379         ok(!memcmp(info->Subject.pbData, encodedCommonName,
2380          info->Subject.cbData), "Unexpected subject\n");
2381         LocalFree(buf);
2382     }
2383 }
2384
2385 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2386 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2387  0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2388  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2389 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2390  0x00, 0x03 };
2391 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2392  0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2393  0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2394 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2395  0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2396  0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2397  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2398  0x2e, 0x6f, 0x72, 0x67 };
2399 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2400  CRL_REASON_AFFILIATION_CHANGED;
2401
2402 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2403 {
2404     CRL_DIST_POINTS_INFO info = { 0 };
2405     CRL_DIST_POINT point = { { 0 } };
2406     CERT_ALT_NAME_ENTRY entry = { 0 };
2407     BOOL ret;
2408     BYTE *buf = NULL;
2409     DWORD size = 0;
2410
2411     /* Test with an empty info */
2412     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2413      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2414     ok(!ret && GetLastError() == E_INVALIDARG,
2415      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2416     /* Test with one empty dist point */
2417     info.cDistPoint = 1;
2418     info.rgDistPoint = &point;
2419     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2420      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2421     if (buf)
2422     {
2423         ok(size == sizeof(emptyDistPoint), "Wrong size %ld\n", size);
2424         ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2425         LocalFree(buf);
2426     }
2427     /* A dist point with an invalid name */
2428     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2429     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2430     U(entry).pwszURL = (LPWSTR)nihongoURL;
2431     U(point.DistPointName).FullName.cAltEntry = 1;
2432     U(point.DistPointName).FullName.rgAltEntry = &entry;
2433     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2434      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2435     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2436      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2437     /* The first invalid character is at index 7 */
2438     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2439      "Expected invalid char at index 7, got %ld\n",
2440      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2441     /* A dist point with (just) a valid name */
2442     U(entry).pwszURL = (LPWSTR)url;
2443     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2444      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2445     if (buf)
2446     {
2447         ok(size == sizeof(distPointWithUrl), "Wrong size %ld\n", size);
2448         ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2449         LocalFree(buf);
2450     }
2451     /* A dist point with (just) reason flags */
2452     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2453     point.ReasonFlags.cbData = sizeof(crlReason);
2454     point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2455     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2456      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2457     if (buf)
2458     {
2459         ok(size == sizeof(distPointWithReason), "Wrong size %ld\n", size);
2460         ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2461         LocalFree(buf);
2462     }
2463     /* A dist point with just an issuer */
2464     point.ReasonFlags.cbData = 0;
2465     point.CRLIssuer.cAltEntry = 1;
2466     point.CRLIssuer.rgAltEntry = &entry;
2467     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2468      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2469     if (buf)
2470     {
2471         ok(size == sizeof(distPointWithIssuer), "Wrong size %ld\n", size);
2472         ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2473         LocalFree(buf);
2474     }
2475     /* A dist point with both a name and an issuer */
2476     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2477     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2478      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2479     if (buf)
2480     {
2481         ok(size == sizeof(distPointWithUrlAndIssuer),
2482          "Wrong size %ld\n", size);
2483         ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2484         LocalFree(buf);
2485     }
2486 }
2487
2488 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2489 {
2490     BOOL ret;
2491     BYTE *buf = NULL;
2492     DWORD size = 0;
2493     PCRL_DIST_POINTS_INFO info;
2494     PCRL_DIST_POINT point;
2495     PCERT_ALT_NAME_ENTRY entry;
2496
2497     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2498      emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2499      (BYTE *)&buf, &size);
2500     if (ret)
2501     {
2502         info = (PCRL_DIST_POINTS_INFO)buf;
2503         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2504          "Wrong size %ld\n", size);
2505         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2506          info->cDistPoint);
2507         point = info->rgDistPoint;
2508         ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2509          "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2510          point->DistPointName.dwDistPointNameChoice);
2511         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2512         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2513         LocalFree(buf);
2514     }
2515     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2516      distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2517      (BYTE *)&buf, &size);
2518     if (ret)
2519     {
2520         info = (PCRL_DIST_POINTS_INFO)buf;
2521         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2522          "Wrong size %ld\n", size);
2523         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2524          info->cDistPoint);
2525         point = info->rgDistPoint;
2526         ok(point->DistPointName.dwDistPointNameChoice ==
2527          CRL_DIST_POINT_FULL_NAME,
2528          "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2529          point->DistPointName.dwDistPointNameChoice);
2530         ok(U(point->DistPointName).FullName.cAltEntry == 1,
2531          "Expected 1 name entry, got %ld\n",
2532          U(point->DistPointName).FullName.cAltEntry);
2533         entry = U(point->DistPointName).FullName.rgAltEntry;
2534         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2535          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2536         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2537         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2538         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2539         LocalFree(buf);
2540     }
2541     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2542      distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2543      NULL, (BYTE *)&buf, &size);
2544     if (ret)
2545     {
2546         info = (PCRL_DIST_POINTS_INFO)buf;
2547         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2548          "Wrong size %ld\n", size);
2549         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2550          info->cDistPoint);
2551         point = info->rgDistPoint;
2552         ok(point->DistPointName.dwDistPointNameChoice ==
2553          CRL_DIST_POINT_NO_NAME,
2554          "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2555          point->DistPointName.dwDistPointNameChoice);
2556         ok(point->ReasonFlags.cbData == sizeof(crlReason),
2557          "Expected reason length\n");
2558         ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2559          "Unexpected reason\n");
2560         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2561         LocalFree(buf);
2562     }
2563     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2564      distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2565      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2566     if (ret)
2567     {
2568         info = (PCRL_DIST_POINTS_INFO)buf;
2569         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2570          "Wrong size %ld\n", size);
2571         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2572          info->cDistPoint);
2573         point = info->rgDistPoint;
2574         ok(point->DistPointName.dwDistPointNameChoice ==
2575          CRL_DIST_POINT_FULL_NAME,
2576          "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2577          point->DistPointName.dwDistPointNameChoice);
2578         ok(U(point->DistPointName).FullName.cAltEntry == 1,
2579          "Expected 1 name entry, got %ld\n",
2580          U(point->DistPointName).FullName.cAltEntry);
2581         entry = U(point->DistPointName).FullName.rgAltEntry;
2582         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2583          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2584         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2585         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2586         ok(point->CRLIssuer.cAltEntry == 1,
2587          "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2588         entry = point->CRLIssuer.rgAltEntry;
2589         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2590          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2591         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2592         LocalFree(buf);
2593     }
2594 }
2595
2596 static const BYTE badFlagsIDP[] = { 0x30,0x06,0x81,0x01,0xff,0x82,0x01,0xff };
2597 static const BYTE emptyNameIDP[] = { 0x30,0x04,0xa0,0x02,0xa0,0x00 };
2598 static const BYTE urlIDP[] = { 0x30,0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,
2599  0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,
2600  0x67 };
2601
2602 static void test_encodeCRLIssuingDistPoint(DWORD dwEncoding)
2603 {
2604     BOOL ret;
2605     BYTE *buf = NULL;
2606     DWORD size = 0;
2607     CRL_ISSUING_DIST_POINT point = { { 0 } };
2608     CERT_ALT_NAME_ENTRY entry;
2609
2610     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, NULL,
2611      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2612     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2613      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2614     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2615      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2616     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2617     if (buf)
2618     {
2619         ok(size == sizeof(emptySequence), "Unexpected size %ld\n", size);
2620         ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
2621         LocalFree(buf);
2622     }
2623     /* nonsensical flags */
2624     point.fOnlyContainsUserCerts = TRUE;
2625     point.fOnlyContainsCACerts = TRUE;
2626     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2627      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2628     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2629     if (buf)
2630     {
2631         ok(size == sizeof(badFlagsIDP), "Unexpected size %ld\n", size);
2632         ok(!memcmp(buf, badFlagsIDP, size), "Unexpected value\n");
2633         LocalFree(buf);
2634     }
2635     /* unimplemented name type */
2636     point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
2637     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_ISSUER_RDN_NAME;
2638     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2639      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2640     ok(!ret && GetLastError() == E_INVALIDARG,
2641      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2642     /* empty name */
2643     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2644     U(point.DistPointName).FullName.cAltEntry = 0;
2645     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2646      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2647     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2648     if (buf)
2649     {
2650         ok(size == sizeof(emptyNameIDP), "Unexpected size %ld\n", size);
2651         ok(!memcmp(buf, emptyNameIDP, size), "Unexpected value\n");
2652         LocalFree(buf);
2653     }
2654     /* name with URL entry */
2655     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2656     U(entry).pwszURL = (LPWSTR)url;
2657     U(point.DistPointName).FullName.cAltEntry = 1;
2658     U(point.DistPointName).FullName.rgAltEntry = &entry;
2659     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
2660      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2661     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2662     if (buf)
2663     {
2664         ok(size == sizeof(urlIDP), "Unexpected size %ld\n", size);
2665         ok(!memcmp(buf, urlIDP, size), "Unexpected value\n");
2666         LocalFree(buf);
2667     }
2668 }
2669
2670 static void compareAltNameEntry(const CERT_ALT_NAME_ENTRY *expected,
2671  const CERT_ALT_NAME_ENTRY *got)
2672 {
2673     ok(expected->dwAltNameChoice == got->dwAltNameChoice,
2674      "Expected name choice %ld, got %ld\n", expected->dwAltNameChoice,
2675      got->dwAltNameChoice);
2676     if (expected->dwAltNameChoice == got->dwAltNameChoice)
2677     {
2678         switch (got->dwAltNameChoice)
2679         {
2680         case CERT_ALT_NAME_RFC822_NAME:
2681         case CERT_ALT_NAME_DNS_NAME:
2682         case CERT_ALT_NAME_EDI_PARTY_NAME:
2683         case CERT_ALT_NAME_URL:
2684         case CERT_ALT_NAME_REGISTERED_ID:
2685             ok((!U(*expected).pwszURL && !U(*got).pwszURL) ||
2686                !lstrcmpW(U(*expected).pwszURL, U(*got).pwszURL), "Unexpected name\n");
2687             break;
2688         case CERT_ALT_NAME_X400_ADDRESS:
2689         case CERT_ALT_NAME_DIRECTORY_NAME:
2690         case CERT_ALT_NAME_IP_ADDRESS:
2691             ok(U(*got).IPAddress.cbData == U(*expected).IPAddress.cbData,
2692                "Unexpected IP address length %ld\n", U(*got).IPAddress.cbData);
2693             ok(!memcmp(U(*got).IPAddress.pbData, U(*got).IPAddress.pbData,
2694                        U(*got).IPAddress.cbData), "Unexpected value\n");
2695             break;
2696         }
2697     }
2698 }
2699
2700 static void compareAltNameInfo(const CERT_ALT_NAME_INFO *expected,
2701  const CERT_ALT_NAME_INFO *got)
2702 {
2703     DWORD i;
2704
2705     ok(expected->cAltEntry == got->cAltEntry, "Expected %ld entries, got %ld\n",
2706      expected->cAltEntry, got->cAltEntry);
2707     for (i = 0; i < min(expected->cAltEntry, got->cAltEntry); i++)
2708         compareAltNameEntry(&expected->rgAltEntry[i], &got->rgAltEntry[i]);
2709 }
2710
2711 static void compareDistPointName(const CRL_DIST_POINT_NAME *expected,
2712  const CRL_DIST_POINT_NAME *got)
2713 {
2714     ok(got->dwDistPointNameChoice == expected->dwDistPointNameChoice,
2715      "Unexpected name choice %ld\n", got->dwDistPointNameChoice);
2716     if (got->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
2717         compareAltNameInfo(&(U(*expected).FullName), &(U(*got).FullName));
2718 }
2719
2720 static void compareCRLIssuingDistPoints(const CRL_ISSUING_DIST_POINT *expected,
2721  const CRL_ISSUING_DIST_POINT *got)
2722 {
2723     compareDistPointName(&expected->DistPointName, &got->DistPointName);
2724     ok(got->fOnlyContainsUserCerts == expected->fOnlyContainsUserCerts,
2725      "Unexpected fOnlyContainsUserCerts\n");
2726     ok(got->fOnlyContainsCACerts == expected->fOnlyContainsCACerts,
2727      "Unexpected fOnlyContainsCACerts\n");
2728     ok(got->OnlySomeReasonFlags.cbData == expected->OnlySomeReasonFlags.cbData,
2729      "Unexpected reason flags\n");
2730     ok(got->fIndirectCRL == expected->fIndirectCRL,
2731      "Unexpected fIndirectCRL\n");
2732 }
2733
2734 static void test_decodeCRLIssuingDistPoint(DWORD dwEncoding)
2735 {
2736     BOOL ret;
2737     BYTE *buf = NULL;
2738     DWORD size = 0;
2739     CRL_ISSUING_DIST_POINT point = { { 0 } };
2740
2741     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2742      emptySequence, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2743      (BYTE *)&buf, &size);
2744     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2745     if (ret)
2746     {
2747         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2748         LocalFree(buf);
2749     }
2750     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2751      badFlagsIDP, badFlagsIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2752      (BYTE *)&buf, &size);
2753     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2754     if (ret)
2755     {
2756         point.fOnlyContainsUserCerts = point.fOnlyContainsCACerts = TRUE;
2757         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2758         LocalFree(buf);
2759     }
2760     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2761      emptyNameIDP, emptyNameIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2762      (BYTE *)&buf, &size);
2763     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2764     if (ret)
2765     {
2766         point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
2767         point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2768         U(point.DistPointName).FullName.cAltEntry = 0;
2769         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2770         LocalFree(buf);
2771     }
2772     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
2773      urlIDP, urlIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2774     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2775     if (ret)
2776     {
2777         CERT_ALT_NAME_ENTRY entry;
2778
2779         entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2780         U(entry).pwszURL = (LPWSTR)url;
2781         U(point.DistPointName).FullName.cAltEntry = 1;
2782         U(point.DistPointName).FullName.rgAltEntry = &entry;
2783         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
2784         LocalFree(buf);
2785     }
2786 }
2787
2788 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2789  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2790  0x30, 0x5a };
2791 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2792  0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2793  0x30, 0x30, 0x30, 0x30, 0x5a };
2794 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2795  0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2796  0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2797  0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2798  0x5a };
2799 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2800  0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2801  0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2802  0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2803  0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2804  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2805 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2806  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2807  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2808  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2809  0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2810  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2811 static const BYTE v1CRLWithEntryExt[] = { 0x30,0x5a,0x30,0x02,0x06,0x00,0x30,
2812  0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
2813  0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
2814  0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x2c,0x30,0x2a,0x02,0x01,
2815  0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,
2816  0x30,0x30,0x5a,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,
2817  0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2818 static const BYTE v1CRLWithExt[] = { 0x30,0x5c,0x30,0x02,0x06,0x00,0x30,0x15,
2819  0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
2820  0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
2821  0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,
2822  0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,
2823  0x30,0x5a,0xa0,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
2824  0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2825 static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06,
2826  0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,
2827  0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,
2828  0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,
2829  0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,
2830  0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,
2831  0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2832 static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01,
2833  0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
2834  0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,
2835  0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,
2836  0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
2837  0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,
2838  0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2839
2840 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2841 {
2842     BOOL ret;
2843     BYTE *buf = NULL;
2844     static CHAR oid_issuing_dist_point[] = szOID_ISSUING_DIST_POINT;
2845     DWORD size = 0;
2846     CRL_INFO info = { 0 };
2847     CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2848     CERT_EXTENSION ext;
2849
2850     /* Test with a V1 CRL */
2851     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2852      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2853     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2854     if (buf)
2855     {
2856         ok(size == sizeof(v1CRL), "Wrong size %ld\n", size);
2857         ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2858         LocalFree(buf);
2859     }
2860     /* Test v2 CRL */
2861     info.dwVersion = CRL_V2;
2862     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2863      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2864     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2865     if (buf)
2866     {
2867         ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2868          v2CRL[1] + 2, size);
2869         ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2870         LocalFree(buf);
2871     }
2872     /* v1 CRL with a name */
2873     info.dwVersion = CRL_V1;
2874     info.Issuer.cbData = sizeof(encodedCommonName);
2875     info.Issuer.pbData = (BYTE *)encodedCommonName;
2876     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2877      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2878     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2879     if (buf)
2880     {
2881         ok(size == sizeof(v1CRLWithIssuer), "Wrong size %ld\n", size);
2882         ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2883         LocalFree(buf);
2884     }
2885     /* v1 CRL with a name and a NULL entry pointer */
2886     info.cCRLEntry = 1;
2887     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2888      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2889     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2890      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2891     /* now set an empty entry */
2892     info.rgCRLEntry = &entry;
2893     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2894      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2895     if (buf)
2896     {
2897         ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2898          "Wrong size %ld\n", size);
2899         ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2900          "Got unexpected value\n");
2901         LocalFree(buf);
2902     }
2903     /* an entry with a serial number */
2904     entry.SerialNumber.cbData = sizeof(serialNum);
2905     entry.SerialNumber.pbData = (BYTE *)serialNum;
2906     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2907      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2908     if (buf)
2909     {
2910         ok(size == sizeof(v1CRLWithIssuerAndEntry),
2911          "Wrong size %ld\n", size);
2912         ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2913          "Got unexpected value\n");
2914         LocalFree(buf);
2915     }
2916     /* an entry with an extension */
2917     entry.cExtension = 1;
2918     entry.rgExtension = &criticalExt;
2919     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2920      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2921     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2922     if (buf)
2923     {
2924         ok(size == sizeof(v1CRLWithEntryExt), "Wrong size %ld\n", size);
2925         ok(!memcmp(buf, v1CRLWithEntryExt, size), "Got unexpected value\n");
2926         LocalFree(buf);
2927     }
2928     /* a CRL with an extension */
2929     entry.cExtension = 0;
2930     info.cExtension = 1;
2931     info.rgExtension = &criticalExt;
2932     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2933      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2934     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2935     if (buf)
2936     {
2937         ok(size == sizeof(v1CRLWithExt), "Wrong size %ld\n", size);
2938         ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2939         LocalFree(buf);
2940     }
2941     /* a v2 CRL with an extension, this time non-critical */
2942     info.dwVersion = CRL_V2;
2943     info.rgExtension = &nonCriticalExt;
2944     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2945      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2946     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2947     if (buf)
2948     {
2949         ok(size == sizeof(v2CRLWithExt), "Wrong size %ld\n", size);
2950         ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n");
2951         LocalFree(buf);
2952     }
2953     /* a v2 CRL with an issuing dist point extension */
2954     ext.pszObjId = oid_issuing_dist_point;
2955     ext.fCritical = TRUE;
2956     ext.Value.cbData = sizeof(urlIDP);
2957     ext.Value.pbData = (LPBYTE)urlIDP;
2958     entry.rgExtension = &ext;
2959     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2960      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2961     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2962     if (buf)
2963     {
2964         ok(size == sizeof(v2CRLWithIssuingDistPoint), "Wrong size %ld\n", size);
2965         ok(!memcmp(buf, v2CRLWithIssuingDistPoint, size), "Unexpected value\n");
2966         LocalFree(buf);
2967     }
2968 }
2969
2970 static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01,
2971  0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
2972  0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06,
2973  0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
2974  0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56,
2975  0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
2976  0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65,
2977  0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
2978  0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
2979  0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43,
2980  0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30,
2981  0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33,
2982  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51,
2983  0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99,
2984  0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31,
2985  0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0,
2986  0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30,
2987  0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30,
2988  0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75,
2989  0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33,
2990  0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30,
2991  0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
2992  0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06,
2993  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03,
2994  0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88,
2995  0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd,
2996  0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf,
2997  0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46,
2998  0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f,
2999  0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75,
3000  0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f,
3001  0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82,
3002  0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07,
3003  0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c,
3004  0xcd };
3005
3006 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
3007 {
3008     static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
3009     BOOL ret;
3010     BYTE *buf = NULL;
3011     DWORD size = 0, i;
3012
3013     for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
3014     {
3015         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3016          corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3017          (BYTE *)&buf, &size);
3018         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
3019          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3020     }
3021     /* at a minimum, a CRL must contain an issuer: */
3022     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3023      v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3024      (BYTE *)&buf, &size);
3025     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3026     if (buf)
3027     {
3028         CRL_INFO *info = (CRL_INFO *)buf;
3029
3030         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3031         ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
3032          info->cCRLEntry);
3033         ok(info->Issuer.cbData == sizeof(encodedCommonName),
3034          "Wrong issuer size %ld\n", info->Issuer.cbData);
3035         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3036          "Unexpected issuer\n");
3037         LocalFree(buf);
3038     }
3039     /* check decoding with an empty CRL entry */
3040     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3041      v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
3042      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3043     todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
3044      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3045     /* with a real CRL entry */
3046     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3047      v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
3048      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3049     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3050     if (buf)
3051     {
3052         CRL_INFO *info = (CRL_INFO *)buf;
3053         CRL_ENTRY *entry;
3054
3055         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3056         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3057          info->cCRLEntry);
3058         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3059         entry = info->rgCRLEntry;
3060         ok(entry->SerialNumber.cbData == 1,
3061          "Expected serial number size 1, got %ld\n",
3062          entry->SerialNumber.cbData);
3063         ok(*entry->SerialNumber.pbData == *serialNum,
3064          "Expected serial number %d, got %d\n", *serialNum,
3065          *entry->SerialNumber.pbData);
3066         ok(info->Issuer.cbData == sizeof(encodedCommonName),
3067          "Wrong issuer size %ld\n", info->Issuer.cbData);
3068         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3069          "Unexpected issuer\n");
3070     }
3071     /* a real CRL from verisign that has extensions */
3072     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3073      verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG,
3074      NULL, (BYTE *)&buf, &size);
3075     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3076     if (buf)
3077     {
3078         CRL_INFO *info = (CRL_INFO *)buf;
3079         CRL_ENTRY *entry;
3080
3081         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3082         ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %ld\n",
3083          info->cCRLEntry);
3084         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3085         entry = info->rgCRLEntry;
3086         ok(info->cExtension == 2, "Expected 2 extensions, got %ld\n",
3087          info->cExtension);
3088     }
3089     /* and finally, with an extension */
3090     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3091      v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3092      NULL, (BYTE *)&buf, &size);
3093     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3094     if (buf)
3095     {
3096         CRL_INFO *info = (CRL_INFO *)buf;
3097         CRL_ENTRY *entry;
3098
3099         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3100         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3101          info->cCRLEntry);
3102         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3103         entry = info->rgCRLEntry;
3104         ok(entry->SerialNumber.cbData == 1,
3105          "Expected serial number size 1, got %ld\n",
3106          entry->SerialNumber.cbData);
3107         ok(*entry->SerialNumber.pbData == *serialNum,
3108          "Expected serial number %d, got %d\n", *serialNum,
3109          *entry->SerialNumber.pbData);
3110         ok(info->Issuer.cbData == sizeof(encodedCommonName),
3111          "Wrong issuer size %ld\n", info->Issuer.cbData);
3112         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3113          "Unexpected issuer\n");
3114         ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3115          info->cExtension);
3116     }
3117     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3118      v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3119      NULL, (BYTE *)&buf, &size);
3120     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3121     if (buf)
3122     {
3123         CRL_INFO *info = (CRL_INFO *)buf;
3124
3125         ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3126          info->cExtension);
3127         LocalFree(buf);
3128     }
3129     /* And again, with an issuing dist point */
3130     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3131      v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint),
3132      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3133     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3134     if (buf)
3135     {
3136         CRL_INFO *info = (CRL_INFO *)buf;
3137
3138         ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3139          info->cExtension);
3140         LocalFree(buf);
3141     }
3142 }
3143
3144 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
3145  szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
3146 static const BYTE encodedUsage[] = {
3147  0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
3148  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
3149  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
3150
3151 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
3152 {
3153     BOOL ret;
3154     BYTE *buf = NULL;
3155     DWORD size = 0;
3156     CERT_ENHKEY_USAGE usage;
3157
3158     /* Test with empty usage */
3159     usage.cUsageIdentifier = 0;
3160     ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3161      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3162     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3163     if (buf)
3164     {
3165         ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
3166         ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
3167         LocalFree(buf);
3168     }
3169     /* Test with a few usages */
3170     usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
3171     usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
3172     ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3173      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3174     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3175     if (buf)
3176     {
3177         ok(size == sizeof(encodedUsage), "Wrong size %ld\n", size);
3178         ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
3179         LocalFree(buf);
3180     }
3181 }
3182
3183 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
3184 {
3185     BOOL ret;
3186     LPBYTE buf = NULL;
3187     DWORD size = 0;
3188
3189     ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3190      emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
3191      (BYTE *)&buf, &size);
3192     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3193     if (buf)
3194     {
3195         CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3196
3197         ok(size >= sizeof(CERT_ENHKEY_USAGE),
3198          "Wrong size %ld\n", size);
3199         ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
3200          usage->cUsageIdentifier);
3201         LocalFree(buf);
3202     }
3203     ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3204      encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
3205      (BYTE *)&buf, &size);
3206     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3207     if (buf)
3208     {
3209         CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3210         DWORD i;
3211
3212         ok(size >= sizeof(CERT_ENHKEY_USAGE),
3213          "Wrong size %ld\n", size);
3214         ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
3215          "Wrong CRL entries count %ld\n", usage->cUsageIdentifier);
3216         for (i = 0; i < usage->cUsageIdentifier; i++)
3217             ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
3218              "Expected OID %s, got %s\n", keyUsages[i],
3219              usage->rgpszUsageIdentifier[i]);
3220         LocalFree(buf);
3221     }
3222 }
3223
3224 /* Free *pInfo with HeapFree */
3225 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
3226 {
3227     BOOL ret;
3228     DWORD size = 0;
3229     HCRYPTKEY key;
3230
3231     /* This crashes
3232     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
3233      */
3234     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
3235     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3236      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3237     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
3238      &size);
3239     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3240      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3241     ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
3242      NULL, &size);
3243     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3244      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3245     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3246      0, NULL, NULL, &size);
3247     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3248      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3249     /* Test with no key */
3250     ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3251      0, NULL, NULL, &size);
3252     ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
3253      GetLastError());
3254     ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
3255     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
3256     if (ret)
3257     {
3258         ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
3259          NULL, 0, NULL, NULL, &size);
3260         ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3261         *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
3262         if (*pInfo)
3263         {
3264             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
3265              X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
3266             ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
3267              GetLastError());
3268             if (ret)
3269             {
3270                 /* By default (we passed NULL as the OID) the OID is
3271                  * szOID_RSA_RSA.
3272                  */
3273                 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
3274                  "Expected %s, got %s\n", szOID_RSA_RSA,
3275                  (*pInfo)->Algorithm.pszObjId);
3276             }
3277         }
3278     }
3279 }
3280
3281 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
3282  0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
3283  0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
3284  0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3285  0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3286  0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3287  0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
3288  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
3289  0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3290  0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3291  0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3292  0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3293  0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
3294  0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
3295  0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
3296  0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
3297  0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
3298  0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
3299  0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
3300  0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
3301  0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
3302  0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
3303  0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
3304  0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
3305  0x49, 0xe5, 0xf9, 0x65, 0xf3 };
3306
3307 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
3308 {
3309     BOOL ret;
3310     HCRYPTKEY key;
3311     PCCERT_CONTEXT context;
3312
3313     /* These crash
3314     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
3315     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
3316     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
3317     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3318      NULL);
3319      */
3320     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3321     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3322      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3323     ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3324     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3325      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3326     ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3327      &key);
3328     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3329      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3330     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3331      &key);
3332     ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3333     CryptDestroyKey(key);
3334
3335     /* Test importing a public key from a certificate context */
3336     context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert,
3337      sizeof(expiredCert));
3338     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
3339      GetLastError());
3340     if (context)
3341     {
3342         ok(!strcmp(szOID_RSA_RSA,
3343          context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId),
3344          "Expected %s, got %s\n", szOID_RSA_RSA,
3345          context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
3346         ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING,
3347          &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key);
3348         ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3349         CryptDestroyKey(key);
3350         CertFreeCertificateContext(context);
3351     }
3352 }
3353
3354 static const char cspName[] = "WineCryptTemp";
3355
3356 static void testPortPublicKeyInfo(void)
3357 {
3358     HCRYPTPROV csp;
3359     BOOL ret;
3360     PCERT_PUBLIC_KEY_INFO info = NULL;
3361
3362     /* Just in case a previous run failed, delete this thing */
3363     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3364      CRYPT_DELETEKEYSET);
3365     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3366      CRYPT_NEWKEYSET);
3367
3368     testExportPublicKey(csp, &info);
3369     testImportPublicKey(csp, info);
3370
3371     HeapFree(GetProcessHeap(), 0, info);
3372     CryptReleaseContext(csp, 0);
3373     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3374      CRYPT_DELETEKEYSET);
3375 }
3376
3377 START_TEST(encode)
3378 {
3379     static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3380      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3381     DWORD i;
3382
3383     for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3384     {
3385         test_encodeInt(encodings[i]);
3386         test_decodeInt(encodings[i]);
3387         test_encodeEnumerated(encodings[i]);
3388         test_decodeEnumerated(encodings[i]);
3389         test_encodeFiletime(encodings[i]);
3390         test_decodeFiletime(encodings[i]);
3391         test_encodeName(encodings[i]);
3392         test_decodeName(encodings[i]);
3393         test_encodeNameValue(encodings[i]);
3394         test_decodeNameValue(encodings[i]);
3395         test_encodeAltName(encodings[i]);
3396         test_decodeAltName(encodings[i]);
3397         test_encodeOctets(encodings[i]);
3398         test_decodeOctets(encodings[i]);
3399         test_encodeBits(encodings[i]);
3400         test_decodeBits(encodings[i]);
3401         test_encodeBasicConstraints(encodings[i]);
3402         test_decodeBasicConstraints(encodings[i]);
3403         test_encodeRsaPublicKey(encodings[i]);
3404         test_decodeRsaPublicKey(encodings[i]);
3405         test_encodeSequenceOfAny(encodings[i]);
3406         test_decodeSequenceOfAny(encodings[i]);
3407         test_encodeExtensions(encodings[i]);
3408         test_decodeExtensions(encodings[i]);
3409         test_encodePublicKeyInfo(encodings[i]);
3410         test_decodePublicKeyInfo(encodings[i]);
3411         test_encodeCertToBeSigned(encodings[i]);
3412         test_decodeCertToBeSigned(encodings[i]);
3413         test_encodeCert(encodings[i]);
3414         test_decodeCert(encodings[i]);
3415         test_encodeCRLDistPoints(encodings[i]);
3416         test_decodeCRLDistPoints(encodings[i]);
3417         test_encodeCRLIssuingDistPoint(encodings[i]);
3418         test_decodeCRLIssuingDistPoint(encodings[i]);
3419         test_encodeCRLToBeSigned(encodings[i]);
3420         test_decodeCRLToBeSigned(encodings[i]);
3421         test_encodeEnhancedKeyUsage(encodings[i]);
3422         test_decodeEnhancedKeyUsage(encodings[i]);
3423     }
3424     testPortPublicKeyInfo();
3425 }