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