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