crypt32/tests: Avoid sizeof in traces.
[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 static const BYTE encodedTwoRDNs[] = {
609 0x30,0x2e,0x31,0x2c,0x30,0x2a,0x06,0x03,0x55,0x04,0x03,0x30,0x23,0x31,0x21,
610 0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,
611 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
612 0x6e,0x67,0x00,
613 };
614
615 static const BYTE us[] = { 0x55, 0x53 };
616 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
617  0x74, 0x61 };
618 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
619  0x6f, 0x6c, 0x69, 0x73 };
620 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
621  0x76, 0x65, 0x72, 0x73 };
622 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
623  0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
624 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
625  0x73, 0x74 };
626 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
627  0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
628
629 #define RDNA(arr)   oid_ ## arr, CERT_RDN_PRINTABLE_STRING, { sizeof(arr), (LPBYTE)arr }
630 #define RDNIA5(arr) oid_ ## arr, CERT_RDN_IA5_STRING,       { sizeof(arr), (LPBYTE)arr }
631
632 static CHAR oid_us[]            = "2.5.4.6",
633             oid_minnesota[]     = "2.5.4.8",
634             oid_minneapolis[]   = "2.5.4.7",
635             oid_codeweavers[]   = "2.5.4.10",
636             oid_wine[]          = "2.5.4.11",
637             oid_localhostAttr[] = "2.5.4.3",
638             oid_aric[]          = "1.2.840.113549.1.9.1";
639 static CERT_RDN_ATTR rdnAttrs[] = { { RDNA(us) },
640                                     { RDNA(minnesota) },
641                                     { RDNA(minneapolis) },
642                                     { RDNA(codeweavers) },
643                                     { RDNA(wine) },
644                                     { RDNA(localhostAttr) },
645                                     { RDNIA5(aric) } };
646 static CERT_RDN_ATTR decodedRdnAttrs[] = { { RDNA(us) },
647                                            { RDNA(localhostAttr) },
648                                            { RDNA(minnesota) },
649                                            { RDNA(minneapolis) },
650                                            { RDNA(codeweavers) },
651                                            { RDNA(wine) },
652                                            { RDNIA5(aric) } };
653
654 #undef RDNIA5
655 #undef RDNA
656
657 static const BYTE encodedRDNAttrs[] = {
658 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
659 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
660 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
661 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
662 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
663 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
664 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
665 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
666 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
667 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
668 };
669
670 static void test_encodeName(DWORD dwEncoding)
671 {
672     CERT_RDN_ATTR attrs[2];
673     CERT_RDN rdn;
674     CERT_NAME_INFO info;
675     static CHAR oid_common_name[] = szOID_COMMON_NAME,
676                 oid_sur_name[]    = szOID_SUR_NAME;
677     BYTE *buf = NULL;
678     DWORD size = 0;
679     BOOL ret;
680
681     /* Test with NULL pvStructInfo */
682     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
683      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
684     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
685      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
686     /* Test with empty CERT_NAME_INFO */
687     info.cRDN = 0;
688     info.rgRDN = NULL;
689     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
690      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
691     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
692     if (buf)
693     {
694         ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
695          "Got unexpected encoding for empty name\n");
696         LocalFree(buf);
697     }
698     /* Test with bogus CERT_RDN */
699     info.cRDN = 1;
700     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
701      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
702     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
703      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
704     /* Test with empty CERT_RDN */
705     rdn.cRDNAttr = 0;
706     rdn.rgRDNAttr = NULL;
707     info.cRDN = 1;
708     info.rgRDN = &rdn;
709     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
710      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
711     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
712     if (buf)
713     {
714         ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
715          "Got unexpected encoding for empty RDN array\n");
716         LocalFree(buf);
717     }
718     /* Test with bogus attr array */
719     rdn.cRDNAttr = 1;
720     rdn.rgRDNAttr = NULL;
721     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
722      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
723     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
724      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
725     /* oddly, a bogus OID is accepted by Windows XP; not testing.
726     attrs[0].pszObjId = "bogus";
727     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
728     attrs[0].Value.cbData = sizeof(commonName);
729     attrs[0].Value.pbData = (BYTE *)commonName;
730     rdn.cRDNAttr = 1;
731     rdn.rgRDNAttr = attrs;
732     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
733      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
734     ok(!ret, "Expected failure, got success\n");
735      */
736     /* Check with two CERT_RDN_ATTRs.  Note DER encoding forces the order of
737      * the encoded attributes to be swapped.
738      */
739     attrs[0].pszObjId = oid_common_name;
740     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
741     attrs[0].Value.cbData = sizeof(commonName);
742     attrs[0].Value.pbData = (BYTE *)commonName;
743     attrs[1].pszObjId = oid_sur_name;
744     attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
745     attrs[1].Value.cbData = sizeof(surName);
746     attrs[1].Value.pbData = (BYTE *)surName;
747     rdn.cRDNAttr = 2;
748     rdn.rgRDNAttr = attrs;
749     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
750      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
751     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
752     if (buf)
753     {
754         ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
755          "Got unexpected encoding for two RDN array\n");
756         LocalFree(buf);
757     }
758     /* A name can be "encoded" with previously encoded RDN attrs. */
759     attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB;
760     attrs[0].Value.pbData = (LPBYTE)twoRDNs;
761     attrs[0].Value.cbData = sizeof(twoRDNs);
762     rdn.cRDNAttr = 1;
763     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
764      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
765     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
766     if (buf)
767     {
768         ok(size == sizeof(encodedTwoRDNs), "Unexpected size %ld\n", size);
769         ok(!memcmp(buf, encodedTwoRDNs, size),
770          "Unexpected value for re-endoded two RDN array\n");
771         LocalFree(buf);
772     }
773     /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
774     rdn.cRDNAttr = 1;
775     attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
776     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
777      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
778     ok(!ret && GetLastError() == E_INVALIDARG,
779      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
780     /* Test a more complex name */
781     rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]);
782     rdn.rgRDNAttr = (PCERT_RDN_ATTR)rdnAttrs;
783     info.cRDN = 1;
784     info.rgRDN = &rdn;
785     buf = NULL;
786     size = 0;
787     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info,
788      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
789     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
790     if (ret)
791     {
792         ok(size == sizeof(encodedRDNAttrs), "Wrong size %ld\n", size);
793         ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n");
794         LocalFree(buf);
795     }
796 }
797
798 static WCHAR commonNameW[] = { 'J','u','a','n',' ','L','a','n','g',0 };
799 static WCHAR surNameW[] = { 'L','a','n','g',0 };
800
801 static const BYTE twoRDNsNoNull[] = {
802  0x30,0x21,0x31,0x1f,0x30,0x0b,0x06,0x03,0x55,0x04,0x04,0x13,0x04,0x4c,0x61,
803  0x6e,0x67,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,
804  0x20,0x4c,0x61,0x6e,0x67 };
805 static const BYTE anyType[] = {
806  0x30,0x2f,0x31,0x2d,0x30,0x2b,0x06,0x03,0x55,0x04,0x03,0x1e,0x24,0x23,0x30,
807  0x21,0x31,0x0c,0x30,0x03,0x06,0x04,0x55,0x13,0x04,0x4c,0x05,0x6e,0x61,0x00,
808  0x67,0x11,0x30,0x03,0x06,0x04,0x55,0x13,0x03,0x4a,0x0a,0x61,0x75,0x20,0x6e,
809  0x61,0x4c,0x67,0x6e };
810
811 static void test_encodeUnicodeName(DWORD dwEncoding)
812 {
813     CERT_RDN_ATTR attrs[2];
814     CERT_RDN rdn;
815     CERT_NAME_INFO info;
816     static CHAR oid_common_name[] = szOID_COMMON_NAME,
817                 oid_sur_name[]    = szOID_SUR_NAME;
818     BYTE *buf = NULL;
819     DWORD size = 0;
820     BOOL ret;
821
822     /* Test with NULL pvStructInfo */
823     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, NULL,
824      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
825     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
826      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
827     /* Test with empty CERT_NAME_INFO */
828     info.cRDN = 0;
829     info.rgRDN = NULL;
830     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
831      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
832     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
833     if (buf)
834     {
835         ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
836          "Got unexpected encoding for empty name\n");
837         LocalFree(buf);
838     }
839     /* Check with one CERT_RDN_ATTR, that has an invalid character for the
840      * encoding (the NULL).
841      */
842     attrs[0].pszObjId = oid_common_name;
843     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
844     attrs[0].Value.cbData = sizeof(commonNameW);
845     attrs[0].Value.pbData = (BYTE *)commonNameW;
846     rdn.cRDNAttr = 1;
847     rdn.rgRDNAttr = attrs;
848     info.cRDN = 1;
849     info.rgRDN = &rdn;
850     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
851      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
852     ok(!ret && GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING,
853      "Expected CRYPT_E_INVALID_PRINTABLE_STRING, got %08lx\n", GetLastError());
854     ok(size == 9, "Unexpected error index %08lx\n", size);
855     /* Check with two NULL-terminated CERT_RDN_ATTRs.  Note DER encoding
856      * forces the order of the encoded attributes to be swapped.
857      */
858     attrs[0].pszObjId = oid_common_name;
859     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
860     attrs[0].Value.cbData = 0;
861     attrs[0].Value.pbData = (BYTE *)commonNameW;
862     attrs[1].pszObjId = oid_sur_name;
863     attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
864     attrs[1].Value.cbData = 0;
865     attrs[1].Value.pbData = (BYTE *)surNameW;
866     rdn.cRDNAttr = 2;
867     rdn.rgRDNAttr = attrs;
868     info.cRDN = 1;
869     info.rgRDN = &rdn;
870     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
871      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
872     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
873     if (buf)
874     {
875         ok(!memcmp(buf, twoRDNsNoNull, sizeof(twoRDNsNoNull)),
876          "Got unexpected encoding for two RDN array\n");
877         LocalFree(buf);
878     }
879     /* A name can be "encoded" with previously encoded RDN attrs. */
880     attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB;
881     attrs[0].Value.pbData = (LPBYTE)twoRDNs;
882     attrs[0].Value.cbData = sizeof(twoRDNs);
883     rdn.cRDNAttr = 1;
884     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
885      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
886     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
887     if (buf)
888     {
889         ok(size == sizeof(encodedTwoRDNs), "Unexpected size %ld\n", size);
890         ok(!memcmp(buf, encodedTwoRDNs, size),
891          "Unexpected value for re-endoded two RDN array\n");
892         LocalFree(buf);
893     }
894     /* Unicode names infer the type for CERT_RDN_ANY_TYPE */
895     rdn.cRDNAttr = 1;
896     attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
897     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info,
898      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
899     todo_wine ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
900     if (buf)
901     {
902         ok(size == sizeof(anyType), "Unexpected size %ld\n", size);
903         ok(!memcmp(buf, anyType, size), "Unexpected value\n");
904         LocalFree(buf);
905     }
906 }
907
908 static void compareNameValues(const CERT_NAME_VALUE *expected,
909  const CERT_NAME_VALUE *got)
910 {
911     ok(got->dwValueType == expected->dwValueType,
912      "Expected string type %ld, got %ld\n", expected->dwValueType,
913      got->dwValueType);
914     ok(got->Value.cbData == expected->Value.cbData,
915      "String type %ld: unexpected data size, got %ld, expected %ld\n",
916      expected->dwValueType, got->Value.cbData, expected->Value.cbData);
917     if (got->Value.cbData && got->Value.pbData)
918         ok(!memcmp(got->Value.pbData, expected->Value.pbData,
919          min(got->Value.cbData, expected->Value.cbData)),
920          "String type %ld: unexpected value\n", expected->dwValueType);
921 }
922
923 static void compareRDNAttrs(const CERT_RDN_ATTR *expected,
924  const CERT_RDN_ATTR *got)
925 {
926     if (expected->pszObjId && strlen(expected->pszObjId))
927     {
928         ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n",
929          expected->pszObjId);
930         if (got->pszObjId)
931         {
932             ok(!strcmp(got->pszObjId, expected->pszObjId),
933              "Got unexpected OID %s, expected %s\n", got->pszObjId,
934              expected->pszObjId);
935         }
936     }
937     compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType,
938      (const CERT_NAME_VALUE *)&got->dwValueType);
939 }
940
941 static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got)
942 {
943     ok(got->cRDNAttr == expected->cRDNAttr,
944      "Expected %ld RDN attrs, got %ld\n", expected->cRDNAttr, got->cRDNAttr);
945     if (got->cRDNAttr)
946     {
947         DWORD i;
948
949         for (i = 0; i < got->cRDNAttr; i++)
950             compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]);
951     }
952 }
953
954 static void compareNames(const CERT_NAME_INFO *expected,
955  const CERT_NAME_INFO *got)
956 {
957     ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
958      expected->cRDN, got->cRDN);
959     if (got->cRDN)
960     {
961         DWORD i;
962
963         for (i = 0; i < got->cRDN; i++)
964             compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]);
965     }
966 }
967
968 static void test_decodeName(DWORD dwEncoding)
969 {
970     BYTE *buf = NULL;
971     DWORD bufSize = 0;
972     BOOL ret;
973     CERT_RDN rdn;
974     CERT_NAME_INFO info = { 1, &rdn };
975
976     /* test empty name */
977     bufSize = 0;
978     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
979      emptySequence[1] + 2,
980      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
981      (BYTE *)&buf, &bufSize);
982     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
983     /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL.  My
984      * decoder works the same way, so only test the count.
985      */
986     if (buf)
987     {
988         ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %ld\n", bufSize);
989         ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
990          "Expected 0 RDNs in empty info, got %ld\n",
991          ((CERT_NAME_INFO *)buf)->cRDN);
992         LocalFree(buf);
993     }
994     /* test empty RDN */
995     bufSize = 0;
996     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
997      emptyRDNs[1] + 2,
998      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
999      (BYTE *)&buf, &bufSize);
1000     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1001     if (buf)
1002     {
1003         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
1004
1005         ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
1006          info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
1007          "Got unexpected value for empty RDN\n");
1008         LocalFree(buf);
1009     }
1010     /* test two RDN attrs */
1011     bufSize = 0;
1012     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
1013      twoRDNs[1] + 2,
1014      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1015      (BYTE *)&buf, &bufSize);
1016     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1017     if (buf)
1018     {
1019         static CHAR oid_sur_name[]    = szOID_SUR_NAME,
1020                     oid_common_name[] = szOID_COMMON_NAME;
1021
1022         CERT_RDN_ATTR attrs[] = {
1023          { oid_sur_name, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
1024           (BYTE *)surName } },
1025          { oid_common_name, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
1026           (BYTE *)commonName } },
1027         };
1028
1029         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
1030         rdn.rgRDNAttr = attrs;
1031         compareNames(&info, (CERT_NAME_INFO *)buf);
1032         LocalFree(buf);
1033     }
1034     /* And, a slightly more complicated name */
1035     buf = NULL;
1036     bufSize = 0;
1037     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs,
1038      sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1039     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1040     if (ret)
1041     {
1042         rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]);
1043         rdn.rgRDNAttr = (PCERT_RDN_ATTR)decodedRdnAttrs;
1044         compareNames(&info, (CERT_NAME_INFO *)buf);
1045         LocalFree(buf);
1046     }
1047 }
1048
1049 static void test_decodeUnicodeName(DWORD dwEncoding)
1050 {
1051     BYTE *buf = NULL;
1052     DWORD bufSize = 0;
1053     BOOL ret;
1054     CERT_RDN rdn;
1055     CERT_NAME_INFO info = { 1, &rdn };
1056
1057     /* test empty name */
1058     bufSize = 0;
1059     ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptySequence,
1060      emptySequence[1] + 2,
1061      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1062      (BYTE *)&buf, &bufSize);
1063     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1064     if (buf)
1065     {
1066         ok(bufSize == sizeof(CERT_NAME_INFO),
1067          "Got wrong bufSize %ld\n", bufSize);
1068         ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
1069          "Expected 0 RDNs in empty info, got %ld\n",
1070          ((CERT_NAME_INFO *)buf)->cRDN);
1071         LocalFree(buf);
1072     }
1073     /* test empty RDN */
1074     bufSize = 0;
1075     ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptyRDNs,
1076      emptyRDNs[1] + 2,
1077      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1078      (BYTE *)&buf, &bufSize);
1079     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1080     if (buf)
1081     {
1082         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
1083
1084         ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
1085          info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
1086          "Got unexpected value for empty RDN\n");
1087         LocalFree(buf);
1088     }
1089     /* test two RDN attrs */
1090     bufSize = 0;
1091     ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, twoRDNsNoNull,
1092      sizeof(twoRDNsNoNull),
1093      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1094      (BYTE *)&buf, &bufSize);
1095     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1096     if (buf)
1097     {
1098         static CHAR oid_sur_name[]    = szOID_SUR_NAME,
1099                     oid_common_name[] = szOID_COMMON_NAME;
1100
1101         CERT_RDN_ATTR attrs[] = {
1102          { oid_sur_name, CERT_RDN_PRINTABLE_STRING,
1103          { lstrlenW(surNameW) * sizeof(WCHAR), (BYTE *)surNameW } },
1104          { oid_common_name, CERT_RDN_PRINTABLE_STRING,
1105          { lstrlenW(commonNameW) * sizeof(WCHAR), (BYTE *)commonNameW } },
1106         };
1107
1108         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
1109         rdn.rgRDNAttr = attrs;
1110         compareNames(&info, (CERT_NAME_INFO *)buf);
1111         LocalFree(buf);
1112     }
1113 }
1114
1115 struct EncodedNameValue
1116 {
1117     CERT_NAME_VALUE value;
1118     const BYTE *encoded;
1119     DWORD encodedSize;
1120 };
1121
1122 static const char bogusIA5[] = "\x80";
1123 static const char bogusPrintable[] = "~";
1124 static const char bogusNumeric[] = "A";
1125 static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 };
1126 static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 };
1127 static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 };
1128 static BYTE octetCommonNameValue[] = {
1129  0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1130 static BYTE numericCommonNameValue[] = {
1131  0x12,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1132 static BYTE printableCommonNameValue[] = {
1133  0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1134 static BYTE t61CommonNameValue[] = {
1135  0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1136 static BYTE videotexCommonNameValue[] = {
1137  0x15,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1138 static BYTE ia5CommonNameValue[] = {
1139  0x16,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1140 static BYTE graphicCommonNameValue[] = {
1141  0x19,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1142 static BYTE visibleCommonNameValue[] = {
1143  0x1a,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1144 static BYTE generalCommonNameValue[] = {
1145  0x1b,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1146 static BYTE bmpCommonNameValue[] = {
1147  0x1e,0x14,0x00,0x4a,0x00,0x75,0x00,0x61,0x00,0x6e,0x00,0x20,0x00,0x4c,0x00,
1148  0x61,0x00,0x6e,0x00,0x67,0x00,0x00 };
1149 static BYTE utf8CommonNameValue[] = {
1150  0x0c,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 };
1151
1152 static struct EncodedNameValue nameValues[] = {
1153  { { CERT_RDN_OCTET_STRING, { sizeof(commonName), (BYTE *)commonName } },
1154      octetCommonNameValue, sizeof(octetCommonNameValue) },
1155  { { CERT_RDN_NUMERIC_STRING, { sizeof(commonName), (BYTE *)commonName } },
1156      numericCommonNameValue, sizeof(numericCommonNameValue) },
1157  { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
1158      printableCommonNameValue, sizeof(printableCommonNameValue) },
1159  { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } },
1160      t61CommonNameValue, sizeof(t61CommonNameValue) },
1161  { { CERT_RDN_VIDEOTEX_STRING, { sizeof(commonName), (BYTE *)commonName } },
1162      videotexCommonNameValue, sizeof(videotexCommonNameValue) },
1163  { { CERT_RDN_IA5_STRING, { sizeof(commonName), (BYTE *)commonName } },
1164      ia5CommonNameValue, sizeof(ia5CommonNameValue) },
1165  { { CERT_RDN_GRAPHIC_STRING, { sizeof(commonName), (BYTE *)commonName } },
1166      graphicCommonNameValue, sizeof(graphicCommonNameValue) },
1167  { { CERT_RDN_VISIBLE_STRING, { sizeof(commonName), (BYTE *)commonName } },
1168      visibleCommonNameValue, sizeof(visibleCommonNameValue) },
1169  { { CERT_RDN_GENERAL_STRING, { sizeof(commonName), (BYTE *)commonName } },
1170      generalCommonNameValue, sizeof(generalCommonNameValue) },
1171  { { CERT_RDN_BMP_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } },
1172      bmpCommonNameValue, sizeof(bmpCommonNameValue) },
1173  { { CERT_RDN_UTF8_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } },
1174      utf8CommonNameValue, sizeof(utf8CommonNameValue) },
1175  /* The following tests succeed under Windows, but really should fail,
1176   * they contain characters that are illegal for the encoding.  I'm
1177   * including them to justify my lazy encoding.
1178   */
1179  { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42,
1180      sizeof(bin42) },
1181  { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable),
1182      (BYTE *)bogusPrintable } }, bin43, sizeof(bin43) },
1183  { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } },
1184      bin44, sizeof(bin44) },
1185 };
1186
1187 static void test_encodeNameValue(DWORD dwEncoding)
1188 {
1189     BYTE *buf = NULL;
1190     DWORD size = 0, i;
1191     BOOL ret;
1192     CERT_NAME_VALUE value = { 0, { 0, NULL } };
1193
1194     value.dwValueType = 14;
1195     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value,
1196      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1197     ok(!ret && GetLastError() == CRYPT_E_ASN1_CHOICE,
1198      "Expected CRYPT_E_ASN1_CHOICE, got %08lx\n", GetLastError());
1199     value.dwValueType = CERT_RDN_ENCODED_BLOB;
1200     value.Value.pbData = printableCommonNameValue;
1201     value.Value.cbData = sizeof(printableCommonNameValue);
1202     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value,
1203      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1204     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1205     if (buf)
1206     {
1207         ok(size == sizeof(printableCommonNameValue), "Unexpected size %ld\n",
1208          size);
1209         ok(!memcmp(buf, printableCommonNameValue, size),
1210          "Unexpected encoding\n");
1211         LocalFree(buf);
1212     }
1213     for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
1214     {
1215         ret = CryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE,
1216          &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1217          &size);
1218         ok(ret, "Type %ld: CryptEncodeObjectEx failed: %08lx\n",
1219          nameValues[i].value.dwValueType, GetLastError());
1220         if (buf)
1221         {
1222             ok(size == nameValues[i].encodedSize,
1223              "Expected size %ld, got %ld\n", nameValues[i].encodedSize, size);
1224             ok(!memcmp(buf, nameValues[i].encoded, size),
1225              "Got unexpected encoding\n");
1226             LocalFree(buf);
1227         }
1228     }
1229 }
1230
1231 static void test_decodeNameValue(DWORD dwEncoding)
1232 {
1233     int i;
1234     BYTE *buf = NULL;
1235     DWORD bufSize = 0;
1236     BOOL ret;
1237
1238     for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++)
1239     {
1240         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE,
1241          nameValues[i].encoded, nameValues[i].encoded[1] + 2,
1242          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
1243          (BYTE *)&buf, &bufSize);
1244         ok(ret, "Value type %ld: CryptDecodeObjectEx failed: %08lx\n",
1245          nameValues[i].value.dwValueType, GetLastError());
1246         if (buf)
1247         {
1248             compareNameValues(&nameValues[i].value,
1249              (const CERT_NAME_VALUE *)buf);
1250             LocalFree(buf);
1251         }
1252     }
1253 }
1254
1255 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
1256 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
1257  'h','q','.','o','r','g',0 };
1258 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
1259  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
1260  0x6f, 0x72, 0x67 };
1261 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
1262  0x575b, 0 };
1263 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
1264 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
1265  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
1266 static const BYTE localhost[] = { 127, 0, 0, 1 };
1267 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
1268  0x01 };
1269
1270 static void test_encodeAltName(DWORD dwEncoding)
1271 {
1272     CERT_ALT_NAME_INFO info = { 0 };
1273     CERT_ALT_NAME_ENTRY entry = { 0 };
1274     BYTE *buf = NULL;
1275     DWORD size = 0;
1276     BOOL ret;
1277
1278     /* Test with empty info */
1279     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1280      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1281     if (buf)
1282     {
1283         ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
1284         ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
1285         LocalFree(buf);
1286     }
1287     /* Test with an empty entry */
1288     info.cAltEntry = 1;
1289     info.rgAltEntry = &entry;
1290     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1291      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1292     ok(!ret && GetLastError() == E_INVALIDARG,
1293      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
1294     /* Test with an empty pointer */
1295     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
1296     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1297      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1298     if (buf)
1299     {
1300         ok(size == sizeof(emptyURL), "Wrong size %ld\n", size);
1301         ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
1302         LocalFree(buf);
1303     }
1304     /* Test with a real URL */
1305     U(entry).pwszURL = (LPWSTR)url;
1306     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1307      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1308     if (buf)
1309     {
1310         ok(size == sizeof(encodedURL), "Wrong size %ld\n", size);
1311         ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
1312         LocalFree(buf);
1313     }
1314     /* Now with the URL containing an invalid IA5 char */
1315     U(entry).pwszURL = (LPWSTR)nihongoURL;
1316     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1317      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1318     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
1319      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
1320     /* The first invalid character is at index 7 */
1321     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
1322      "Expected invalid char at index 7, got %ld\n",
1323      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
1324     /* Now with the URL missing a scheme */
1325     U(entry).pwszURL = (LPWSTR)dnsName;
1326     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1327      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1328     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1329     if (buf)
1330     {
1331         /* This succeeds, but it shouldn't, so don't worry about conforming */
1332         LocalFree(buf);
1333     }
1334     /* Now with a DNS name */
1335     entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
1336     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1337      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1338     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1339     if (buf)
1340     {
1341         ok(size == sizeof(encodedDnsName), "Wrong size %ld\n", size);
1342         ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
1343         LocalFree(buf);
1344     }
1345     /* Test with an IP address */
1346     entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1347     U(entry).IPAddress.cbData = sizeof(localhost);
1348     U(entry).IPAddress.pbData = (LPBYTE)localhost;
1349     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1350      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1351     if (buf)
1352     {
1353         ok(size == sizeof(encodedIPAddr), "Wrong size %ld\n", size);
1354         ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1355         LocalFree(buf);
1356     }
1357 }
1358
1359 static void test_decodeAltName(DWORD dwEncoding)
1360 {
1361     static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1362      0x00, 0x00, 0x01 };
1363     static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1364      0x01 };
1365     BOOL ret;
1366     BYTE *buf = NULL;
1367     DWORD bufSize = 0;
1368     CERT_ALT_NAME_INFO *info;
1369
1370     /* Test some bogus ones first */
1371     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1372      unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1373      NULL, (BYTE *)&buf, &bufSize);
1374     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1375      "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1376     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1377      bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1378      &bufSize);
1379     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1380      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1381     /* Now expected cases */
1382     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
1383      emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1384      &bufSize);
1385     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1386     if (buf)
1387     {
1388         info = (CERT_ALT_NAME_INFO *)buf;
1389
1390         ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1391          info->cAltEntry);
1392         LocalFree(buf);
1393     }
1394     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1395      emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1396      &bufSize);
1397     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1398     if (buf)
1399     {
1400         info = (CERT_ALT_NAME_INFO *)buf;
1401
1402         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1403          info->cAltEntry);
1404         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1405          "Expected CERT_ALT_NAME_URL, got %ld\n",
1406          info->rgAltEntry[0].dwAltNameChoice);
1407         ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1408          "Expected empty URL\n");
1409         LocalFree(buf);
1410     }
1411     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1412      encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1413      &bufSize);
1414     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1415     if (buf)
1416     {
1417         info = (CERT_ALT_NAME_INFO *)buf;
1418
1419         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1420          info->cAltEntry);
1421         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1422          "Expected CERT_ALT_NAME_URL, got %ld\n",
1423          info->rgAltEntry[0].dwAltNameChoice);
1424         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1425         LocalFree(buf);
1426     }
1427     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1428      encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1429      &bufSize);
1430     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1431     if (buf)
1432     {
1433         info = (CERT_ALT_NAME_INFO *)buf;
1434
1435         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1436          info->cAltEntry);
1437         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1438          "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1439          info->rgAltEntry[0].dwAltNameChoice);
1440         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1441          "Unexpected DNS name\n");
1442         LocalFree(buf);
1443     }
1444     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1445      encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1446      &bufSize);
1447     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1448     if (buf)
1449     {
1450         info = (CERT_ALT_NAME_INFO *)buf;
1451
1452         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1453          info->cAltEntry);
1454         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1455          "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1456          info->rgAltEntry[0].dwAltNameChoice);
1457         ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1458          "Unexpected IP address length %ld\n",
1459           U(info->rgAltEntry[0]).IPAddress.cbData);
1460         ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1461          sizeof(localhost)), "Unexpected IP address value\n");
1462         LocalFree(buf);
1463     }
1464 }
1465
1466 struct UnicodeExpectedError
1467 {
1468     DWORD   valueType;
1469     LPCWSTR str;
1470     DWORD   errorIndex;
1471     DWORD   error;
1472 };
1473
1474 static const WCHAR oneW[] = { '1',0 };
1475 static const WCHAR aW[] = { 'a',0 };
1476 static const WCHAR quoteW[] = { '"', 0 };
1477
1478 static struct UnicodeExpectedError unicodeErrors[] = {
1479  { CERT_RDN_ANY_TYPE,         oneW,       0, CRYPT_E_NOT_CHAR_STRING },
1480  { CERT_RDN_ENCODED_BLOB,     oneW,       0, CRYPT_E_NOT_CHAR_STRING },
1481  { CERT_RDN_OCTET_STRING,     oneW,       0, CRYPT_E_NOT_CHAR_STRING },
1482  { 14,                        oneW,       0, CRYPT_E_ASN1_CHOICE },
1483  { CERT_RDN_NUMERIC_STRING,   aW,         0, CRYPT_E_INVALID_NUMERIC_STRING },
1484  { CERT_RDN_PRINTABLE_STRING, quoteW,     0, CRYPT_E_INVALID_PRINTABLE_STRING },
1485  { CERT_RDN_IA5_STRING,       nihongoURL, 7, CRYPT_E_INVALID_IA5_STRING },
1486 };
1487
1488 struct UnicodeExpectedResult
1489 {
1490     DWORD           valueType;
1491     LPCWSTR         str;
1492     CRYPT_DATA_BLOB encoded;
1493 };
1494
1495 static BYTE oneNumeric[] = { 0x12, 0x01, 0x31 };
1496 static BYTE onePrintable[] = { 0x13, 0x01, 0x31 };
1497 static BYTE oneTeletex[] = { 0x14, 0x01, 0x31 };
1498 static BYTE oneVideotex[] = { 0x15, 0x01, 0x31 };
1499 static BYTE oneIA5[] = { 0x16, 0x01, 0x31 };
1500 static BYTE oneGraphic[] = { 0x19, 0x01, 0x31 };
1501 static BYTE oneVisible[] = { 0x1a, 0x01, 0x31 };
1502 static BYTE oneUniversal[] = { 0x1c, 0x04, 0x00, 0x00, 0x00, 0x31 };
1503 static BYTE oneGeneral[] = { 0x1b, 0x01, 0x31 };
1504 static BYTE oneBMP[] = { 0x1e, 0x02, 0x00, 0x31 };
1505 static BYTE oneUTF8[] = { 0x0c, 0x01, 0x31 };
1506 static BYTE nihongoT61[] = { 0x14,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,
1507  0x5b };
1508 static BYTE nihongoGeneral[] = { 0x1b,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
1509  0x6f,0x5b };
1510 static BYTE nihongoBMP[] = { 0x1e,0x12,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,
1511  0x00,0x3a,0x00,0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b };
1512 static BYTE nihongoUTF8[] = { 0x0c,0x0d,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
1513  0xe2,0x89,0xaf,0xe5,0x9d,0x9b };
1514
1515 static struct UnicodeExpectedResult unicodeResults[] = {
1516  { CERT_RDN_NUMERIC_STRING,   oneW, { sizeof(oneNumeric), oneNumeric } },
1517  { CERT_RDN_PRINTABLE_STRING, oneW, { sizeof(onePrintable), onePrintable } },
1518  { CERT_RDN_TELETEX_STRING,   oneW, { sizeof(oneTeletex), oneTeletex } },
1519  { CERT_RDN_VIDEOTEX_STRING,  oneW, { sizeof(oneVideotex), oneVideotex } },
1520  { CERT_RDN_IA5_STRING,       oneW, { sizeof(oneIA5), oneIA5 } },
1521  { CERT_RDN_GRAPHIC_STRING,   oneW, { sizeof(oneGraphic), oneGraphic } },
1522  { CERT_RDN_VISIBLE_STRING,   oneW, { sizeof(oneVisible), oneVisible } },
1523  { CERT_RDN_UNIVERSAL_STRING, oneW, { sizeof(oneUniversal), oneUniversal } },
1524  { CERT_RDN_GENERAL_STRING,   oneW, { sizeof(oneGeneral), oneGeneral } },
1525  { CERT_RDN_BMP_STRING,       oneW, { sizeof(oneBMP), oneBMP } },
1526  { CERT_RDN_UTF8_STRING,      oneW, { sizeof(oneUTF8), oneUTF8 } },
1527  { CERT_RDN_BMP_STRING,     nihongoURL, { sizeof(nihongoBMP), nihongoBMP } },
1528  { CERT_RDN_UTF8_STRING,    nihongoURL, { sizeof(nihongoUTF8), nihongoUTF8 } },
1529 };
1530
1531 static struct UnicodeExpectedResult unicodeWeirdness[] = {
1532  { CERT_RDN_TELETEX_STRING, nihongoURL, { sizeof(nihongoT61), nihongoT61 } },
1533  { CERT_RDN_GENERAL_STRING, nihongoURL, { sizeof(nihongoGeneral), nihongoGeneral } },
1534 };
1535
1536 static void test_encodeUnicodeNameValue(DWORD dwEncoding)
1537 {
1538     BYTE *buf = NULL;
1539     DWORD size = 0, i;
1540     BOOL ret;
1541     CERT_NAME_VALUE value;
1542
1543     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, NULL,
1544      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1545     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
1546      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
1547     /* Have to have a string of some sort */
1548     value.dwValueType = 0; /* aka CERT_RDN_ANY_TYPE */
1549     value.Value.pbData = NULL;
1550     value.Value.cbData = 0;
1551     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1552      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1553     ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1554      "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1555     value.dwValueType = CERT_RDN_ENCODED_BLOB;
1556     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1557      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1558     ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1559      "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1560     value.dwValueType = CERT_RDN_ANY_TYPE;
1561     value.Value.pbData = (LPBYTE)oneW;
1562     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1563      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1564     ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1565      "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1566     value.Value.cbData = sizeof(oneW);
1567     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1568      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1569     ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1570      "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1571     /* An encoded string with specified length isn't good enough either */
1572     value.dwValueType = CERT_RDN_ENCODED_BLOB;
1573     value.Value.pbData = oneUniversal;
1574     value.Value.cbData = sizeof(oneUniversal);
1575     ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1576      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1577     ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING,
1578      "Expected CRYPT_E_NOT_CHAR_STRING, got %08lx\n", GetLastError());
1579     /* More failure checking */
1580     value.Value.cbData = 0;
1581     for (i = 0; i < sizeof(unicodeErrors) / sizeof(unicodeErrors[0]); i++)
1582     {
1583         value.Value.pbData = (LPBYTE)unicodeErrors[i].str;
1584         value.dwValueType = unicodeErrors[i].valueType;
1585         ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1586          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1587         ok(!ret && GetLastError() == unicodeErrors[i].error,
1588          "Value type %ld: expected %08lx, got %08lx\n", value.dwValueType,
1589          unicodeErrors[i].error, GetLastError());
1590         ok(size == unicodeErrors[i].errorIndex,
1591          "Expected error index %ld, got %ld\n", unicodeErrors[i].errorIndex,
1592          size);
1593     }
1594     /* cbData can be zero if the string is NULL-terminated */
1595     value.Value.cbData = 0;
1596     for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++)
1597     {
1598         value.Value.pbData = (LPBYTE)unicodeResults[i].str;
1599         value.dwValueType = unicodeResults[i].valueType;
1600         ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1601          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1602         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1603         if (buf)
1604         {
1605             ok(size == unicodeResults[i].encoded.cbData,
1606              "Value type %ld: expected size %ld, got %ld\n",
1607              value.dwValueType, unicodeResults[i].encoded.cbData, size);
1608             ok(!memcmp(unicodeResults[i].encoded.pbData, buf, size),
1609              "Value type %ld: unexpected value\n", value.dwValueType);
1610             LocalFree(buf);
1611         }
1612     }
1613     /* These "encode," but they do so by truncating each unicode character
1614      * rather than properly encoding it.  Kept separate from the proper results,
1615      * because the encoded forms won't decode to their original strings.
1616      */
1617     for (i = 0; i < sizeof(unicodeWeirdness) / sizeof(unicodeWeirdness[0]); i++)
1618     {
1619         value.Value.pbData = (LPBYTE)unicodeWeirdness[i].str;
1620         value.dwValueType = unicodeWeirdness[i].valueType;
1621         ret = CryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value,
1622          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1623         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1624         if (buf)
1625         {
1626             ok(size == unicodeWeirdness[i].encoded.cbData,
1627              "Value type %ld: expected size %ld, got %ld\n",
1628              value.dwValueType, unicodeWeirdness[i].encoded.cbData, size);
1629             ok(!memcmp(unicodeWeirdness[i].encoded.pbData, buf, size),
1630              "Value type %ld: unexpected value\n", value.dwValueType);
1631             LocalFree(buf);
1632         }
1633     }
1634 }
1635
1636 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
1637 {
1638     if (n <= 0) return 0;
1639     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
1640     return *str1 - *str2;
1641 }
1642
1643 static void test_decodeUnicodeNameValue(DWORD dwEncoding)
1644 {
1645     DWORD i;
1646
1647     for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++)
1648     {
1649         BYTE *buf = NULL;
1650         BOOL ret;
1651         DWORD size = 0;
1652
1653         ret = CryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE,
1654          unicodeResults[i].encoded.pbData, unicodeResults[i].encoded.cbData,
1655          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1656         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1657         if (ret && buf)
1658         {
1659             PCERT_NAME_VALUE value = (PCERT_NAME_VALUE)buf;
1660
1661             ok(value->dwValueType == unicodeResults[i].valueType,
1662              "Expected value type %ld, got %ld\n", unicodeResults[i].valueType,
1663              value->dwValueType);
1664             ok(!strncmpW((LPWSTR)value->Value.pbData, unicodeResults[i].str,
1665              value->Value.cbData / sizeof(WCHAR)),
1666              "Unexpected decoded value for index %ld (value type %ld)\n", i,
1667              unicodeResults[i].valueType);
1668             LocalFree(buf);
1669         }
1670     }
1671 }
1672
1673 struct encodedOctets
1674 {
1675     const BYTE *val;
1676     const BYTE *encoded;
1677 };
1678
1679 static const unsigned char bin46[] = { 'h','i',0 };
1680 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1681 static const unsigned char bin48[] = {
1682      's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1683 static const unsigned char bin49[] = {
1684      0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1685 static const unsigned char bin50[] = { 0 };
1686 static const unsigned char bin51[] = { 0x04,0x00,0 };
1687
1688 static const struct encodedOctets octets[] = {
1689     { bin46, bin47 },
1690     { bin48, bin49 },
1691     { bin50, bin51 },
1692 };
1693
1694 static void test_encodeOctets(DWORD dwEncoding)
1695 {
1696     CRYPT_DATA_BLOB blob;
1697     DWORD i;
1698
1699     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1700     {
1701         BYTE *buf = NULL;
1702         BOOL ret;
1703         DWORD bufSize = 0;
1704
1705         blob.cbData = strlen((const char*)octets[i].val);
1706         blob.pbData = (BYTE*)octets[i].val;
1707         ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1708          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1709         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1710         if (buf)
1711         {
1712             ok(buf[0] == 4,
1713              "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1714             ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1715              buf[1], octets[i].encoded[1]);
1716             ok(!memcmp(buf + 1, octets[i].encoded + 1,
1717              octets[i].encoded[1] + 1), "Got unexpected value\n");
1718             LocalFree(buf);
1719         }
1720     }
1721 }
1722
1723 static void test_decodeOctets(DWORD dwEncoding)
1724 {
1725     DWORD i;
1726
1727     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1728     {
1729         BYTE *buf = NULL;
1730         BOOL ret;
1731         DWORD bufSize = 0;
1732
1733         ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1734          (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1735          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1736         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1737         ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1738          "Expected size >= %d, got %ld\n",
1739            (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1740         ok(buf != NULL, "Expected allocated buffer\n");
1741         if (buf)
1742         {
1743             CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1744
1745             if (blob->cbData)
1746                 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1747                  "Unexpected value\n");
1748             LocalFree(buf);
1749         }
1750     }
1751 }
1752
1753 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1754
1755 struct encodedBits
1756 {
1757     DWORD cUnusedBits;
1758     const BYTE *encoded;
1759     DWORD cbDecoded;
1760     const BYTE *decoded;
1761 };
1762
1763 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff };
1764 static const unsigned char bin53[] = { 0xff,0xff };
1765 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe };
1766 static const unsigned char bin55[] = { 0xff,0xfe };
1767 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe };
1768 static const unsigned char bin57[] = { 0xfe };
1769 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
1770
1771 static const struct encodedBits bits[] = {
1772     /* normal test cases */
1773     { 0, bin52, 2, bin53 },
1774     { 1, bin54, 2, bin55 },
1775     /* strange test case, showing cUnusedBits >= 8 is allowed */
1776     { 9, bin56, 1, bin57 },
1777     /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1778     { 17, bin58, 0, NULL },
1779 };
1780
1781 static void test_encodeBits(DWORD dwEncoding)
1782 {
1783     DWORD i;
1784
1785     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1786     {
1787         CRYPT_BIT_BLOB blob;
1788         BOOL ret;
1789         BYTE *buf = NULL;
1790         DWORD bufSize = 0;
1791
1792         blob.cbData = sizeof(bytesToEncode);
1793         blob.pbData = (BYTE *)bytesToEncode;
1794         blob.cUnusedBits = bits[i].cUnusedBits;
1795         ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1796          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1797         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1798         if (buf)
1799         {
1800             ok(bufSize == bits[i].encoded[1] + 2,
1801              "Got unexpected size %ld, expected %d\n", bufSize,
1802              bits[i].encoded[1] + 2);
1803             ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1804              "Unexpected value\n");
1805             LocalFree(buf);
1806         }
1807     }
1808 }
1809
1810 static void test_decodeBits(DWORD dwEncoding)
1811 {
1812     static const BYTE ber[] = "\x03\x02\x01\xff";
1813     static const BYTE berDecoded = 0xfe;
1814     DWORD i;
1815     BOOL ret;
1816     BYTE *buf = NULL;
1817     DWORD bufSize = 0;
1818
1819     /* normal cases */
1820     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1821     {
1822         ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1823          bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1824          &bufSize);
1825         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1826         if (buf)
1827         {
1828             CRYPT_BIT_BLOB *blob;
1829
1830             ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1831              "Got unexpected size %ld, expected >= %ld\n", bufSize,
1832              sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1833             blob = (CRYPT_BIT_BLOB *)buf;
1834             ok(blob->cbData == bits[i].cbDecoded,
1835              "Got unexpected length %ld, expected %ld\n", blob->cbData,
1836              bits[i].cbDecoded);
1837             if (blob->cbData && bits[i].cbDecoded)
1838                 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1839                  "Unexpected value\n");
1840             LocalFree(buf);
1841         }
1842     }
1843     /* special case: check that something that's valid in BER but not in DER
1844      * decodes successfully
1845      */
1846     ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1847      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1848     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1849     if (buf)
1850     {
1851         CRYPT_BIT_BLOB *blob;
1852
1853         ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1854            "Got unexpected size %ld\n", bufSize);
1855         blob = (CRYPT_BIT_BLOB *)buf;
1856         ok(blob->cbData == sizeof(berDecoded),
1857            "Got unexpected length %ld\n", blob->cbData);
1858         if (blob->cbData)
1859             ok(*blob->pbData == berDecoded, "Unexpected value\n");
1860         LocalFree(buf);
1861     }
1862 }
1863
1864 struct Constraints2
1865 {
1866     CERT_BASIC_CONSTRAINTS2_INFO info;
1867     const BYTE *encoded;
1868 };
1869
1870 static const unsigned char bin59[] = { 0x30,0x00 };
1871 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
1872 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
1873 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1874 static const struct Constraints2 constraints2[] = {
1875  /* empty constraints */
1876  { { FALSE, FALSE, 0}, bin59 },
1877  /* can be a CA */
1878  { { TRUE,  FALSE, 0}, bin60 },
1879  /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1880   * but that's not the case
1881   */
1882  { { FALSE, TRUE,  0}, bin61 },
1883  /* can be a CA and has path length constraints set */
1884  { { TRUE,  TRUE,  1}, bin62 },
1885 };
1886
1887 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
1888 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
1889  0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
1890  0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
1891  0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1892 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
1893  0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
1894  0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
1895  0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
1896  0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
1897
1898 static void test_encodeBasicConstraints(DWORD dwEncoding)
1899 {
1900     DWORD i, bufSize = 0;
1901     CERT_BASIC_CONSTRAINTS_INFO info;
1902     CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
1903      (LPBYTE)encodedDomainName };
1904     BOOL ret;
1905     BYTE *buf = NULL;
1906
1907     /* First test with the simpler info2 */
1908     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1909     {
1910         ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1911          &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1912          &bufSize);
1913         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1914         if (buf)
1915         {
1916             ok(bufSize == constraints2[i].encoded[1] + 2,
1917              "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1918              bufSize);
1919             ok(!memcmp(buf, constraints2[i].encoded,
1920              constraints2[i].encoded[1] + 2), "Unexpected value\n");
1921             LocalFree(buf);
1922         }
1923     }
1924     /* Now test with more complex basic constraints */
1925     info.SubjectType.cbData = 0;
1926     info.fPathLenConstraint = FALSE;
1927     info.cSubtreesConstraint = 0;
1928     ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1929      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1930     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1931     if (buf)
1932     {
1933         ok(bufSize == sizeof(emptyConstraint), "Wrong size %ld\n", bufSize);
1934         ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
1935          "Unexpected value\n");
1936         LocalFree(buf);
1937     }
1938     /* None of the certs I examined had any subtree constraint, but I test one
1939      * anyway just in case.
1940      */
1941     info.cSubtreesConstraint = 1;
1942     info.rgSubtreesConstraint = &nameBlob;
1943     ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
1944      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1945     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1946     if (buf)
1947     {
1948         ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %ld\n", bufSize);
1949         ok(!memcmp(buf, constraintWithDomainName,
1950          sizeof(constraintWithDomainName)), "Unexpected value\n");
1951         LocalFree(buf);
1952     }
1953     /* FIXME: test encoding with subject type. */
1954 }
1955
1956 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
1957 static const unsigned char encodedCommonName[] = {
1958     0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
1959
1960 static void test_decodeBasicConstraints(DWORD dwEncoding)
1961 {
1962     static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
1963      0xff };
1964     static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1965     DWORD i;
1966     BOOL ret;
1967     BYTE *buf = NULL;
1968     DWORD bufSize = 0;
1969
1970     /* First test with simpler info2 */
1971     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1972     {
1973         ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1974          constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1975          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1976         ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1977          GetLastError());
1978         if (buf)
1979         {
1980             CERT_BASIC_CONSTRAINTS2_INFO *info =
1981              (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1982
1983             ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1984              "Unexpected value for item %ld\n", i);
1985             LocalFree(buf);
1986         }
1987     }
1988     /* Check with the order of encoded elements inverted */
1989     buf = (PBYTE)1;
1990     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1991      inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1992      &bufSize);
1993     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1994      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1995     ok(!buf, "Expected buf to be set to NULL\n");
1996     /* Check with a non-DER bool */
1997     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1998      badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1999      (BYTE *)&buf, &bufSize);
2000     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2001     if (buf)
2002     {
2003         CERT_BASIC_CONSTRAINTS2_INFO *info =
2004          (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
2005
2006         ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
2007         LocalFree(buf);
2008     }
2009     /* Check with a non-basic constraints value */
2010     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2011      (LPBYTE)encodedCommonName, encodedCommonName[1] + 2,
2012      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2013     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2014      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2015     /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
2016     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
2017      emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
2018      (BYTE *)&buf, &bufSize);
2019     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2020     if (buf)
2021     {
2022         CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
2023
2024         ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
2025         ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
2026         ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
2027         LocalFree(buf);
2028     }
2029     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
2030      constraintWithDomainName, sizeof(constraintWithDomainName),
2031      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2032     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2033     if (buf)
2034     {
2035         CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
2036
2037         ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
2038         ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
2039         ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
2040         if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
2041         {
2042             ok(info->rgSubtreesConstraint[0].cbData ==
2043              sizeof(encodedDomainName), "Wrong size %ld\n",
2044              info->rgSubtreesConstraint[0].cbData);
2045             ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
2046              sizeof(encodedDomainName)), "Unexpected value\n");
2047         }
2048         LocalFree(buf);
2049     }
2050 }
2051
2052 /* These are terrible public keys of course, I'm just testing encoding */
2053 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
2054 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
2055 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
2056 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
2057 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
2058 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
2059 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
2060 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
2061
2062 struct EncodedRSAPubKey
2063 {
2064     const BYTE *modulus;
2065     size_t modulusLen;
2066     const BYTE *encoded;
2067     size_t decodedModulusLen;
2068 };
2069
2070 struct EncodedRSAPubKey rsaPubKeys[] = {
2071     { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
2072     { modulus2, sizeof(modulus2), mod2_encoded, 5 },
2073     { modulus3, sizeof(modulus3), mod3_encoded, 5 },
2074     { modulus4, sizeof(modulus4), mod4_encoded, 8 },
2075 };
2076
2077 static void test_encodeRsaPublicKey(DWORD dwEncoding)
2078 {
2079     BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
2080     BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
2081     RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
2082     BOOL ret;
2083     BYTE *buf = NULL;
2084     DWORD bufSize = 0, i;
2085
2086     /* Try with a bogus blob type */
2087     hdr->bType = 2;
2088     hdr->bVersion = CUR_BLOB_VERSION;
2089     hdr->reserved = 0;
2090     hdr->aiKeyAlg = CALG_RSA_KEYX;
2091     rsaPubKey->magic = 0x31415352;
2092     rsaPubKey->bitlen = sizeof(modulus1) * 8;
2093     rsaPubKey->pubexp = 65537;
2094     memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
2095      sizeof(modulus1));
2096
2097     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2098      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2099      &bufSize);
2100     ok(!ret && GetLastError() == E_INVALIDARG,
2101      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2102     /* Now with a bogus reserved field */
2103     hdr->bType = PUBLICKEYBLOB;
2104     hdr->reserved = 1;
2105     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2106      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2107      &bufSize);
2108     if (buf)
2109     {
2110         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2111          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2112         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2113         LocalFree(buf);
2114     }
2115     /* Now with a bogus blob version */
2116     hdr->reserved = 0;
2117     hdr->bVersion = 0;
2118     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2119      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2120      &bufSize);
2121     if (buf)
2122     {
2123         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2124          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2125         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2126         LocalFree(buf);
2127     }
2128     /* And with a bogus alg ID */
2129     hdr->bVersion = CUR_BLOB_VERSION;
2130     hdr->aiKeyAlg = CALG_DES;
2131     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2132      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2133      &bufSize);
2134     if (buf)
2135     {
2136         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2137          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2138         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2139         LocalFree(buf);
2140     }
2141     /* Check a couple of RSA-related OIDs */
2142     hdr->aiKeyAlg = CALG_RSA_KEYX;
2143     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
2144      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2145     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2146      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2147     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
2148      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2149     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2150      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2151     /* Finally, all valid */
2152     hdr->aiKeyAlg = CALG_RSA_KEYX;
2153     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2154     {
2155         memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2156          rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
2157         ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2158          toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2159         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2160         if (buf)
2161         {
2162             ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
2163              "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
2164              bufSize);
2165             ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
2166              "Unexpected value\n");
2167             LocalFree(buf);
2168         }
2169     }
2170 }
2171
2172 static void test_decodeRsaPublicKey(DWORD dwEncoding)
2173 {
2174     DWORD i;
2175     LPBYTE buf = NULL;
2176     DWORD bufSize = 0;
2177     BOOL ret;
2178
2179     /* Try with a bad length */
2180     ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2181      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
2182      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2183     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2184      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
2185     /* Try with a couple of RSA-related OIDs */
2186     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
2187      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2188      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2189     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2190      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2191     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
2192      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2193      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2194     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2195      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2196     /* Now try success cases */
2197     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2198     {
2199         bufSize = 0;
2200         ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2201          rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
2202          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2203         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2204         if (buf)
2205         {
2206             BLOBHEADER *hdr = (BLOBHEADER *)buf;
2207             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
2208
2209             ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
2210              rsaPubKeys[i].decodedModulusLen,
2211              "Wrong size %ld\n", bufSize);
2212             ok(hdr->bType == PUBLICKEYBLOB,
2213              "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
2214              hdr->bType);
2215             ok(hdr->bVersion == CUR_BLOB_VERSION,
2216              "Expected version CUR_BLOB_VERSION (%d), got %d\n",
2217              CUR_BLOB_VERSION, hdr->bVersion);
2218             ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
2219              hdr->reserved);
2220             ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
2221              "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
2222             ok(rsaPubKey->magic == 0x31415352,
2223              "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
2224             ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
2225              "Wrong bit len %ld\n", rsaPubKey->bitlen);
2226             ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
2227              rsaPubKey->pubexp);
2228             ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2229              rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
2230              "Unexpected modulus\n");
2231             LocalFree(buf);
2232         }
2233     }
2234 }
2235
2236 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
2237  0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
2238  0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2239
2240 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
2241  0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
2242  0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
2243  0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2244
2245 static void test_encodeSequenceOfAny(DWORD dwEncoding)
2246 {
2247     CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
2248     CRYPT_SEQUENCE_OF_ANY seq;
2249     DWORD i;
2250     BOOL ret;
2251     BYTE *buf = NULL;
2252     DWORD bufSize = 0;
2253
2254     /* Encode a homogenous sequence */
2255     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
2256     {
2257         blobs[i].cbData = ints[i].encoded[1] + 2;
2258         blobs[i].pbData = (BYTE *)ints[i].encoded;
2259     }
2260     seq.cValue = sizeof(ints) / sizeof(ints[0]);
2261     seq.rgValue = blobs;
2262
2263     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2264      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2265     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2266     if (buf)
2267     {
2268         ok(bufSize == sizeof(intSequence), "Wrong size %ld\n", bufSize);
2269         ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
2270         LocalFree(buf);
2271     }
2272     /* Change the type of the first element in the sequence, and give it
2273      * another go
2274      */
2275     blobs[0].cbData = times[0].encodedTime[1] + 2;
2276     blobs[0].pbData = (BYTE *)times[0].encodedTime;
2277     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2278      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2279     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2280     if (buf)
2281     {
2282         ok(bufSize == sizeof(mixedSequence), "Wrong size %ld\n", bufSize);
2283         ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
2284          "Unexpected value\n");
2285         LocalFree(buf);
2286     }
2287 }
2288
2289 static void test_decodeSequenceOfAny(DWORD dwEncoding)
2290 {
2291     BOOL ret;
2292     BYTE *buf = NULL;
2293     DWORD bufSize = 0;
2294
2295     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
2296      intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2297     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2298     if (buf)
2299     {
2300         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2301         DWORD i;
2302
2303         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2304          "Wrong elements %ld\n", seq->cValue);
2305         for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
2306         {
2307             ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
2308              "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
2309              seq->rgValue[i].cbData);
2310             ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
2311              ints[i].encoded[1] + 2), "Unexpected value\n");
2312         }
2313         LocalFree(buf);
2314     }
2315     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
2316      mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2317      &bufSize);
2318     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2319     if (buf)
2320     {
2321         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2322
2323         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2324          "Wrong elements %ld\n", seq->cValue);
2325         /* Just check the first element since it's all that changed */
2326         ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
2327          "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
2328          seq->rgValue[0].cbData);
2329         ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
2330          times[0].encodedTime[1] + 2), "Unexpected value\n");
2331         LocalFree(buf);
2332     }
2333 }
2334
2335 struct encodedExtensions
2336 {
2337     CERT_EXTENSIONS exts;
2338     const BYTE *encoded;
2339 };
2340
2341 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2342 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2343 static CHAR oid_basic_constraints2[] = szOID_BASIC_CONSTRAINTS2;
2344 static CERT_EXTENSION criticalExt =
2345  { oid_basic_constraints2, TRUE, { 8, crit_ext_data } };
2346 static CERT_EXTENSION nonCriticalExt =
2347  { oid_basic_constraints2, FALSE, { 8, noncrit_ext_data } };
2348
2349 static const BYTE ext0[] = { 0x30,0x00 };
2350 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
2351                              0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2352 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
2353                              0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2354
2355 static const struct encodedExtensions exts[] = {
2356  { { 0, NULL }, ext0 },
2357  { { 1, &criticalExt }, ext1 },
2358  { { 1, &nonCriticalExt }, ext2 },
2359 };
2360
2361 static void test_encodeExtensions(DWORD dwEncoding)
2362 {
2363     DWORD i;
2364
2365     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2366     {
2367         BOOL ret;
2368         BYTE *buf = NULL;
2369         DWORD bufSize = 0;
2370
2371         ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
2372          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2373         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2374         if (buf)
2375         {
2376             ok(bufSize == exts[i].encoded[1] + 2,
2377              "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
2378             ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
2379              "Unexpected value\n");
2380             LocalFree(buf);
2381         }
2382     }
2383 }
2384
2385 static void test_decodeExtensions(DWORD dwEncoding)
2386 {
2387     DWORD i;
2388
2389     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2390     {
2391         BOOL ret;
2392         BYTE *buf = NULL;
2393         DWORD bufSize = 0;
2394
2395         ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
2396          exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2397          NULL, (BYTE *)&buf, &bufSize);
2398         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2399         if (buf)
2400         {
2401             CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
2402             DWORD j;
2403
2404             ok(ext->cExtension == exts[i].exts.cExtension,
2405              "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
2406              ext->cExtension);
2407             for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
2408             {
2409                 ok(!strcmp(ext->rgExtension[j].pszObjId,
2410                  exts[i].exts.rgExtension[j].pszObjId),
2411                  "Expected OID %s, got %s\n",
2412                  exts[i].exts.rgExtension[j].pszObjId,
2413                  ext->rgExtension[j].pszObjId);
2414                 ok(!memcmp(ext->rgExtension[j].Value.pbData,
2415                  exts[i].exts.rgExtension[j].Value.pbData,
2416                  exts[i].exts.rgExtension[j].Value.cbData),
2417                  "Unexpected value\n");
2418             }
2419             LocalFree(buf);
2420         }
2421     }
2422 }
2423
2424 /* MS encodes public key info with a NULL if the algorithm identifier's
2425  * parameters are empty.  However, when encoding an algorithm in a CERT_INFO,
2426  * it encodes them by omitting the algorithm parameters.  This latter approach
2427  * seems more correct, so accept either form.
2428  */
2429 struct encodedPublicKey
2430 {
2431     CERT_PUBLIC_KEY_INFO info;
2432     const BYTE *encoded;
2433     const BYTE *encodedNoNull;
2434     CERT_PUBLIC_KEY_INFO decoded;
2435 };
2436
2437 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2438  0xe, 0xf };
2439 static const BYTE params[] = { 0x02, 0x01, 0x01 };
2440
2441 static const unsigned char bin64[] = {
2442     0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
2443 static const unsigned char bin65[] = {
2444     0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
2445 static const unsigned char bin66[] = {
2446     0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
2447 static const unsigned char bin67[] = {
2448     0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
2449 static const unsigned char bin68[] = {
2450     0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
2451     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2452 static const unsigned char bin69[] = {
2453     0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
2454     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2455 static const unsigned char bin70[] = {
2456     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2457     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2458     0x0f};
2459 static const unsigned char bin71[] = {
2460     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2461     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2462     0x0f};
2463 static unsigned char bin72[] = { 0x05,0x00};
2464
2465 static CHAR oid_bogus[] = "1.2.3",
2466             oid_rsa[]   = szOID_RSA;
2467
2468 static const struct encodedPublicKey pubKeys[] = {
2469  /* with a bogus OID */
2470  { { { oid_bogus, { 0, NULL } }, { 0, NULL, 0 } },
2471   bin64, bin65,
2472   { { oid_bogus, { 2, bin72 } }, { 0, NULL, 0 } } },
2473  /* some normal keys */
2474  { { { oid_rsa, { 0, NULL } }, { 0, NULL, 0} },
2475   bin66, bin67,
2476   { { oid_rsa, { 2, bin72 } }, { 0, NULL, 0 } } },
2477  { { { oid_rsa, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2478   bin68, bin69,
2479   { { oid_rsa, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2480  /* with add'l parameters--note they must be DER-encoded */
2481  { { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2482   (BYTE *)aKey, 0 } },
2483   bin70, bin71,
2484   { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2485   (BYTE *)aKey, 0 } } },
2486 };
2487
2488 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2489 {
2490     DWORD i;
2491
2492     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2493     {
2494         BOOL ret;
2495         BYTE *buf = NULL;
2496         DWORD bufSize = 0;
2497
2498         ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2499          &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
2500          &bufSize);
2501         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2502         if (buf)
2503         {
2504             ok(bufSize == pubKeys[i].encoded[1] + 2 ||
2505              bufSize == pubKeys[i].encodedNoNull[1] + 2,
2506              "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
2507              pubKeys[i].encodedNoNull[1] + 2, bufSize);
2508             if (bufSize == pubKeys[i].encoded[1] + 2)
2509                 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2510                  "Unexpected value\n");
2511             else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
2512                 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
2513                  pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
2514             LocalFree(buf);
2515         }
2516     }
2517 }
2518
2519 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
2520  const CERT_PUBLIC_KEY_INFO *got)
2521 {
2522     ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
2523      "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
2524      got->Algorithm.pszObjId);
2525     ok(expected->Algorithm.Parameters.cbData ==
2526      got->Algorithm.Parameters.cbData,
2527      "Expected parameters of %ld bytes, got %ld\n",
2528      expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
2529     if (expected->Algorithm.Parameters.cbData)
2530         ok(!memcmp(expected->Algorithm.Parameters.pbData,
2531          got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
2532          "Unexpected algorithm parameters\n");
2533     ok(expected->PublicKey.cbData == got->PublicKey.cbData,
2534      "Expected public key of %ld bytes, got %ld\n",
2535      expected->PublicKey.cbData, got->PublicKey.cbData);
2536     if (expected->PublicKey.cbData)
2537         ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
2538          got->PublicKey.cbData), "Unexpected public key value\n");
2539 }
2540
2541 static void test_decodePublicKeyInfo(DWORD dwEncoding)
2542 {
2543     static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06,
2544      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03,
2545      0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
2546      0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
2547     DWORD i;
2548     BOOL ret;
2549     BYTE *buf = NULL;
2550     DWORD bufSize = 0;
2551
2552     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2553     {
2554         /* The NULL form decodes to the decoded member */
2555         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2556          pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2557          NULL, (BYTE *)&buf, &bufSize);
2558         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2559         if (buf)
2560         {
2561             comparePublicKeyInfo(&pubKeys[i].decoded,
2562              (CERT_PUBLIC_KEY_INFO *)buf);
2563             LocalFree(buf);
2564         }
2565         /* The non-NULL form decodes to the original */
2566         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2567          pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
2568          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2569         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2570         if (buf)
2571         {
2572             comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
2573             LocalFree(buf);
2574         }
2575     }
2576     /* Test with bogus (not valid DER) parameters */
2577     ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2578      bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2579      NULL, (BYTE *)&buf, &bufSize);
2580     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2581      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2582 }
2583
2584 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
2585  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2586  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
2587  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
2588  0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2589 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
2590  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2591  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2592  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2593  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2594 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
2595  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2596  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
2597  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2598  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
2599 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
2600  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2601  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2602  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2603  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2604  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2605  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2606 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
2607  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
2608  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
2609  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2610  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
2611  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2612  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2613 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2614  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2615  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
2616  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
2617  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
2618  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
2619  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
2620  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
2621  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
2622  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2623
2624 static const BYTE serialNum[] = { 0x01 };
2625
2626 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2627 {
2628     BOOL ret;
2629     BYTE *buf = NULL;
2630     DWORD size = 0;
2631     CERT_INFO info = { 0 };
2632
2633     /* Test with NULL pvStructInfo */
2634     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2635      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2636     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2637      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2638     /* Test with a V1 cert */
2639     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2640      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2641     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2642     if (buf)
2643     {
2644         ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2645          v1Cert[1] + 2, size);
2646         ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2647         LocalFree(buf);
2648     }
2649     /* Test v2 cert */
2650     info.dwVersion = CERT_V2;
2651     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2652      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2653     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2654     if (buf)
2655     {
2656         ok(size == sizeof(v2Cert), "Wrong size %ld\n", size);
2657         ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2658         LocalFree(buf);
2659     }
2660     /* Test v3 cert */
2661     info.dwVersion = CERT_V3;
2662     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2663      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2664     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2665     if (buf)
2666     {
2667         ok(size == sizeof(v3Cert), "Wrong size %ld\n", size);
2668         ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2669         LocalFree(buf);
2670     }
2671     /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2672      * API doesn't prevent it)
2673      */
2674     info.dwVersion = CERT_V1;
2675     info.cExtension = 1;
2676     info.rgExtension = &criticalExt;
2677     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2678      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2679     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2680     if (buf)
2681     {
2682         ok(size == sizeof(v1CertWithConstraints), "Wrong size %ld\n", size);
2683         ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2684         LocalFree(buf);
2685     }
2686     /* test v1 cert with a serial number */
2687     info.SerialNumber.cbData = sizeof(serialNum);
2688     info.SerialNumber.pbData = (BYTE *)serialNum;
2689     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2690      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2691     if (buf)
2692     {
2693         ok(size == sizeof(v1CertWithSerial), "Wrong size %ld\n", size);
2694         ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2695         LocalFree(buf);
2696     }
2697     /* Test v1 cert with an issuer name, a subject name, and a serial number */
2698     info.Issuer.cbData = sizeof(encodedCommonName);
2699     info.Issuer.pbData = (BYTE *)encodedCommonName;
2700     info.Subject.cbData = sizeof(encodedCommonName);
2701     info.Subject.pbData = (BYTE *)encodedCommonName;
2702     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2703      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2704     if (buf)
2705     {
2706         ok(size == sizeof(bigCert), "Wrong size %ld\n", size);
2707         ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2708         LocalFree(buf);
2709     }
2710     /* for now, I let more interesting tests be done for each subcomponent,
2711      * rather than retesting them all here.
2712      */
2713 }
2714
2715 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2716 {
2717     static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2718      v1CertWithConstraints, v1CertWithSerial };
2719     BOOL ret;
2720     BYTE *buf = NULL;
2721     DWORD size = 0, i;
2722
2723     /* Test with NULL pbEncoded */
2724     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2725      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2726     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2727      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2728     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2729      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2730     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2731      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2732     /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2733      * minimum a cert must have a non-zero serial number, an issuer, and a
2734      * subject.
2735      */
2736     for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2737     {
2738         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2739          corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2740          (BYTE *)&buf, &size);
2741         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2742          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2743     }
2744     /* Now check with serial number, subject and issuer specified */
2745     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2746      sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2747     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2748     if (buf)
2749     {
2750         CERT_INFO *info = (CERT_INFO *)buf;
2751
2752         ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2753         ok(info->SerialNumber.cbData == 1,
2754          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2755         ok(*info->SerialNumber.pbData == *serialNum,
2756          "Expected serial number %d, got %d\n", *serialNum,
2757          *info->SerialNumber.pbData);
2758         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2759          "Wrong size %ld\n", info->Issuer.cbData);
2760         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2761          "Unexpected issuer\n");
2762         ok(info->Subject.cbData == sizeof(encodedCommonName),
2763          "Wrong size %ld\n", info->Subject.cbData);
2764         ok(!memcmp(info->Subject.pbData, encodedCommonName,
2765          info->Subject.cbData), "Unexpected subject\n");
2766         LocalFree(buf);
2767     }
2768 }
2769
2770 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2771  0xe, 0xf };
2772
2773 static const BYTE signedBigCert[] = {
2774  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2775  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2776  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2777  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2778  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2779  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2780  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2781  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2782  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2783  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2784  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2785  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2786
2787 static void test_encodeCert(DWORD dwEncoding)
2788 {
2789     /* Note the SignatureAlgorithm must match that in the encoded cert.  Note
2790      * also that bigCert is a NULL-terminated string, so don't count its
2791      * last byte (otherwise the signed cert won't decode.)
2792      */
2793     CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2794      { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2795     BOOL ret;
2796     BYTE *buf = NULL;
2797     DWORD bufSize = 0;
2798
2799     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2800      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2801     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2802     if (buf)
2803     {
2804         ok(bufSize == sizeof(signedBigCert), "Wrong size %ld\n", bufSize);
2805         ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2806         LocalFree(buf);
2807     }
2808 }
2809
2810 static void test_decodeCert(DWORD dwEncoding)
2811 {
2812     BOOL ret;
2813     BYTE *buf = NULL;
2814     DWORD size = 0;
2815
2816     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2817      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2818     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2819     if (buf)
2820     {
2821         CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2822
2823         ok(info->ToBeSigned.cbData == sizeof(bigCert),
2824          "Wrong cert size %ld\n", info->ToBeSigned.cbData);
2825         ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2826          "Unexpected cert\n");
2827         ok(info->Signature.cbData == sizeof(hash),
2828          "Wrong signature size %ld\n", info->Signature.cbData);
2829         ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2830          "Unexpected signature\n");
2831         LocalFree(buf);
2832     }
2833     /* A signed cert decodes as a CERT_INFO too */
2834     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, signedBigCert,
2835      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2836     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2837     if (buf)
2838     {
2839         CERT_INFO *info = (CERT_INFO *)buf;
2840
2841         ok(size >= sizeof(CERT_INFO), "Wrong size %ld\n", size);
2842         ok(info->SerialNumber.cbData == 1,
2843          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2844         ok(*info->SerialNumber.pbData == *serialNum,
2845          "Expected serial number %d, got %d\n", *serialNum,
2846          *info->SerialNumber.pbData);
2847         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2848          "Wrong size %ld\n", info->Issuer.cbData);
2849         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2850          "Unexpected issuer\n");
2851         ok(info->Subject.cbData == sizeof(encodedCommonName),
2852          "Wrong size %ld\n", info->Subject.cbData);
2853         ok(!memcmp(info->Subject.pbData, encodedCommonName,
2854          info->Subject.cbData), "Unexpected subject\n");
2855         LocalFree(buf);
2856     }
2857 }
2858
2859 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2860 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2861  0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2862  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2863 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2864  0x00, 0x03 };
2865 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2866  0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2867  0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2868 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2869  0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2870  0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2871  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2872  0x2e, 0x6f, 0x72, 0x67 };
2873 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2874  CRL_REASON_AFFILIATION_CHANGED;
2875
2876 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2877 {
2878     CRL_DIST_POINTS_INFO info = { 0 };
2879     CRL_DIST_POINT point = { { 0 } };
2880     CERT_ALT_NAME_ENTRY entry = { 0 };
2881     BOOL ret;
2882     BYTE *buf = NULL;
2883     DWORD size = 0;
2884
2885     /* Test with an empty info */
2886     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2887      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2888     ok(!ret && GetLastError() == E_INVALIDARG,
2889      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
2890     /* Test with one empty dist point */
2891     info.cDistPoint = 1;
2892     info.rgDistPoint = &point;
2893     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2894      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2895     if (buf)
2896     {
2897         ok(size == sizeof(emptyDistPoint), "Wrong size %ld\n", size);
2898         ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2899         LocalFree(buf);
2900     }
2901     /* A dist point with an invalid name */
2902     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2903     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2904     U(entry).pwszURL = (LPWSTR)nihongoURL;
2905     U(point.DistPointName).FullName.cAltEntry = 1;
2906     U(point.DistPointName).FullName.rgAltEntry = &entry;
2907     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2908      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2909     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2910      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2911     /* The first invalid character is at index 7 */
2912     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2913      "Expected invalid char at index 7, got %ld\n",
2914      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2915     /* A dist point with (just) a valid name */
2916     U(entry).pwszURL = (LPWSTR)url;
2917     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2918      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2919     if (buf)
2920     {
2921         ok(size == sizeof(distPointWithUrl), "Wrong size %ld\n", size);
2922         ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2923         LocalFree(buf);
2924     }
2925     /* A dist point with (just) reason flags */
2926     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2927     point.ReasonFlags.cbData = sizeof(crlReason);
2928     point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2929     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2930      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2931     if (buf)
2932     {
2933         ok(size == sizeof(distPointWithReason), "Wrong size %ld\n", size);
2934         ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2935         LocalFree(buf);
2936     }
2937     /* A dist point with just an issuer */
2938     point.ReasonFlags.cbData = 0;
2939     point.CRLIssuer.cAltEntry = 1;
2940     point.CRLIssuer.rgAltEntry = &entry;
2941     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2942      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2943     if (buf)
2944     {
2945         ok(size == sizeof(distPointWithIssuer), "Wrong size %ld\n", size);
2946         ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2947         LocalFree(buf);
2948     }
2949     /* A dist point with both a name and an issuer */
2950     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2951     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2952      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2953     if (buf)
2954     {
2955         ok(size == sizeof(distPointWithUrlAndIssuer),
2956          "Wrong size %ld\n", size);
2957         ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2958         LocalFree(buf);
2959     }
2960 }
2961
2962 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2963 {
2964     BOOL ret;
2965     BYTE *buf = NULL;
2966     DWORD size = 0;
2967     PCRL_DIST_POINTS_INFO info;
2968     PCRL_DIST_POINT point;
2969     PCERT_ALT_NAME_ENTRY entry;
2970
2971     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2972      emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2973      (BYTE *)&buf, &size);
2974     if (ret)
2975     {
2976         info = (PCRL_DIST_POINTS_INFO)buf;
2977         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2978          "Wrong size %ld\n", size);
2979         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2980          info->cDistPoint);
2981         point = info->rgDistPoint;
2982         ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2983          "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2984          point->DistPointName.dwDistPointNameChoice);
2985         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2986         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2987         LocalFree(buf);
2988     }
2989     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2990      distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2991      (BYTE *)&buf, &size);
2992     if (ret)
2993     {
2994         info = (PCRL_DIST_POINTS_INFO)buf;
2995         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2996          "Wrong size %ld\n", size);
2997         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2998          info->cDistPoint);
2999         point = info->rgDistPoint;
3000         ok(point->DistPointName.dwDistPointNameChoice ==
3001          CRL_DIST_POINT_FULL_NAME,
3002          "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
3003          point->DistPointName.dwDistPointNameChoice);
3004         ok(U(point->DistPointName).FullName.cAltEntry == 1,
3005          "Expected 1 name entry, got %ld\n",
3006          U(point->DistPointName).FullName.cAltEntry);
3007         entry = U(point->DistPointName).FullName.rgAltEntry;
3008         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
3009          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
3010         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
3011         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
3012         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
3013         LocalFree(buf);
3014     }
3015     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
3016      distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
3017      NULL, (BYTE *)&buf, &size);
3018     if (ret)
3019     {
3020         info = (PCRL_DIST_POINTS_INFO)buf;
3021         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
3022          "Wrong size %ld\n", size);
3023         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
3024          info->cDistPoint);
3025         point = info->rgDistPoint;
3026         ok(point->DistPointName.dwDistPointNameChoice ==
3027          CRL_DIST_POINT_NO_NAME,
3028          "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
3029          point->DistPointName.dwDistPointNameChoice);
3030         ok(point->ReasonFlags.cbData == sizeof(crlReason),
3031          "Expected reason length\n");
3032         ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
3033          "Unexpected reason\n");
3034         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
3035         LocalFree(buf);
3036     }
3037     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
3038      distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
3039      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3040     if (ret)
3041     {
3042         info = (PCRL_DIST_POINTS_INFO)buf;
3043         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
3044          "Wrong size %ld\n", size);
3045         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
3046          info->cDistPoint);
3047         point = info->rgDistPoint;
3048         ok(point->DistPointName.dwDistPointNameChoice ==
3049          CRL_DIST_POINT_FULL_NAME,
3050          "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
3051          point->DistPointName.dwDistPointNameChoice);
3052         ok(U(point->DistPointName).FullName.cAltEntry == 1,
3053          "Expected 1 name entry, got %ld\n",
3054          U(point->DistPointName).FullName.cAltEntry);
3055         entry = U(point->DistPointName).FullName.rgAltEntry;
3056         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
3057          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
3058         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
3059         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
3060         ok(point->CRLIssuer.cAltEntry == 1,
3061          "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
3062         entry = point->CRLIssuer.rgAltEntry;
3063         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
3064          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
3065         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
3066         LocalFree(buf);
3067     }
3068 }
3069
3070 static const BYTE badFlagsIDP[] = { 0x30,0x06,0x81,0x01,0xff,0x82,0x01,0xff };
3071 static const BYTE emptyNameIDP[] = { 0x30,0x04,0xa0,0x02,0xa0,0x00 };
3072 static const BYTE urlIDP[] = { 0x30,0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,
3073  0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,
3074  0x67 };
3075
3076 static void test_encodeCRLIssuingDistPoint(DWORD dwEncoding)
3077 {
3078     BOOL ret;
3079     BYTE *buf = NULL;
3080     DWORD size = 0;
3081     CRL_ISSUING_DIST_POINT point = { { 0 } };
3082     CERT_ALT_NAME_ENTRY entry;
3083
3084     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, NULL,
3085      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3086     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
3087      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
3088     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3089      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3090     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3091     if (buf)
3092     {
3093         ok(size == sizeof(emptySequence), "Unexpected size %ld\n", size);
3094         ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
3095         LocalFree(buf);
3096     }
3097     /* nonsensical flags */
3098     point.fOnlyContainsUserCerts = TRUE;
3099     point.fOnlyContainsCACerts = TRUE;
3100     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3101      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3102     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3103     if (buf)
3104     {
3105         ok(size == sizeof(badFlagsIDP), "Unexpected size %ld\n", size);
3106         ok(!memcmp(buf, badFlagsIDP, size), "Unexpected value\n");
3107         LocalFree(buf);
3108     }
3109     /* unimplemented name type */
3110     point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
3111     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_ISSUER_RDN_NAME;
3112     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3113      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3114     ok(!ret && GetLastError() == E_INVALIDARG,
3115      "Expected E_INVALIDARG, got %08lx\n", GetLastError());
3116     /* empty name */
3117     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
3118     U(point.DistPointName).FullName.cAltEntry = 0;
3119     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3120      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3121     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3122     if (buf)
3123     {
3124         ok(size == sizeof(emptyNameIDP), "Unexpected size %ld\n", size);
3125         ok(!memcmp(buf, emptyNameIDP, size), "Unexpected value\n");
3126         LocalFree(buf);
3127     }
3128     /* name with URL entry */
3129     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
3130     U(entry).pwszURL = (LPWSTR)url;
3131     U(point.DistPointName).FullName.cAltEntry = 1;
3132     U(point.DistPointName).FullName.rgAltEntry = &entry;
3133     ret = CryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point,
3134      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3135     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3136     if (buf)
3137     {
3138         ok(size == sizeof(urlIDP), "Unexpected size %ld\n", size);
3139         ok(!memcmp(buf, urlIDP, size), "Unexpected value\n");
3140         LocalFree(buf);
3141     }
3142 }
3143
3144 static void compareAltNameEntry(const CERT_ALT_NAME_ENTRY *expected,
3145  const CERT_ALT_NAME_ENTRY *got)
3146 {
3147     ok(expected->dwAltNameChoice == got->dwAltNameChoice,
3148      "Expected name choice %ld, got %ld\n", expected->dwAltNameChoice,
3149      got->dwAltNameChoice);
3150     if (expected->dwAltNameChoice == got->dwAltNameChoice)
3151     {
3152         switch (got->dwAltNameChoice)
3153         {
3154         case CERT_ALT_NAME_RFC822_NAME:
3155         case CERT_ALT_NAME_DNS_NAME:
3156         case CERT_ALT_NAME_EDI_PARTY_NAME:
3157         case CERT_ALT_NAME_URL:
3158         case CERT_ALT_NAME_REGISTERED_ID:
3159             ok((!U(*expected).pwszURL && !U(*got).pwszURL) ||
3160                !lstrcmpW(U(*expected).pwszURL, U(*got).pwszURL), "Unexpected name\n");
3161             break;
3162         case CERT_ALT_NAME_X400_ADDRESS:
3163         case CERT_ALT_NAME_DIRECTORY_NAME:
3164         case CERT_ALT_NAME_IP_ADDRESS:
3165             ok(U(*got).IPAddress.cbData == U(*expected).IPAddress.cbData,
3166                "Unexpected IP address length %ld\n", U(*got).IPAddress.cbData);
3167             ok(!memcmp(U(*got).IPAddress.pbData, U(*got).IPAddress.pbData,
3168                        U(*got).IPAddress.cbData), "Unexpected value\n");
3169             break;
3170         }
3171     }
3172 }
3173
3174 static void compareAltNameInfo(const CERT_ALT_NAME_INFO *expected,
3175  const CERT_ALT_NAME_INFO *got)
3176 {
3177     DWORD i;
3178
3179     ok(expected->cAltEntry == got->cAltEntry, "Expected %ld entries, got %ld\n",
3180      expected->cAltEntry, got->cAltEntry);
3181     for (i = 0; i < min(expected->cAltEntry, got->cAltEntry); i++)
3182         compareAltNameEntry(&expected->rgAltEntry[i], &got->rgAltEntry[i]);
3183 }
3184
3185 static void compareDistPointName(const CRL_DIST_POINT_NAME *expected,
3186  const CRL_DIST_POINT_NAME *got)
3187 {
3188     ok(got->dwDistPointNameChoice == expected->dwDistPointNameChoice,
3189      "Unexpected name choice %ld\n", got->dwDistPointNameChoice);
3190     if (got->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
3191         compareAltNameInfo(&(U(*expected).FullName), &(U(*got).FullName));
3192 }
3193
3194 static void compareCRLIssuingDistPoints(const CRL_ISSUING_DIST_POINT *expected,
3195  const CRL_ISSUING_DIST_POINT *got)
3196 {
3197     compareDistPointName(&expected->DistPointName, &got->DistPointName);
3198     ok(got->fOnlyContainsUserCerts == expected->fOnlyContainsUserCerts,
3199      "Unexpected fOnlyContainsUserCerts\n");
3200     ok(got->fOnlyContainsCACerts == expected->fOnlyContainsCACerts,
3201      "Unexpected fOnlyContainsCACerts\n");
3202     ok(got->OnlySomeReasonFlags.cbData == expected->OnlySomeReasonFlags.cbData,
3203      "Unexpected reason flags\n");
3204     ok(got->fIndirectCRL == expected->fIndirectCRL,
3205      "Unexpected fIndirectCRL\n");
3206 }
3207
3208 static void test_decodeCRLIssuingDistPoint(DWORD dwEncoding)
3209 {
3210     BOOL ret;
3211     BYTE *buf = NULL;
3212     DWORD size = 0;
3213     CRL_ISSUING_DIST_POINT point = { { 0 } };
3214
3215     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3216      emptySequence, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3217      (BYTE *)&buf, &size);
3218     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3219     if (ret)
3220     {
3221         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3222         LocalFree(buf);
3223     }
3224     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3225      badFlagsIDP, badFlagsIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3226      (BYTE *)&buf, &size);
3227     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3228     if (ret)
3229     {
3230         point.fOnlyContainsUserCerts = point.fOnlyContainsCACerts = TRUE;
3231         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3232         LocalFree(buf);
3233     }
3234     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3235      emptyNameIDP, emptyNameIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3236      (BYTE *)&buf, &size);
3237     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3238     if (ret)
3239     {
3240         point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE;
3241         point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
3242         U(point.DistPointName).FullName.cAltEntry = 0;
3243         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3244         LocalFree(buf);
3245     }
3246     ret = CryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT,
3247      urlIDP, urlIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3248     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3249     if (ret)
3250     {
3251         CERT_ALT_NAME_ENTRY entry;
3252
3253         entry.dwAltNameChoice = CERT_ALT_NAME_URL;
3254         U(entry).pwszURL = (LPWSTR)url;
3255         U(point.DistPointName).FullName.cAltEntry = 1;
3256         U(point.DistPointName).FullName.rgAltEntry = &entry;
3257         compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf);
3258         LocalFree(buf);
3259     }
3260 }
3261
3262 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
3263  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
3264  0x30, 0x5a };
3265 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
3266  0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
3267  0x30, 0x30, 0x30, 0x30, 0x5a };
3268 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
3269  0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
3270  0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
3271  0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
3272  0x5a };
3273 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
3274  0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
3275  0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
3276  0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
3277  0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
3278  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
3279 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
3280  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
3281  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
3282  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
3283  0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
3284  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
3285 static const BYTE v1CRLWithEntryExt[] = { 0x30,0x5a,0x30,0x02,0x06,0x00,0x30,
3286  0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,
3287  0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
3288  0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x2c,0x30,0x2a,0x02,0x01,
3289  0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,
3290  0x30,0x30,0x5a,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,
3291  0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3292 static const BYTE v1CRLWithExt[] = { 0x30,0x5c,0x30,0x02,0x06,0x00,0x30,0x15,
3293  0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,
3294  0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
3295  0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,
3296  0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,
3297  0x30,0x5a,0xa0,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
3298  0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3299 static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06,
3300  0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,
3301  0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,
3302  0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,
3303  0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,
3304  0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,
3305  0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3306 static const BYTE v2CRLWithIssuingDistPoint[] = { 0x30,0x5c,0x02,0x01,0x01,
3307  0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
3308  0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,
3309  0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,
3310  0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,
3311  0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,
3312  0x03,0x55,0x1d,0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
3313
3314 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
3315 {
3316     BOOL ret;
3317     BYTE *buf = NULL;
3318     static CHAR oid_issuing_dist_point[] = szOID_ISSUING_DIST_POINT;
3319     DWORD size = 0;
3320     CRL_INFO info = { 0 };
3321     CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
3322     CERT_EXTENSION ext;
3323
3324     /* Test with a V1 CRL */
3325     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3326      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3327     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3328     if (buf)
3329     {
3330         ok(size == sizeof(v1CRL), "Wrong size %ld\n", size);
3331         ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
3332         LocalFree(buf);
3333     }
3334     /* Test v2 CRL */
3335     info.dwVersion = CRL_V2;
3336     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3337      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3338     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3339     if (buf)
3340     {
3341         ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
3342          v2CRL[1] + 2, size);
3343         ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
3344         LocalFree(buf);
3345     }
3346     /* v1 CRL with a name */
3347     info.dwVersion = CRL_V1;
3348     info.Issuer.cbData = sizeof(encodedCommonName);
3349     info.Issuer.pbData = (BYTE *)encodedCommonName;
3350     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3351      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3352     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3353     if (buf)
3354     {
3355         ok(size == sizeof(v1CRLWithIssuer), "Wrong size %ld\n", size);
3356         ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
3357         LocalFree(buf);
3358     }
3359     /* v1 CRL with a name and a NULL entry pointer */
3360     info.cCRLEntry = 1;
3361     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3362      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3363     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
3364      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
3365     /* now set an empty entry */
3366     info.rgCRLEntry = &entry;
3367     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3368      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3369     if (buf)
3370     {
3371         ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
3372          "Wrong size %ld\n", size);
3373         ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
3374          "Got unexpected value\n");
3375         LocalFree(buf);
3376     }
3377     /* an entry with a serial number */
3378     entry.SerialNumber.cbData = sizeof(serialNum);
3379     entry.SerialNumber.pbData = (BYTE *)serialNum;
3380     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3381      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3382     if (buf)
3383     {
3384         ok(size == sizeof(v1CRLWithIssuerAndEntry),
3385          "Wrong size %ld\n", size);
3386         ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
3387          "Got unexpected value\n");
3388         LocalFree(buf);
3389     }
3390     /* an entry with an extension */
3391     entry.cExtension = 1;
3392     entry.rgExtension = &criticalExt;
3393     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3394      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3395     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3396     if (buf)
3397     {
3398         ok(size == sizeof(v1CRLWithEntryExt), "Wrong size %ld\n", size);
3399         ok(!memcmp(buf, v1CRLWithEntryExt, size), "Got unexpected value\n");
3400         LocalFree(buf);
3401     }
3402     /* a CRL with an extension */
3403     entry.cExtension = 0;
3404     info.cExtension = 1;
3405     info.rgExtension = &criticalExt;
3406     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3407      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3408     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3409     if (buf)
3410     {
3411         ok(size == sizeof(v1CRLWithExt), "Wrong size %ld\n", size);
3412         ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
3413         LocalFree(buf);
3414     }
3415     /* a v2 CRL with an extension, this time non-critical */
3416     info.dwVersion = CRL_V2;
3417     info.rgExtension = &nonCriticalExt;
3418     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3419      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3420     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3421     if (buf)
3422     {
3423         ok(size == sizeof(v2CRLWithExt), "Wrong size %ld\n", size);
3424         ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n");
3425         LocalFree(buf);
3426     }
3427     /* a v2 CRL with an issuing dist point extension */
3428     ext.pszObjId = oid_issuing_dist_point;
3429     ext.fCritical = TRUE;
3430     ext.Value.cbData = sizeof(urlIDP);
3431     ext.Value.pbData = (LPBYTE)urlIDP;
3432     entry.rgExtension = &ext;
3433     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
3434      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3435     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3436     if (buf)
3437     {
3438         ok(size == sizeof(v2CRLWithIssuingDistPoint), "Wrong size %ld\n", size);
3439         ok(!memcmp(buf, v2CRLWithIssuingDistPoint, size), "Unexpected value\n");
3440         LocalFree(buf);
3441     }
3442 }
3443
3444 static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01,
3445  0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3446  0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06,
3447  0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
3448  0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56,
3449  0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
3450  0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65,
3451  0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
3452  0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
3453  0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43,
3454  0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30,
3455  0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33,
3456  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51,
3457  0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99,
3458  0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31,
3459  0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0,
3460  0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30,
3461  0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30,
3462  0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75,
3463  0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33,
3464  0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30,
3465  0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06,
3466  0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06,
3467  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03,
3468  0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88,
3469  0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd,
3470  0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf,
3471  0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46,
3472  0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f,
3473  0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75,
3474  0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f,
3475  0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82,
3476  0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07,
3477  0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c,
3478  0xcd };
3479
3480 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
3481 {
3482     static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
3483     BOOL ret;
3484     BYTE *buf = NULL;
3485     DWORD size = 0, i;
3486
3487     for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
3488     {
3489         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3490          corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3491          (BYTE *)&buf, &size);
3492         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
3493          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3494     }
3495     /* at a minimum, a CRL must contain an issuer: */
3496     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3497      v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
3498      (BYTE *)&buf, &size);
3499     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3500     if (buf)
3501     {
3502         CRL_INFO *info = (CRL_INFO *)buf;
3503
3504         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3505         ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
3506          info->cCRLEntry);
3507         ok(info->Issuer.cbData == sizeof(encodedCommonName),
3508          "Wrong issuer size %ld\n", info->Issuer.cbData);
3509         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3510          "Unexpected issuer\n");
3511         LocalFree(buf);
3512     }
3513     /* check decoding with an empty CRL entry */
3514     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3515      v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
3516      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3517     todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
3518      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
3519     /* with a real CRL entry */
3520     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3521      v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
3522      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3523     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3524     if (buf)
3525     {
3526         CRL_INFO *info = (CRL_INFO *)buf;
3527         CRL_ENTRY *entry;
3528
3529         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3530         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3531          info->cCRLEntry);
3532         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3533         entry = info->rgCRLEntry;
3534         ok(entry->SerialNumber.cbData == 1,
3535          "Expected serial number size 1, got %ld\n",
3536          entry->SerialNumber.cbData);
3537         ok(*entry->SerialNumber.pbData == *serialNum,
3538          "Expected serial number %d, got %d\n", *serialNum,
3539          *entry->SerialNumber.pbData);
3540         ok(info->Issuer.cbData == sizeof(encodedCommonName),
3541          "Wrong issuer size %ld\n", info->Issuer.cbData);
3542         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3543          "Unexpected issuer\n");
3544     }
3545     /* a real CRL from verisign that has extensions */
3546     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3547      verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG,
3548      NULL, (BYTE *)&buf, &size);
3549     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3550     if (buf)
3551     {
3552         CRL_INFO *info = (CRL_INFO *)buf;
3553         CRL_ENTRY *entry;
3554
3555         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3556         ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %ld\n",
3557          info->cCRLEntry);
3558         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3559         entry = info->rgCRLEntry;
3560         ok(info->cExtension == 2, "Expected 2 extensions, got %ld\n",
3561          info->cExtension);
3562     }
3563     /* and finally, with an extension */
3564     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3565      v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3566      NULL, (BYTE *)&buf, &size);
3567     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3568     if (buf)
3569     {
3570         CRL_INFO *info = (CRL_INFO *)buf;
3571         CRL_ENTRY *entry;
3572
3573         ok(size >= sizeof(CRL_INFO), "Wrong size %ld\n", size);
3574         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
3575          info->cCRLEntry);
3576         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
3577         entry = info->rgCRLEntry;
3578         ok(entry->SerialNumber.cbData == 1,
3579          "Expected serial number size 1, got %ld\n",
3580          entry->SerialNumber.cbData);
3581         ok(*entry->SerialNumber.pbData == *serialNum,
3582          "Expected serial number %d, got %d\n", *serialNum,
3583          *entry->SerialNumber.pbData);
3584         ok(info->Issuer.cbData == sizeof(encodedCommonName),
3585          "Wrong issuer size %ld\n", info->Issuer.cbData);
3586         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
3587          "Unexpected issuer\n");
3588         ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3589          info->cExtension);
3590     }
3591     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3592      v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
3593      NULL, (BYTE *)&buf, &size);
3594     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3595     if (buf)
3596     {
3597         CRL_INFO *info = (CRL_INFO *)buf;
3598
3599         ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3600          info->cExtension);
3601         LocalFree(buf);
3602     }
3603     /* And again, with an issuing dist point */
3604     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
3605      v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint),
3606      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3607     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3608     if (buf)
3609     {
3610         CRL_INFO *info = (CRL_INFO *)buf;
3611
3612         ok(info->cExtension == 1, "Expected 1 extensions, got %ld\n",
3613          info->cExtension);
3614         LocalFree(buf);
3615     }
3616 }
3617
3618 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
3619  szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
3620 static const BYTE encodedUsage[] = {
3621  0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
3622  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
3623  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
3624
3625 static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
3626 {
3627     BOOL ret;
3628     BYTE *buf = NULL;
3629     DWORD size = 0;
3630     CERT_ENHKEY_USAGE usage;
3631
3632     /* Test with empty usage */
3633     usage.cUsageIdentifier = 0;
3634     ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3635      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3636     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3637     if (buf)
3638     {
3639         ok(size == sizeof(emptySequence), "Wrong size %ld\n", size);
3640         ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
3641         LocalFree(buf);
3642     }
3643     /* Test with a few usages */
3644     usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
3645     usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
3646     ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
3647      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
3648     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
3649     if (buf)
3650     {
3651         ok(size == sizeof(encodedUsage), "Wrong size %ld\n", size);
3652         ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
3653         LocalFree(buf);
3654     }
3655 }
3656
3657 static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
3658 {
3659     BOOL ret;
3660     LPBYTE buf = NULL;
3661     DWORD size = 0;
3662
3663     ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3664      emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
3665      (BYTE *)&buf, &size);
3666     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3667     if (buf)
3668     {
3669         CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3670
3671         ok(size >= sizeof(CERT_ENHKEY_USAGE),
3672          "Wrong size %ld\n", size);
3673         ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
3674          usage->cUsageIdentifier);
3675         LocalFree(buf);
3676     }
3677     ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
3678      encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
3679      (BYTE *)&buf, &size);
3680     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
3681     if (buf)
3682     {
3683         CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
3684         DWORD i;
3685
3686         ok(size >= sizeof(CERT_ENHKEY_USAGE),
3687          "Wrong size %ld\n", size);
3688         ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
3689          "Wrong CRL entries count %ld\n", usage->cUsageIdentifier);
3690         for (i = 0; i < usage->cUsageIdentifier; i++)
3691             ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
3692              "Expected OID %s, got %s\n", keyUsages[i],
3693              usage->rgpszUsageIdentifier[i]);
3694         LocalFree(buf);
3695     }
3696 }
3697
3698 /* Free *pInfo with HeapFree */
3699 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
3700 {
3701     BOOL ret;
3702     DWORD size = 0;
3703     HCRYPTKEY key;
3704
3705     /* This crashes
3706     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
3707      */
3708     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
3709     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3710      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3711     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
3712      &size);
3713     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3714      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3715     ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
3716      NULL, &size);
3717     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3718      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3719     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3720      0, NULL, NULL, &size);
3721     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3722      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3723     /* Test with no key */
3724     ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
3725      0, NULL, NULL, &size);
3726     ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
3727      GetLastError());
3728     ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
3729     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
3730     if (ret)
3731     {
3732         ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
3733          NULL, 0, NULL, NULL, &size);
3734         ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3735         *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
3736         if (*pInfo)
3737         {
3738             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
3739              X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
3740             ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
3741              GetLastError());
3742             if (ret)
3743             {
3744                 /* By default (we passed NULL as the OID) the OID is
3745                  * szOID_RSA_RSA.
3746                  */
3747                 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
3748                  "Expected %s, got %s\n", szOID_RSA_RSA,
3749                  (*pInfo)->Algorithm.pszObjId);
3750             }
3751         }
3752     }
3753 }
3754
3755 static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2,
3756  0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6,
3757  0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06,
3758  0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3759  0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3760  0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3761  0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30,
3762  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30,
3763  0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30,
3764  0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40,
3765  0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63,
3766  0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
3767  0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
3768  0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29,
3769  0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e,
3770  0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5,
3771  0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a,
3772  0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b,
3773  0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
3774  0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0,
3775  0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3,
3776  0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31,
3777  0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70,
3778  0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef,
3779  0x49, 0xe5, 0xf9, 0x65, 0xf3 };
3780
3781 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
3782 {
3783     BOOL ret;
3784     HCRYPTKEY key;
3785     PCCERT_CONTEXT context;
3786
3787     /* These crash
3788     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
3789     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
3790     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
3791     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3792      NULL);
3793      */
3794     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
3795     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3796      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3797     ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
3798     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
3799      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
3800     ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
3801      &key);
3802     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
3803      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
3804     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
3805      &key);
3806     ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3807     CryptDestroyKey(key);
3808
3809     /* Test importing a public key from a certificate context */
3810     context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert,
3811      sizeof(expiredCert));
3812     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
3813      GetLastError());
3814     if (context)
3815     {
3816         ok(!strcmp(szOID_RSA_RSA,
3817          context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId),
3818          "Expected %s, got %s\n", szOID_RSA_RSA,
3819          context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
3820         ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING,
3821          &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key);
3822         ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
3823         CryptDestroyKey(key);
3824         CertFreeCertificateContext(context);
3825     }
3826 }
3827
3828 static const char cspName[] = "WineCryptTemp";
3829
3830 static void testPortPublicKeyInfo(void)
3831 {
3832     HCRYPTPROV csp;
3833     BOOL ret;
3834     PCERT_PUBLIC_KEY_INFO info = NULL;
3835
3836     /* Just in case a previous run failed, delete this thing */
3837     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3838      CRYPT_DELETEKEYSET);
3839     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3840      CRYPT_NEWKEYSET);
3841
3842     testExportPublicKey(csp, &info);
3843     testImportPublicKey(csp, info);
3844
3845     HeapFree(GetProcessHeap(), 0, info);
3846     CryptReleaseContext(csp, 0);
3847     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
3848      CRYPT_DELETEKEYSET);
3849 }
3850
3851 START_TEST(encode)
3852 {
3853     static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
3854      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
3855     DWORD i;
3856
3857     for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
3858     {
3859         test_encodeInt(encodings[i]);
3860         test_decodeInt(encodings[i]);
3861         test_encodeEnumerated(encodings[i]);
3862         test_decodeEnumerated(encodings[i]);
3863         test_encodeFiletime(encodings[i]);
3864         test_decodeFiletime(encodings[i]);
3865         test_encodeName(encodings[i]);
3866         test_decodeName(encodings[i]);
3867         test_encodeUnicodeName(encodings[i]);
3868         test_decodeUnicodeName(encodings[i]);
3869         test_encodeNameValue(encodings[i]);
3870         test_decodeNameValue(encodings[i]);
3871         test_encodeUnicodeNameValue(encodings[i]);
3872         test_decodeUnicodeNameValue(encodings[i]);
3873         test_encodeAltName(encodings[i]);
3874         test_decodeAltName(encodings[i]);
3875         test_encodeOctets(encodings[i]);
3876         test_decodeOctets(encodings[i]);
3877         test_encodeBits(encodings[i]);
3878         test_decodeBits(encodings[i]);
3879         test_encodeBasicConstraints(encodings[i]);
3880         test_decodeBasicConstraints(encodings[i]);
3881         test_encodeRsaPublicKey(encodings[i]);
3882         test_decodeRsaPublicKey(encodings[i]);
3883         test_encodeSequenceOfAny(encodings[i]);
3884         test_decodeSequenceOfAny(encodings[i]);
3885         test_encodeExtensions(encodings[i]);
3886         test_decodeExtensions(encodings[i]);
3887         test_encodePublicKeyInfo(encodings[i]);
3888         test_decodePublicKeyInfo(encodings[i]);
3889         test_encodeCertToBeSigned(encodings[i]);
3890         test_decodeCertToBeSigned(encodings[i]);
3891         test_encodeCert(encodings[i]);
3892         test_decodeCert(encodings[i]);
3893         test_encodeCRLDistPoints(encodings[i]);
3894         test_decodeCRLDistPoints(encodings[i]);
3895         test_encodeCRLIssuingDistPoint(encodings[i]);
3896         test_decodeCRLIssuingDistPoint(encodings[i]);
3897         test_encodeCRLToBeSigned(encodings[i]);
3898         test_decodeCRLToBeSigned(encodings[i]);
3899         test_encodeEnhancedKeyUsage(encodings[i]);
3900         test_decodeEnhancedKeyUsage(encodings[i]);
3901     }
3902     testPortPublicKeyInfo();
3903 }