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