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