Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[wine] / dlls / crypt32 / tests / encode.c
1 /*
2  * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
3  *
4  * Copyright 2005 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
26
27 #include "wine/test.h"
28
29 struct encodedInt
30 {
31     int val;
32     const BYTE *encoded;
33 };
34
35 static const BYTE bin1[] = {0x02,0x01,0x01,0};
36 static const BYTE bin2[] = {0x02,0x01,0x7f,0};
37 static const BYTE bin3[] = {0x02,0x02,0x00,0x80,0};
38 static const BYTE bin4[] = {0x02,0x02,0x01,0x00,0};
39 static const BYTE bin5[] = {0x02,0x01,0x80,0};
40 static const BYTE bin6[] = {0x02,0x02,0xff,0x7f,0};
41 static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d,0};
42
43 static const struct encodedInt ints[] = {
44  { 1,          bin1 },
45  { 127,        bin2 },
46  { 128,        bin3 },
47  { 256,        bin4 },
48  { -128,       bin5 },
49  { -129,       bin6 },
50  { 0xbaddf00d, bin7 },
51 };
52
53 struct encodedBigInt
54 {
55     const BYTE *val;
56     const BYTE *encoded;
57     const BYTE *decoded;
58 };
59
60 static const BYTE bin8[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
61 static const BYTE bin9[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
62 static const BYTE bin10[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
63
64 static const BYTE bin11[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
65 static const BYTE bin12[] = {0x02,0x09,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
66 static const BYTE bin13[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0};
67
68 static const struct encodedBigInt bigInts[] = {
69  { bin8, bin9, bin10 },
70  { bin11, bin12, bin13 },
71 };
72
73 static const BYTE bin14[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
74 static const BYTE bin15[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0};
75 static const BYTE bin16[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0};
76 static const BYTE bin17[] = {0x02,0x0c,0x00,0xff,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0};
77
78 /* Decoded is the same as original, so don't bother storing a separate copy */
79 static const struct encodedBigInt bigUInts[] = {
80  { bin14, bin15, NULL },
81  { bin16, bin17, NULL },
82 };
83
84 static void test_encodeInt(DWORD dwEncoding)
85 {
86     DWORD bufSize = 0;
87     int i;
88     BOOL ret;
89     CRYPT_INTEGER_BLOB blob;
90     BYTE *buf = NULL;
91
92     /* CryptEncodeObjectEx with NULL bufSize crashes..
93     ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
94      NULL);
95      */
96     /* check bogus encoding */
97     ret = CryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
98      &bufSize);
99     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
100      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
101     /* check with NULL integer buffer.  Windows XP incorrectly returns an
102      * NTSTATUS.
103      */
104     ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
105      &bufSize);
106     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
107      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
108     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
109     {
110         /* encode as normal integer */
111         ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
112          NULL, NULL, &bufSize);
113         ok(ret, "Expected success, got %ld\n", GetLastError());
114         ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
115          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
116         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
117         if (buf)
118         {
119             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
120              buf[0]);
121             ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
122              buf[1], ints[i].encoded[1]);
123             ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
124              "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
125             LocalFree(buf);
126         }
127         /* encode as multibyte integer */
128         blob.cbData = sizeof(ints[i].val);
129         blob.pbData = (BYTE *)&ints[i].val;
130         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
131          0, NULL, NULL, &bufSize);
132         ok(ret, "Expected success, got %ld\n", GetLastError());
133         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
134          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
135         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
136         if (buf)
137         {
138             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
139              buf[0]);
140             ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
141              buf[1], ints[i].encoded[1]);
142             ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
143              "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
144             LocalFree(buf);
145         }
146     }
147     /* encode a couple bigger ints, just to show it's little-endian and leading
148      * sign bytes are dropped
149      */
150     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
151     {
152         blob.cbData = strlen((const char*)bigInts[i].val);
153         blob.pbData = (BYTE *)bigInts[i].val;
154         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
155          0, NULL, NULL, &bufSize);
156         ok(ret, "Expected success, got %ld\n", GetLastError());
157         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
158          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
159         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
160         if (buf)
161         {
162             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
163              buf[0]);
164             ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
165              buf[1], bigInts[i].encoded[1]);
166             ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
167              bigInts[i].encoded[1] + 1),
168              "Encoded value didn't match expected\n");
169             LocalFree(buf);
170         }
171     }
172     /* and, encode some uints */
173     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
174     {
175         blob.cbData = strlen((const char*)bigUInts[i].val);
176         blob.pbData = (BYTE*)bigUInts[i].val;
177         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
178          0, NULL, NULL, &bufSize);
179         ok(ret, "Expected success, got %ld\n", GetLastError());
180         ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
181          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
182         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
183         if (buf)
184         {
185             ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
186              buf[0]);
187             ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
188              buf[1], bigUInts[i].encoded[1]);
189             ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
190              bigUInts[i].encoded[1] + 1),
191              "Encoded value didn't match expected\n");
192             LocalFree(buf);
193         }
194     }
195 }
196
197 static void test_decodeInt(DWORD dwEncoding)
198 {
199     static const BYTE bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
200     static const BYTE testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
201     static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
202     static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
203     BYTE *buf = NULL;
204     DWORD bufSize = 0;
205     int i;
206     BOOL ret;
207
208     /* CryptDecodeObjectEx with NULL bufSize crashes..
209     ret = CryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded, 
210      ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
211      */
212     /* check bogus encoding */
213     ret = CryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded, 
214      ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
215     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
216      "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
217     /* check with NULL integer buffer */
218     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
219      &bufSize);
220     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
221      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
222     /* check with a valid, but too large, integer */
223     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
224      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
225     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
226      "Expected CRYPT_E_ASN1_LARGE, got %ld\n", GetLastError());
227     /* check with a DER-encoded string */
228     ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
229      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
230     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
231      "Expected CRYPT_E_ASN1_BADTAG, got %ld\n", GetLastError());
232     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
233     {
234         /* When the output buffer is NULL, this always succeeds */
235         SetLastError(0xdeadbeef);
236         ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
237          (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
238          &bufSize);
239         ok(ret && GetLastError() == NOERROR,
240          "Expected success and NOERROR, got %ld\n", GetLastError());
241         ret = CryptDecodeObjectEx(dwEncoding, X509_INTEGER,
242          (BYTE *)ints[i].encoded, ints[i].encoded[1] + 2,
243          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
244         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
245         ok(bufSize == sizeof(int), "Expected size %d, got %ld\n", sizeof(int),
246          bufSize);
247         ok(buf != NULL, "Expected allocated buffer\n");
248         if (buf)
249         {
250             ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
251              ints[i].val, *(int *)buf);
252             LocalFree(buf);
253         }
254     }
255     for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
256     {
257         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
258          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
259          &bufSize);
260         ok(ret && GetLastError() == NOERROR,
261          "Expected success and NOERROR, got %ld\n", GetLastError());
262         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
263          (BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
264          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
265         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
266         ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
267          "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
268          bufSize);
269         ok(buf != NULL, "Expected allocated buffer\n");
270         if (buf)
271         {
272             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
273
274             ok(blob->cbData == strlen((const char*)bigInts[i].decoded),
275              "Expected len %d, got %ld\n", strlen((const char*)bigInts[i].decoded),
276              blob->cbData);
277             ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
278              "Unexpected value\n");
279             LocalFree(buf);
280         }
281     }
282     for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
283     {
284         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
285          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
286          &bufSize);
287         ok(ret && GetLastError() == NOERROR,
288          "Expected success and NOERROR, got %ld\n", GetLastError());
289         ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
290          (BYTE *)bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
291          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
292         ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
293         ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
294          "Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
295          bufSize);
296         ok(buf != NULL, "Expected allocated buffer\n");
297         if (buf)
298         {
299             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
300
301             ok(blob->cbData == strlen((const char*)bigUInts[i].val),
302              "Expected len %d, got %ld\n", strlen((const char*)bigUInts[i].val),
303              blob->cbData);
304             ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
305              "Unexpected value\n");
306             LocalFree(buf);
307         }
308     }
309     /* Decode the value 1 with long-form length */
310     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
311      sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
312     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
313     if (buf)
314     {
315         ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
316         LocalFree(buf);
317     }
318     /* Try to decode some bogus large items */
319     /* The buffer size is smaller than the encoded length, so this should fail
320      * with CRYPT_E_ASN1_EOD if it's being decoded.
321      * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
322      * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
323      * So this test unfortunately isn't useful.
324     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
325      0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
326     ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
327      "Expected CRYPT_E_ASN1_LARGE, got %08lx\n", GetLastError());
328      */
329     /* This will try to decode the buffer and overflow it, check that it's
330      * caught.
331      */
332     ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
333      0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
334     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
335      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
336 }
337
338 static const BYTE bin18[] = {0x0a,0x01,0x01,0};
339 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80,0};
340
341 /* These are always encoded unsigned, and aren't constrained to be any
342  * particular value
343  */
344 static const struct encodedInt enums[] = {
345  { 1,    bin18 },
346  { -128, bin19 },
347 };
348
349 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
350  * X509_ENUMERATED.
351  */
352 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
353  szOID_CRL_REASON_CODE };
354
355 static void test_encodeEnumerated(DWORD dwEncoding)
356 {
357     DWORD i, j;
358
359     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
360     {
361         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
362         {
363             BOOL ret;
364             BYTE *buf = NULL;
365             DWORD bufSize = 0;
366
367             ret = CryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
368              &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
369              &bufSize);
370             ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
371             if (buf)
372             {
373                 ok(buf[0] == 0xa,
374                  "Got unexpected type %d for enumerated (expected 0xa)\n",
375                  buf[0]);
376                 ok(buf[1] == enums[j].encoded[1],
377                  "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
378                 ok(!memcmp(buf + 1, enums[j].encoded + 1,
379                  enums[j].encoded[1] + 1),
380                  "Encoded value of 0x%08x didn't match expected\n",
381                  enums[j].val);
382                 LocalFree(buf);
383             }
384         }
385     }
386 }
387
388 static void test_decodeEnumerated(DWORD dwEncoding)
389 {
390     DWORD i, j;
391
392     for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
393     {
394         for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
395         {
396             BOOL ret;
397             DWORD bufSize = sizeof(int);
398             int val;
399
400             ret = CryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
401              enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
402              (BYTE *)&val, &bufSize);
403             ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
404             ok(bufSize == sizeof(int),
405              "Got unexpected size %ld for enumerated (expected %d)\n",
406              bufSize, sizeof(int));
407             ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
408              val, enums[j].val);
409         }
410     }
411 }
412
413 struct encodedFiletime
414 {
415     SYSTEMTIME sysTime;
416     const BYTE *encodedTime;
417 };
418
419 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
420  const struct encodedFiletime *time)
421 {
422     FILETIME ft = { 0 };
423     BYTE *buf = NULL;
424     DWORD bufSize = 0;
425     BOOL ret;
426
427     ret = SystemTimeToFileTime(&time->sysTime, &ft);
428     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
429     ret = CryptEncodeObjectEx(dwEncoding, structType, &ft,
430      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
431     /* years other than 1950-2050 are not allowed for encodings other than
432      * X509_CHOICE_OF_TIME.
433      */
434     if (structType == X509_CHOICE_OF_TIME ||
435      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
436     {
437         ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
438          GetLastError());
439         ok(buf != NULL, "Expected an allocated buffer\n");
440         if (buf)
441         {
442             ok(buf[0] == time->encodedTime[0],
443              "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
444              buf[0]);
445             ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
446              time->encodedTime[1], bufSize);
447             ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
448              "Got unexpected value for time encoding\n");
449             LocalFree(buf);
450         }
451     }
452     else
453         ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
454          "Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
455 }
456
457 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
458  const struct encodedFiletime *time)
459 {
460     FILETIME ft1 = { 0 }, ft2 = { 0 };
461     DWORD size = sizeof(ft2);
462     BOOL ret;
463
464     ret = SystemTimeToFileTime(&time->sysTime, &ft1);
465     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
466     ret = CryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
467      time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
468     /* years other than 1950-2050 are not allowed for encodings other than
469      * X509_CHOICE_OF_TIME.
470      */
471     if (structType == X509_CHOICE_OF_TIME ||
472      (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
473     {
474         ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
475          GetLastError());
476         ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
477          "Got unexpected value for time decoding\n");
478     }
479     else
480         ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
481          "Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
482 }
483
484 static const BYTE bin20[] = {
485     0x17,0x0d,'0','5','0','6','0','6','1','6','1','0','0','0','Z',0};
486 static const BYTE bin21[] = {
487     0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z',0};
488 static const BYTE bin22[] = {
489     0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z',0};
490
491 static const struct encodedFiletime times[] = {
492  { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 },
493  { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 },
494  { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 },
495 };
496
497 static void test_encodeFiletime(DWORD dwEncoding)
498 {
499     DWORD i;
500
501     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
502     {
503         testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
504         testTimeEncoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
505         testTimeEncoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
506     }
507 }
508
509 static const BYTE bin23[] = {
510     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','0','0','0','Z',0};
511 static const BYTE bin24[] = {
512     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','9','9','9','Z',0};
513 static const BYTE bin25[] = {
514     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','+','0','1','0','0',0};
515 static const BYTE bin26[] = {
516     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','0','0',0};
517 static const BYTE bin27[] = {
518     0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','1','5',0};
519 static const BYTE bin28[] = {
520     0x18,0x0a,'2','1','4','5','0','6','0','6','1','6',0};
521 static const BYTE bin29[] = {
522     0x17,0x0a,'4','5','0','6','0','6','1','6','1','0',0};
523 static const BYTE bin30[] = {
524     0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z',0};
525 static const BYTE bin31[] = {
526     0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1',0};
527 static const BYTE bin32[] = {
528     0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1',0};
529 static const BYTE bin33[] = {
530     0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0',0};
531 static const BYTE bin34[] = {
532     0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0',0};
533 static const BYTE bin35[] = {
534     0x17,0x08, '4','5','0','6','0','6','1','6',0};
535 static const BYTE bin36[] = {
536     0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z',0};
537 static const BYTE bin37[] = {
538     0x18,0x04, '2','1','4','5',0};
539 static const BYTE bin38[] = {
540     0x18,0x08, '2','1','4','5','0','6','0','6',0};
541
542 static void test_decodeFiletime(DWORD dwEncoding)
543 {
544     static const struct encodedFiletime otherTimes[] = {
545      { { 1945, 6, 1, 6, 16, 10, 0, 0 },   bin23 },
546      { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 },
547      { { 1945, 6, 1, 6, 17, 10, 0, 0 },   bin25 },
548      { { 1945, 6, 1, 6, 15, 10, 0, 0 },   bin26 },
549      { { 1945, 6, 1, 6, 14, 55, 0, 0 },   bin27 },
550      { { 2145, 6, 1, 6, 16,  0, 0, 0 },   bin28 },
551      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   bin29 },
552      { { 2045, 6, 1, 6, 16, 10, 0, 0 },   bin30 },
553      { { 2045, 6, 1, 6, 17, 10, 0, 0 },   bin31 },
554      { { 2045, 6, 1, 6, 15, 10, 0, 0 },   bin32 },
555      { { 2045, 6, 1, 6, 17, 10, 0, 0 },   bin33 },
556      { { 2045, 6, 1, 6, 15, 10, 0, 0 },   bin34 },
557     };
558     /* An oddball case that succeeds in Windows, but doesn't seem correct
559      { { 2145, 6, 1, 2, 11, 31, 0, 0 },   "\x18" "\x13" "21450606161000-9999" },
560      */
561     static const unsigned char *bogusTimes[] = {
562      /* oddly, this succeeds on Windows, with year 2765
563      "\x18" "\x0f" "21r50606161000Z",
564       */
565      bin35,
566      bin36,
567      bin37,
568      bin38,
569     };
570     DWORD i, size;
571     FILETIME ft1 = { 0 }, ft2 = { 0 };
572     BOOL ret;
573
574     /* Check bogus length with non-NULL buffer */
575     ret = SystemTimeToFileTime(&times[0].sysTime, &ft1);
576     ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
577     size = 1;
578     ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
579      times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
580     ok(!ret && GetLastError() == ERROR_MORE_DATA,
581      "Expected ERROR_MORE_DATA, got %ld\n", GetLastError());
582     /* Normal tests */
583     for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
584     {
585         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &times[i]);
586         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &times[i]);
587         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &times[i]);
588     }
589     for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
590     {
591         testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
592         testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
593         testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
594     }
595     for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
596     {
597         size = sizeof(ft1);
598         ret = CryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
599          bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
600         ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
601          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
602     }
603 }
604
605 struct EncodedName
606 {
607     CERT_RDN_ATTR attr;
608     const BYTE *encoded;
609 };
610
611 static const char commonName[] = "Juan Lang";
612 static const char surName[] = "Lang";
613 static const char bogusIA5[] = "\x80";
614 static const char bogusPrintable[] = "~";
615 static const char bogusNumeric[] = "A";
616 static const unsigned char bin39[] = {
617     0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
618 static const unsigned char bin40[] = {
619     0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x16,0x0a,'J','u','a','n',' ','L','a','n','g',0};
620 static const unsigned char bin41[] = {
621     0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x16,0x05,'L','a','n','g',0};
622 static const unsigned char bin42[] = {
623     0x30,0x12,0x31,0x10,0x30,0x0e,0x06,0x00,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0};
624 static const unsigned char bin43[] = {
625     0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x16,0x02,0x80,0};
626 static const unsigned char bin44[] = {
627     0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x13,0x02,0x7e,0};
628 static const unsigned char bin45[] = {
629     0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x03,0x12,0x02,0x41,0};
630 static const struct EncodedName names[] = {
631  { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
632    { sizeof(commonName), (BYTE *)commonName } }, bin39 },
633  { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
634    { sizeof(commonName), (BYTE *)commonName } }, bin40 },
635  { { szOID_SUR_NAME, CERT_RDN_IA5_STRING,
636    { sizeof(surName), (BYTE *)surName } }, bin41 },
637  { { NULL, CERT_RDN_PRINTABLE_STRING,
638    { sizeof(commonName), (BYTE *)commonName } }, bin42 },
639 /* The following test isn't a very good one, because it doesn't encode any
640  * Japanese characters.  I'm leaving it out for now.
641  { { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
642    { sizeof(commonName), (BYTE *)commonName } },
643  "\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
644  */
645  /* The following tests succeed under Windows, but really should fail,
646   * they contain characters that are illegal for the encoding.  I'm
647   * including them to justify my lazy encoding.
648   */
649  { { szOID_COMMON_NAME, CERT_RDN_IA5_STRING,
650    { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin43 },
651  { { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING,
652    { sizeof(bogusPrintable), (BYTE *)bogusPrintable } }, bin44 },
653  { { szOID_COMMON_NAME, CERT_RDN_NUMERIC_STRING,
654    { sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, bin45 },
655 };
656
657 static const BYTE emptyName[] = { 0x30, 0 };
658 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
659 static const BYTE twoRDNs[] = {
660     0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
661     0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
662     0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
663
664 static void test_encodeName(DWORD dwEncoding)
665 {
666     CERT_RDN_ATTR attrs[2];
667     CERT_RDN rdn;
668     CERT_NAME_INFO info;
669     BYTE *buf = NULL;
670     DWORD size = 0, i;
671     BOOL ret;
672
673     /* Test with NULL pvStructInfo */
674     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
675      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
676     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
677      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
678     /* Test with empty CERT_NAME_INFO */
679     info.cRDN = 0;
680     info.rgRDN = NULL;
681     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
682      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
683     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
684     if (buf)
685     {
686         ok(!memcmp(buf, emptyName, sizeof(emptyName)),
687          "Got unexpected encoding for empty name\n");
688         LocalFree(buf);
689     }
690     /* Test with bogus CERT_RDN */
691     info.cRDN = 1;
692     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
693      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
694     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
695      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
696     /* Test with empty CERT_RDN */
697     rdn.cRDNAttr = 0;
698     rdn.rgRDNAttr = NULL;
699     info.cRDN = 1;
700     info.rgRDN = &rdn;
701     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
702      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
703     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
704     if (buf)
705     {
706         ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)),
707          "Got unexpected encoding for empty RDN array\n");
708         LocalFree(buf);
709     }
710     /* Test with bogus attr array */
711     rdn.cRDNAttr = 1;
712     rdn.rgRDNAttr = NULL;
713     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
714      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
715     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
716      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
717     /* oddly, a bogus OID is accepted by Windows XP; not testing.
718     attrs[0].pszObjId = "bogus";
719     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
720     attrs[0].Value.cbData = sizeof(commonName);
721     attrs[0].Value.pbData = (BYTE *)commonName;
722     rdn.cRDNAttr = 1;
723     rdn.rgRDNAttr = attrs;
724     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
725      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
726     ok(!ret, "Expected failure, got success\n");
727      */
728     /* Check with two CERT_RDN_ATTRs.  Note DER encoding forces the order of
729      * the encoded attributes to be swapped.
730      */
731     attrs[0].pszObjId = szOID_COMMON_NAME;
732     attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
733     attrs[0].Value.cbData = sizeof(commonName);
734     attrs[0].Value.pbData = (BYTE *)commonName;
735     attrs[1].pszObjId = szOID_SUR_NAME;
736     attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING;
737     attrs[1].Value.cbData = sizeof(surName);
738     attrs[1].Value.pbData = (BYTE *)surName;
739     rdn.cRDNAttr = 2;
740     rdn.rgRDNAttr = attrs;
741     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
742      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
743     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
744     if (buf)
745     {
746         ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)),
747          "Got unexpected encoding for two RDN array\n");
748         LocalFree(buf);
749     }
750     /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
751     rdn.cRDNAttr = 1;
752     attrs[0].dwValueType = CERT_RDN_ANY_TYPE;
753     ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
754      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
755     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
756      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
757     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
758     {
759         rdn.cRDNAttr = 1;
760         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
761         ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
762          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
763         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
764         if (buf)
765         {
766             ok(size == names[i].encoded[1] + 2, "Expected size %d, got %ld\n",
767              names[i].encoded[1] + 2, size);
768             ok(!memcmp(buf, names[i].encoded, names[i].encoded[1] + 2),
769              "Got unexpected encoding\n");
770             LocalFree(buf);
771         }
772     }
773 }
774
775 static void compareNames(const CERT_NAME_INFO *expected,
776  const CERT_NAME_INFO *got)
777 {
778     ok(got->cRDN == expected->cRDN, "Expected %ld RDNs, got %ld\n",
779      expected->cRDN, got->cRDN);
780     if (expected->cRDN)
781     {
782         ok(got->rgRDN[0].cRDNAttr == expected->rgRDN[0].cRDNAttr,
783          "Expected %ld RDN attrs, got %ld\n", expected->rgRDN[0].cRDNAttr,
784          got->rgRDN[0].cRDNAttr);
785         if (expected->rgRDN[0].cRDNAttr)
786         {
787             if (expected->rgRDN[0].rgRDNAttr[0].pszObjId &&
788              strlen(expected->rgRDN[0].rgRDNAttr[0].pszObjId))
789             {
790                 ok(got->rgRDN[0].rgRDNAttr[0].pszObjId != NULL,
791                  "Expected OID %s, got NULL\n",
792                  expected->rgRDN[0].rgRDNAttr[0].pszObjId);
793                 if (got->rgRDN[0].rgRDNAttr[0].pszObjId)
794                     ok(!strcmp(got->rgRDN[0].rgRDNAttr[0].pszObjId,
795                      expected->rgRDN[0].rgRDNAttr[0].pszObjId),
796                      "Got unexpected OID %s, expected %s\n",
797                      got->rgRDN[0].rgRDNAttr[0].pszObjId,
798                      expected->rgRDN[0].rgRDNAttr[0].pszObjId);
799             }
800             ok(got->rgRDN[0].rgRDNAttr[0].Value.cbData ==
801              expected->rgRDN[0].rgRDNAttr[0].Value.cbData,
802              "Unexpected data size, got %ld, expected %ld\n",
803              got->rgRDN[0].rgRDNAttr[0].Value.cbData,
804              expected->rgRDN[0].rgRDNAttr[0].Value.cbData);
805             if (expected->rgRDN[0].rgRDNAttr[0].Value.pbData)
806                 ok(!memcmp(got->rgRDN[0].rgRDNAttr[0].Value.pbData,
807                  expected->rgRDN[0].rgRDNAttr[0].Value.pbData,
808                  expected->rgRDN[0].rgRDNAttr[0].Value.cbData),
809                  "Unexpected value\n");
810         }
811     }
812 }
813
814 static void test_decodeName(DWORD dwEncoding)
815 {
816     int i;
817     BYTE *buf = NULL;
818     DWORD bufSize = 0;
819     BOOL ret;
820     CERT_RDN rdn;
821     CERT_NAME_INFO info = { 1, &rdn };
822
823     for (i = 0; i < sizeof(names) / sizeof(names[0]); i++)
824     {
825         /* When the output buffer is NULL, this always succeeds */
826         SetLastError(0xdeadbeef);
827         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
828          names[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
829         ok(ret && GetLastError() == NOERROR,
830          "Expected success and NOERROR, got %08lx\n", GetLastError());
831         ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, names[i].encoded,
832          names[i].encoded[1] + 2,
833          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
834          (BYTE *)&buf, &bufSize);
835         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
836         rdn.cRDNAttr = 1;
837         rdn.rgRDNAttr = (CERT_RDN_ATTR *)&names[i].attr;
838         if (buf)
839         {
840             compareNames((CERT_NAME_INFO *)buf, &info);
841             LocalFree(buf);
842         }
843     }
844     /* test empty name */
845     bufSize = 0;
846     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
847      emptyName[1] + 2,
848      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
849      (BYTE *)&buf, &bufSize);
850     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
851     /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL.  My
852      * decoder works the same way, so only test the count.
853      */
854     if (buf)
855     {
856         ok(bufSize == sizeof(CERT_NAME_INFO),
857          "Expected bufSize %d, got %ld\n", sizeof(CERT_NAME_INFO), bufSize);
858         ok(((CERT_NAME_INFO *)buf)->cRDN == 0,
859          "Expected 0 RDNs in empty info, got %ld\n",
860          ((CERT_NAME_INFO *)buf)->cRDN);
861         LocalFree(buf);
862     }
863     /* test empty RDN */
864     bufSize = 0;
865     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs,
866      emptyRDNs[1] + 2,
867      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
868      (BYTE *)&buf, &bufSize);
869     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
870     if (buf)
871     {
872         CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf;
873
874         ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) &&
875          info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0,
876          "Got unexpected value for empty RDN\n");
877         LocalFree(buf);
878     }
879     /* test two RDN attrs */
880     bufSize = 0;
881     ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs,
882      twoRDNs[1] + 2,
883      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
884      (BYTE *)&buf, &bufSize);
885     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
886     if (buf)
887     {
888         CERT_RDN_ATTR attrs[] = {
889          { szOID_SUR_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(surName),
890           (BYTE *)surName } },
891          { szOID_COMMON_NAME, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName),
892           (BYTE *)commonName } },
893         };
894
895         rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]);
896         rdn.rgRDNAttr = attrs;
897         compareNames((CERT_NAME_INFO *)buf, &info);
898         LocalFree(buf);
899     }
900 }
901
902 static const BYTE emptyAltName[] = { 0x30, 0x00 };
903 static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
904 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
905  'h','q','.','o','r','g',0 };
906 static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74,
907  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e,
908  0x6f, 0x72, 0x67 };
909 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
910  0x575b, 0 };
911 static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 };
912 static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69,
913  0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 };
914 static const BYTE localhost[] = { 127, 0, 0, 1 };
915 static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00,
916  0x01 };
917
918 static void test_encodeAltName(DWORD dwEncoding)
919 {
920     CERT_ALT_NAME_INFO info = { 0 };
921     CERT_ALT_NAME_ENTRY entry = { 0 };
922     BYTE *buf = NULL;
923     DWORD size = 0;
924     BOOL ret;
925
926     /* Test with empty info */
927     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
928      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
929     if (buf)
930     {
931         ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n",
932          sizeof(emptyAltName), size);
933         ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n");
934         LocalFree(buf);
935     }
936     /* Test with an empty entry */
937     info.cAltEntry = 1;
938     info.rgAltEntry = &entry;
939     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
940      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
941     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
942      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
943      GetLastError());
944     /* Test with an empty pointer */
945     entry.dwAltNameChoice = CERT_ALT_NAME_URL;
946     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
947      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
948     if (buf)
949     {
950         ok(size == sizeof(emptyURL), "Expected size %d, got %ld\n",
951          sizeof(emptyURL), size);
952         ok(!memcmp(buf, emptyURL, size), "Unexpected value\n");
953         LocalFree(buf);
954     }
955     /* Test with a real URL */
956     U(entry).pwszURL = (LPWSTR)url;
957     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
958      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
959     if (buf)
960     {
961         ok(size == sizeof(encodedURL), "Expected size %d, got %ld\n",
962          sizeof(encodedURL), size);
963         ok(!memcmp(buf, encodedURL, size), "Unexpected value\n");
964         LocalFree(buf);
965     }
966     /* Now with the URL containing an invalid IA5 char */
967     U(entry).pwszURL = (LPWSTR)nihongoURL;
968     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
969      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
970     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
971      "Expected CRYPT_E_INVALID_IA5_STRING, got %08lx\n", GetLastError());
972     /* The first invalid character is at index 7 */
973     ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7,
974      "Expected invalid char at index 7, got %ld\n",
975      GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size));
976     /* Now with the URL missing a scheme */
977     U(entry).pwszURL = (LPWSTR)dnsName;
978     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
979      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
980     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
981     if (buf)
982     {
983         /* This succeeds, but it shouldn't, so don't worry about conforming */
984         LocalFree(buf);
985     }
986     /* Now with a DNS name */
987     entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
988     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
989      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
990     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
991     if (buf)
992     {
993         ok(size == sizeof(encodedDnsName), "Expected size %d, got %ld\n",
994          sizeof(encodedDnsName), size);
995         ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n");
996         LocalFree(buf);
997     }
998     /* Test with an IP address */
999     entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS;
1000     U(entry).IPAddress.cbData = sizeof(localhost);
1001     U(entry).IPAddress.pbData = (LPBYTE)localhost;
1002     ret = CryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info,
1003      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
1004     if (buf)
1005     {
1006         ok(size == sizeof(encodedIPAddr), "Expected size %d, got %ld\n",
1007          sizeof(encodedIPAddr), size);
1008         ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n");
1009         LocalFree(buf);
1010     }
1011 }
1012
1013 static void test_decodeAltName(DWORD dwEncoding)
1014 {
1015     static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f,
1016      0x00, 0x00, 0x01 };
1017     static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00,
1018      0x01 };
1019     BOOL ret;
1020     BYTE *buf = NULL;
1021     DWORD bufSize = 0;
1022     CERT_ALT_NAME_INFO *info;
1023
1024     /* Test some bogus ones first */
1025     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1026      unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG,
1027      NULL, (BYTE *)&buf, &bufSize);
1028     ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
1029      "Expected CRYPT_E_ASN1_BADTAG, got %08lx\n", GetLastError());
1030     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME,
1031      bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1032      &bufSize);
1033     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1034      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1035     /* Now expected cases */
1036     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName,
1037      emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1038      &bufSize);
1039     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1040     if (buf)
1041     {
1042         info = (CERT_ALT_NAME_INFO *)buf;
1043
1044         ok(info->cAltEntry == 0, "Expected 0 entries, got %ld\n",
1045          info->cAltEntry);
1046         LocalFree(buf);
1047     }
1048     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL,
1049      emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1050      &bufSize);
1051     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1052     if (buf)
1053     {
1054         info = (CERT_ALT_NAME_INFO *)buf;
1055
1056         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1057          info->cAltEntry);
1058         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1059          "Expected CERT_ALT_NAME_URL, got %ld\n",
1060          info->rgAltEntry[0].dwAltNameChoice);
1061         ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL,
1062          "Expected empty URL\n");
1063         LocalFree(buf);
1064     }
1065     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL,
1066      encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1067      &bufSize);
1068     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1069     if (buf)
1070     {
1071         info = (CERT_ALT_NAME_INFO *)buf;
1072
1073         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1074          info->cAltEntry);
1075         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL,
1076          "Expected CERT_ALT_NAME_URL, got %ld\n",
1077          info->rgAltEntry[0].dwAltNameChoice);
1078         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n");
1079         LocalFree(buf);
1080     }
1081     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName,
1082      encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1083      &bufSize);
1084     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1085     if (buf)
1086     {
1087         info = (CERT_ALT_NAME_INFO *)buf;
1088
1089         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1090          info->cAltEntry);
1091         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME,
1092          "Expected CERT_ALT_NAME_DNS_NAME, got %ld\n",
1093          info->rgAltEntry[0].dwAltNameChoice);
1094         ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName),
1095          "Unexpected DNS name\n");
1096         LocalFree(buf);
1097     }
1098     ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr,
1099      encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1100      &bufSize);
1101     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1102     if (buf)
1103     {
1104         info = (CERT_ALT_NAME_INFO *)buf;
1105
1106         ok(info->cAltEntry == 1, "Expected 1 entries, got %ld\n",
1107          info->cAltEntry);
1108         ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS,
1109          "Expected CERT_ALT_NAME_IP_ADDRESS, got %ld\n",
1110          info->rgAltEntry[0].dwAltNameChoice);
1111         ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost),
1112          "Unexpected IP address length %ld\n",
1113           U(info->rgAltEntry[0]).IPAddress.cbData);
1114         ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost,
1115          sizeof(localhost)), "Unexpected IP address value\n");
1116         LocalFree(buf);
1117     }
1118 }
1119
1120 struct encodedOctets
1121 {
1122     const BYTE *val;
1123     const BYTE *encoded;
1124 };
1125
1126 static const unsigned char bin46[] = { 'h','i',0 };
1127 static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 };
1128 static const unsigned char bin48[] = {
1129      's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1130 static const unsigned char bin49[] = {
1131      0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 };
1132 static const unsigned char bin50[] = { 0 };
1133 static const unsigned char bin51[] = { 0x04,0x00,0 };
1134
1135 static const struct encodedOctets octets[] = {
1136     { bin46, bin47 },
1137     { bin48, bin49 },
1138     { bin50, bin51 },
1139 };
1140
1141 static void test_encodeOctets(DWORD dwEncoding)
1142 {
1143     CRYPT_DATA_BLOB blob;
1144     DWORD i;
1145
1146     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1147     {
1148         BYTE *buf = NULL;
1149         BOOL ret;
1150         DWORD bufSize = 0;
1151
1152         blob.cbData = strlen((const char*)octets[i].val);
1153         blob.pbData = (BYTE*)octets[i].val;
1154         ret = CryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob,
1155          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1156         ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
1157         if (buf)
1158         {
1159             ok(buf[0] == 4,
1160              "Got unexpected type %d for octet string (expected 4)\n", buf[0]);
1161             ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n",
1162              buf[1], octets[i].encoded[1]);
1163             ok(!memcmp(buf + 1, octets[i].encoded + 1,
1164              octets[i].encoded[1] + 1), "Got unexpected value\n");
1165             LocalFree(buf);
1166         }
1167     }
1168 }
1169
1170 static void test_decodeOctets(DWORD dwEncoding)
1171 {
1172     DWORD i;
1173
1174     for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++)
1175     {
1176         BYTE *buf = NULL;
1177         BOOL ret;
1178         DWORD bufSize = 0;
1179
1180         ret = CryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING,
1181          (BYTE *)octets[i].encoded, octets[i].encoded[1] + 2,
1182          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1183         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1184         ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1],
1185          "Expected size >= %d, got %ld\n",
1186          sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize);
1187         ok(buf != NULL, "Expected allocated buffer\n");
1188         if (buf)
1189         {
1190             CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf;
1191
1192             if (blob->cbData)
1193                 ok(!memcmp(blob->pbData, octets[i].val, blob->cbData),
1194                  "Unexpected value\n");
1195             LocalFree(buf);
1196         }
1197     }
1198 }
1199
1200 static const BYTE bytesToEncode[] = { 0xff, 0xff };
1201
1202 struct encodedBits
1203 {
1204     DWORD cUnusedBits;
1205     const BYTE *encoded;
1206     DWORD cbDecoded;
1207     const BYTE *decoded;
1208 };
1209
1210 static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff,0 };
1211 static const unsigned char bin53[] = { 0xff,0xff,0 };
1212 static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe,0 };
1213 static const unsigned char bin55[] = { 0xff,0xfe,0 };
1214 static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe,0 };
1215 static const unsigned char bin57[] = { 0xfe,0 };
1216 static const unsigned char bin58[] = { 0x03,0x01,0x00,0 };
1217
1218 static const struct encodedBits bits[] = {
1219     /* normal test cases */
1220     { 0, bin52, 2, bin53 },
1221     { 1, bin54, 2, bin55 },
1222     /* strange test case, showing cUnusedBits >= 8 is allowed */
1223     { 9, bin56, 1, bin57 },
1224     /* even stranger test case, showing cUnusedBits > cbData * 8 is allowed */
1225     { 17, bin58, 0, NULL },
1226 };
1227
1228 static void test_encodeBits(DWORD dwEncoding)
1229 {
1230     DWORD i;
1231
1232     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1233     {
1234         CRYPT_BIT_BLOB blob;
1235         BOOL ret;
1236         BYTE *buf = NULL;
1237         DWORD bufSize = 0;
1238
1239         blob.cbData = sizeof(bytesToEncode);
1240         blob.pbData = (BYTE *)bytesToEncode;
1241         blob.cUnusedBits = bits[i].cUnusedBits;
1242         ret = CryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
1243          CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1244         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1245         if (buf)
1246         {
1247             ok(bufSize == bits[i].encoded[1] + 2,
1248              "Got unexpected size %ld, expected %d\n", bufSize,
1249              bits[i].encoded[1] + 2);
1250             ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
1251              "Unexpected value\n");
1252             LocalFree(buf);
1253         }
1254     }
1255 }
1256
1257 static void test_decodeBits(DWORD dwEncoding)
1258 {
1259     static const BYTE ber[] = "\x03\x02\x01\xff";
1260     static const BYTE berDecoded = 0xfe;
1261     DWORD i;
1262     BOOL ret;
1263     BYTE *buf = NULL;
1264     DWORD bufSize = 0;
1265
1266     /* normal cases */
1267     for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
1268     {
1269         ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
1270          bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1271          &bufSize);
1272         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1273         if (buf)
1274         {
1275             CRYPT_BIT_BLOB *blob;
1276
1277             ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
1278              "Got unexpected size %ld, expected >= %ld\n", bufSize,
1279              sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded);
1280             blob = (CRYPT_BIT_BLOB *)buf;
1281             ok(blob->cbData == bits[i].cbDecoded,
1282              "Got unexpected length %ld, expected %ld\n", blob->cbData,
1283              bits[i].cbDecoded);
1284             if (blob->cbData && bits[i].cbDecoded)
1285                 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
1286                  "Unexpected value\n");
1287             LocalFree(buf);
1288         }
1289     }
1290     /* special case: check that something that's valid in BER but not in DER
1291      * decodes successfully
1292      */
1293     ret = CryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
1294      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1295     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1296     if (buf)
1297     {
1298         CRYPT_BIT_BLOB *blob;
1299
1300         ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
1301          "Got unexpected size %ld, expected >= %d\n", bufSize,
1302          sizeof(CRYPT_BIT_BLOB) + berDecoded);
1303         blob = (CRYPT_BIT_BLOB *)buf;
1304         ok(blob->cbData == sizeof(berDecoded),
1305          "Got unexpected length %ld, expected %d\n", blob->cbData,
1306          sizeof(berDecoded));
1307         if (blob->cbData)
1308             ok(*blob->pbData == berDecoded, "Unexpected value\n");
1309         LocalFree(buf);
1310     }
1311 }
1312
1313 struct Constraints2
1314 {
1315     CERT_BASIC_CONSTRAINTS2_INFO info;
1316     const BYTE *encoded;
1317 };
1318
1319 static const unsigned char bin59[] = { 0x30,0x00,0 };
1320 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff,0 };
1321 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00,0 };
1322 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0 };
1323 static const struct Constraints2 constraints2[] = {
1324  /* empty constraints */
1325  { { FALSE, FALSE, 0}, bin59 },
1326  /* can be a CA */
1327  { { TRUE,  FALSE, 0}, bin60 },
1328  /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
1329   * but that's not the case
1330   */
1331  { { FALSE, TRUE,  0}, bin61 },
1332  /* can be a CA and has path length constraints set */
1333  { { TRUE,  TRUE,  1}, bin62 },
1334 };
1335
1336 static void test_encodeBasicConstraints(DWORD dwEncoding)
1337 {
1338     DWORD i;
1339
1340     /* First test with the simpler info2 */
1341     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1342     {
1343         BOOL ret;
1344         BYTE *buf = NULL;
1345         DWORD bufSize = 0;
1346
1347         ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1348          &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1349          &bufSize);
1350         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1351         if (buf)
1352         {
1353             ok(bufSize == constraints2[i].encoded[1] + 2,
1354              "Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
1355              bufSize);
1356             ok(!memcmp(buf, constraints2[i].encoded,
1357              constraints2[i].encoded[1] + 2), "Unexpected value\n");
1358             LocalFree(buf);
1359         }
1360     }
1361 }
1362
1363 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01,0 };
1364
1365 static void test_decodeBasicConstraints(DWORD dwEncoding)
1366 {
1367     static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
1368     static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
1369     DWORD i;
1370     BOOL ret;
1371     BYTE *buf = NULL;
1372     DWORD bufSize = 0;
1373
1374     /* First test with simpler info2 */
1375     for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
1376     {
1377         ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1378          constraints2[i].encoded, constraints2[i].encoded[1] + 2,
1379          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1380         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1381         if (buf)
1382         {
1383             CERT_BASIC_CONSTRAINTS2_INFO *info =
1384              (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1385
1386             ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
1387              "Unexpected value\n");
1388             LocalFree(buf);
1389         }
1390     }
1391     /* Check with the order of encoded elements inverted */
1392     buf = (PBYTE)1;
1393     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1394      inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1395      &bufSize);
1396     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1397      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1398     ok(!buf, "Expected buf to be set to NULL\n");
1399     /* Check with a non-DER bool */
1400     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1401      badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1402      (BYTE *)&buf, &bufSize);
1403     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1404     if (buf)
1405     {
1406         CERT_BASIC_CONSTRAINTS2_INFO *info =
1407          (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
1408
1409         ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
1410         LocalFree(buf);
1411     }
1412     /* Check with a non-basic constraints value */
1413     ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
1414      names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
1415      (BYTE *)&buf, &bufSize);
1416     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1417      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1418 }
1419
1420 /* These are terrible public keys of course, I'm just testing encoding */
1421 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
1422 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
1423 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
1424 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
1425 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
1426 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1427 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
1428 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
1429
1430 struct EncodedRSAPubKey
1431 {
1432     const BYTE *modulus;
1433     size_t modulusLen;
1434     const BYTE *encoded;
1435     size_t decodedModulusLen;
1436 };
1437
1438 struct EncodedRSAPubKey rsaPubKeys[] = {
1439     { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
1440     { modulus2, sizeof(modulus2), mod2_encoded, 5 },
1441     { modulus3, sizeof(modulus3), mod3_encoded, 5 },
1442     { modulus4, sizeof(modulus4), mod4_encoded, 8 },
1443 };
1444
1445 static void test_encodeRsaPublicKey(DWORD dwEncoding)
1446 {
1447     BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
1448     BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
1449     RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
1450     BOOL ret;
1451     BYTE *buf = NULL;
1452     DWORD bufSize = 0, i;
1453
1454     /* Try with a bogus blob type */
1455     hdr->bType = 2;
1456     hdr->bVersion = CUR_BLOB_VERSION;
1457     hdr->reserved = 0;
1458     hdr->aiKeyAlg = CALG_RSA_KEYX;
1459     rsaPubKey->magic = 0x31415352;
1460     rsaPubKey->bitlen = sizeof(modulus1) * 8;
1461     rsaPubKey->pubexp = 65537;
1462     memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
1463      sizeof(modulus1));
1464
1465     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1466      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1467      &bufSize);
1468     ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
1469      "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
1470      GetLastError());
1471     /* Now with a bogus reserved field */
1472     hdr->bType = PUBLICKEYBLOB;
1473     hdr->reserved = 1;
1474     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1475      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1476      &bufSize);
1477     if (buf)
1478     {
1479         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1480          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1481         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1482         LocalFree(buf);
1483     }
1484     /* Now with a bogus blob version */
1485     hdr->reserved = 0;
1486     hdr->bVersion = 0;
1487     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1488      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1489      &bufSize);
1490     if (buf)
1491     {
1492         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1493          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1494         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1495         LocalFree(buf);
1496     }
1497     /* And with a bogus alg ID */
1498     hdr->bVersion = CUR_BLOB_VERSION;
1499     hdr->aiKeyAlg = CALG_DES;
1500     ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1501      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1502      &bufSize);
1503     if (buf)
1504     {
1505         ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
1506          "Expected size %d, got %ld\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
1507         ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
1508         LocalFree(buf);
1509     }
1510     /* Check a couple of RSA-related OIDs */
1511     hdr->aiKeyAlg = CALG_RSA_KEYX;
1512     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
1513      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1514     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1515      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1516     ret = CryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1517      toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1518     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1519      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1520     /* Finally, all valid */
1521     hdr->aiKeyAlg = CALG_RSA_KEYX;
1522     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1523     {
1524         memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1525          rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
1526         ret = CryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1527          toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1528         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1529         if (buf)
1530         {
1531             ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
1532              "Expected size %d, got %ld\n", rsaPubKeys[i].encoded[1] + 2,
1533              bufSize);
1534             ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
1535              "Unexpected value\n");
1536             LocalFree(buf);
1537         }
1538     }
1539 }
1540
1541 static void test_decodeRsaPublicKey(DWORD dwEncoding)
1542 {
1543     DWORD i;
1544     LPBYTE buf = NULL;
1545     DWORD bufSize = 0;
1546     BOOL ret;
1547
1548     /* Try with a bad length */
1549     ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1550      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
1551      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1552     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
1553      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", CRYPT_E_ASN1_EOD);
1554     /* Try with a couple of RSA-related OIDs */
1555     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
1556      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1557      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1558     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1559      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1560     ret = CryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
1561      rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
1562      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1563     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
1564      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
1565     /* Now try success cases */
1566     for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
1567     {
1568         bufSize = 0;
1569         ret = CryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
1570          rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
1571          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1572         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1573         if (buf)
1574         {
1575             BLOBHEADER *hdr = (BLOBHEADER *)buf;
1576             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1577
1578             ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1579              rsaPubKeys[i].decodedModulusLen,
1580              "Expected size at least %d, got %ld\n",
1581              sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
1582              rsaPubKeys[i].decodedModulusLen, bufSize);
1583             ok(hdr->bType == PUBLICKEYBLOB,
1584              "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
1585              hdr->bType);
1586             ok(hdr->bVersion == CUR_BLOB_VERSION,
1587              "Expected version CUR_BLOB_VERSION (%d), got %d\n",
1588              CUR_BLOB_VERSION, hdr->bVersion);
1589             ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
1590              hdr->reserved);
1591             ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
1592              "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
1593             ok(rsaPubKey->magic == 0x31415352,
1594              "Expected magic RSA1, got %08lx\n", rsaPubKey->magic);
1595             ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
1596              "Expected bit len %d, got %ld\n",
1597              rsaPubKeys[i].decodedModulusLen * 8, rsaPubKey->bitlen);
1598             ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %ld\n",
1599              rsaPubKey->pubexp);
1600             ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
1601              rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
1602              "Unexpected modulus\n");
1603             LocalFree(buf);
1604         }
1605     }
1606 }
1607
1608 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
1609  0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
1610  0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1611
1612 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
1613  0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
1614  0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
1615  0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
1616
1617 static void test_encodeSequenceOfAny(DWORD dwEncoding)
1618 {
1619     CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
1620     CRYPT_SEQUENCE_OF_ANY seq;
1621     DWORD i;
1622     BOOL ret;
1623     BYTE *buf = NULL;
1624     DWORD bufSize = 0;
1625
1626     /* Encode a homogenous sequence */
1627     for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
1628     {
1629         blobs[i].cbData = ints[i].encoded[1] + 2;
1630         blobs[i].pbData = (BYTE *)ints[i].encoded;
1631     }
1632     seq.cValue = sizeof(ints) / sizeof(ints[0]);
1633     seq.rgValue = blobs;
1634
1635     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1636      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1637     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1638     if (buf)
1639     {
1640         ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
1641          sizeof(intSequence), bufSize);
1642         ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
1643         LocalFree(buf);
1644     }
1645     /* Change the type of the first element in the sequence, and give it
1646      * another go
1647      */
1648     blobs[0].cbData = times[0].encodedTime[1] + 2;
1649     blobs[0].pbData = (BYTE *)times[0].encodedTime;
1650     ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
1651      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1652     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1653     if (buf)
1654     {
1655         ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
1656          sizeof(mixedSequence), bufSize);
1657         ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
1658          "Unexpected value\n");
1659         LocalFree(buf);
1660     }
1661 }
1662
1663 static void test_decodeSequenceOfAny(DWORD dwEncoding)
1664 {
1665     BOOL ret;
1666     BYTE *buf = NULL;
1667     DWORD bufSize = 0;
1668
1669     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
1670      intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1671     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1672     if (buf)
1673     {
1674         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1675         DWORD i;
1676
1677         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1678          "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1679          seq->cValue);
1680         for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
1681         {
1682             ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
1683              "Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
1684              seq->rgValue[i].cbData);
1685             ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
1686              ints[i].encoded[1] + 2), "Unexpected value\n");
1687         }
1688         LocalFree(buf);
1689     }
1690     ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
1691      mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1692      &bufSize);
1693     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1694     if (buf)
1695     {
1696         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
1697
1698         ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
1699          "Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
1700          seq->cValue);
1701         /* Just check the first element since it's all that changed */
1702         ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
1703          "Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
1704          seq->rgValue[0].cbData);
1705         ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
1706          times[0].encodedTime[1] + 2), "Unexpected value\n");
1707         LocalFree(buf);
1708     }
1709 }
1710
1711 struct encodedExtensions
1712 {
1713     CERT_EXTENSIONS exts;
1714     const BYTE *encoded;
1715 };
1716
1717 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1718 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1719
1720 static CERT_EXTENSION criticalExt =
1721  { szOID_BASIC_CONSTRAINTS2, TRUE, { 8, crit_ext_data } };
1722 static CERT_EXTENSION nonCriticalExt =
1723  { szOID_BASIC_CONSTRAINTS2, FALSE, { 8, noncrit_ext_data } };
1724
1725 static const BYTE ext0[] = { 0x30,0x00 };
1726 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
1727                              0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1728 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
1729                              0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
1730
1731 static const struct encodedExtensions exts[] = {
1732  { { 0, NULL }, ext0 },
1733  { { 1, &criticalExt }, ext1 },
1734  { { 1, &nonCriticalExt }, ext2 },
1735 };
1736
1737 static void test_encodeExtensions(DWORD dwEncoding)
1738 {
1739     DWORD i;
1740
1741     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1742     {
1743         BOOL ret;
1744         BYTE *buf = NULL;
1745         DWORD bufSize = 0;
1746
1747         ret = CryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
1748          CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
1749         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1750         if (buf)
1751         {
1752             ok(bufSize == exts[i].encoded[1] + 2,
1753              "Expected %d bytes, got %ld\n", exts[i].encoded[1] + 2, bufSize);
1754             ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
1755              "Unexpected value\n");
1756             LocalFree(buf);
1757         }
1758     }
1759 }
1760
1761 static void test_decodeExtensions(DWORD dwEncoding)
1762 {
1763     DWORD i;
1764
1765     for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
1766     {
1767         BOOL ret;
1768         BYTE *buf = NULL;
1769         DWORD bufSize = 0;
1770
1771         ret = CryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
1772          exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1773          NULL, (BYTE *)&buf, &bufSize);
1774         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1775         if (buf)
1776         {
1777             CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
1778             DWORD j;
1779
1780             ok(ext->cExtension == exts[i].exts.cExtension,
1781              "Expected %ld extensions, see %ld\n", exts[i].exts.cExtension,
1782              ext->cExtension);
1783             for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
1784             {
1785                 ok(!strcmp(ext->rgExtension[j].pszObjId,
1786                  exts[i].exts.rgExtension[j].pszObjId),
1787                  "Expected OID %s, got %s\n",
1788                  exts[i].exts.rgExtension[j].pszObjId,
1789                  ext->rgExtension[j].pszObjId);
1790                 ok(!memcmp(ext->rgExtension[j].Value.pbData,
1791                  exts[i].exts.rgExtension[j].Value.pbData,
1792                  exts[i].exts.rgExtension[j].Value.cbData),
1793                  "Unexpected value\n");
1794             }
1795             LocalFree(buf);
1796         }
1797     }
1798 }
1799
1800 /* MS encodes public key info with a NULL if the algorithm identifier's
1801  * parameters are empty.  However, when encoding an algorithm in a CERT_INFO,
1802  * it encodes them by omitting the algorithm parameters.  This latter approach
1803  * seems more correct, so accept either form.
1804  */
1805 struct encodedPublicKey
1806 {
1807     CERT_PUBLIC_KEY_INFO info;
1808     const BYTE *encoded;
1809     const BYTE *encodedNoNull;
1810     CERT_PUBLIC_KEY_INFO decoded;
1811 };
1812
1813 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
1814  0xe, 0xf };
1815 static const BYTE params[] = { 0x02, 0x01, 0x01 };
1816
1817 static const unsigned char bin64[] = {
1818     0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00,0};
1819 static const unsigned char bin65[] = {
1820     0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00,0};
1821 static const unsigned char bin66[] = {
1822     0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00,0};
1823 static const unsigned char bin67[] = {
1824     0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00,0};
1825 static const unsigned char bin68[] = {
1826     0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
1827     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0};
1828 static const unsigned char bin69[] = {
1829     0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
1830     0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0};
1831 static const unsigned char bin70[] = {
1832     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1833     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1834     0x0f,0};
1835 static const unsigned char bin71[] = {
1836     0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
1837     0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
1838     0x0f,0};
1839 static unsigned char bin72[] = { 0x05,0x00,0};
1840
1841 static const struct encodedPublicKey pubKeys[] = {
1842  /* with a bogus OID */
1843  { { { "1.2.3", { 0, NULL } }, { 0, NULL, 0 } },
1844   bin64, bin65,
1845   { { "1.2.3", { 2, bin72 } }, { 0, NULL, 0 } } },
1846  /* some normal keys */
1847  { { { szOID_RSA, { 0, NULL } }, { 0, NULL, 0} },
1848   bin66, bin67,
1849   { { szOID_RSA, { 2, bin72 } }, { 0, NULL, 0 } } },
1850  { { { szOID_RSA, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
1851   bin68, bin69,
1852   { { szOID_RSA, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
1853  /* with add'l parameters--note they must be DER-encoded */
1854  { { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1855   (BYTE *)aKey, 0 } },
1856   bin70, bin71,
1857   { { szOID_RSA, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
1858   (BYTE *)aKey, 0 } } },
1859 };
1860
1861 static void test_encodePublicKeyInfo(DWORD dwEncoding)
1862 {
1863     DWORD i;
1864
1865     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1866     {
1867         BOOL ret;
1868         BYTE *buf = NULL;
1869         DWORD bufSize = 0;
1870
1871         ret = CryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1872          &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
1873          &bufSize);
1874         ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
1875         if (buf)
1876         {
1877             ok(bufSize == pubKeys[i].encoded[1] + 2 ||
1878              bufSize == pubKeys[i].encodedNoNull[1] + 2,
1879              "Expected %d or %d bytes, got %ld\n", pubKeys[i].encoded[1] + 2,
1880              pubKeys[i].encodedNoNull[1] + 2, bufSize);
1881             if (bufSize == pubKeys[i].encoded[1] + 2)
1882                 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
1883                  "Unexpected value\n");
1884             else if (bufSize == pubKeys[i].encodedNoNull[1] + 2)
1885                 ok(!memcmp(buf, pubKeys[i].encodedNoNull,
1886                  pubKeys[i].encodedNoNull[1] + 2), "Unexpected value\n");
1887             LocalFree(buf);
1888         }
1889     }
1890 }
1891
1892 static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected,
1893  const CERT_PUBLIC_KEY_INFO *got)
1894 {
1895     ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId),
1896      "Expected OID %s, got %s\n", expected->Algorithm.pszObjId,
1897      got->Algorithm.pszObjId);
1898     ok(expected->Algorithm.Parameters.cbData ==
1899      got->Algorithm.Parameters.cbData,
1900      "Expected parameters of %ld bytes, got %ld\n",
1901      expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData);
1902     if (expected->Algorithm.Parameters.cbData)
1903         ok(!memcmp(expected->Algorithm.Parameters.pbData,
1904          got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData),
1905          "Unexpected algorithm parameters\n");
1906     ok(expected->PublicKey.cbData == got->PublicKey.cbData,
1907      "Expected public key of %ld bytes, got %ld\n",
1908      expected->PublicKey.cbData, got->PublicKey.cbData);
1909     if (expected->PublicKey.cbData)
1910         ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData,
1911          got->PublicKey.cbData), "Unexpected public key value\n");
1912 }
1913
1914 static void test_decodePublicKeyInfo(DWORD dwEncoding)
1915 {
1916     static const BYTE bogusPubKeyInfo[] =
1917      "\x30\x22\x30\x0d\x06\x06\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x01\x01"
1918      "\x03\x11\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
1919      "\x0f";
1920     DWORD i;
1921     BOOL ret;
1922     BYTE *buf = NULL;
1923     DWORD bufSize = 0;
1924
1925     for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
1926     {
1927         /* The NULL form decodes to the decoded member */
1928         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1929          pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1930          NULL, (BYTE *)&buf, &bufSize);
1931         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1932         if (buf)
1933         {
1934             comparePublicKeyInfo(&pubKeys[i].decoded,
1935              (CERT_PUBLIC_KEY_INFO *)buf);
1936             LocalFree(buf);
1937         }
1938         /* The non-NULL form decodes to the original */
1939         ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1940          pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2,
1941          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
1942         ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
1943         if (buf)
1944         {
1945             comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf);
1946             LocalFree(buf);
1947         }
1948     }
1949     /* Test with bogus (not valid DER) parameters */
1950     ret = CryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
1951      bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
1952      NULL, (BYTE *)&buf, &bufSize);
1953     ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
1954      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
1955 }
1956
1957 static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00,
1958  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
1959  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
1960  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30,
1961  0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
1962 static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02,
1963  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
1964  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
1965  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1966  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
1967 static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
1968  0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
1969  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f,
1970  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
1971  0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 };
1972 static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30,
1973  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
1974  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
1975  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
1976  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
1977  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
1978  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1979 static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30,
1980  0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31,
1981  0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36,
1982  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
1983  0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14,
1984  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
1985  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1986 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
1987  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
1988  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
1989  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
1990  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
1991  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
1992  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
1993  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
1994  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
1995  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
1996
1997 /* This is the encoded form of the printable string "Juan Lang" */
1998 static const BYTE encodedCommonName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
1999  0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c,
2000  0x61, 0x6e, 0x67, 0x00 };
2001 static const BYTE serialNum[] = { 0x01 };
2002
2003 static void test_encodeCertToBeSigned(DWORD dwEncoding)
2004 {
2005     BOOL ret;
2006     BYTE *buf = NULL;
2007     DWORD size = 0;
2008     CERT_INFO info = { 0 };
2009
2010     /* Test with NULL pvStructInfo */
2011     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL,
2012      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2013     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2014      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2015     /* Test with a V1 cert */
2016     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2017      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2018     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2019     if (buf)
2020     {
2021         ok(size == v1Cert[1] + 2, "Expected size %d, got %ld\n",
2022          v1Cert[1] + 2, size);
2023         ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n");
2024         LocalFree(buf);
2025     }
2026     /* Test v2 cert */
2027     info.dwVersion = CERT_V2;
2028     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2029      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2030     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2031     if (buf)
2032     {
2033         ok(size == sizeof(v2Cert), "Expected size %d, got %ld\n",
2034          sizeof(v2Cert), size);
2035         ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n");
2036         LocalFree(buf);
2037     }
2038     /* Test v3 cert */
2039     info.dwVersion = CERT_V3;
2040     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2041      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2042     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2043     if (buf)
2044     {
2045         ok(size == sizeof(v3Cert), "Expected size %d, got %ld\n",
2046          sizeof(v3Cert), size);
2047         ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n");
2048         LocalFree(buf);
2049     }
2050     /* see if a V1 cert can have basic constraints set (RFC3280 says no, but
2051      * API doesn't prevent it)
2052      */
2053     info.dwVersion = CERT_V1;
2054     info.cExtension = 1;
2055     info.rgExtension = &criticalExt;
2056     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2057      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2058     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2059     if (buf)
2060     {
2061         ok(size == sizeof(v1CertWithConstraints), "Expected size %d, got %ld\n",
2062          sizeof(v1CertWithConstraints), size);
2063         ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n");
2064         LocalFree(buf);
2065     }
2066     /* test v1 cert with a serial number */
2067     info.SerialNumber.cbData = sizeof(serialNum);
2068     info.SerialNumber.pbData = (BYTE *)serialNum;
2069     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2070      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2071     if (buf)
2072     {
2073         ok(size == sizeof(v1CertWithSerial), "Expected size %d, got %ld\n",
2074          sizeof(v1CertWithSerial), size);
2075         ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n");
2076         LocalFree(buf);
2077     }
2078     /* Test v1 cert with an issuer name, a subject name, and a serial number */
2079     info.Issuer.cbData = sizeof(encodedCommonName);
2080     info.Issuer.pbData = (BYTE *)encodedCommonName;
2081     info.Subject.cbData = sizeof(encodedCommonName);
2082     info.Subject.pbData = (BYTE *)encodedCommonName;
2083     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info,
2084      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2085     if (buf)
2086     {
2087         ok(size == sizeof(bigCert), "Expected size %d, got %ld\n",
2088          sizeof(bigCert), size);
2089         ok(!memcmp(buf, bigCert, size), "Got unexpected value\n");
2090         LocalFree(buf);
2091     }
2092     /* for now, I let more interesting tests be done for each subcomponent,
2093      * rather than retesting them all here.
2094      */
2095 }
2096
2097 static void test_decodeCertToBeSigned(DWORD dwEncoding)
2098 {
2099     static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert,
2100      v1CertWithConstraints, v1CertWithSerial };
2101     BOOL ret;
2102     BYTE *buf = NULL;
2103     DWORD size = 0, i;
2104
2105     /* Test with NULL pbEncoded */
2106     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0,
2107      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2108     ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
2109      "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
2110     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1,
2111      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2112     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2113      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2114     /* The following certs all fail with CRYPT_E_ASN1_CORRUPT, because at a
2115      * minimum a cert must have a non-zero serial number, an issuer, and a
2116      * subject.
2117      */
2118     for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++)
2119     {
2120         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED,
2121          corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2122          (BYTE *)&buf, &size);
2123         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2124          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2125     }
2126     /* Now check with serial number, subject and issuer specified */
2127     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert,
2128      sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2129     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2130     if (buf)
2131     {
2132         CERT_INFO *info = (CERT_INFO *)buf;
2133
2134         ok(size >= sizeof(CERT_INFO), "Expected size at least %d, got %ld\n",
2135          sizeof(CERT_INFO), size);
2136         ok(info->SerialNumber.cbData == 1,
2137          "Expected serial number size 1, got %ld\n", info->SerialNumber.cbData);
2138         ok(*info->SerialNumber.pbData == *serialNum,
2139          "Expected serial number %d, got %d\n", *serialNum,
2140          *info->SerialNumber.pbData);
2141         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2142          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2143          info->Issuer.cbData);
2144         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2145          "Unexpected issuer\n");
2146         ok(info->Subject.cbData == sizeof(encodedCommonName),
2147          "Expected subject of %d bytes, got %ld\n", sizeof(encodedCommonName),
2148          info->Subject.cbData);
2149         ok(!memcmp(info->Subject.pbData, encodedCommonName,
2150          info->Subject.cbData), "Unexpected subject\n");
2151         LocalFree(buf);
2152     }
2153 }
2154
2155 static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2156  0xe, 0xf };
2157
2158 static const BYTE signedBigCert[] = {
2159  0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30,
2160  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2161  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f,
2162  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2163  0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
2164  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
2165  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
2166  0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3,
2167  0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
2168  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2169  0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
2170  0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
2171
2172 static void test_encodeCert(DWORD dwEncoding)
2173 {
2174     /* Note the SignatureAlgorithm must match that in the encoded cert.  Note
2175      * also that bigCert is a NULL-terminated string, so don't count its
2176      * last byte (otherwise the signed cert won't decode.)
2177      */
2178     CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert },
2179      { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } };
2180     BOOL ret;
2181     BYTE *buf = NULL;
2182     DWORD bufSize = 0;
2183
2184     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT, &info,
2185      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
2186     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2187     if (buf)
2188     {
2189         ok(bufSize == sizeof(signedBigCert), "Expected size %d, got %ld\n",
2190          sizeof(signedBigCert), bufSize);
2191         ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n");
2192         LocalFree(buf);
2193     }
2194 }
2195
2196 static void test_decodeCert(DWORD dwEncoding)
2197 {
2198     BOOL ret;
2199     BYTE *buf = NULL;
2200     DWORD size = 0;
2201
2202     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert,
2203      sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2204     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2205     if (buf)
2206     {
2207         CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf;
2208
2209         ok(info->ToBeSigned.cbData == sizeof(bigCert),
2210          "Expected cert to be %d bytes, got %ld\n", sizeof(bigCert),
2211          info->ToBeSigned.cbData);
2212         ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData),
2213          "Unexpected cert\n");
2214         ok(info->Signature.cbData == sizeof(hash),
2215          "Expected signature size %d, got %ld\n", sizeof(hash),
2216          info->Signature.cbData);
2217         ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData),
2218          "Unexpected signature\n");
2219         LocalFree(buf);
2220     }
2221 }
2222
2223 static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f,
2224  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2225  0x30, 0x5a };
2226 static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
2227  0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
2228  0x30, 0x30, 0x30, 0x30, 0x5a };
2229 static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00,
2230  0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
2231  0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31,
2232  0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2233  0x5a };
2234 static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02,
2235  0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
2236  0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18,
2237  0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
2238  0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36,
2239  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2240 static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06,
2241  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
2242  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f,
2243  0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
2244  0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36,
2245  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a };
2246 static const BYTE v1CRLWithExt[] = { 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x30,
2247  0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a,
2248  0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, 0x36,
2249  0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
2250  0x30, 0x2c, 0x30, 0x2a, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31,
2251  0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x14,
2252  0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
2253  0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
2254
2255 static void test_encodeCRLToBeSigned(DWORD dwEncoding)
2256 {
2257     BOOL ret;
2258     BYTE *buf = NULL;
2259     DWORD size = 0;
2260     CRL_INFO info = { 0 };
2261     CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 };
2262
2263     /* Test with a V1 CRL */
2264     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2265      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2266     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2267     if (buf)
2268     {
2269         ok(size == sizeof(v1CRL), "Expected size %d, got %ld\n",
2270          sizeof(v1CRL), size);
2271         ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n");
2272         LocalFree(buf);
2273     }
2274     /* Test v2 CRL */
2275     info.dwVersion = CRL_V2;
2276     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2277      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2278     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2279     if (buf)
2280     {
2281         ok(size == v2CRL[1] + 2, "Expected size %d, got %ld\n",
2282          v2CRL[1] + 2, size);
2283         ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n");
2284         LocalFree(buf);
2285     }
2286     /* v1 CRL with a name */
2287     info.dwVersion = CRL_V1;
2288     info.Issuer.cbData = sizeof(encodedCommonName);
2289     info.Issuer.pbData = (BYTE *)encodedCommonName;
2290     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2291      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2292     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2293     if (buf)
2294     {
2295         ok(size == sizeof(v1CRLWithIssuer), "Expected size %d, got %ld\n",
2296          sizeof(v1CRLWithIssuer), size);
2297         ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n");
2298         LocalFree(buf);
2299     }
2300     /* v1 CRL with a name and a NULL entry pointer */
2301     info.cCRLEntry = 1;
2302     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2303      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2304     ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
2305      "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
2306     /* now set an empty entry */
2307     info.rgCRLEntry = &entry;
2308     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2309      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2310     if (buf)
2311     {
2312         ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry),
2313          "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEmptyEntry),
2314          size);
2315         ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size),
2316          "Got unexpected value\n");
2317         LocalFree(buf);
2318     }
2319     /* an entry with a serial number */
2320     entry.SerialNumber.cbData = sizeof(serialNum);
2321     entry.SerialNumber.pbData = (BYTE *)serialNum;
2322     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2323      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2324     if (buf)
2325     {
2326         ok(size == sizeof(v1CRLWithIssuerAndEntry),
2327          "Expected size %d, got %ld\n", sizeof(v1CRLWithIssuerAndEntry), size);
2328         ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size),
2329          "Got unexpected value\n");
2330         LocalFree(buf);
2331     }
2332     /* and finally, an entry with an extension */
2333     entry.cExtension = 1;
2334     entry.rgExtension = &criticalExt;
2335     ret = CryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info,
2336      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2337     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
2338     if (buf)
2339     {
2340         ok(size == sizeof(v1CRLWithExt), "Expected size %d, got %ld\n",
2341          sizeof(v1CRLWithExt), size);
2342         ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n");
2343         LocalFree(buf);
2344     }
2345 }
2346
2347 static void test_decodeCRLToBeSigned(DWORD dwEncoding)
2348 {
2349     static const BYTE *corruptCRLs[] = { v1CRL, v2CRL };
2350     BOOL ret;
2351     BYTE *buf = NULL;
2352     DWORD size = 0, i;
2353
2354     for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++)
2355     {
2356         ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2357          corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2358          (BYTE *)&buf, &size);
2359         ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT),
2360          "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2361     }
2362     /* at a minimum, a CRL must contain an issuer: */
2363     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2364      v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2365      (BYTE *)&buf, &size);
2366     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2367     if (buf)
2368     {
2369         CRL_INFO *info = (CRL_INFO *)buf;
2370
2371         ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2372          sizeof(CRL_INFO), size);
2373         ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %ld\n",
2374          info->cCRLEntry);
2375         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2376          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2377          info->Issuer.cbData);
2378         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2379          "Unexpected issuer\n");
2380         LocalFree(buf);
2381     }
2382     /* check decoding with an empty CRL entry */
2383     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2384      v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2,
2385      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2386     todo_wine ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
2387      "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
2388     /* with a real CRL entry */
2389     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2390      v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2,
2391      CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
2392     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2393     if (buf)
2394     {
2395         CRL_INFO *info = (CRL_INFO *)buf;
2396         CRL_ENTRY *entry;
2397
2398         ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2399          sizeof(CRL_INFO), size);
2400         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2401          info->cCRLEntry);
2402         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2403         entry = info->rgCRLEntry;
2404         ok(entry->SerialNumber.cbData == 1,
2405          "Expected serial number size 1, got %ld\n",
2406          entry->SerialNumber.cbData);
2407         ok(*entry->SerialNumber.pbData == *serialNum,
2408          "Expected serial number %d, got %d\n", *serialNum,
2409          *entry->SerialNumber.pbData);
2410         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2411          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2412          info->Issuer.cbData);
2413         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2414          "Unexpected issuer\n");
2415     }
2416     /* and finally, with an extension */
2417     ret = CryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED,
2418      v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG,
2419      NULL, (BYTE *)&buf, &size);
2420     ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
2421     if (buf)
2422     {
2423         CRL_INFO *info = (CRL_INFO *)buf;
2424         CRL_ENTRY *entry;
2425
2426         ok(size >= sizeof(CRL_INFO), "Expected size at least %d, got %ld\n",
2427          sizeof(CRL_INFO), size);
2428         ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %ld\n",
2429          info->cCRLEntry);
2430         ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n");
2431         entry = info->rgCRLEntry;
2432         ok(entry->SerialNumber.cbData == 1,
2433          "Expected serial number size 1, got %ld\n",
2434          entry->SerialNumber.cbData);
2435         ok(*entry->SerialNumber.pbData == *serialNum,
2436          "Expected serial number %d, got %d\n", *serialNum,
2437          *entry->SerialNumber.pbData);
2438         ok(info->Issuer.cbData == sizeof(encodedCommonName),
2439          "Expected issuer of %d bytes, got %ld\n", sizeof(encodedCommonName),
2440          info->Issuer.cbData);
2441         ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData),
2442          "Unexpected issuer\n");
2443         /* Oddly, the extensions don't seem to be decoded. Is this just an MS
2444          * bug, or am I missing something?
2445          */
2446         ok(info->cExtension == 0, "Expected 0 extensions, got %ld\n",
2447          info->cExtension);
2448     }
2449 }
2450
2451 static void test_registerOIDFunction(void)
2452 {
2453     static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
2454     BOOL ret;
2455
2456     /* oddly, this succeeds under WinXP; the function name key is merely
2457      * omitted.  This may be a side effect of the registry code, I don't know.
2458      * I don't check it because I doubt anyone would depend on it.
2459     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
2460      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2461      */
2462     /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
2463      * HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)
2464      */
2465     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
2466      NULL);
2467     ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() ==
2468      HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)),
2469      "Expected ERROR_INVALID_PARAMETER: %ld\n", GetLastError());
2470     /* This has no effect, but "succeeds" on XP */
2471     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
2472      "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
2473     ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
2474     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
2475      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2476     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2477     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
2478      "1.2.3.4.5.6.7.8.9.10");
2479     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
2480     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
2481      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2482     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2483     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
2484      "1.2.3.4.5.6.7.8.9.10");
2485     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
2486     /* This has no effect */
2487     ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
2488      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2489     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2490     /* Check with bogus encoding type: */
2491     ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
2492      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2493     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2494     /* This is written with value 3 verbatim.  Thus, the encoding type isn't
2495      * (for now) treated as a mask.
2496      */
2497     ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
2498      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
2499     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
2500     ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
2501      "1.2.3.4.5.6.7.8.9.10");
2502     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
2503 }
2504
2505 /* Free *pInfo with HeapFree */
2506 static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
2507 {
2508     BOOL ret;
2509     DWORD size = 0;
2510     HCRYPTKEY key;
2511
2512     /* This crashes
2513     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL);
2514      */
2515     ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size);
2516     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2517      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2518     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL,
2519      &size);
2520     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2521      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2522     ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL,
2523      NULL, &size);
2524     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2525      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2526     ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2527      0, NULL, NULL, &size);
2528     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2529      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2530     /* Test with no key */
2531     ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
2532      0, NULL, NULL, &size);
2533     ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08lx\n",
2534      GetLastError());
2535     ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
2536     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
2537     if (ret)
2538     {
2539         ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
2540          NULL, 0, NULL, NULL, &size);
2541         ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2542         *pInfo = HeapAlloc(GetProcessHeap(), 0, size);
2543         if (*pInfo)
2544         {
2545             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
2546              X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size);
2547             ok(ret, "CryptExportPublicKeyInfoEx failed: %08lx\n",
2548              GetLastError());
2549             if (ret)
2550             {
2551                 /* By default (we passed NULL as the OID) the OID is
2552                  * szOID_RSA_RSA.
2553                  */
2554                 ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA),
2555                  "Expected %s, got %s\n", szOID_RSA_RSA,
2556                  (*pInfo)->Algorithm.pszObjId);
2557             }
2558         }
2559     }
2560 }
2561
2562 static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
2563 {
2564     BOOL ret;
2565     HCRYPTKEY key;
2566
2567     /* These crash
2568     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL);
2569     ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key);
2570     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL);
2571     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2572      NULL);
2573      */
2574     ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key);
2575     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2576      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2577     ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key);
2578     ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2579      "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
2580     ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL,
2581      &key);
2582     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
2583      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
2584     ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL,
2585      &key);
2586     ok(ret, "CryptImportPublicKeyInfoEx failed: %08lx\n", GetLastError());
2587     CryptDestroyKey(key);
2588 }
2589
2590 static const char cspName[] = "WineCryptTemp";
2591
2592 static void testPortPublicKeyInfo(void)
2593 {
2594     HCRYPTPROV csp;
2595     BOOL ret;
2596     PCERT_PUBLIC_KEY_INFO info = NULL;
2597
2598     /* Just in case a previous run failed, delete this thing */
2599     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2600      CRYPT_DELETEKEYSET);
2601     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2602      CRYPT_NEWKEYSET);
2603
2604     testExportPublicKey(csp, &info);
2605     testImportPublicKey(csp, info);
2606
2607     HeapFree(GetProcessHeap(), 0, info);
2608     CryptReleaseContext(csp, 0);
2609     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
2610      CRYPT_DELETEKEYSET);
2611 }
2612
2613 START_TEST(encode)
2614 {
2615     static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
2616      X509_ASN_ENCODING | PKCS_7_ASN_ENCODING };
2617     DWORD i;
2618
2619     for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
2620     {
2621         test_encodeInt(encodings[i]);
2622         test_decodeInt(encodings[i]);
2623         test_encodeEnumerated(encodings[i]);
2624         test_decodeEnumerated(encodings[i]);
2625         test_encodeFiletime(encodings[i]);
2626         test_decodeFiletime(encodings[i]);
2627         test_encodeName(encodings[i]);
2628         test_decodeName(encodings[i]);
2629         test_encodeAltName(encodings[i]);
2630         test_decodeAltName(encodings[i]);
2631         test_encodeOctets(encodings[i]);
2632         test_decodeOctets(encodings[i]);
2633         test_encodeBits(encodings[i]);
2634         test_decodeBits(encodings[i]);
2635         test_encodeBasicConstraints(encodings[i]);
2636         test_decodeBasicConstraints(encodings[i]);
2637         test_encodeRsaPublicKey(encodings[i]);
2638         test_decodeRsaPublicKey(encodings[i]);
2639         test_encodeSequenceOfAny(encodings[i]);
2640         test_decodeSequenceOfAny(encodings[i]);
2641         test_encodeExtensions(encodings[i]);
2642         test_decodeExtensions(encodings[i]);
2643         test_encodePublicKeyInfo(encodings[i]);
2644         test_decodePublicKeyInfo(encodings[i]);
2645         test_encodeCertToBeSigned(encodings[i]);
2646         test_decodeCertToBeSigned(encodings[i]);
2647         test_encodeCert(encodings[i]);
2648         test_decodeCert(encodings[i]);
2649         test_encodeCRLToBeSigned(encodings[i]);
2650         test_decodeCRLToBeSigned(encodings[i]);
2651     }
2652     test_registerOIDFunction();
2653     testPortPublicKeyInfo();
2654 }