~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/tests/encode.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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