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