d1cb42f0cd81a462feddf20bcdc27d41bc6b0f23
[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 static const unsigned char bin58[] = { 0x03,0x01,0x00 };
2059
2060 static const struct encodedBits bits[] = {
2061 /* normal test cases */
2062 { 0, bin52, 2, bin53 },
2063 { 1, bin54, 2, bin55 },
2064 /* strange test case, showing cUnusedBits >= 8 is allowed */
2065 { 9, bin56, 1, bin57 },
2066 };
2067
2068 static void test_encodeBits(DWORD dwEncoding)
2069 {
2070 DWORD i;
2071
2072 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
2073 {
2074 CRYPT_BIT_BLOB blob;
2075 BOOL ret;
2076 BYTE *buf = NULL;
2077 DWORD bufSize = 0;
2078
2079 blob.cbData = sizeof(bytesToEncode);
2080 blob.pbData = (BYTE *)bytesToEncode;
2081 blob.cUnusedBits = bits[i].cUnusedBits;
2082 ret = pCryptEncodeObjectEx(dwEncoding, X509_BITS, &blob,
2083 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2084 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2085 if (ret)
2086 {
2087 ok(bufSize == bits[i].encoded[1] + 2,
2088 "%d: Got unexpected size %d, expected %d\n", i, bufSize,
2089 bits[i].encoded[1] + 2);
2090 ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2),
2091 "%d: Unexpected value\n", i);
2092 LocalFree(buf);
2093 }
2094 }
2095 }
2096
2097 static void test_decodeBits(DWORD dwEncoding)
2098 {
2099 static const BYTE ber[] = "\x03\x02\x01\xff";
2100 static const BYTE berDecoded = 0xfe;
2101 DWORD i;
2102 BOOL ret;
2103 BYTE *buf = NULL;
2104 DWORD bufSize = 0;
2105
2106 /* normal cases */
2107 for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++)
2108 {
2109 ret = pCryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded,
2110 bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
2111 &bufSize);
2112 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2113 if (ret)
2114 {
2115 CRYPT_BIT_BLOB *blob;
2116
2117 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded,
2118 "Got unexpected size %d\n", bufSize);
2119 blob = (CRYPT_BIT_BLOB *)buf;
2120 ok(blob->cbData == bits[i].cbDecoded,
2121 "Got unexpected length %d, expected %d\n", blob->cbData,
2122 bits[i].cbDecoded);
2123 if (blob->cbData && bits[i].cbDecoded)
2124 ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded),
2125 "Unexpected value\n");
2126 LocalFree(buf);
2127 }
2128 }
2129 /* special case: check that something that's valid in BER but not in DER
2130 * decodes successfully
2131 */
2132 ret = pCryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2,
2133 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2134 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2135 if (ret)
2136 {
2137 CRYPT_BIT_BLOB *blob;
2138
2139 ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded),
2140 "Got unexpected size %d\n", bufSize);
2141 blob = (CRYPT_BIT_BLOB *)buf;
2142 ok(blob->cbData == sizeof(berDecoded),
2143 "Got unexpected length %d\n", blob->cbData);
2144 if (blob->cbData)
2145 ok(*blob->pbData == berDecoded, "Unexpected value\n");
2146 LocalFree(buf);
2147 }
2148 }
2149
2150 struct Constraints2
2151 {
2152 CERT_BASIC_CONSTRAINTS2_INFO info;
2153 const BYTE *encoded;
2154 };
2155
2156 static const unsigned char bin59[] = { 0x30,0x00 };
2157 static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff };
2158 static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 };
2159 static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2160 static const struct Constraints2 constraints2[] = {
2161 /* empty constraints */
2162 { { FALSE, FALSE, 0}, bin59 },
2163 /* can be a CA */
2164 { { TRUE, FALSE, 0}, bin60 },
2165 /* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
2166 * but that's not the case
2167 */
2168 { { FALSE, TRUE, 0}, bin61 },
2169 /* can be a CA and has path length constraints set */
2170 { { TRUE, TRUE, 1}, bin62 },
2171 };
2172
2173 static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
2174 static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
2175 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
2176 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
2177 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
2178 static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
2179 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
2180 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
2181 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
2182 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
2183
2184 static void test_encodeBasicConstraints(DWORD dwEncoding)
2185 {
2186 DWORD i, bufSize = 0;
2187 CERT_BASIC_CONSTRAINTS_INFO info = { { 0 } };
2188 CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
2189 (LPBYTE)encodedDomainName };
2190 BOOL ret;
2191 BYTE *buf = NULL;
2192
2193 /* First test with the simpler info2 */
2194 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
2195 {
2196 ret = pCryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2197 &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf,
2198 &bufSize);
2199 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2200 if (ret)
2201 {
2202 ok(bufSize == constraints2[i].encoded[1] + 2,
2203 "Expected %d bytes, got %d\n", constraints2[i].encoded[1] + 2,
2204 bufSize);
2205 ok(!memcmp(buf, constraints2[i].encoded,
2206 constraints2[i].encoded[1] + 2), "Unexpected value\n");
2207 LocalFree(buf);
2208 }
2209 }
2210 /* Now test with more complex basic constraints */
2211 info.SubjectType.cbData = 0;
2212 info.fPathLenConstraint = FALSE;
2213 info.cSubtreesConstraint = 0;
2214 ret = pCryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
2215 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2216 ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */,
2217 "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2218 if (ret)
2219 {
2220 ok(bufSize == sizeof(emptyConstraint), "Wrong size %d\n", bufSize);
2221 ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
2222 "Unexpected value\n");
2223 LocalFree(buf);
2224 }
2225 /* None of the certs I examined had any subtree constraint, but I test one
2226 * anyway just in case.
2227 */
2228 info.cSubtreesConstraint = 1;
2229 info.rgSubtreesConstraint = &nameBlob;
2230 ret = pCryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
2231 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2232 ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */,
2233 "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2234 if (ret)
2235 {
2236 ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %d\n", bufSize);
2237 ok(!memcmp(buf, constraintWithDomainName,
2238 sizeof(constraintWithDomainName)), "Unexpected value\n");
2239 LocalFree(buf);
2240 }
2241 /* FIXME: test encoding with subject type. */
2242 }
2243
2244 static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 };
2245
2246 static void test_decodeBasicConstraints(DWORD dwEncoding)
2247 {
2248 static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01,
2249 0xff };
2250 static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 };
2251 DWORD i;
2252 BOOL ret;
2253 BYTE *buf = NULL;
2254 DWORD bufSize = 0;
2255
2256 /* First test with simpler info2 */
2257 for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
2258 {
2259 ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2260 constraints2[i].encoded, constraints2[i].encoded[1] + 2,
2261 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2262 ok(ret, "CryptDecodeObjectEx failed for item %d: %08x\n", i,
2263 GetLastError());
2264 if (ret)
2265 {
2266 CERT_BASIC_CONSTRAINTS2_INFO *info =
2267 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
2268
2269 ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
2270 "Unexpected value for item %d\n", i);
2271 LocalFree(buf);
2272 }
2273 }
2274 /* Check with the order of encoded elements inverted */
2275 buf = (PBYTE)1;
2276 ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2277 inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
2278 &bufSize);
2279 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT ||
2280 GetLastError() == OSS_DATA_ERROR /* Win9x */),
2281 "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n",
2282 GetLastError());
2283 ok(!buf, "Expected buf to be set to NULL\n");
2284 /* Check with a non-DER bool */
2285 ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2286 badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
2287 &buf, &bufSize);
2288 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2289 if (ret)
2290 {
2291 CERT_BASIC_CONSTRAINTS2_INFO *info =
2292 (CERT_BASIC_CONSTRAINTS2_INFO *)buf;
2293
2294 ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
2295 LocalFree(buf);
2296 }
2297 /* Check with a non-basic constraints value */
2298 ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
2299 encodedCommonName, encodedCommonName[1] + 2,
2300 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2301 ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT ||
2302 GetLastError() == OSS_DATA_ERROR /* Win9x */),
2303 "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n",
2304 GetLastError());
2305 /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
2306 ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
2307 emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
2308 &buf, &bufSize);
2309 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2310 if (ret)
2311 {
2312 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
2313
2314 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
2315 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
2316 ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
2317 LocalFree(buf);
2318 }
2319 ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
2320 constraintWithDomainName, sizeof(constraintWithDomainName),
2321 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2322 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2323 if (ret)
2324 {
2325 CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
2326
2327 ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
2328 ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
2329 ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
2330 if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
2331 {
2332 ok(info->rgSubtreesConstraint[0].cbData ==
2333 sizeof(encodedDomainName), "Wrong size %d\n",
2334 info->rgSubtreesConstraint[0].cbData);
2335 ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
2336 sizeof(encodedDomainName)), "Unexpected value\n");
2337 }
2338 LocalFree(buf);
2339 }
2340 }
2341
2342 /* These are terrible public keys of course, I'm just testing encoding */
2343 static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 };
2344 static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 };
2345 static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 };
2346 static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 };
2347 static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 };
2348 static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
2349 static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 };
2350 static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 };
2351
2352 struct EncodedRSAPubKey
2353 {
2354 const BYTE *modulus;
2355 size_t modulusLen;
2356 const BYTE *encoded;
2357 size_t decodedModulusLen;
2358 };
2359
2360 static const struct EncodedRSAPubKey rsaPubKeys[] = {
2361 { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) },
2362 { modulus2, sizeof(modulus2), mod2_encoded, 5 },
2363 { modulus3, sizeof(modulus3), mod3_encoded, 5 },
2364 { modulus4, sizeof(modulus4), mod4_encoded, 8 },
2365 };
2366
2367 static void test_encodeRsaPublicKey(DWORD dwEncoding)
2368 {
2369 BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)];
2370 BLOBHEADER *hdr = (BLOBHEADER *)toEncode;
2371 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER));
2372 BOOL ret;
2373 BYTE *buf = NULL;
2374 DWORD bufSize = 0, i;
2375
2376 /* Try with a bogus blob type */
2377 hdr->bType = 2;
2378 hdr->bVersion = CUR_BLOB_VERSION;
2379 hdr->reserved = 0;
2380 hdr->aiKeyAlg = CALG_RSA_KEYX;
2381 rsaPubKey->magic = 0x31415352;
2382 rsaPubKey->bitlen = sizeof(modulus1) * 8;
2383 rsaPubKey->pubexp = 65537;
2384 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1,
2385 sizeof(modulus1));
2386
2387 ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2388 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2389 ok(!ret && GetLastError() == E_INVALIDARG,
2390 "Expected E_INVALIDARG, got %08x\n", GetLastError());
2391 /* Now with a bogus reserved field */
2392 hdr->bType = PUBLICKEYBLOB;
2393 hdr->reserved = 1;
2394 ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2395 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2396 if (ret)
2397 {
2398 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2399 "Expected size %d, got %d\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2400 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2401 LocalFree(buf);
2402 }
2403 /* Now with a bogus blob version */
2404 hdr->reserved = 0;
2405 hdr->bVersion = 0;
2406 ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2407 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2408 if (ret)
2409 {
2410 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2411 "Expected size %d, got %d\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2412 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2413 LocalFree(buf);
2414 }
2415 /* And with a bogus alg ID */
2416 hdr->bVersion = CUR_BLOB_VERSION;
2417 hdr->aiKeyAlg = CALG_DES;
2418 ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2419 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2420 if (ret)
2421 {
2422 ok(bufSize == rsaPubKeys[0].encoded[1] + 2,
2423 "Expected size %d, got %d\n", rsaPubKeys[0].encoded[1] + 2, bufSize);
2424 ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n");
2425 LocalFree(buf);
2426 }
2427 /* Check a couple of RSA-related OIDs */
2428 hdr->aiKeyAlg = CALG_RSA_KEYX;
2429 ret = pCryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA,
2430 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2431 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2432 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
2433 ret = pCryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
2434 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2435 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2436 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
2437 /* Finally, all valid */
2438 hdr->aiKeyAlg = CALG_RSA_KEYX;
2439 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2440 {
2441 memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2442 rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen);
2443 ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2444 toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2445 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2446 if (ret)
2447 {
2448 ok(bufSize == rsaPubKeys[i].encoded[1] + 2,
2449 "Expected size %d, got %d\n", rsaPubKeys[i].encoded[1] + 2,
2450 bufSize);
2451 ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize),
2452 "Unexpected value\n");
2453 LocalFree(buf);
2454 }
2455 }
2456 }
2457
2458 static void test_decodeRsaPublicKey(DWORD dwEncoding)
2459 {
2460 DWORD i;
2461 LPBYTE buf = NULL;
2462 DWORD bufSize = 0;
2463 BOOL ret;
2464
2465 /* Try with a bad length */
2466 ret = pCryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2467 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1],
2468 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2469 ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD ||
2470 GetLastError() == OSS_MORE_INPUT /* Win9x/NT4 */),
2471 "Expected CRYPT_E_ASN1_EOD or OSS_MORE_INPUT, got %08x\n",
2472 GetLastError());
2473 /* Try with a couple of RSA-related OIDs */
2474 ret = pCryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA,
2475 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2476 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2477 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2478 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
2479 ret = pCryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA,
2480 rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2,
2481 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2482 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
2483 "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError());
2484 /* Now try success cases */
2485 for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++)
2486 {
2487 bufSize = 0;
2488 ret = pCryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB,
2489 rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2,
2490 CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2491 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2492 if (ret)
2493 {
2494 BLOBHEADER *hdr = (BLOBHEADER *)buf;
2495 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
2496
2497 ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
2498 rsaPubKeys[i].decodedModulusLen,
2499 "Wrong size %d\n", bufSize);
2500 ok(hdr->bType == PUBLICKEYBLOB,
2501 "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB,
2502 hdr->bType);
2503 ok(hdr->bVersion == CUR_BLOB_VERSION,
2504 "Expected version CUR_BLOB_VERSION (%d), got %d\n",
2505 CUR_BLOB_VERSION, hdr->bVersion);
2506 ok(hdr->reserved == 0, "Expected reserved 0, got %d\n",
2507 hdr->reserved);
2508 ok(hdr->aiKeyAlg == CALG_RSA_KEYX,
2509 "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg);
2510 ok(rsaPubKey->magic == 0x31415352,
2511 "Expected magic RSA1, got %08x\n", rsaPubKey->magic);
2512 ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8,
2513 "Wrong bit len %d\n", rsaPubKey->bitlen);
2514 ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %d\n",
2515 rsaPubKey->pubexp);
2516 ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
2517 rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen),
2518 "Unexpected modulus\n");
2519 LocalFree(buf);
2520 }
2521 }
2522 }
2523
2524 static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
2525 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
2526 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2527
2528 static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
2529 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
2530 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
2531 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
2532
2533 static void test_encodeSequenceOfAny(DWORD dwEncoding)
2534 {
2535 CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
2536 CRYPT_SEQUENCE_OF_ANY seq;
2537 DWORD i;
2538 BOOL ret;
2539 BYTE *buf = NULL;
2540 DWORD bufSize = 0;
2541
2542 /* Encode a homogeneous sequence */
2543 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
2544 {
2545 blobs[i].cbData = ints[i].encoded[1] + 2;
2546 blobs[i].pbData = (BYTE *)ints[i].encoded;
2547 }
2548 seq.cValue = sizeof(ints) / sizeof(ints[0]);
2549 seq.rgValue = blobs;
2550
2551 ret = pCryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2552 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2553 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2554 if (ret)
2555 {
2556 ok(bufSize == sizeof(intSequence), "Wrong size %d\n", bufSize);
2557 ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
2558 LocalFree(buf);
2559 }
2560 /* Change the type of the first element in the sequence, and give it
2561 * another go
2562 */
2563 blobs[0].cbData = times[0].encodedTime[1] + 2;
2564 blobs[0].pbData = (BYTE *)times[0].encodedTime;
2565 ret = pCryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
2566 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2567 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2568 if (ret)
2569 {
2570 ok(bufSize == sizeof(mixedSequence), "Wrong size %d\n", bufSize);
2571 ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
2572 "Unexpected value\n");
2573 LocalFree(buf);
2574 }
2575 }
2576
2577 static void test_decodeSequenceOfAny(DWORD dwEncoding)
2578 {
2579 BOOL ret;
2580 BYTE *buf = NULL;
2581 DWORD bufSize = 0;
2582
2583 ret = pCryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
2584 intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2585 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2586 if (ret)
2587 {
2588 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2589 DWORD i;
2590
2591 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2592 "Wrong elements %d\n", seq->cValue);
2593 for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
2594 {
2595 ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
2596 "Expected %d bytes, got %d\n", ints[i].encoded[1] + 2,
2597 seq->rgValue[i].cbData);
2598 ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
2599 ints[i].encoded[1] + 2), "Unexpected value\n");
2600 }
2601 LocalFree(buf);
2602 }
2603 ret = pCryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
2604 mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
2605 &bufSize);
2606 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2607 if (ret)
2608 {
2609 CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
2610
2611 ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
2612 "Wrong elements %d\n", seq->cValue);
2613 /* Just check the first element since it's all that changed */
2614 ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
2615 "Expected %d bytes, got %d\n", times[0].encodedTime[1] + 2,
2616 seq->rgValue[0].cbData);
2617 ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
2618 times[0].encodedTime[1] + 2), "Unexpected value\n");
2619 LocalFree(buf);
2620 }
2621 }
2622
2623 struct encodedExtensions
2624 {
2625 CERT_EXTENSIONS exts;
2626 const BYTE *encoded;
2627 };
2628
2629 static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2630 static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2631 static CHAR oid_basic_constraints2[] = szOID_BASIC_CONSTRAINTS2;
2632 static CERT_EXTENSION criticalExt =
2633 { oid_basic_constraints2, TRUE, { 8, crit_ext_data } };
2634 static CERT_EXTENSION nonCriticalExt =
2635 { oid_basic_constraints2, FALSE, { 8, noncrit_ext_data } };
2636 static CHAR oid_short[] = "1.1";
2637 static CERT_EXTENSION extWithShortOid =
2638 { oid_short, FALSE, { 0, NULL } };
2639
2640 static const BYTE ext0[] = { 0x30,0x00 };
2641 static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,
2642 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2643 static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04,
2644 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 };
2645 static const BYTE ext3[] = { 0x30,0x07,0x30,0x05,0x06,0x01,0x29,0x04,0x00 };
2646
2647 static const struct encodedExtensions exts[] = {
2648 { { 0, NULL }, ext0 },
2649 { { 1, &criticalExt }, ext1 },
2650 { { 1, &nonCriticalExt }, ext2 },
2651 { { 1, &extWithShortOid }, ext3 }
2652 };
2653
2654 static void test_encodeExtensions(DWORD dwEncoding)
2655 {
2656 DWORD i;
2657
2658 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2659 {
2660 BOOL ret;
2661 BYTE *buf = NULL;
2662 DWORD bufSize = 0;
2663
2664 ret = pCryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts,
2665 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
2666 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2667 if (ret)
2668 {
2669 ok(bufSize == exts[i].encoded[1] + 2,
2670 "Expected %d bytes, got %d\n", exts[i].encoded[1] + 2, bufSize);
2671 ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2),
2672 "Unexpected value\n");
2673 LocalFree(buf);
2674 }
2675 }
2676 }
2677
2678 static void test_decodeExtensions(DWORD dwEncoding)
2679 {
2680 DWORD i;
2681
2682 for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++)
2683 {
2684 BOOL ret;
2685 BYTE *buf = NULL;
2686 DWORD bufSize = 0;
2687
2688 ret = pCryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
2689 exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG,
2690 NULL, &buf, &bufSize);
2691 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2692 if (ret)
2693 {
2694 CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf;
2695 DWORD j;
2696
2697 ok(ext->cExtension == exts[i].exts.cExtension,
2698 "Expected %d extensions, see %d\n", exts[i].exts.cExtension,
2699 ext->cExtension);
2700 for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++)
2701 {
2702 ok(!strcmp(ext->rgExtension[j].pszObjId,
2703 exts[i].exts.rgExtension[j].pszObjId),
2704 "Expected OID %s, got %s\n",
2705 exts[i].exts.rgExtension[j].pszObjId,
2706 ext->rgExtension[j].pszObjId);
2707 ok(!memcmp(ext->rgExtension[j].Value.pbData,
2708 exts[i].exts.rgExtension[j].Value.pbData,
2709 exts[i].exts.rgExtension[j].Value.cbData),
2710 "Unexpected value\n");
2711 }
2712 LocalFree(buf);
2713 }
2714 ret = pCryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
2715 exts[i].encoded, exts[i].encoded[1] + 2, 0, NULL, NULL, &bufSize);
2716 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2717 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize);
2718 if (buf)
2719 {
2720 ret = pCryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS,
2721 exts[i].encoded, exts[i].encoded[1] + 2, 0, NULL, buf, &bufSize);
2722 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
2723 HeapFree(GetProcessHeap(), 0, buf);
2724 }
2725 }
2726 }
2727
2728 /* MS encodes public key info with a NULL if the algorithm identifier's
2729 * parameters are empty. However, when encoding an algorithm in a CERT_INFO,
2730 * it encodes them by omitting the algorithm parameters. It accepts either
2731 * form for decoding.
2732 */
2733 struct encodedPublicKey
2734 {
2735 CERT_PUBLIC_KEY_INFO info;
2736 const BYTE *encoded;
2737 const BYTE *encodedNoNull;
2738 CERT_PUBLIC_KEY_INFO decoded;
2739 };
2740
2741 static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd,
2742 0xe, 0xf };
2743 static const BYTE params[] = { 0x02, 0x01, 0x01 };
2744
2745 static const unsigned char bin64[] = {
2746 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00};
2747 static const unsigned char bin65[] = {
2748 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00};
2749 static const unsigned char bin66[] = {
2750 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00};
2751 static const unsigned char bin67[] = {
2752 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00};
2753 static const unsigned char bin68[] = {
2754 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01,
2755 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2756 static const unsigned char bin69[] = {
2757 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01,
2758 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
2759 static const unsigned char bin70[] = {
2760 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2761 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2762 0x0f};
2763 static const unsigned char bin71[] = {
2764 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01,
2765 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
2766 0x0f};
2767 static unsigned char bin72[] = { 0x05,0x00};
2768
2769 static CHAR oid_bogus[] = "1.2.3",
2770 oid_rsa[] = szOID_RSA;
2771
2772 static const struct encodedPublicKey pubKeys[] = {
2773 /* with a bogus OID */
2774 { { { oid_bogus, { 0, NULL } }, { 0, NULL, 0 } },
2775 bin64, bin65,
2776 { { oid_bogus, { 2, bin72 } }, { 0, NULL, 0 } } },
2777 /* some normal keys */
2778 { { { oid_rsa, { 0, NULL } }, { 0, NULL, 0} },
2779 bin66, bin67,
2780 { { oid_rsa, { 2, bin72 } }, { 0, NULL, 0 } } },
2781 { { { oid_rsa, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} },
2782 bin68, bin69,
2783 { { oid_rsa, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } },
2784 /* with add'l parameters--note they must be DER-encoded */
2785 { { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2786 (BYTE *)aKey, 0 } },
2787 bin70, bin71,
2788 { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey),
2789 (BYTE *)aKey, 0 } } },
2790 };
2791
2792 static void test_encodePublicKeyInfo(DWORD dwEncoding)
2793 {
2794 DWORD i;
2795
2796 for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++)
2797 {
2798 BOOL ret;
2799 BYTE *buf = NULL;
2800 DWORD bufSize = 0;
2801
2802 ret = pCryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO,
2803 &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf,
2804 &bufSize);
2805 ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */,
2806 "CryptEncodeObjectEx failed: %08x\n", GetLastError());
2807 if (ret)
2808 {
2809 ok(bufSize == pubKeys[i].encoded[1] + 2,
2810 "Expected %d bytes, got %d\n", pubKeys[i].encoded[1] + 2, bufSize);
2811 if (bufSize == pubKeys[i].encoded[1] + 2)
2812 ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2),
2813 "Unexpected value\n");
2814 LocalFree(buf);
2815 }
2816 }
2817 }