kernel: Add some more tests for FindFirstChangeNotification.
[wine] / dlls / crypt32 / tests / encode.c
1 /*
2  * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
3  *
4  * Copyright 2005 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
26
27 #include "wine/test.h"
28
29 struct encodedInt
30 {
31     int val;
32     const BYTE *encoded;
33 };
34
35 static const BYTE bin1[] = {0x02,0x01,0x01,0};
36 static const BYTE bin2[] = {0x02,0x01,0x7f,0};
37 static const BYTE bin3[] = {0x02,0x02,0x00,0x80,0};
38 static const BYTE bin4[] = {0x02,0x02,0x01,0x00,0};
39 static const BYTE bin5[] = {0x02,0x01,0x80,0};
40 static const BYTE bin6[] = {0x02,0x02,0xff,0x7f,0};
41 static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d,0};
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", strlen((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", strlen((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,0};
339 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80,0};
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',0};
486 static const BYTE bin21[] = {
487     0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z',0};
488 static const BYTE bin22[] = {
489     0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z',0};
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',0};
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',0};
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',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',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',0};
519 static const BYTE bin28[] = {
520     0x18,0x0a,'2','1','4','5','0','6','0','6','1','6',0};
521 static const BYTE bin29[] = {
522     0x17,0x0a,'4','5','0','6','0','6','1','6','1','0',0};
523 static const BYTE bin30[] = {
524     0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z',0};
525 static const BYTE bin31[] = {
526     0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1',0};
527 static const BYTE bin32[] = {
528     0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1',0};
529 static const BYTE bin33[] = {
530     0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0',0};
531 static const BYTE bin34[] = {
532     0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0',0};
533 static const BYTE bin35[] = {
534     0x17,0x08, '4','5','0','6','0','6','1','6',0};
535 static const BYTE bin36[] = {
536     0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z',0};
537 static const BYTE bin37[] = {
538     0x18,0x04, '2','1','4','5',0};
539 static const BYTE bin38[] = {
540     0x18,0x08, '2','1','4','5','0','6','0','6',0};
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 struct EncodedName
606 {
607     CERT_RDN_ATTR attr;
608     const BYTE *encoded;
609 };
610
611 static const char commonName[] = "Juan Lang";
612 static const char surName[] = "Lang";
613 static const char bogusIA5[] = "\x80";
614 static const char bogusPrintable[] = "~";
615 static const char bogusNumeric[] = "A";
616 static const unsigned char bin39[] = {
617     0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
618 static const unsigned char bin40[] = {
619     0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x16,0x0a,'J','u','a','n',' ','L','a','n','g',0};
620 static const unsigned char bin41[] = {
621     0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x16,0x05,'L','a','n','g',0};
622 static const unsigned char bin42[] = {
623     0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x00,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
624 static const unsigned char bin43[] = {
625     0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x16,0x02,0x80,0};
626 static const unsigned char bin44[] = {
627     0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x13,0x02,0x7e,0};
628 static const unsigned char bin45[] = {
629     0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x12,0x02,0x41,0};
630 static const struct EncodedName names[] = {
631  { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
632    { sizeof(commonName), (BYTE *)commonName } }, bin39 },
633  { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
634    { sizeof(commonName), (BYTE *)commonName } }, bin40 },
635  { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
636    { sizeof(surName), (BYTE *)surName } }, bin41 },
637  { { NULL, CERT_RDN_PRINTABLE_STRING,
638    { sizeof(commonName), (BYTE *)commonName } }, bin42 },
639 /* The following test isn't a very good one, because it doesn't encode any
640  * Japanese characters.  I'm leaving it out for now.
641  { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
642    { sizeof(commonName), (BYTE *)commonName } },
643  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
644  */
645  /* The following tests succeed under Windows, but really should fail,
646   * they contain characters that are illegal for the encoding.  I'm
647   * including them to justify my lazy encoding.
648   */
649  { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
650    { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin43 },
651  { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
652    { sizeof(bogusPrintable), (BYTE *)bogusPrintable } }, bin44 },
653  { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
654    { sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, bin45 },
655 };
656
657 static const BYTE emptyName[] = { 0x30, 0 };
658 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
659 static const BYTE twoRDNs[] = {
660     0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
661     0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
662     0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
663
664 static void test_encodeName(DWORD dwEncoding)
665 {
666     CERT_RDN_ATTR attrs[2];
667     CERT_RDN rdn;
668     CERT_NAME_INFO info;
669     BYTE *buf = NULL;
670     DWORD size = 0, i;
671     BOOL ret;
672
673     /* Test with NULL pvStructInfo */
674     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
675      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
676     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
677      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
678     /* Test with empty CERT_NAME_INFO */
679     info.cRDN = 0;
680     info.rgRDN = NULL;
681     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
682      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
683     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
684     if (buf)
685     {
686         ok(!memcmp(buf, emptyName, sizeof(emptyName)),
687          "Got unexpected encoding for empty name\n");
688         LocalFree(buf);
689     }
690     /* Test with bogus CERT_RDN */
691     info.cRDN = 1;
692     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
693      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
694     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
695      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
696     /* Test with empty CERT_RDN */
697     rdn.cRDNAttr = 0;
698     rdn.rgRDNAttr = NULL;
699     info.cRDN = 1;
700     info.rgRDN = &rdn;
701     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
702      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
703     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
704     if (buf)
705     {
706         ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
707          "Got unexpected encoding for empty RDN array\n");
708         LocalFree(buf);
709     }
710     /* Test with bogus attr array */
711     rdn.cRDNAttr = 1;
712     rdn.rgRDNAttr = NULL;
713     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
714      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
715     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
716      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
717     /* oddly, a bogus OID is accepted by Windows XP; not testing.
718     attrs[0].pszObjId = "bogus";
719     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
720     attrs[0].Value.cbData = sizeof(commonName);
721     attrs[0].Value.pbData = (BYTE *)commonName;
722     rdn.cRDNAttr = 1;
723     rdn.rgRDNAttr = attrs;
724     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
725      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
726     ok(!ret, "Expected failure, got success\n");
727      */
728     /* Check with two CERT_RDN_ATTRs.  Note DER encoding forces the order of
729      * the encoded attributes to be swapped.
730      */
731     attrs[0].pszObjId = szOID_COMMON_NAME;
732     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
733     attrs[0].Value.cbData = sizeof(commonName);
734     attrs[0].Value.pbData = (BYTE *)commonName;
735     attrs[1].pszObjId = szOID_SUR_NAME;
736     attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
737     attrs[1].Value.cbData = sizeof(surName);
738     attrs[1].Value.pbData = (BYTE *)surName;
739     rdn.cRDNAttr = 2;
740     rdn.rgRDNAttr = attrs;
741     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
742      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
743     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
744     if (buf)
745     {
746         ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
747          "Got unexpected encoding for two RDN array\n");
748         LocalFree(buf);
749     }
750     /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
751     rdn.cRDNAttr = 1;
752     attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
753     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
754      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
755     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
756      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
757     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
758     {
759         rdn.cRDNAttr = 1;
760         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
761         ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
762          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
763         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
764         if (buf)
765         {
766             ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
767              names[i].encoded[1] + 2, size);
768             ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
769              "Got unexpected encoding\n");
770             LocalFree(buf);
771         }
772     }
773 }
774
775 static void compareNames(const CERT_NAME_INFO *expected,
776  const CERT_NAME_INFO *got)
777 {
778     ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
779      expected->cRDN, got->cRDN);
780     if (got->cRDN)
781     {
782         ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
783          "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
784          got->rgRDN[0].cRDNAttr);
785         if (got->rgRDN[0].cRDNAttr)
786         {
787             if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
788              strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
789             {
790                 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
791                  "Expected OID %s, got NULL\n",
792                  expected->rgRDN[0].rgRDNAttr[0].pszObjId);
793                 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
794                     ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
795                      expected->rgRDN[0].rgRDNAttr[0].pszObjId),
796                      "Got unexpected OID %s, expected %s\n",
797                      got->rgRDN[0].rgRDNAttr[0].pszObjId,
798                      expected->rgRDN[0].rgRDNAttr[0].pszObjId);
799             }
800             ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
801              expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
802              "Unexpected data size, got %ld, expected %ld\n",
803              got->rgRDN[0].rgRDNAttr[0].Value.cbData,
804              expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
805             if (got->rgRDN[0].rgRDNAttr[0].Value.cbData &&
806              got->rgRDN[0].rgRDNAttr[0].Value.pbData)
807                 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
808                  expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
809                  min(got->rgRDN[0].rgRDNAttr[0].Value.cbData,
810                  expected->rgRDN[0].rgRDNAttr[0].Value.cbData)),
811                  "Unexpected value\n");
812         }
813     }
814 }
815
816 static void test_decodeName(DWORD dwEncoding)
817 {
818     int i;
819     BYTE *buf = NULL;
820     DWORD bufSize = 0;
821     BOOL ret;
822     CERT_RDN rdn;
823     CERT_NAME_INFO info = { 1, &rdn };
824
825     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
826     {
827         /* When the output buffer is NULL, this always succeeds */
828         SetLastError(0xdeadbeef);
829         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
830          names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
831         ok(ret && GetLastError() == NOERROR,
832          "Expected success and NOERROR, got %08lx\n", GetLastError());
833         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
834          names[i].encoded[1] + 2,
835          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
836          (BYTE *)&buf, &bufSize);
837         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
838         rdn.cRDNAttr = 1;
839         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
840         if (buf)
841         {
842             compareNames(&info, (CERT_NAME_INFO *)buf);
843             LocalFree(buf);
844         }
845     }
846     /* test empty name */
847     bufSize = 0;
848     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
849      emptyName[1] + 2,
850      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
851      (BYTE *)&buf, &bufSize);
852     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
853     /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL.  My
854      * decoder works the same way, so only test the count.
855      */
856     if (buf)
857     {
858         ok(bufSize == sizeof(CERT_NAME_INFO),
859          "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
860         ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
861          "Expected 0 RDNs in empty info, got %ld\n",
862          ((CERT_NAME_INFO *)buf)->cRDN);
863         LocalFree(buf);
864     }
865     /* test empty RDN */
866     bufSize = 0;
867     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
868      emptyRDNs[1] + 2,
869      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
870      (BYTE *)&buf, &bufSize);
871     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
872     if (buf)
873     {
874         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
875
876         ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
877          info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
878          "Got unexpected value for empty RDN\n");
879         LocalFree(buf);
880     }
881     /* test two RDN attrs */
882     bufSize = 0;
883     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
884      twoRDNs[1] + 2,
885      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
886      (BYTE *)&buf, &bufSize);
887     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
888     if (buf)
889     {
890         CERT_RDN_ATTR attrs[] = {
891          { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
892           (BYTE *)surName } },
893          { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
894           (BYTE *)commonName } },
895         };
896
897         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
898         rdn.rgRDNAttr = attrs;
899         compareNames(&info, (CERT_NAME_INFO *)buf);
900         LocalFree(buf);
901     }
902 }
903
904 static const BYTE emptyAltName[] = { 0x30, 0x00 };
905 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
906 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
907  'h','q','.','o','r','g',0 };
908 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
909  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
910  0x6f, 0x72, 0x67 };
911 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
912  0x575b, 0 };
913 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
914 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
915  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
916 static const BYTE localhost[] = { 127, 0, 0, 1 };
917 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
918  0x01 };
919
920 static void test_encodeAltName(DWORD dwEncoding)
921 {
922     CERT_ALT_NAME_INFO info = { 0 };
923     CERT_ALT_NAME_ENTRY entry = { 0 };
924     BYTE *buf = NULL;
925     DWORD size = 0;
926     BOOL ret;
927
928     /* Test with empty info */
929     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
930      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
931     if (buf)
932     {
933         ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n",
934          sizeof(emptyAltName), size);
935         ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n");
936         LocalFree(buf);
937     }
938     /* Test with an empty entry */
939     info.cAltEntry = 1;
940     info.rgAltEntry = &entry;
941     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
942      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
943     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
944      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
945      GetLastError());
946     /* Test with an empty pointer */
947     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
948     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
949      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
950     if (buf)
951     {
952         ok(size == sizeof(emptyURL), "Expected size %d, got %ld\n",
953          sizeof(emptyURL), size);
954         ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
955         LocalFree(buf);
956     }
957     /* Test with a real URL */
958     U(entry).pwszURL = (LPWSTR)url;
959     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
960      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
961     if (buf)
962     {
963         ok(size == sizeof(encodedURL), "Expected size %d, got %ld\n",
964          sizeof(encodedURL), size);
965         ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
966         LocalFree(buf);
967     }
968     /* Now with the URL containing an invalid IA5 char */
969     U(entry).pwszURL = (LPWSTR)nihongoURL;
970     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
971      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
972     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
973      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
974     /* The first invalid character is at index 7 */
975     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
976      "Expected invalid char at index 7, got %ld\n",
977      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
978     /* Now with the URL missing a scheme */
979     U(entry).pwszURL = (LPWSTR)dnsName;
980     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
981      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
982     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
983     if (buf)
984     {
985         /* This succeeds, but it shouldn't, so don't worry about conforming */
986         LocalFree(buf);
987     }
988     /* Now with a DNS name */
989     entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
990     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
991      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
992     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
993     if (buf)
994     {
995         ok(size == sizeof(encodedDnsName), "Expected size %d, got %ld\n",
996          sizeof(encodedDnsName), size);
997         ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
998         LocalFree(buf);
999     }
1000     /* Test with an IP address */
1001     entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1002     U(entry).IPAddress.cbData = sizeof(localhost);
1003     U(entry).IPAddress.pbData = (LPBYTE)localhost;
1004     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1005      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1006     if (buf)
1007     {
1008         ok(size == sizeof(encodedIPAddr), "Expected size %d, got %ld\n",
1009          sizeof(encodedIPAddr), size);
1010         ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1011         LocalFree(buf);
1012     }
1013 }
1014
1015 static void test_decodeAltName(DWORD dwEncoding)
1016 {
1017     static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1018      0x00, 0x00, 0x01 };
1019     static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1020      0x01 };
1021     BOOL ret;
1022     BYTE *buf = NULL;
1023     DWORD bufSize = 0;
1024     CERT_ALT_NAME_INFO *info;
1025
1026     /* Test some bogus ones first */
1027     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1028      unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1029      NULL, (BYTE *)&buf, &bufSize);
1030     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1031      "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1032     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1033      bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1034      &bufSize);
1035     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1036      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1037     /* Now expected cases */
1038     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName,
1039      emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1040      &bufSize);
1041     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1042     if (buf)
1043     {
1044         info = (CERT_ALT_NAME_INFO *)buf;
1045
1046         ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1047          info->cAltEntry);
1048         LocalFree(buf);
1049     }
1050     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1051      emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1052      &bufSize);
1053     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1054     if (buf)
1055     {
1056         info = (CERT_ALT_NAME_INFO *)buf;
1057
1058         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1059          info->cAltEntry);
1060         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1061          "Expected CERT_ALT_NAME_URL, got %ld\n",
1062          info->rgAltEntry[0].dwAltNameChoice);
1063         ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1064          "Expected empty URL\n");
1065         LocalFree(buf);
1066     }
1067     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1068      encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1069      &bufSize);
1070     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1071     if (buf)
1072     {
1073         info = (CERT_ALT_NAME_INFO *)buf;
1074
1075         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1076          info->cAltEntry);
1077         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1078          "Expected CERT_ALT_NAME_URL, got %ld\n",
1079          info->rgAltEntry[0].dwAltNameChoice);
1080         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1081         LocalFree(buf);
1082     }
1083     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1084      encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1085      &bufSize);
1086     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1087     if (buf)
1088     {
1089         info = (CERT_ALT_NAME_INFO *)buf;
1090
1091         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1092          info->cAltEntry);
1093         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1094          "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1095          info->rgAltEntry[0].dwAltNameChoice);
1096         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1097          "Unexpected DNS name\n");
1098         LocalFree(buf);
1099     }
1100     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1101      encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1102      &bufSize);
1103     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1104     if (buf)
1105     {
1106         info = (CERT_ALT_NAME_INFO *)buf;
1107
1108         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1109          info->cAltEntry);
1110         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1111          "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1112          info->rgAltEntry[0].dwAltNameChoice);
1113         ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1114          "Unexpected IP address length %ld\n",
1115           U(info->rgAltEntry[0]).IPAddress.cbData);
1116         ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1117          sizeof(localhost)), "Unexpected IP address value\n");
1118         LocalFree(buf);
1119     }
1120 }
1121
1122 struct encodedOctets
1123 {
1124     const BYTE *val;
1125     const BYTE *encoded;
1126 };
1127
1128 static const unsigned char bin46[] = { 'h','i',0 };
1129 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1130 static const unsigned char bin48[] = {
1131      's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1132 static const unsigned char bin49[] = {
1133      0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1134 static const unsigned char bin50[] = { 0 };
1135 static const unsigned char bin51[] = { 0x04,0x00,0 };
1136
1137 static const struct encodedOctets octets[] = {
1138     { bin46, bin47 },
1139     { bin48, bin49 },
1140     { bin50, bin51 },
1141 };
1142
1143 static void test_encodeOctets(DWORD dwEncoding)
1144 {
1145     CRYPT_DATA_BLOB blob;
1146     DWORD i;
1147
1148     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1149     {
1150         BYTE *buf = NULL;
1151         BOOL ret;
1152         DWORD bufSize = 0;
1153
1154         blob.cbData = strlen((const char*)octets[i].val);
1155         blob.pbData = (BYTE*)octets[i].val;
1156         ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1157          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1158         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1159         if (buf)
1160         {
1161             ok(buf[0] == 4,
1162              "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1163             ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1164              buf[1], octets[i].encoded[1]);
1165             ok(!memcmp(buf + 1, octets[i].encoded + 1,
1166              octets[i].encoded[1] + 1), "Got unexpected value\n");
1167             LocalFree(buf);
1168         }
1169     }
1170 }
1171
1172 static void test_decodeOctets(DWORD dwEncoding)
1173 {
1174     DWORD i;
1175
1176     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1177     {
1178         BYTE *buf = NULL;
1179         BOOL ret;
1180         DWORD bufSize = 0;
1181
1182         ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1183          (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1184          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1185         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1186         ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1187          "Expected size >= %d, got %ld\n",
1188          sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1189         ok(buf != NULL, "Expected allocated buffer\n");
1190         if (buf)
1191         {
1192             CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1193
1194             if (blob->cbData)
1195                 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1196                  "Unexpected value\n");
1197             LocalFree(buf);
1198         }
1199     }
1200 }
1201
1202 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1203
1204 struct encodedBits
1205 {
1206     DWORD cUnusedBits;
1207     const BYTE *encoded;
1208     DWORD cbDecoded;
1209     const BYTE *decoded;
1210 };
1211
1212 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff,0 };
1213 static const unsigned char bin53[] = { 0xff,0xff,0 };
1214 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe,0 };
1215 static const unsigned char bin55[] = { 0xff,0xfe,0 };
1216 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe,0 };
1217 static const unsigned char bin57[] = { 0xfe,0 };
1218 static const unsigned char bin58[] = { 0x03,0x01,0x00,0 };
1219
1220 static const struct encodedBits bits[] = {
1221     /* normal test cases */
1222     { 0, bin52, 2, bin53 },
1223     { 1, bin54, 2, bin55 },
1224     /* strange test case, showing cUnusedBits >= 8 is allowed */
1225     { 9, bin56, 1, bin57 },
1226     /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1227     { 17, bin58, 0, NULL },
1228 };
1229
1230 static void test_encodeBits(DWORD dwEncoding)
1231 {
1232     DWORD i;
1233
1234     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1235     {
1236         CRYPT_BIT_BLOB blob;
1237         BOOL ret;
1238         BYTE *buf = NULL;
1239         DWORD bufSize = 0;
1240
1241         blob.cbData = sizeof(bytesToEncode);
1242         blob.pbData = (BYTE *)bytesToEncode;
1243         blob.cUnusedBits = bits[i].cUnusedBits;
1244         ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1245          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1246         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1247         if (buf)
1248         {
1249             ok(bufSize == bits[i].encoded[1] + 2,
1250              "Got unexpected size %ld, expected %d\n", bufSize,
1251              bits[i].encoded[1] + 2);
1252             ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1253              "Unexpected value\n");
1254             LocalFree(buf);
1255         }
1256     }
1257 }
1258
1259 static void test_decodeBits(DWORD dwEncoding)
1260 {
1261     static const BYTE ber[] = "\x03\x02\x01\xff";
1262     static const BYTE berDecoded = 0xfe;
1263     DWORD i;
1264     BOOL ret;
1265     BYTE *buf = NULL;
1266     DWORD bufSize = 0;
1267
1268     /* normal cases */
1269     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1270     {
1271         ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1272          bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1273          &bufSize);
1274         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1275         if (buf)
1276         {
1277             CRYPT_BIT_BLOB *blob;
1278
1279             ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1280              "Got unexpected size %ld, expected >= %ld\n", bufSize,
1281              sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1282             blob = (CRYPT_BIT_BLOB *)buf;
1283             ok(blob->cbData == bits[i].cbDecoded,
1284              "Got unexpected length %ld, expected %ld\n", blob->cbData,
1285              bits[i].cbDecoded);
1286             if (blob->cbData && bits[i].cbDecoded)
1287                 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1288                  "Unexpected value\n");
1289             LocalFree(buf);
1290         }
1291     }
1292     /* special case: check that something that's valid in BER but not in DER
1293      * decodes successfully
1294      */
1295     ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1296      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1297     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1298     if (buf)
1299     {
1300         CRYPT_BIT_BLOB *blob;
1301
1302         ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1303          "Got unexpected size %ld, expected >= %d\n", bufSize,
1304          sizeof(CRYPT_BIT_BLOB) + berDecoded);
1305         blob = (CRYPT_BIT_BLOB *)buf;
1306         ok(blob->cbData == sizeof(berDecoded),
1307          "Got unexpected length %ld, expected %d\n", blob->cbData,
1308          sizeof(berDecoded));
1309         if (blob->cbData)
1310             ok(*blob->pbData == berDecoded, "Unexpected value\n");
1311         LocalFree(buf);
1312     }
1313 }
1314
1315 struct Constraints2
1316 {
1317     CERT_BASIC_CONSTRAINTS2_INFO info;
1318     const BYTE *encoded;
1319 };
1320
1321 static const unsigned char bin59[] = { 0x30,0x00,0 };
1322 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff,0 };
1323 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00,0 };
1324 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0 };
1325 static const struct Constraints2 constraints2[] = {
1326  /* empty constraints */
1327  { { FALSE, FALSE, 0}, bin59 },
1328  /* can be a CA */
1329  { { TRUE,  FALSE, 0}, bin60 },
1330  /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1331   * but that's not the case
1332   */
1333  { { FALSE, TRUE,  0}, bin61 },
1334  /* can be a CA and has path length constraints set */
1335  { { TRUE,  TRUE,  1}, bin62 },
1336 };
1337
1338 static void test_encodeBasicConstraints(DWORD dwEncoding)
1339 {
1340     DWORD i;
1341
1342     /* First test with the simpler info2 */
1343     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1344     {
1345         BOOL ret;
1346         BYTE *buf = NULL;
1347         DWORD bufSize = 0;
1348
1349         ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1350          &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1351          &bufSize);
1352         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1353         if (buf)
1354         {
1355             ok(bufSize == constraints2[i].encoded[1] + 2,
1356              "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1357              bufSize);
1358             ok(!memcmp(buf, constraints2[i].encoded,
1359              constraints2[i].encoded[1] + 2), "Unexpected value\n");
1360             LocalFree(buf);
1361         }
1362     }
1363 }
1364
1365 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01,0 };
1366
1367 static void test_decodeBasicConstraints(DWORD dwEncoding)
1368 {
1369     static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
1370     static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1371     DWORD i;
1372     BOOL ret;
1373     BYTE *buf = NULL;
1374     DWORD bufSize = 0;
1375
1376     /* First test with simpler info2 */
1377     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1378     {
1379         ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1380          constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1381          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1382         ok(ret, "CryptDecodeObjectEx failed for item %ld: %08lx\n", i,
1383          GetLastError());
1384         if (buf)
1385         {
1386             CERT_BASIC_CONSTRAINTS2_INFO *info =
1387              (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1388
1389             ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1390              "Unexpected value for item %ld\n", i);
1391             LocalFree(buf);
1392         }
1393     }
1394     /* Check with the order of encoded elements inverted */
1395     buf = (PBYTE)1;
1396     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1397      inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1398      &bufSize);
1399     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1400      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1401     ok(!buf, "Expected buf to be set to NULL\n");
1402     /* Check with a non-DER bool */
1403     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1404      badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1405      (BYTE *)&buf, &bufSize);
1406     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1407     if (buf)
1408     {
1409         CERT_BASIC_CONSTRAINTS2_INFO *info =
1410          (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1411
1412         ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1413         LocalFree(buf);
1414     }
1415     /* Check with a non-basic constraints value */
1416     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1417      names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1418      (BYTE *)&buf, &bufSize);
1419     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1420      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1421 }
1422
1423 /* These are terrible public keys of course, I'm just testing encoding */
1424 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1425 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1426 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1427 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1428 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1429 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1430 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1431 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1432
1433 struct EncodedRSAPubKey
1434 {
1435     const BYTE *modulus;
1436     size_t modulusLen;
1437     const BYTE *encoded;
1438     size_t decodedModulusLen;
1439 };
1440
1441 struct EncodedRSAPubKey rsaPubKeys[] = {
1442     { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1443     { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1444     { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1445     { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1446 };
1447
1448 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1449 {
1450     BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1451     BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1452     RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1453     BOOL ret;
1454     BYTE *buf = NULL;
1455     DWORD bufSize = 0, i;
1456
1457     /* Try with a bogus blob type */
1458     hdr->bType = 2;
1459     hdr->bVersion = CUR_BLOB_VERSION;
1460     hdr->reserved = 0;
1461     hdr->aiKeyAlg = CALG_RSA_KEYX;
1462     rsaPubKey->magic = 0x31415352;
1463     rsaPubKey->bitlen = sizeof(modulus1) * 8;
1464     rsaPubKey->pubexp = 65537;
1465     memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1466      sizeof(modulus1));
1467
1468     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1469      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1470      &bufSize);
1471     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1472      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1473      GetLastError());
1474     /* Now with a bogus reserved field */
1475     hdr->bType = PUBLICKEYBLOB;
1476     hdr->reserved = 1;
1477     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1478      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1479      &bufSize);
1480     if (buf)
1481     {
1482         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1483          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1484         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1485         LocalFree(buf);
1486     }
1487     /* Now with a bogus blob version */
1488     hdr->reserved = 0;
1489     hdr->bVersion = 0;
1490     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1491      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1492      &bufSize);
1493     if (buf)
1494     {
1495         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1496          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1497         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1498         LocalFree(buf);
1499     }
1500     /* And with a bogus alg ID */
1501     hdr->bVersion = CUR_BLOB_VERSION;
1502     hdr->aiKeyAlg = CALG_DES;
1503     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1504      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1505      &bufSize);
1506     if (buf)
1507     {
1508         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1509          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1510         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1511         LocalFree(buf);
1512     }
1513     /* Check a couple of RSA-related OIDs */
1514     hdr->aiKeyAlg = CALG_RSA_KEYX;
1515     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1516      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1517     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1518      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1519     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1520      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1521     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1522      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1523     /* Finally, all valid */
1524     hdr->aiKeyAlg = CALG_RSA_KEYX;
1525     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1526     {
1527         memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1528          rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1529         ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1530          toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1531         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1532         if (buf)
1533         {
1534             ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1535              "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1536              bufSize);
1537             ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1538              "Unexpected value\n");
1539             LocalFree(buf);
1540         }
1541     }
1542 }
1543
1544 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1545 {
1546     DWORD i;
1547     LPBYTE buf = NULL;
1548     DWORD bufSize = 0;
1549     BOOL ret;
1550
1551     /* Try with a bad length */
1552     ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1553      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1554      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1555     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1556      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1557     /* Try with a couple of RSA-related OIDs */
1558     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1559      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1560      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1561     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1562      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1563     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1564      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1565      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1566     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1567      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1568     /* Now try success cases */
1569     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1570     {
1571         bufSize = 0;
1572         ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1573          rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1574          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1575         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1576         if (buf)
1577         {
1578             BLOBHEADER *hdr = (BLOBHEADER *)buf;
1579             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1580
1581             ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1582              rsaPubKeys[i].decodedModulusLen,
1583              "Expected size at least %d, got %ld\n",
1584              sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1585              rsaPubKeys[i].decodedModulusLen, bufSize);
1586             ok(hdr->bType == PUBLICKEYBLOB,
1587              "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1588              hdr->bType);
1589             ok(hdr->bVersion == CUR_BLOB_VERSION,
1590              "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1591              CUR_BLOB_VERSION, hdr->bVersion);
1592             ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1593              hdr->reserved);
1594             ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1595              "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1596             ok(rsaPubKey->magic == 0x31415352,
1597              "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1598             ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1599              "Expected bit len %d, got %ld\n",
1600              rsaPubKeys[i].decodedModulusLen * 8, rsaPubKey->bitlen);
1601             ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1602              rsaPubKey->pubexp);
1603             ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1604              rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1605              "Unexpected modulus\n");
1606             LocalFree(buf);
1607         }
1608     }
1609 }
1610
1611 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1612  0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1613  0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1614
1615 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1616  0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1617  0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1618  0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1619
1620 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1621 {
1622     CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1623     CRYPT_SEQUENCE_OF_ANY seq;
1624     DWORD i;
1625     BOOL ret;
1626     BYTE *buf = NULL;
1627     DWORD bufSize = 0;
1628
1629     /* Encode a homogenous sequence */
1630     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1631     {
1632         blobs[i].cbData = ints[i].encoded[1] + 2;
1633         blobs[i].pbData = (BYTE *)ints[i].encoded;
1634     }
1635     seq.cValue = sizeof(ints) / sizeof(ints[0]);
1636     seq.rgValue = blobs;
1637
1638     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1639      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1640     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1641     if (buf)
1642     {
1643         ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1644          sizeof(intSequence), bufSize);
1645         ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1646         LocalFree(buf);
1647     }
1648     /* Change the type of the first element in the sequence, and give it
1649      * another go
1650      */
1651     blobs[0].cbData = times[0].encodedTime[1] + 2;
1652     blobs[0].pbData = (BYTE *)times[0].encodedTime;
1653     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1654      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1655     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1656     if (buf)
1657     {
1658         ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1659          sizeof(mixedSequence), bufSize);
1660         ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1661          "Unexpected value\n");
1662         LocalFree(buf);
1663     }
1664 }
1665
1666 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1667 {
1668     BOOL ret;
1669     BYTE *buf = NULL;
1670     DWORD bufSize = 0;
1671
1672     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1673      intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1674     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1675     if (buf)
1676     {
1677         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1678         DWORD i;
1679
1680         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1681          "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1682          seq->cValue);
1683         for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1684         {
1685             ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1686              "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1687              seq->rgValue[i].cbData);
1688             ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1689              ints[i].encoded[1] + 2), "Unexpected value\n");
1690         }
1691         LocalFree(buf);
1692     }
1693     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1694      mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1695      &bufSize);
1696     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1697     if (buf)
1698     {
1699         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1700
1701         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1702          "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1703          seq->cValue);
1704         /* Just check the first element since it's all that changed */
1705         ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1706          "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1707          seq->rgValue[0].cbData);
1708         ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1709          times[0].encodedTime[1] + 2), "Unexpected value\n");
1710         LocalFree(buf);
1711     }
1712 }
1713
1714 struct encodedExtensions
1715 {
1716     CERT_EXTENSIONS exts;
1717     const BYTE *encoded;
1718 };
1719
1720 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1721 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1722
1723 static CERT_EXTENSION criticalExt =
1724  { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1725 static CERT_EXTENSION nonCriticalExt =
1726  { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1727
1728 static const BYTE ext0[] = { 0x30,0x00 };
1729 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1730                              0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1731 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1732                              0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1733
1734 static const struct encodedExtensions exts[] = {
1735  { { 0, NULL }, ext0 },
1736  { { 1, &criticalExt }, ext1 },
1737  { { 1, &nonCriticalExt }, ext2 },
1738 };
1739
1740 static void test_encodeExtensions(DWORD dwEncoding)
1741 {
1742     DWORD i;
1743
1744     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1745     {
1746         BOOL ret;
1747         BYTE *buf = NULL;
1748         DWORD bufSize = 0;
1749
1750         ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1751          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1752         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1753         if (buf)
1754         {
1755             ok(bufSize == exts[i].encoded[1] + 2,
1756              "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1757             ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1758              "Unexpected value\n");
1759             LocalFree(buf);
1760         }
1761     }
1762 }
1763
1764 static void test_decodeExtensions(DWORD dwEncoding)
1765 {
1766     DWORD i;
1767
1768     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1769     {
1770         BOOL ret;
1771         BYTE *buf = NULL;
1772         DWORD bufSize = 0;
1773
1774         ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1775          exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1776          NULL, (BYTE *)&buf, &bufSize);
1777         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1778         if (buf)
1779         {
1780             CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1781             DWORD j;
1782
1783             ok(ext->cExtension == exts[i].exts.cExtension,
1784              "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1785              ext->cExtension);
1786             for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1787             {
1788                 ok(!strcmp(ext->rgExtension[j].pszObjId,
1789                  exts[i].exts.rgExtension[j].pszObjId),
1790                  "Expected OID %s, got %s\n",
1791                  exts[i].exts.rgExtension[j].pszObjId,
1792                  ext->rgExtension[j].pszObjId);
1793                 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1794                  exts[i].exts.rgExtension[j].Value.pbData,
1795                  exts[i].exts.rgExtension[j].Value.cbData),
1796                  "Unexpected value\n");
1797             }
1798             LocalFree(buf);
1799         }
1800     }
1801 }
1802
1803 /* MS encodes public key info with a NULL if the algorithm identifier's
1804  * parameters are empty.  However, when encoding an algorithm in a CERT_INFO,
1805  * it encodes them by omitting the algorithm parameters.  This latter approach
1806  * seems more correct, so accept either form.
1807  */
1808 struct encodedPublicKey
1809 {
1810     CERT_PUBLIC_KEY_INFO info;
1811     const BYTE *encoded;
1812     const BYTE *encodedNoNull;
1813     CERT_PUBLIC_KEY_INFO decoded;
1814 };
1815
1816 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1817  0xe, 0xf };
1818 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1819
1820 static const unsigned char bin64[] = {
1821     0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00,0};
1822 static const unsigned char bin65[] = {
1823     0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00,0};
1824 static const unsigned char bin66[] = {
1825     0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00,0};
1826 static const unsigned char bin67[] = {
1827     0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00,0};
1828 static const unsigned char bin68[] = {
1829     0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1830     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0};
1831 static const unsigned char bin69[] = {
1832     0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
1833     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0};
1834 static const unsigned char bin70[] = {
1835     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1836     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1837     0x0f,0};
1838 static const unsigned char bin71[] = {
1839     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1840     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1841     0x0f,0};
1842 static unsigned char bin72[] = { 0x05,0x00,0};
1843
1844 static const struct encodedPublicKey pubKeys[] = {
1845  /* with a bogus OID */
1846  { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1847   bin64, bin65,
1848   { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
1849  /* some normal keys */
1850  { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1851   bin66, bin67,
1852   { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
1853  { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
1854   bin68, bin69,
1855   { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
1856  /* with add'l parameters--note they must be DER-encoded */
1857  { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1858   (BYTE *)aKey, 0 } },
1859   bin70, bin71,
1860   { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1861   (BYTE *)aKey, 0 } } },
1862 };
1863
1864 static void test_encodePublicKeyInfo(DWORD dwEncoding)
1865 {
1866     DWORD i;
1867
1868     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1869     {
1870         BOOL ret;
1871         BYTE *buf = NULL;
1872         DWORD bufSize = 0;
1873
1874         ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1875          &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1876          &bufSize);
1877         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1878         if (buf)
1879         {
1880             ok(bufSize == pubKeys[i].encoded[1] + 2 ||
1881              bufSize == pubKeys[i].encodedNoNull[1] + 2,
1882              "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
1883              pubKeys[i].encodedNoNull[1] + 2, bufSize);
1884             if (bufSize == pubKeys[i].encoded[1] + 2)
1885                 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
1886                  "Unexpected value\n");
1887             else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
1888                 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
1889                  pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
1890             LocalFree(buf);
1891         }
1892     }
1893 }
1894
1895 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
1896  const CERT_PUBLIC_KEY_INFO *got)
1897 {
1898     ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
1899      "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
1900      got->Algorithm.pszObjId);
1901     ok(expected->Algorithm.Parameters.cbData ==
1902      got->Algorithm.Parameters.cbData,
1903      "Expected parameters of %ld bytes, got %ld\n",
1904      expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
1905     if (expected->Algorithm.Parameters.cbData)
1906         ok(!memcmp(expected->Algorithm.Parameters.pbData,
1907          got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
1908          "Unexpected algorithm parameters\n");
1909     ok(expected->PublicKey.cbData == got->PublicKey.cbData,
1910      "Expected public key of %ld bytes, got %ld\n",
1911      expected->PublicKey.cbData, got->PublicKey.cbData);
1912     if (expected->PublicKey.cbData)
1913         ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
1914          got->PublicKey.cbData), "Unexpected public key value\n");
1915 }
1916
1917 static void test_decodePublicKeyInfo(DWORD dwEncoding)
1918 {
1919     static const BYTE bogusPubKeyInfo[] =
1920      "\x30\x22\x30\x0d\x06\x06\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x01\x01"
1921      "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1922      "\x0f";
1923     DWORD i;
1924     BOOL ret;
1925     BYTE *buf = NULL;
1926     DWORD bufSize = 0;
1927
1928     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1929     {
1930         /* The NULL form decodes to the decoded member */
1931         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1932          pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1933          NULL, (BYTE *)&buf, &bufSize);
1934         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1935         if (buf)
1936         {
1937             comparePublicKeyInfo(&pubKeys[i].decoded,
1938              (CERT_PUBLIC_KEY_INFO *)buf);
1939             LocalFree(buf);
1940         }
1941         /* The non-NULL form decodes to the original */
1942         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1943          pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
1944          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1945         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1946         if (buf)
1947         {
1948             comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
1949             LocalFree(buf);
1950         }
1951     }
1952     /* Test with bogus (not valid DER) parameters */
1953     ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1954      bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1955      NULL, (BYTE *)&buf, &bufSize);
1956     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1957      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1958 }
1959
1960 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
1961  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
1962  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
1963  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
1964  0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
1965 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
1966  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
1967  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
1968  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1969  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
1970 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
1971  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
1972  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
1973  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1974  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
1975 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
1976  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
1977  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
1978  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
1979  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
1980  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
1981  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1982 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
1983  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
1984  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
1985  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
1986  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
1987  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
1988  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1989 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
1990  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
1991  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
1992  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
1993  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
1994  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
1995  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
1996  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
1997  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
1998  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1999
2000 /* This is the encoded form of the printable string "Juan Lang" */
2001 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
2002  0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
2003  0x61, 0x6e, 0x67, 0x00 };
2004 static const BYTE serialNum[] = { 0x01 };
2005
2006 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2007 {
2008     BOOL ret;
2009     BYTE *buf = NULL;
2010     DWORD size = 0;
2011     CERT_INFO info = { 0 };
2012
2013     /* Test with NULL pvStructInfo */
2014     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2015      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2016     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2017      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2018     /* Test with a V1 cert */
2019     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2020      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2021     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2022     if (buf)
2023     {
2024         ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2025          v1Cert[1] + 2, size);
2026         ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2027         LocalFree(buf);
2028     }
2029     /* Test v2 cert */
2030     info.dwVersion = CERT_V2;
2031     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2032      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2033     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2034     if (buf)
2035     {
2036         ok(size == sizeof(v2Cert), "Expected size %d, got %ld\n",
2037          sizeof(v2Cert), size);
2038         ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2039         LocalFree(buf);
2040     }
2041     /* Test v3 cert */
2042     info.dwVersion = CERT_V3;
2043     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2044      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2045     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2046     if (buf)
2047     {
2048         ok(size == sizeof(v3Cert), "Expected size %d, got %ld\n",
2049          sizeof(v3Cert), size);
2050         ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2051         LocalFree(buf);
2052     }
2053     /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2054      * API doesn't prevent it)
2055      */
2056     info.dwVersion = CERT_V1;
2057     info.cExtension = 1;
2058     info.rgExtension = &criticalExt;
2059     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2060      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2061     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2062     if (buf)
2063     {
2064         ok(size == sizeof(v1CertWithConstraints), "Expected size %d, got %ld\n",
2065          sizeof(v1CertWithConstraints), size);
2066         ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2067         LocalFree(buf);
2068     }
2069     /* test v1 cert with a serial number */
2070     info.SerialNumber.cbData = sizeof(serialNum);
2071     info.SerialNumber.pbData = (BYTE *)serialNum;
2072     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2073      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2074     if (buf)
2075     {
2076         ok(size == sizeof(v1CertWithSerial), "Expected size %d, got %ld\n",
2077          sizeof(v1CertWithSerial), size);
2078         ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2079         LocalFree(buf);
2080     }
2081     /* Test v1 cert with an issuer name, a subject name, and a serial number */
2082     info.Issuer.cbData = sizeof(encodedCommonName);
2083     info.Issuer.pbData = (BYTE *)encodedCommonName;
2084     info.Subject.cbData = sizeof(encodedCommonName);
2085     info.Subject.pbData = (BYTE *)encodedCommonName;
2086     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2087      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2088     if (buf)
2089     {
2090         ok(size == sizeof(bigCert), "Expected size %d, got %ld\n",
2091          sizeof(bigCert), size);
2092         ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2093         LocalFree(buf);
2094     }
2095     /* for now, I let more interesting tests be done for each subcomponent,
2096      * rather than retesting them all here.
2097      */
2098 }
2099
2100 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2101 {
2102     static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2103      v1CertWithConstraints, v1CertWithSerial };
2104     BOOL ret;
2105     BYTE *buf = NULL;
2106     DWORD size = 0, i;
2107
2108     /* Test with NULL pbEncoded */
2109     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2110      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2111     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2112      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2113     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2114      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2115     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2116      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2117     /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2118      * minimum a cert must have a non-zero serial number, an issuer, and a
2119      * subject.
2120      */
2121     for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2122     {
2123         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2124          corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2125          (BYTE *)&buf, &size);
2126         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2127          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2128     }
2129     /* Now check with serial number, subject and issuer specified */
2130     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2131      sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2132     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2133     if (buf)
2134     {
2135         CERT_INFO *info = (CERT_INFO *)buf;
2136
2137         ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
2138          sizeof(CERT_INFO), size);
2139         ok(info->SerialNumber.cbData == 1,
2140          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2141         ok(*info->SerialNumber.pbData == *serialNum,
2142          "Expected serial number %d, got %d\n", *serialNum,
2143          *info->SerialNumber.pbData);
2144         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2145          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2146          info->Issuer.cbData);
2147         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2148          "Unexpected issuer\n");
2149         ok(info->Subject.cbData == sizeof(encodedCommonName),
2150          "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
2151          info->Subject.cbData);
2152         ok(!memcmp(info->Subject.pbData, encodedCommonName,
2153          info->Subject.cbData), "Unexpected subject\n");
2154         LocalFree(buf);
2155     }
2156 }
2157
2158 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2159  0xe, 0xf };
2160
2161 static const BYTE signedBigCert[] = {
2162  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2163  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2164  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2165  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2166  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2167  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2168  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2169  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2170  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2171  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2172  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2173  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2174
2175 static void test_encodeCert(DWORD dwEncoding)
2176 {
2177     /* Note the SignatureAlgorithm must match that in the encoded cert.  Note
2178      * also that bigCert is a NULL-terminated string, so don't count its
2179      * last byte (otherwise the signed cert won't decode.)
2180      */
2181     CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2182      { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2183     BOOL ret;
2184     BYTE *buf = NULL;
2185     DWORD bufSize = 0;
2186
2187     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2188      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2189     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2190     if (buf)
2191     {
2192         ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
2193          sizeof(signedBigCert), bufSize);
2194         ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2195         LocalFree(buf);
2196     }
2197 }
2198
2199 static void test_decodeCert(DWORD dwEncoding)
2200 {
2201     BOOL ret;
2202     BYTE *buf = NULL;
2203     DWORD size = 0;
2204
2205     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2206      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2207     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2208     if (buf)
2209     {
2210         CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2211
2212         ok(info->ToBeSigned.cbData == sizeof(bigCert),
2213          "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert),
2214          info->ToBeSigned.cbData);
2215         ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2216          "Unexpected cert\n");
2217         ok(info->Signature.cbData == sizeof(hash),
2218          "Expected signature size %d, got %ld\n", sizeof(hash),
2219          info->Signature.cbData);
2220         ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2221          "Unexpected signature\n");
2222         LocalFree(buf);
2223     }
2224 }
2225
2226 static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 };
2227 static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15,
2228  0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69,
2229  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2230 static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02,
2231  0x00, 0x03 };
2232 static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13,
2233  0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65,
2234  0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
2235 static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0,
2236  0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
2237  0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11,
2238  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71,
2239  0x2e, 0x6f, 0x72, 0x67 };
2240 static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE |
2241  CRL_REASON_AFFILIATION_CHANGED;
2242
2243 static void test_encodeCRLDistPoints(DWORD dwEncoding)
2244 {
2245     CRL_DIST_POINTS_INFO info = { 0 };
2246     CRL_DIST_POINT point = { { 0 } };
2247     CERT_ALT_NAME_ENTRY entry = { 0 };
2248     BOOL ret;
2249     BYTE *buf = NULL;
2250     DWORD size = 0;
2251
2252     /* Test with an empty info */
2253     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2254      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2255     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
2256      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
2257      GetLastError());
2258     /* Test with one empty dist point */
2259     info.cDistPoint = 1;
2260     info.rgDistPoint = &point;
2261     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2262      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2263     if (buf)
2264     {
2265         ok(size == sizeof(emptyDistPoint), "Expected size %d, got %ld\n",
2266          sizeof(emptyDistPoint), size);
2267         ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n");
2268         LocalFree(buf);
2269     }
2270     /* A dist point with an invalid name */
2271     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2272     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
2273     U(entry).pwszURL = (LPWSTR)nihongoURL;
2274     U(point.DistPointName).FullName.cAltEntry = 1;
2275     U(point.DistPointName).FullName.rgAltEntry = &entry;
2276     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2277      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2278     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
2279      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
2280     /* The first invalid character is at index 7 */
2281     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
2282      "Expected invalid char at index 7, got %ld\n",
2283      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
2284     /* A dist point with (just) a valid name */
2285     U(entry).pwszURL = (LPWSTR)url;
2286     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2287      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2288     if (buf)
2289     {
2290         ok(size == sizeof(distPointWithUrl), "Expected size %d, got %ld\n",
2291          sizeof(distPointWithUrl), size);
2292         ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n");
2293         LocalFree(buf);
2294     }
2295     /* A dist point with (just) reason flags */
2296     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME;
2297     point.ReasonFlags.cbData = sizeof(crlReason);
2298     point.ReasonFlags.pbData = (LPBYTE)&crlReason;
2299     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2300      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2301     if (buf)
2302     {
2303         ok(size == sizeof(distPointWithReason), "Expected size %d, got %ld\n",
2304          sizeof(distPointWithReason), size);
2305         ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n");
2306         LocalFree(buf);
2307     }
2308     /* A dist point with just an issuer */
2309     point.ReasonFlags.cbData = 0;
2310     point.CRLIssuer.cAltEntry = 1;
2311     point.CRLIssuer.rgAltEntry = &entry;
2312     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2313      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2314     if (buf)
2315     {
2316         ok(size == sizeof(distPointWithIssuer), "Expected size %d, got %ld\n",
2317          sizeof(distPointWithIssuer), size);
2318         ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n");
2319         LocalFree(buf);
2320     }
2321     /* A dist point with both a name and an issuer */
2322     point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME;
2323     ret = CryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info,
2324      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2325     if (buf)
2326     {
2327         ok(size == sizeof(distPointWithUrlAndIssuer),
2328          "Expected size %d, got %ld\n", sizeof(distPointWithUrlAndIssuer),
2329          size);
2330         ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n");
2331         LocalFree(buf);
2332     }
2333 }
2334
2335 static void test_decodeCRLDistPoints(DWORD dwEncoding)
2336 {
2337     BOOL ret;
2338     BYTE *buf = NULL;
2339     DWORD size = 0;
2340     PCRL_DIST_POINTS_INFO info;
2341     PCRL_DIST_POINT point;
2342     PCERT_ALT_NAME_ENTRY entry;
2343
2344     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2345      emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2346      (BYTE *)&buf, &size);
2347     if (ret)
2348     {
2349         info = (PCRL_DIST_POINTS_INFO)buf;
2350         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2351          "Expected size at least %d, got %ld\n",
2352          sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2353         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2354          info->cDistPoint);
2355         point = info->rgDistPoint;
2356         ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME,
2357          "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2358          point->DistPointName.dwDistPointNameChoice);
2359         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2360         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2361         LocalFree(buf);
2362     }
2363     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2364      distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2365      (BYTE *)&buf, &size);
2366     if (ret)
2367     {
2368         info = (PCRL_DIST_POINTS_INFO)buf;
2369         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2370          "Expected size at least %d, got %ld\n",
2371          sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2372         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2373          info->cDistPoint);
2374         point = info->rgDistPoint;
2375         ok(point->DistPointName.dwDistPointNameChoice ==
2376          CRL_DIST_POINT_FULL_NAME,
2377          "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2378          point->DistPointName.dwDistPointNameChoice);
2379         ok(U(point->DistPointName).FullName.cAltEntry == 1,
2380          "Expected 1 name entry, got %ld\n",
2381          U(point->DistPointName).FullName.cAltEntry);
2382         entry = U(point->DistPointName).FullName.rgAltEntry;
2383         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2384          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2385         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2386         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2387         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2388         LocalFree(buf);
2389     }
2390     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2391      distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2392      NULL, (BYTE *)&buf, &size);
2393     if (ret)
2394     {
2395         info = (PCRL_DIST_POINTS_INFO)buf;
2396         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2397          "Expected size at least %d, got %ld\n",
2398          sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2399         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2400          info->cDistPoint);
2401         point = info->rgDistPoint;
2402         ok(point->DistPointName.dwDistPointNameChoice ==
2403          CRL_DIST_POINT_NO_NAME,
2404          "Expected CRL_DIST_POINT_NO_NAME, got %ld\n",
2405          point->DistPointName.dwDistPointNameChoice);
2406         ok(point->ReasonFlags.cbData == sizeof(crlReason),
2407          "Expected reason length\n");
2408         ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)),
2409          "Unexpected reason\n");
2410         ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n");
2411         LocalFree(buf);
2412     }
2413     ret = CryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS,
2414      distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2,
2415      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2416     if (ret)
2417     {
2418         info = (PCRL_DIST_POINTS_INFO)buf;
2419         ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT),
2420          "Expected size at least %d, got %ld\n",
2421          sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), size);
2422         ok(info->cDistPoint == 1, "Expected 1 dist points, got %ld\n",
2423          info->cDistPoint);
2424         point = info->rgDistPoint;
2425         ok(point->DistPointName.dwDistPointNameChoice ==
2426          CRL_DIST_POINT_FULL_NAME,
2427          "Expected CRL_DIST_POINT_FULL_NAME, got %ld\n",
2428          point->DistPointName.dwDistPointNameChoice);
2429         ok(U(point->DistPointName).FullName.cAltEntry == 1,
2430          "Expected 1 name entry, got %ld\n",
2431          U(point->DistPointName).FullName.cAltEntry);
2432         entry = U(point->DistPointName).FullName.rgAltEntry;
2433         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2434          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2435         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2436         ok(point->ReasonFlags.cbData == 0, "Expected no reason\n");
2437         ok(point->CRLIssuer.cAltEntry == 1,
2438          "Expected 1 issuer entry, got %ld\n", point->CRLIssuer.cAltEntry);
2439         entry = point->CRLIssuer.rgAltEntry;
2440         ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL,
2441          "Expected CERT_ALT_NAME_URL, got %ld\n", entry->dwAltNameChoice);
2442         ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n");
2443         LocalFree(buf);
2444     }
2445 }
2446
2447 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2448  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2449  0x30, 0x5a };
2450 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2451  0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2452  0x30, 0x30, 0x30, 0x30, 0x5a };
2453 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2454  0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2455  0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2456  0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2457  0x5a };
2458 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2459  0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2460  0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2461  0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2462  0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2463  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2464 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2465  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2466  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2467  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2468  0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2469  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2470 static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
2471  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2472  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
2473  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2474  0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2475  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
2476  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2477  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2478
2479 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2480 {
2481     BOOL ret;
2482     BYTE *buf = NULL;
2483     DWORD size = 0;
2484     CRL_INFO info = { 0 };
2485     CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2486
2487     /* Test with a V1 CRL */
2488     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2489      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2490     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2491     if (buf)
2492     {
2493         ok(size == sizeof(v1CRL), "Expected size %d, got %ld\n",
2494          sizeof(v1CRL), size);
2495         ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2496         LocalFree(buf);
2497     }
2498     /* Test v2 CRL */
2499     info.dwVersion = CRL_V2;
2500     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2501      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2502     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2503     if (buf)
2504     {
2505         ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2506          v2CRL[1] + 2, size);
2507         ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2508         LocalFree(buf);
2509     }
2510     /* v1 CRL with a name */
2511     info.dwVersion = CRL_V1;
2512     info.Issuer.cbData = sizeof(encodedCommonName);
2513     info.Issuer.pbData = (BYTE *)encodedCommonName;
2514     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2515      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2516     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2517     if (buf)
2518     {
2519         ok(size == sizeof(v1CRLWithIssuer), "Expected size %d, got %ld\n",
2520          sizeof(v1CRLWithIssuer), size);
2521         ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2522         LocalFree(buf);
2523     }
2524     /* v1 CRL with a name and a NULL entry pointer */
2525     info.cCRLEntry = 1;
2526     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2527      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2528     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2529      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2530     /* now set an empty entry */
2531     info.rgCRLEntry = &entry;
2532     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2533      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2534     if (buf)
2535     {
2536         ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2537          "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEmptyEntry),
2538          size);
2539         ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2540          "Got unexpected value\n");
2541         LocalFree(buf);
2542     }
2543     /* an entry with a serial number */
2544     entry.SerialNumber.cbData = sizeof(serialNum);
2545     entry.SerialNumber.pbData = (BYTE *)serialNum;
2546     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2547      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2548     if (buf)
2549     {
2550         ok(size == sizeof(v1CRLWithIssuerAndEntry),
2551          "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEntry), size);
2552         ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2553          "Got unexpected value\n");
2554         LocalFree(buf);
2555     }
2556     /* and finally, an entry with an extension */
2557     entry.cExtension = 1;
2558     entry.rgExtension = &criticalExt;
2559     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2560      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2561     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2562     if (buf)
2563     {
2564         ok(size == sizeof(v1CRLWithExt), "Expected size %d, got %ld\n",
2565          sizeof(v1CRLWithExt), size);
2566         ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2567         LocalFree(buf);
2568     }
2569 }
2570
2571 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
2572 {
2573     static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
2574     BOOL ret;
2575     BYTE *buf = NULL;
2576     DWORD size = 0, i;
2577
2578     for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
2579     {
2580         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2581          corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2582          (BYTE *)&buf, &size);
2583         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2584          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2585     }
2586     /* at a minimum, a CRL must contain an issuer: */
2587     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2588      v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2589      (BYTE *)&buf, &size);
2590     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2591     if (buf)
2592     {
2593         CRL_INFO *info = (CRL_INFO *)buf;
2594
2595         ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2596          sizeof(CRL_INFO), size);
2597         ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
2598          info->cCRLEntry);
2599         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2600          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2601          info->Issuer.cbData);
2602         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2603          "Unexpected issuer\n");
2604         LocalFree(buf);
2605     }
2606     /* check decoding with an empty CRL entry */
2607     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2608      v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
2609      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2610     todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2611      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2612     /* with a real CRL entry */
2613     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2614      v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
2615      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2616     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2617     if (buf)
2618     {
2619         CRL_INFO *info = (CRL_INFO *)buf;
2620         CRL_ENTRY *entry;
2621
2622         ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2623          sizeof(CRL_INFO), size);
2624         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2625          info->cCRLEntry);
2626         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2627         entry = info->rgCRLEntry;
2628         ok(entry->SerialNumber.cbData == 1,
2629          "Expected serial number size 1, got %ld\n",
2630          entry->SerialNumber.cbData);
2631         ok(*entry->SerialNumber.pbData == *serialNum,
2632          "Expected serial number %d, got %d\n", *serialNum,
2633          *entry->SerialNumber.pbData);
2634         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2635          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2636          info->Issuer.cbData);
2637         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2638          "Unexpected issuer\n");
2639     }
2640     /* and finally, with an extension */
2641     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2642      v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2643      NULL, (BYTE *)&buf, &size);
2644     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2645     if (buf)
2646     {
2647         CRL_INFO *info = (CRL_INFO *)buf;
2648         CRL_ENTRY *entry;
2649
2650         ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2651          sizeof(CRL_INFO), size);
2652         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2653          info->cCRLEntry);
2654         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2655         entry = info->rgCRLEntry;
2656         ok(entry->SerialNumber.cbData == 1,
2657          "Expected serial number size 1, got %ld\n",
2658          entry->SerialNumber.cbData);
2659         ok(*entry->SerialNumber.pbData == *serialNum,
2660          "Expected serial number %d, got %d\n", *serialNum,
2661          *entry->SerialNumber.pbData);
2662         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2663          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2664          info->Issuer.cbData);
2665         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2666          "Unexpected issuer\n");
2667         /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2668          * bug, or am I missing something?
2669          */
2670         ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2671          info->cExtension);
2672     }
2673 }
2674
2675 /* Free *pInfo with HeapFree */
2676 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
2677 {
2678     BOOL ret;
2679     DWORD size = 0;
2680     HCRYPTKEY key;
2681
2682     /* This crashes
2683     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
2684      */
2685     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
2686     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2687      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2688     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
2689      &size);
2690     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2691      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2692     ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
2693      NULL, &size);
2694     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2695      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2696     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2697      0, NULL, NULL, &size);
2698     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2699      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2700     /* Test with no key */
2701     ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2702      0, NULL, NULL, &size);
2703     ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
2704      GetLastError());
2705     ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
2706     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
2707     if (ret)
2708     {
2709         ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
2710          NULL, 0, NULL, NULL, &size);
2711         ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2712         *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
2713         if (*pInfo)
2714         {
2715             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
2716              X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
2717             ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
2718              GetLastError());
2719             if (ret)
2720             {
2721                 /* By default (we passed NULL as the OID) the OID is
2722                  * szOID_RSA_RSA.
2723                  */
2724                 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
2725                  "Expected %s, got %s\n", szOID_RSA_RSA,
2726                  (*pInfo)->Algorithm.pszObjId);
2727             }
2728         }
2729     }
2730 }
2731
2732 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
2733 {
2734     BOOL ret;
2735     HCRYPTKEY key;
2736
2737     /* These crash
2738     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
2739     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
2740     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
2741     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2742      NULL);
2743      */
2744     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
2745     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2746      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2747     ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
2748     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2749      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2750     ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
2751      &key);
2752     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2753      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2754     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2755      &key);
2756     ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2757     CryptDestroyKey(key);
2758 }
2759
2760 static const char cspName[] = "WineCryptTemp";
2761
2762 static void testPortPublicKeyInfo(void)
2763 {
2764     HCRYPTPROV csp;
2765     BOOL ret;
2766     PCERT_PUBLIC_KEY_INFO info = NULL;
2767
2768     /* Just in case a previous run failed, delete this thing */
2769     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2770      CRYPT_DELETEKEYSET);
2771     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2772      CRYPT_NEWKEYSET);
2773
2774     testExportPublicKey(csp, &info);
2775     testImportPublicKey(csp, info);
2776
2777     HeapFree(GetProcessHeap(), 0, info);
2778     CryptReleaseContext(csp, 0);
2779     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2780      CRYPT_DELETEKEYSET);
2781 }
2782
2783 START_TEST(encode)
2784 {
2785     static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
2786      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
2787     DWORD i;
2788
2789     for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
2790     {
2791         test_encodeInt(encodings[i]);
2792         test_decodeInt(encodings[i]);
2793         test_encodeEnumerated(encodings[i]);
2794         test_decodeEnumerated(encodings[i]);
2795         test_encodeFiletime(encodings[i]);
2796         test_decodeFiletime(encodings[i]);
2797         test_encodeName(encodings[i]);
2798         test_decodeName(encodings[i]);
2799         test_encodeAltName(encodings[i]);
2800         test_decodeAltName(encodings[i]);
2801         test_encodeOctets(encodings[i]);
2802         test_decodeOctets(encodings[i]);
2803         test_encodeBits(encodings[i]);
2804         test_decodeBits(encodings[i]);
2805         test_encodeBasicConstraints(encodings[i]);
2806         test_decodeBasicConstraints(encodings[i]);
2807         test_encodeRsaPublicKey(encodings[i]);
2808         test_decodeRsaPublicKey(encodings[i]);
2809         test_encodeSequenceOfAny(encodings[i]);
2810         test_decodeSequenceOfAny(encodings[i]);
2811         test_encodeExtensions(encodings[i]);
2812         test_decodeExtensions(encodings[i]);
2813         test_encodePublicKeyInfo(encodings[i]);
2814         test_decodePublicKeyInfo(encodings[i]);
2815         test_encodeCertToBeSigned(encodings[i]);
2816         test_decodeCertToBeSigned(encodings[i]);
2817         test_encodeCert(encodings[i]);
2818         test_decodeCert(encodings[i]);
2819         test_encodeCRLDistPoints(encodings[i]);
2820         test_decodeCRLDistPoints(encodings[i]);
2821         test_encodeCRLToBeSigned(encodings[i]);
2822         test_decodeCRLToBeSigned(encodings[i]);
2823     }
2824     testPortPublicKeyInfo();
2825 }