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