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