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