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