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 /* check with NULL integer buffer. Windows XP incorrectly returns an
106 * NTSTATUS.
107 */
108 ret = pCryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL,
109 &bufSize);
110 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
111 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
112 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
113 {
114 /* encode as normal integer */
115 ret = pCryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
116 NULL, NULL, &bufSize);
117 ok(ret, "Expected success, got %d\n", GetLastError());
118 ret = pCryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val,
119 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
120 ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError());
121 if (buf)
122 {
123 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
124 buf[0]);
125 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
126 buf[1], ints[i].encoded[1]);
127 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
128 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
129 LocalFree(buf);
130 }
131 /* encode as multibyte integer */
132 blob.cbData = sizeof(ints[i].val);
133 blob.pbData = (BYTE *)&ints[i].val;
134 ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
135 0, NULL, NULL, &bufSize);
136 ok(ret, "Expected success, got %d\n", GetLastError());
137 ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
138 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
139 ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError());
140 if (buf)
141 {
142 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
143 buf[0]);
144 ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
145 buf[1], ints[i].encoded[1]);
146 ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
147 "Encoded value of 0x%08x didn't match expected\n", ints[i].val);
148 LocalFree(buf);
149 }
150 }
151 /* encode a couple bigger ints, just to show it's little-endian and leading
152 * sign bytes are dropped
153 */
154 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
155 {
156 blob.cbData = strlen((const char*)bigInts[i].val);
157 blob.pbData = (BYTE *)bigInts[i].val;
158 ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
159 0, NULL, NULL, &bufSize);
160 ok(ret, "Expected success, got %d\n", GetLastError());
161 ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
162 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
163 ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError());
164 if (buf)
165 {
166 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
167 buf[0]);
168 ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
169 buf[1], bigInts[i].encoded[1]);
170 ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
171 bigInts[i].encoded[1] + 1),
172 "Encoded value didn't match expected\n");
173 LocalFree(buf);
174 }
175 }
176 /* and, encode some uints */
177 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
178 {
179 blob.cbData = strlen((const char*)bigUInts[i].val);
180 blob.pbData = (BYTE*)bigUInts[i].val;
181 ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
182 0, NULL, NULL, &bufSize);
183 ok(ret, "Expected success, got %d\n", GetLastError());
184 ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob,
185 CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize);
186 ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError());
187 if (buf)
188 {
189 ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
190 buf[0]);
191 ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n",
192 buf[1], bigUInts[i].encoded[1]);
193 ok(!memcmp(buf + 1, bigUInts[i].encoded + 1,
194 bigUInts[i].encoded[1] + 1),
195 "Encoded value didn't match expected\n");
196 LocalFree(buf);
197 }
198 }
199 }
200
201 static void test_decodeInt(DWORD dwEncoding)
202 {
203 static const BYTE bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
204 static const BYTE testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
205 static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 };
206 static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 };
207 static const BYTE extraBytes[] = { 2, 1, 1, 0, 0, 0, 0 };
208 BYTE *buf = NULL;
209 DWORD bufSize = 0;
210 int i;
211 BOOL ret;
212
213 /* CryptDecodeObjectEx with NULL bufSize crashes..
214 ret = pCryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded,
215 ints[0].encoded[1] + 2, 0, NULL, NULL, NULL);
216 */
217 /* check bogus encoding */
218 ret = pCryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded,
219 ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize);
220 ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
221 "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
222 /* check with NULL integer buffer */
223 ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL,
224 &bufSize);
225 ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
226 "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError());
227 /* check with a valid, but too large, integer */
228 ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2,
229 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
230 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
231 "Expected CRYPT_E_ASN1_LARGE, got %d\n", GetLastError());
232 /* check with a DER-encoded string */
233 ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2,
234 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
235 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
236 "Expected CRYPT_E_ASN1_BADTAG, got %d\n", GetLastError());
237 for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
238 {
239 /* When the output buffer is NULL, this always succeeds */
240 SetLastError(0xdeadbeef);
241 ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER,
242 ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL,
243 &bufSize);
244 ok(ret && GetLastError() == NOERROR,
245 "Expected success and NOERROR, got %d\n", GetLastError());
246 ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER,
247 ints[i].encoded, ints[i].encoded[1] + 2,
248 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
249 ok(ret, "CryptDecodeObjectEx failed: %d\n", GetLastError());
250 ok(bufSize == sizeof(int), "Wrong size %d\n", bufSize);
251 ok(buf != NULL, "Expected allocated buffer\n");
252 if (buf)
253 {
254 ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n",
255 ints[i].val, *(int *)buf);
256 LocalFree(buf);
257 }
258 }
259 for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
260 {
261 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
262 bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
263 &bufSize);
264 ok(ret && GetLastError() == NOERROR,
265 "Expected success and NOERROR, got %d\n", GetLastError());
266 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
267 bigInts[i].encoded, bigInts[i].encoded[1] + 2,
268 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
269 ok(ret, "CryptDecodeObjectEx failed: %d\n", GetLastError());
270 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %d\n", bufSize);
271 ok(buf != NULL, "Expected allocated buffer\n");
272 if (buf)
273 {
274 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
275
276 ok(blob->cbData == strlen((const char*)bigInts[i].decoded),
277 "Expected len %d, got %d\n", lstrlenA((const char*)bigInts[i].decoded),
278 blob->cbData);
279 ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
280 "Unexpected value\n");
281 LocalFree(buf);
282 }
283 }
284 for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++)
285 {
286 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
287 bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL,
288 &bufSize);
289 ok(ret && GetLastError() == NOERROR,
290 "Expected success and NOERROR, got %d\n", GetLastError());
291 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT,
292 bigUInts[i].encoded, bigUInts[i].encoded[1] + 2,
293 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
294 ok(ret, "CryptDecodeObjectEx failed: %d\n", GetLastError());
295 ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %d\n", bufSize);
296 ok(buf != NULL, "Expected allocated buffer\n");
297 if (buf)
298 {
299 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
300
301 ok(blob->cbData == strlen((const char*)bigUInts[i].val),
302 "Expected len %d, got %d\n", lstrlenA((const char*)bigUInts[i].val),
303 blob->cbData);
304 ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData),
305 "Unexpected value\n");
306 LocalFree(buf);
307 }
308 }
309 /* Decode the value 1 with long-form length */
310 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm,
311 sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
312 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
313 if (buf)
314 {
315 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
316 LocalFree(buf);
317 }
318 /* check with extra bytes at the end */
319 ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, extraBytes,
320 sizeof(extraBytes), CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
321 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
322 if (buf)
323 {
324 ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf);
325 LocalFree(buf);
326 }
327 /* Try to decode some bogus large items */
328 /* The buffer size is smaller than the encoded length, so this should fail
329 * with CRYPT_E_ASN1_EOD if it's being decoded.
330 * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit
331 * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes.
332 * So this test unfortunately isn't useful.
333 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig,
334 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
335 ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE,
336 "Expected CRYPT_E_ASN1_LARGE, got %08x\n", GetLastError());
337 */
338 /* This will try to decode the buffer and overflow it, check that it's
339 * caught.
340 */
341 if (0)
342 {
343 /* a large buffer isn't guaranteed to crash, it depends on memory allocation order */
344 ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus,
345 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
346 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
347 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
348 }
349 }
350
351 static const BYTE bin18[] = {0x0a,0x01,0x01};
352 static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80};
353
354 /* These are always encoded unsigned, and aren't constrained to be any
355 * particular value
356 */
357 static const struct encodedInt enums[] = {
358 { 1, bin18 },
359 { -128, bin19 },
360 };
361
362 /* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to
363 * X509_ENUMERATED.
364 */
365 static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED,
366 szOID_CRL_REASON_CODE };
367
368 static void test_encodeEnumerated(DWORD dwEncoding)
369 {
370 DWORD i, j;
371
372 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
373 {
374 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
375 {
376 BOOL ret;
377 BYTE *buf = NULL;
378 DWORD bufSize = 0;
379
380 ret = pCryptEncodeObjectEx(dwEncoding, enumeratedTypes[i],
381 &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
382 &bufSize);
383 ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError());
384 if (buf)
385 {
386 ok(buf[0] == 0xa,
387 "Got unexpected type %d for enumerated (expected 0xa)\n",
388 buf[0]);
389 ok(buf[1] == enums[j].encoded[1],
390 "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]);
391 ok(!memcmp(buf + 1, enums[j].encoded + 1,
392 enums[j].encoded[1] + 1),
393 "Encoded value of 0x%08x didn't match expected\n",
394 enums[j].val);
395 LocalFree(buf);
396 }
397 }
398 }
399 }
400
401 static void test_decodeEnumerated(DWORD dwEncoding)
402 {
403 DWORD i, j;
404
405 for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++)
406 {
407 for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++)
408 {
409 BOOL ret;
410 DWORD bufSize = sizeof(int);
411 int val;
412
413 ret = pCryptDecodeObjectEx(dwEncoding, enumeratedTypes[i],
414 enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL,
415 (BYTE *)&val, &bufSize);
416 ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
417 ok(bufSize == sizeof(int),
418 "Got unexpected size %d for enumerated\n", bufSize);
419 ok(val == enums[j].val, "Unexpected value %d, expected %d\n",
420 val, enums[j].val);
421 }
422 }
423 }
424
425 struct encodedFiletime
426 {
427 SYSTEMTIME sysTime;
428 const BYTE *encodedTime;
429 };
430
431 static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType,
432 const struct encodedFiletime *time)
433 {
434 FILETIME ft = { 0 };
435 BYTE *buf = NULL;
436 DWORD bufSize = 0;
437 BOOL ret;
438
439 ret = SystemTimeToFileTime(&time->sysTime, &ft);
440 ok(ret, "SystemTimeToFileTime failed: %d\n", GetLastError());
441 ret = pCryptEncodeObjectEx(dwEncoding, structType, &ft,
442 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
443 /* years other than 1950-2050 are not allowed for encodings other than
444 * X509_CHOICE_OF_TIME.
445 */
446 if (structType == X509_CHOICE_OF_TIME ||
447 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
448 {
449 ok(ret, "CryptEncodeObjectEx failed: %d (0x%08x)\n", GetLastError(),
450 GetLastError());
451 ok(buf != NULL, "Expected an allocated buffer\n");
452 if (buf)
453 {
454 ok(buf[0] == time->encodedTime[0],
455 "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
456 buf[0]);
457 ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %d\n",
458 time->encodedTime[1], bufSize);
459 ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
460 "Got unexpected value for time encoding\n");
461 LocalFree(buf);
462 }
463 }
464 else
465 ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
466 "Expected CRYPT_E_BAD_ENCODE, got 0x%08x\n", GetLastError());
467 }
468
469 static const char *printSystemTime(const SYSTEMTIME *st)
470 {
471 static char buf[25];
472
473 sprintf(buf, "%02d-%02d-%04d %02d:%02d:%02d.%03d", st->wMonth, st->wDay,
474 st->wYear, st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
475 return buf;
476 }
477
478 static const char *printFileTime(const FILETIME *ft)
479 {
480 static char buf[25];
481 SYSTEMTIME st;
482
483 FileTimeToSystemTime(ft, &st);
484 sprintf(buf, "%02d-%02d-%04d %02d:%02d:%02d.%03d", st.wMonth, st.wDay,
485 st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
486 return buf;
487 }
488
489 static void compareTime(const SYSTEMTIME *expected, const FILETIME *got)
490 {
491 SYSTEMTIME st;
492
493 FileTimeToSystemTime(got, &st);
494 ok(expected->wYear == st.wYear &&
495 expected->wMonth == st.wMonth &&
496 expected->wDay == st.wDay &&
497 expected->wHour == st.wHour &&
498 expected->wMinute == st.wMinute &&
499 expected->wSecond == st.wSecond &&
500 abs(expected->wMilliseconds - st.wMilliseconds) <= 1,
501 "Got unexpected value for time decoding:\nexpected %s, got %s\n",
502 printSystemTime(expected), printFileTime(got));
503 }
504
505 static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType,
506 const struct encodedFiletime *time)
507 {
508 FILETIME ft = { 0 };
509 DWORD size = sizeof(ft);
510 BOOL ret;
511
512 ret = pCryptDecodeObjectEx(dwEncoding, structType, time->encodedTime,
513 time->encodedTime[1] + 2, 0, NULL, &ft, &size);
514 /* years other than 1950-2050 are not allowed for encodings other than
515 * X509_CHOICE_OF_TIME.
516 */
517 if (structType == X509_CHOICE_OF_TIME ||
518 (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
519 {
520 ok(ret, "CryptDecodeObjectEx failed: %d (0x%08x)\n", GetLastError(),
521 GetLastError());
522 compareTime(&time->sysTime, &ft);
523 }
524 else
525 ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
526 "Expected CRYPT_E_ASN1_BADTAG, got 0x%08x\n", GetLastError());
527 }
528
529 static const BYTE bin20[] = {
530 0x17,0x0d,'','5','','6','','6','1','6','1','','','','Z'};
531 static const BYTE bin21[] = {
532 0x18,0x0f,'1','9','4','5','','6','','6','1','6','1','','','','Z'};
533 static const BYTE bin22[] = {
534 0x18,0x0f,'2','1','4','5','','6','','6','1','6','1','','','','Z'};
535
536 static const struct encodedFiletime times[] = {
537 { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 },
538 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 },
539 { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 },
540 };
541
542 static void test_encodeFiletime(DWORD dwEncoding)
543 {
544 DWORD i;
545
546 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
547 {
548 testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
549 testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
550 testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
551 }
552 }
553
554 static const BYTE bin23[] = {
555 0x18,0x13,'1','9','4','5','','6','','6','1','6','1','','','','.','','','','Z'};
556 static const BYTE bin24[] = {
557 0x18,0x13,'1','9','4','5','','6','','6','1','6','1','','','','.','9','9','9','Z'};
558 static const BYTE bin25[] = {
559 0x18,0x13,'1','9','4','5','','6','','6','1','6','1','','','','+','','1','',''};
560 static const BYTE bin26[] = {
561 0x18,0x13,'1','9','4','5','','6','','6','1','6','1','','','','-','','1','',''};
562 static const BYTE bin27[] = {
563 0x18,0x13,'1','9','4','5','','6','','6','1','6','1','','','','-','','1','1','5'};
564 static const BYTE bin28[] = {
565 0x18,0x0a,'2','1','4','5','','6','','6','1','6'};
566 static const BYTE bin29[] = {
567 0x17,0x0a,'4','5','','6','','6','1','6','1',''};
568 static const BYTE bin30[] = {
569 0x17,0x0b,'4','5','','6','','6','1','6','1','','Z'};
570 static const BYTE bin31[] = {
571 0x17,0x0d,'4','5','','6','','6','1','6','1','','+','','1'};
572 static const BYTE bin32[] = {
573 0x17,0x0d,'4','5','','6','','6','1','6','1','','-','','1'};
574 static const BYTE bin33[] = {
575 0x17,0x0f,'4','5','','6','','6','1','6','1','','+','','1','',''};
576 static const BYTE bin34[] = {
577 0x17,0x0f,'4','5','','6','','6','1','6','1','','-','','1','',''};
578 static const BYTE bin35[] = {
579 0x17,0x08, '4','5','','6','','6','1','6'};
580 static const BYTE bin36[] = {
581 0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z'};
582 static const BYTE bin37[] = {
583 0x18,0x04, '2','1','4','5'};
584 static const BYTE bin38[] = {
585 0x18,0x08, '2','1','4','5','','6','','6'};
586
587 static void test_decodeFiletime(DWORD dwEncoding)
588 {
589 static const struct encodedFiletime otherTimes[] = {
590 { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin23 },
591 { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 },
592 { { 1945, 6, 1, 6, 17, 10, 0, 0 }, bin25 },
593 { { 1945, 6, 1, 6, 15, 10, 0, 0 }, bin26 },
594 { { 1945, 6, 1, 6, 14, 55, 0, 0 }, bin27 },
595 { { 2145, 6, 1, 6, 16, 0, 0, 0 }, bin28 },
596 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin29 },
597 { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin30 },
598 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin31 },
599 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin32 },
600 { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin33 },
601 { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin34 },
602 };
603 /* An oddball case that succeeds in Windows, but doesn't seem correct
604 { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
605 */
606 static const unsigned char *bogusTimes[] = {
607 /* oddly, this succeeds on Windows, with year 2765
608 "\x18" "\x0f" "21r50606161000Z",
609 */
610 bin35,
611 bin36,
612 bin37,
613 bin38,
614 };
615 DWORD i, size;
616 FILETIME ft1 = { 0 }, ft2 = { 0 };
617 BOOL ret;
618
619 /* Check bogus length with non-NULL buffer */
620 ret = SystemTimeToFileTime(×[0].sysTime, &ft1);
621 ok(ret, "SystemTimeToFileTime failed: %d\n", GetLastError());
622 size = 1;
623 ret = pCryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
624 times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size);
625 ok(!ret && GetLastError() == ERROR_MORE_DATA,
626 "Expected ERROR_MORE_DATA, got %d\n", GetLastError());
627 /* Normal tests */
628 for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
629 {
630 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]);
631 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]);
632 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]);
633 }
634 for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
635 {
636 testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]);
637 testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]);
638 testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]);
639 }
640 for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
641 {
642 size = sizeof(ft1);
643 ret = pCryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME,
644 bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size);
645 ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
646 "Expected CRYPT_E_ASN1_CORRUPT, got %08x\n", GetLastError());
647 }
648 }
649
650 static const char commonName[] = "Juan Lang";
651 static const char surName[] = "Lang";
652
653 static const BYTE emptySequence[] = { 0x30, 0 };
654 static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
655 static const BYTE twoRDNs[] = {
656 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
657 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03,
658 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0};
659 static const BYTE encodedTwoRDNs[] = {
660 0x30,0x2e,0x31,0x2c,0x30,0x2a,0x06,0x03,0x55,0x04,0x03,0x30,0x23,0x31,0x21,
661 0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,
662 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
663 0x6e,0x67,0x00,
664 };
665
666 static const BYTE us[] = { 0x55, 0x53 };
667 static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f,
668 0x74, 0x61 };
669 static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70,
670 0x6f, 0x6c, 0x69, 0x73 };
671 static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61,
672 0x76, 0x65, 0x72, 0x73 };
673 static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76,
674 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 };
675 static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f,
676 0x73, 0x74 };
677 static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64,
678 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d };
679
680 #define RDNA(arr) oid_ ## arr, CERT_RDN_PRINTABLE_STRING, { sizeof(arr), (LPBYTE)arr }
681 #define RDNIA5(arr) oid_ ## arr, CERT_RDN_IA5_STRING, { sizeof(arr), (LPBYTE)arr }
682
683 static CHAR oid_us[] = "2.5.4.6",
684 oid_minnesota[] = "2.5.4.8",
685 oid_minneapolis[] = "2.5.4.7",
686 oid_codeweavers[] = "2.5.4.10",
687 oid_wine[] = "2.5.4.11",
688 oid_localhostAttr[] = "2.5.4.3",
689 oid_aric[] = "1.2.840.113549.1.9.1";
690 static CERT_RDN_ATTR rdnAttrs[] = { { RDNA(us) },
691 { RDNA(minnesota) },
692 { RDNA(minneapolis) },
693 { RDNA(codeweavers) },
694 { RDNA(wine) },
695 { RDNA(localhostAttr) },
696 { RDNIA5(aric) } };
697 static CERT_RDN_ATTR decodedRdnAttrs[] = { { RDNA(us) },
698 { RDNA(localhostAttr) },
699 { RDNA(minnesota) },
700 { RDNA(minneapolis) },
701 { RDNA(codeweavers) },
702 { RDNA(wine) },
703 { RDNIA5(aric) } };
704
705 #undef RDNIA5
706 #undef RDNA
707
708 static const BYTE encodedRDNAttrs[] = {
709 0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
710 0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68,
711 0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e,
712 0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69,
713 0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,
714 0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06,
715 0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,
716 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
717 0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,
718 0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d
719 };
720
721 static void test_encodeName(DWORD dwEncoding)
722 {
723 CERT_RDN_ATTR attrs[2];
724 CERT_RDN rdn;
725 CERT_NAME_INFO info;
726 static CHAR oid_common_name[] = szOID_COMMON_NAME,
727 oid_sur_name[] = szOID_SUR_NAME;
728 BYTE *buf = NULL;
729 DWORD size = 0;
730 BOOL ret;
731
732 /* Test with NULL pvStructInfo */
733 ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, NULL,
734 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
735 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
736 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
737 /* Test with empty CERT_NAME_INFO */
738 info.cRDN = 0;
739 info.rgRDN = NULL;
740 ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
741 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
742 ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
743 if (buf)
744 {
745 ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
746 "Got unexpected encoding for empty name\n");
747 LocalFree(buf);
748 }
749 /* Test with bogus CERT_RDN */
750 info.cRDN = 1;
751 ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
752 CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
753 ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
754 "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError());
755 /* Test with empty CERT_RDN */
756 rdn.cRDNAttr = 0;
757 rdn.rgRDNAttr = NULL;
758