urlmon: Implemented IUri_GetHostType.
[wine] / dlls / wintrust / tests / asn.c
1 /* Unit test suite for wintrust asn functions
2  *
3  * Copyright 2007 Juan Lang
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  */
20 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winerror.h"
24 #include "wincrypt.h"
25 #include "wintrust.h"
26
27 #include "wine/test.h"
28
29 static BOOL (WINAPI *pCryptDecodeObjectEx)(DWORD,LPCSTR,const BYTE*,DWORD,DWORD,PCRYPT_DECODE_PARA,void*,DWORD*);
30 static BOOL (WINAPI *pCryptEncodeObjectEx)(DWORD,LPCSTR,const void*,DWORD,PCRYPT_ENCODE_PARA,void*,DWORD*);
31
32 static const BYTE falseCriteria[] = { 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00 };
33 static const BYTE trueCriteria[] = { 0x30,0x06,0x01,0x01,0xff,0x01,0x01,0xff };
34
35 static void test_encodeSPCFinancialCriteria(void)
36 {
37     BOOL ret;
38     DWORD size = 0;
39     LPBYTE buf;
40     SPC_FINANCIAL_CRITERIA criteria = { FALSE, FALSE };
41
42     if (!pCryptEncodeObjectEx)
43     {
44         win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeFinancialCriteria tests\n");
45         return;
46     }
47     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT,
48      &criteria, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
49     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
50     if (ret)
51     {
52         ok(size == sizeof(falseCriteria), "Unexpected size %d\n", size);
53         ok(!memcmp(buf, falseCriteria, size), "Unexpected value\n");
54         LocalFree(buf);
55     }
56     criteria.fFinancialInfoAvailable = criteria.fMeetsCriteria = TRUE;
57     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT,
58      &criteria, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
59     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
60     if (ret)
61     {
62         ok(size == sizeof(trueCriteria), "Unexpected size %d\n", size);
63         ok(!memcmp(buf, trueCriteria, size), "Unexpected value\n");
64         LocalFree(buf);
65     }
66 }
67
68 static void test_decodeSPCFinancialCriteria(void)
69 {
70     BOOL ret;
71     SPC_FINANCIAL_CRITERIA criteria;
72     DWORD size = sizeof(criteria);
73
74     if (!pCryptDecodeObjectEx)
75     {
76         win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeSPCFinancialCriteria tests\n");
77         return;
78     }
79
80     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT,
81      falseCriteria, sizeof(falseCriteria), 0, NULL, &criteria, &size);
82     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
83     if (ret)
84     {
85         ok(!criteria.fFinancialInfoAvailable, "expected FALSE\n");
86         ok(!criteria.fMeetsCriteria, "expected FALSE\n");
87     }
88     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT,
89      trueCriteria, sizeof(trueCriteria), 0, NULL, &criteria, &size);
90     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
91     if (ret)
92     {
93         ok(criteria.fFinancialInfoAvailable, "expected TRUE\n");
94         ok(criteria.fMeetsCriteria, "expected TRUE\n");
95     }
96 }
97
98 static WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.',
99  'o','r','g',0 };
100 static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f,
101  0x575b, 0 };
102 static const BYTE emptyURLSPCLink[] = { 0x80,0x00 };
103 static const BYTE urlSPCLink[] = {
104 0x80,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,
105 0x2e,0x6f,0x72,0x67};
106 static const BYTE fileSPCLink[] = {
107 0xa2,0x14,0x80,0x12,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
108 0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b };
109 static const BYTE emptyMonikerSPCLink[] = {
110 0xa1,0x14,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111 0x00,0x00,0x00,0x00,0x00,0x04,0x00 };
112 static BYTE data[] = { 0xba, 0xad, 0xf0, 0x0d };
113 static const BYTE monikerSPCLink[] = {
114 0xa1,0x18,0x04,0x10,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,
115 0xea,0xea,0xea,0xea,0xea,0x04,0x04,0xba,0xad,0xf0,0x0d };
116
117 static void test_encodeSPCLink(void)
118 {
119     BOOL ret;
120     DWORD size = 0;
121     LPBYTE buf;
122     SPC_LINK link = { 0 };
123
124     if (!pCryptEncodeObjectEx)
125     {
126         win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeSPCLink tests\n");
127         return;
128     }
129
130     SetLastError(0xdeadbeef);
131     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
132      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
133     ok(!ret && GetLastError() == E_INVALIDARG,
134      "Expected E_INVALIDARG, got %08x\n", GetLastError());
135     link.dwLinkChoice = SPC_URL_LINK_CHOICE;
136     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
137      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
138     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
139     if (ret)
140     {
141         ok(size == sizeof(emptyURLSPCLink), "Unexpected size %d\n", size);
142         ok(!memcmp(buf, emptyURLSPCLink, size), "Unexpected value\n");
143         LocalFree(buf);
144     }
145     /* With an invalid char: */
146     U(link).pwszUrl = (LPWSTR)nihongoURL;
147     size = 1;
148     SetLastError(0xdeadbeef);
149     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
150      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
151     ok(!ret &&
152      (GetLastError() == CRYPT_E_INVALID_IA5_STRING ||
153      GetLastError() == OSS_BAD_PTR /* Win9x */),
154      "Expected CRYPT_E_INVALID_IA5_STRING, got %08x\n", GetLastError());
155     /* Unlike the crypt32 string encoding routines, size is not set to the
156      * index of the first invalid character.
157      */
158     ok(size == 0, "Expected size 0, got %d\n", size);
159     U(link).pwszUrl = url;
160     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
161      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
162     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
163     if (ret)
164     {
165         ok(size == sizeof(urlSPCLink), "Unexpected size %d\n", size);
166         ok(!memcmp(buf, urlSPCLink, size), "Unexpected value\n");
167         LocalFree(buf);
168     }
169     link.dwLinkChoice = SPC_FILE_LINK_CHOICE;
170     U(link).pwszFile = (LPWSTR)nihongoURL;
171     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
172      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
173     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
174     if (ret)
175     {
176         ok(size == sizeof(fileSPCLink), "Unexpected size %d\n", size);
177         ok(!memcmp(buf, fileSPCLink, size), "Unexpected value\n");
178         LocalFree(buf);
179     }
180     link.dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
181     memset(&U(link).Moniker, 0, sizeof(U(link).Moniker));
182     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
183      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
184     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
185     if (ret)
186     {
187         ok(size == sizeof(emptyMonikerSPCLink), "Unexpected size %d\n", size);
188         ok(!memcmp(buf, emptyMonikerSPCLink, size), "Unexpected value\n");
189         LocalFree(buf);
190     }
191     memset(&U(link).Moniker.ClassId, 0xea, sizeof(U(link).Moniker.ClassId));
192     U(link).Moniker.SerializedData.pbData = data;
193     U(link).Moniker.SerializedData.cbData = sizeof(data);
194     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
195      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
196     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
197     if (ret)
198     {
199         ok(size == sizeof(monikerSPCLink), "Unexpected size %d\n", size);
200         ok(!memcmp(buf, monikerSPCLink, size), "Unexpected value\n");
201         LocalFree(buf);
202     }
203 }
204
205 static const BYTE badMonikerSPCLink[] = {
206 0xa1,0x19,0x04,0x11,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,
207 0xea,0xea,0xea,0xea,0xea,0xea,0x04,0x04,0xba,0xad,0xf0,0x0d };
208
209 static void test_decodeSPCLink(void)
210 {
211     BOOL ret;
212     LPBYTE buf = NULL;
213     DWORD size = 0;
214     SPC_LINK *link;
215
216     if (!pCryptDecodeObjectEx)
217     {
218         win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeSPCLink tests\n");
219         return;
220     }
221
222     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
223      emptyURLSPCLink, sizeof(emptyURLSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
224      &buf, &size);
225     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
226     if (ret)
227     {
228         link = (SPC_LINK *)buf;
229         ok(link->dwLinkChoice == SPC_URL_LINK_CHOICE,
230          "Expected SPC_URL_LINK_CHOICE, got %d\n", link->dwLinkChoice);
231         ok(lstrlenW(U(*link).pwszUrl) == 0, "Expected empty string\n");
232         LocalFree(buf);
233     }
234     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
235      urlSPCLink, sizeof(urlSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
236      &buf, &size);
237     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
238     if (ret)
239     {
240         link = (SPC_LINK *)buf;
241         ok(link->dwLinkChoice == SPC_URL_LINK_CHOICE,
242          "Expected SPC_URL_LINK_CHOICE, got %d\n", link->dwLinkChoice);
243         ok(!lstrcmpW(U(*link).pwszUrl, url), "Unexpected URL\n");
244         LocalFree(buf);
245     }
246     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
247      fileSPCLink, sizeof(fileSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
248      &buf, &size);
249     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
250     if (ret)
251     {
252         link = (SPC_LINK *)buf;
253         ok(link->dwLinkChoice == SPC_FILE_LINK_CHOICE,
254          "Expected SPC_FILE_LINK_CHOICE, got %d\n", link->dwLinkChoice);
255         ok(!lstrcmpW(U(*link).pwszFile, nihongoURL), "Unexpected file\n");
256         LocalFree(buf);
257     }
258     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
259      emptyMonikerSPCLink, sizeof(emptyMonikerSPCLink), CRYPT_DECODE_ALLOC_FLAG,
260      NULL, &buf, &size);
261     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
262     if (ret)
263     {
264         SPC_SERIALIZED_OBJECT emptyMoniker = { { 0 } };
265
266         link = (SPC_LINK *)buf;
267         ok(link->dwLinkChoice == SPC_MONIKER_LINK_CHOICE,
268          "Expected SPC_MONIKER_LINK_CHOICE, got %d\n", link->dwLinkChoice);
269         ok(!memcmp(&U(*link).Moniker.ClassId, &emptyMoniker.ClassId,
270          sizeof(emptyMoniker.ClassId)), "Unexpected value\n");
271         ok(U(*link).Moniker.SerializedData.cbData == 0,
272          "Expected no serialized data\n");
273         LocalFree(buf);
274     }
275     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
276      monikerSPCLink, sizeof(monikerSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
277      &buf, &size);
278     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
279     if (ret)
280     {
281         SPC_UUID id;
282
283         link = (SPC_LINK *)buf;
284         ok(link->dwLinkChoice == SPC_MONIKER_LINK_CHOICE,
285          "Expected SPC_MONIKER_LINK_CHOICE, got %d\n", link->dwLinkChoice);
286         memset(&id, 0xea, sizeof(id));
287         ok(!memcmp(&U(*link).Moniker.ClassId, &id, sizeof(id)),
288          "Unexpected value\n");
289         ok(U(*link).Moniker.SerializedData.cbData == sizeof(data),
290            "Unexpected data size %d\n", U(*link).Moniker.SerializedData.cbData);
291         ok(!memcmp(U(*link).Moniker.SerializedData.pbData, data, sizeof(data)),
292          "Unexpected value\n");
293         LocalFree(buf);
294     }
295     SetLastError(0xdeadbeef);
296     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
297      badMonikerSPCLink, sizeof(badMonikerSPCLink), CRYPT_DECODE_ALLOC_FLAG,
298      NULL, &buf, &size);
299     ok(!ret &&
300      (GetLastError() == CRYPT_E_BAD_ENCODE ||
301      GetLastError() == OSS_DATA_ERROR /* Win9x */),
302      "Expected CRYPT_E_BAD_ENCODE, got %08x\n", GetLastError());
303 }
304
305 static const BYTE emptySequence[] = { 0x30,0x00 };
306 static BYTE flags[] = { 1 };
307 static const BYTE onlyFlagsPEImage[] = { 0x30,0x04,0x03,0x02,0x00,0x01 };
308 static const BYTE moreFlagsPEImage[] = {
309 0x30,0x06,0x03,0x04,0x04,0xff,0x80,0x10 };
310 static const BYTE onlyEmptyFilePEImage[] = {
311 0x30,0x06,0xa0,0x04,0xa2,0x02,0x80,0x00 };
312 static const BYTE flagsAndEmptyFilePEImage[] = {
313 0x30,0x0a,0x03,0x02,0x00,0x01,0xa0,0x04,0xa2,0x02,0x80,0x00 };
314 static const BYTE flagsAndFilePEImage[] = {
315 0x30,0x1c,0x03,0x02,0x00,0x01,0xa0,0x16,0xa2,0x14,0x80,0x12,0x00,0x68,0x00,
316 0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b };
317
318 static void test_encodeSPCPEImage(void)
319 {
320     BOOL ret;
321     DWORD size = 0;
322     LPBYTE buf;
323     SPC_PE_IMAGE_DATA imageData = { { 0 } };
324     SPC_LINK link = { 0 };
325
326     if (!pCryptEncodeObjectEx)
327     {
328         win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeSPCPEImage tests\n");
329         return;
330     }
331
332     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
333      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
334     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
335     if (ret)
336     {
337         ok(size == sizeof(emptySequence), "Unexpected size %d\n", size);
338         ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
339          "Unexpected value\n");
340         LocalFree(buf);
341     }
342     /* With an invalid link: */
343     imageData.pFile = &link;
344     SetLastError(0xdeadbeef);
345     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
346      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
347     ok(!ret && GetLastError () == E_INVALIDARG,
348      "Expected E_INVALIDARG, got %08x\n", GetLastError());
349     /* With just unused bits field set: */
350     imageData.pFile = NULL;
351     imageData.Flags.cUnusedBits = 1;
352     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
353      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
354     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
355     if (ret)
356     {
357         ok(size == sizeof(emptySequence), "Unexpected size %d\n", size);
358         ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
359          "Unexpected value\n");
360         LocalFree(buf);
361     }
362     /* With flags set: */
363     imageData.Flags.cUnusedBits = 0;
364     imageData.Flags.pbData = flags;
365     imageData.Flags.cbData = sizeof(flags);
366     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
367      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
368     if (!ret && GetLastError() == OSS_TOO_LONG)
369     {
370         skip("SPC_PE_IMAGE_DATA_STRUCT not supported\n");
371         return;
372     }
373     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
374     if (ret)
375     {
376         ok(size == sizeof(onlyFlagsPEImage), "Unexpected size %d\n", size);
377         ok(!memcmp(buf, onlyFlagsPEImage, sizeof(onlyFlagsPEImage)),
378          "Unexpected value\n");
379         LocalFree(buf);
380     }
381     /* With just an empty file: */
382     imageData.Flags.cbData = 0;
383     link.dwLinkChoice = SPC_FILE_LINK_CHOICE;
384     imageData.pFile = &link;
385     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
386      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
387     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
388     if (ret)
389     {
390         ok(size == sizeof(onlyEmptyFilePEImage), "Unexpected size %d\n", size);
391         ok(!memcmp(buf, onlyEmptyFilePEImage, sizeof(onlyEmptyFilePEImage)),
392          "Unexpected value\n");
393         LocalFree(buf);
394     }
395     /* With flags and an empty file: */
396     imageData.Flags.pbData = flags;
397     imageData.Flags.cbData = sizeof(flags);
398     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
399      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
400     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
401     if (ret)
402     {
403         ok(size == sizeof(flagsAndEmptyFilePEImage), "Unexpected size %d\n",
404          size);
405         ok(!memcmp(buf, flagsAndEmptyFilePEImage,
406          sizeof(flagsAndEmptyFilePEImage)), "Unexpected value\n");
407         LocalFree(buf);
408     }
409     /* Finally, a non-empty file: */
410     U(link).pwszFile = (LPWSTR)nihongoURL;
411     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
412      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
413     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
414     if (ret)
415     {
416         ok(size == sizeof(flagsAndFilePEImage), "Unexpected size %d\n", size);
417         ok(!memcmp(buf, flagsAndFilePEImage, sizeof(flagsAndFilePEImage)),
418          "Unexpected value\n");
419         LocalFree(buf);
420     }
421 }
422
423 static void test_decodeSPCPEImage(void)
424 {
425     static const WCHAR emptyString[] = { 0 };
426     BOOL ret;
427     LPBYTE buf = NULL;
428     DWORD size = 0;
429     SPC_PE_IMAGE_DATA *imageData;
430
431     if (!pCryptDecodeObjectEx)
432     {
433         win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeSPCPEImage tests\n");
434         return;
435     }
436
437     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
438      emptySequence, sizeof(emptySequence),
439      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
440     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
441     if (ret)
442     {
443         imageData = (SPC_PE_IMAGE_DATA *)buf;
444         ok(imageData->Flags.cbData == 0, "Expected empty flags, got %d\n",
445          imageData->Flags.cbData);
446         ok(imageData->pFile == NULL, "Expected no file\n");
447         LocalFree(buf);
448     }
449     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
450      onlyFlagsPEImage, sizeof(onlyFlagsPEImage),
451      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
452     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
453     if (ret)
454     {
455         imageData = (SPC_PE_IMAGE_DATA *)buf;
456         ok(imageData->Flags.cbData == sizeof(flags),
457          "Unexpected flags size %d\n", imageData->Flags.cbData);
458         if (imageData->Flags.cbData)
459             ok(!memcmp(imageData->Flags.pbData, flags, sizeof(flags)),
460              "Unexpected flags\n");
461         ok(imageData->pFile == NULL, "Expected no file\n");
462         LocalFree(buf);
463     }
464     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
465      onlyEmptyFilePEImage, sizeof(onlyEmptyFilePEImage),
466      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
467     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
468     if (ret)
469     {
470         imageData = (SPC_PE_IMAGE_DATA *)buf;
471         ok(imageData->Flags.cbData == 0, "Expected empty flags, got %d\n",
472          imageData->Flags.cbData);
473         ok(imageData->pFile != NULL, "Expected a file\n");
474         if (imageData->pFile)
475         {
476             ok(imageData->pFile->dwLinkChoice == SPC_FILE_LINK_CHOICE,
477              "Expected SPC_FILE_LINK_CHOICE, got %d\n",
478              imageData->pFile->dwLinkChoice);
479             ok(!lstrcmpW(U(*imageData->pFile).pwszFile, emptyString),
480              "Unexpected file\n");
481         }
482         LocalFree(buf);
483     }
484     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
485      flagsAndEmptyFilePEImage, sizeof(flagsAndEmptyFilePEImage),
486      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
487     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
488     if (ret)
489     {
490         imageData = (SPC_PE_IMAGE_DATA *)buf;
491         ok(imageData->Flags.cbData == sizeof(flags),
492          "Unexpected flags size %d\n", imageData->Flags.cbData);
493         if (imageData->Flags.cbData)
494             ok(!memcmp(imageData->Flags.pbData, flags, sizeof(flags)),
495              "Unexpected flags\n");
496         ok(imageData->pFile != NULL, "Expected a file\n");
497         if (imageData->pFile)
498         {
499             ok(imageData->pFile->dwLinkChoice == SPC_FILE_LINK_CHOICE,
500              "Expected SPC_FILE_LINK_CHOICE, got %d\n",
501              imageData->pFile->dwLinkChoice);
502             ok(!lstrcmpW(U(*imageData->pFile).pwszFile, emptyString),
503              "Unexpected file\n");
504         }
505         LocalFree(buf);
506     }
507     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
508      flagsAndFilePEImage, sizeof(flagsAndFilePEImage),
509      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
510     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
511     if (ret)
512     {
513         imageData = (SPC_PE_IMAGE_DATA *)buf;
514         ok(imageData->Flags.cbData == sizeof(flags),
515          "Unexpected flags size %d\n", imageData->Flags.cbData);
516         if (imageData->Flags.cbData)
517             ok(!memcmp(imageData->Flags.pbData, flags, sizeof(flags)),
518              "Unexpected flags\n");
519         ok(imageData->pFile != NULL, "Expected a file\n");
520         if (imageData->pFile)
521         {
522             ok(imageData->pFile->dwLinkChoice == SPC_FILE_LINK_CHOICE,
523              "Expected SPC_FILE_LINK_CHOICE, got %d\n",
524              imageData->pFile->dwLinkChoice);
525             ok(!lstrcmpW(U(*imageData->pFile).pwszFile, nihongoURL),
526              "Unexpected file\n");
527         }
528         LocalFree(buf);
529     }
530 }
531
532 static WCHAR foo[] = { 'f','o','o',0 };
533 static WCHAR guidStr[] = { '{','8','b','c','9','6','b','0','0','-',
534  '8','d','a','1','-','1','1','c','f','-','8','7','3','6','-','0','0',
535  'a','a','0','0','a','4','8','5','e','b','}',0 };
536
537 static const BYTE emptyCatMemberInfo[] = { 0x30,0x05,0x1e,0x00,0x02,0x01,0x00 };
538 static const BYTE catMemberInfoWithSillyGuid[] = {
539 0x30,0x0b,0x1e,0x06,0x00,0x66,0x00,0x6f,0x00,0x6f,0x02,0x01,0x00 };
540 static const BYTE catMemberInfoWithGuid[] = {
541 0x30,0x51,0x1e,0x4c,0x00,0x7b,0x00,0x38,0x00,0x62,0x00,0x63,0x00,0x39,0x00,0x36,
542 0x00,0x62,0x00,0x30,0x00,0x30,0x00,0x2d,0x00,0x38,0x00,0x64,0x00,0x61,0x00,0x31,
543 0x00,0x2d,0x00,0x31,0x00,0x31,0x00,0x63,0x00,0x66,0x00,0x2d,0x00,0x38,0x00,0x37,
544 0x00,0x33,0x00,0x36,0x00,0x2d,0x00,0x30,0x00,0x30,0x00,0x61,0x00,0x61,0x00,0x30,
545 0x00,0x30,0x00,0x61,0x00,0x34,0x00,0x38,0x00,0x35,0x00,0x65,0x00,0x62,0x00,0x7d,
546 0x02,0x01,0x00 };
547
548 static void test_encodeCatMemberInfo(void)
549 {
550     CAT_MEMBERINFO info;
551     BOOL ret;
552     DWORD size = 0;
553     LPBYTE buf;
554
555     memset(&info, 0, sizeof(info));
556
557     if (!pCryptEncodeObjectEx)
558     {
559         win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeCatMemberInfo tests\n");
560         return;
561     }
562
563     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT,
564      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
565     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
566     if (ret)
567     {
568         ok(size == sizeof(emptyCatMemberInfo), "Unexpected size %d\n", size);
569         ok(!memcmp(buf, emptyCatMemberInfo, sizeof(emptyCatMemberInfo)),
570          "Unexpected value\n");
571         LocalFree(buf);
572     }
573     info.pwszSubjGuid = foo;
574     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT,
575      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
576     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
577     if (ret)
578     {
579         ok(size == sizeof(catMemberInfoWithSillyGuid), "Unexpected size %d\n",
580          size);
581         ok(!memcmp(buf, catMemberInfoWithSillyGuid,
582          sizeof(catMemberInfoWithSillyGuid)), "Unexpected value\n");
583         LocalFree(buf);
584     }
585     info.pwszSubjGuid = guidStr;
586     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT,
587      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
588     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
589     if (ret)
590     {
591         ok(size == sizeof(catMemberInfoWithGuid), "Unexpected size %d\n",
592          size);
593         ok(!memcmp(buf, catMemberInfoWithGuid, sizeof(catMemberInfoWithGuid)),
594          "Unexpected value\n");
595         LocalFree(buf);
596     }
597 }
598
599 static void test_decodeCatMemberInfo(void)
600 {
601    BOOL ret;
602    LPBYTE buf;
603    DWORD size;
604    CAT_MEMBERINFO *info;
605
606     if (!pCryptDecodeObjectEx)
607     {
608         win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeCatMemberInfo tests\n");
609         return;
610     }
611
612     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT,
613      emptyCatMemberInfo, sizeof(emptyCatMemberInfo),
614      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
615     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
616     if (ret)
617     {
618         info = (CAT_MEMBERINFO *)buf;
619         ok(!info->pwszSubjGuid || !info->pwszSubjGuid[0],
620          "expected empty pwszSubjGuid\n");
621         ok(info->dwCertVersion == 0, "expected dwCertVersion == 0, got %d\n",
622          info->dwCertVersion);
623         LocalFree(buf);
624     }
625     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT,
626      catMemberInfoWithSillyGuid, sizeof(catMemberInfoWithSillyGuid),
627      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
628     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
629     if (ret)
630     {
631         info = (CAT_MEMBERINFO *)buf;
632         ok(info->pwszSubjGuid && !lstrcmpW(info->pwszSubjGuid, foo),
633          "unexpected pwszSubjGuid\n");
634         ok(info->dwCertVersion == 0, "expected dwCertVersion == 0, got %d\n",
635          info->dwCertVersion);
636         LocalFree(buf);
637     }
638     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT,
639      catMemberInfoWithGuid, sizeof(catMemberInfoWithGuid),
640      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
641     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
642     if (ret)
643     {
644         info = (CAT_MEMBERINFO *)buf;
645         ok(info->pwszSubjGuid && !lstrcmpW(info->pwszSubjGuid, guidStr),
646          "unexpected pwszSubjGuid\n");
647         ok(info->dwCertVersion == 0, "expected dwCertVersion == 0, got %d\n",
648          info->dwCertVersion);
649         LocalFree(buf);
650     }
651 }
652
653 static const BYTE emptyCatNameValue[] = {
654 0x30,0x07,0x1e,0x00,0x02,0x01,0x00,0x04,0x00 };
655 static const BYTE catNameValueWithTag[] = {
656 0x30,0x0d,0x1e,0x06,0x00,0x66,0x00,0x6f,0x00,0x6f,0x02,0x01,0x00,0x04,0x00 };
657 static const BYTE catNameValueWithFlags[] = {
658 0x30,0x0a,0x1e,0x00,0x02,0x04,0xf0,0x0d,0xd0,0x0d,0x04,0x00 };
659 static const BYTE catNameValueWithValue[] = {
660 0x30,0x0b,0x1e,0x00,0x02,0x01,0x00,0x04,0x04,0x01,0x02,0x03,0x04 };
661
662 static BYTE aVal[] = { 1,2,3,4 };
663
664 static void test_encodeCatNameValue(void)
665 {
666     static WCHAR foo[] = { 'f','o','o',0 };
667     BOOL ret;
668     LPBYTE buf;
669     DWORD size;
670     CAT_NAMEVALUE value;
671
672     memset(&value, 0, sizeof(value));
673     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
674      &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
675     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
676     if (ret)
677     {
678         ok(size == sizeof(emptyCatNameValue), "Unexpected size %d\n", size);
679         ok(!memcmp(buf, emptyCatNameValue, sizeof(emptyCatNameValue)),
680          "Unexpected value\n");
681         LocalFree(buf);
682     }
683     value.pwszTag = foo;
684     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
685      &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
686     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
687     if (ret)
688     {
689         ok(size == sizeof(catNameValueWithTag), "Unexpected size %d\n", size);
690         ok(!memcmp(buf, catNameValueWithTag, sizeof(catNameValueWithTag)),
691          "Unexpected value\n");
692         LocalFree(buf);
693     }
694     value.pwszTag = NULL;
695     value.fdwFlags = 0xf00dd00d;
696     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
697      &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
698     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
699     if (ret)
700     {
701         ok(size == sizeof(catNameValueWithFlags), "Unexpected size %d\n", size);
702         ok(!memcmp(buf, catNameValueWithFlags, sizeof(catNameValueWithFlags)),
703          "Unexpected value\n");
704         LocalFree(buf);
705     }
706     value.fdwFlags = 0;
707     value.Value.cbData = sizeof(aVal);
708     value.Value.pbData = aVal;
709     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
710      &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
711     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
712     if (ret)
713     {
714         ok(size == sizeof(catNameValueWithValue), "Unexpected size %d\n", size);
715         ok(!memcmp(buf, catNameValueWithValue, sizeof(catNameValueWithValue)),
716          "Unexpected value\n");
717         LocalFree(buf);
718     }
719 }
720
721 static void test_decodeCatNameValue(void)
722 {
723     BOOL ret;
724     LPBYTE buf;
725     DWORD size;
726     CAT_NAMEVALUE *value;
727
728     buf = NULL;
729     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
730      emptyCatNameValue, sizeof(emptyCatNameValue),
731      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
732     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
733     if (ret)
734     {
735         value = (CAT_NAMEVALUE *)buf;
736         ok(!value->pwszTag || !value->pwszTag[0], "expected empty pwszTag\n");
737         ok(value->fdwFlags == 0, "expected fdwFlags == 0, got %08x\n",
738          value->fdwFlags);
739         ok(value->Value.cbData == 0, "expected 0-length value, got %d\n",
740          value->Value.cbData);
741         LocalFree(buf);
742     }
743     buf = NULL;
744     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
745      catNameValueWithTag, sizeof(catNameValueWithTag),
746      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
747     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
748     if (ret)
749     {
750         value = (CAT_NAMEVALUE *)buf;
751         ok(value->pwszTag && !lstrcmpW(value->pwszTag, foo),
752          "unexpected pwszTag\n");
753         ok(value->fdwFlags == 0, "expected fdwFlags == 0, got %08x\n",
754          value->fdwFlags);
755         ok(value->Value.cbData == 0, "expected 0-length value, got %d\n",
756          value->Value.cbData);
757         LocalFree(buf);
758     }
759     buf = NULL;
760     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
761      catNameValueWithFlags, sizeof(catNameValueWithFlags),
762      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
763     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
764     if (ret)
765     {
766         value = (CAT_NAMEVALUE *)buf;
767         ok(!value->pwszTag || !value->pwszTag[0], "expected empty pwszTag\n");
768         ok(value->fdwFlags == 0xf00dd00d,
769          "expected fdwFlags == 0xf00dd00d, got %08x\n", value->fdwFlags);
770         ok(value->Value.cbData == 0, "expected 0-length value, got %d\n",
771          value->Value.cbData);
772         LocalFree(buf);
773     }
774     buf = NULL;
775     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT,
776      catNameValueWithValue, sizeof(catNameValueWithValue),
777      CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size);
778     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
779     if (ret)
780     {
781         value = (CAT_NAMEVALUE *)buf;
782         ok(!value->pwszTag || !value->pwszTag[0], "expected empty pwszTag\n");
783         ok(value->fdwFlags == 0, "expected fdwFlags == 0, got %08x\n",
784          value->fdwFlags);
785         ok(value->Value.cbData == sizeof(aVal), "unexpected size %d\n",
786          value->Value.cbData);
787         ok(!memcmp(value->Value.pbData, aVal, value->Value.cbData),
788          "unexpected value\n");
789         LocalFree(buf);
790     }
791 }
792
793 static const WCHAR progName[] = { 'A',' ','p','r','o','g','r','a','m',0 };
794 static const BYTE spOpusInfoWithProgramName[] = {
795 0x30,0x16,0xa0,0x14,0x80,0x12,0x00,0x41,0x00,0x20,0x00,0x70,0x00,0x72,0x00,0x6f,
796 0x00,0x67,0x00,0x72,0x00,0x61,0x00,0x6d };
797 static WCHAR winehq[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q',
798  '.','o','r','g','/',0 };
799 static const BYTE spOpusInfoWithMoreInfo[] = {
800 0x30,0x16,0xa1,0x14,0x80,0x12,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,
801 0x65,0x68,0x71,0x2e,0x6f,0x72,0x67,0x2f };
802 static const BYTE spOpusInfoWithPublisherInfo[] = {
803 0x30,0x16,0xa2,0x14,0x80,0x12,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,
804 0x65,0x68,0x71,0x2e,0x6f,0x72,0x67,0x2f };
805
806 static void test_encodeSpOpusInfo(void)
807 {
808     BOOL ret;
809     LPBYTE buf;
810     DWORD size;
811     SPC_SP_OPUS_INFO info;
812     SPC_LINK moreInfo;
813
814     memset(&info, 0, sizeof(info));
815     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
816      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
817     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
818     if (ret)
819     {
820         ok(size == sizeof(emptySequence), "unexpected size %d\n", size);
821         ok(!memcmp(buf, emptySequence, size), "unexpected value\n");
822         LocalFree(buf);
823     }
824     info.pwszProgramName = progName;
825     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
826      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
827     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
828     if (ret)
829     {
830         ok(size == sizeof(spOpusInfoWithProgramName), "unexpected size %d\n",
831          size);
832         ok(!memcmp(buf, spOpusInfoWithProgramName, size),
833          "unexpected value\n");
834         LocalFree(buf);
835     }
836     info.pwszProgramName = NULL;
837     memset(&moreInfo, 0, sizeof(moreInfo));
838     info.pMoreInfo = &moreInfo;
839     SetLastError(0xdeadbeef);
840     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
841      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
842     ok(!ret && GetLastError() == E_INVALIDARG,
843      "expected E_INVALIDARG, got %08x\n", GetLastError());
844     moreInfo.dwLinkChoice = SPC_URL_LINK_CHOICE;
845     U(moreInfo).pwszUrl = winehq;
846     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
847      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
848     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
849     if (ret)
850     {
851         ok(size == sizeof(spOpusInfoWithMoreInfo),
852          "unexpected size %d\n", size);
853         ok(!memcmp(buf, spOpusInfoWithMoreInfo, size),
854          "unexpected value\n");
855         LocalFree(buf);
856     }
857     info.pMoreInfo = NULL;
858     info.pPublisherInfo = &moreInfo;
859     ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
860      &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
861     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
862     if (ret)
863     {
864         ok(size == sizeof(spOpusInfoWithPublisherInfo),
865          "unexpected size %d\n", size);
866         ok(!memcmp(buf, spOpusInfoWithPublisherInfo, size),
867          "unexpected value\n");
868         LocalFree(buf);
869     }
870 }
871
872 static void test_decodeSpOpusInfo(void)
873 {
874     BOOL ret;
875     DWORD size;
876     SPC_SP_OPUS_INFO *info;
877
878     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
879      emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
880      &info, &size);
881     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
882     if (ret)
883     {
884         ok(!info->pwszProgramName, "expected NULL\n");
885         ok(!info->pMoreInfo, "expected NULL\n");
886         ok(!info->pPublisherInfo, "expected NULL\n");
887         LocalFree(info);
888     }
889     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
890      spOpusInfoWithProgramName, sizeof(spOpusInfoWithProgramName),
891      CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
892     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
893     if (ret)
894     {
895         ok(info->pwszProgramName && !lstrcmpW(info->pwszProgramName,
896          progName), "unexpected program name\n");
897         ok(!info->pMoreInfo, "expected NULL\n");
898         ok(!info->pPublisherInfo, "expected NULL\n");
899         LocalFree(info);
900     }
901     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
902      spOpusInfoWithMoreInfo, sizeof(spOpusInfoWithMoreInfo),
903      CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
904     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
905     if (ret)
906     {
907         ok(!info->pwszProgramName, "expected NULL\n");
908         ok(info->pMoreInfo != NULL, "expected a value for pMoreInfo\n");
909         if (info->pMoreInfo)
910         {
911             ok(info->pMoreInfo->dwLinkChoice == SPC_URL_LINK_CHOICE,
912              "unexpected link choice %d\n", info->pMoreInfo->dwLinkChoice);
913             ok(!lstrcmpW(U(*info->pMoreInfo).pwszUrl, winehq),
914              "unexpected link value\n");
915         }
916         ok(!info->pPublisherInfo, "expected NULL\n");
917         LocalFree(info);
918     }
919     ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT,
920      spOpusInfoWithPublisherInfo, sizeof(spOpusInfoWithPublisherInfo),
921      CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
922     ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
923     if (ret)
924     {
925         ok(!info->pwszProgramName, "expected NULL\n");
926         ok(!info->pMoreInfo, "expected NULL\n");
927         ok(info->pPublisherInfo != NULL,
928          "expected a value for pPublisherInfo\n");
929         if (info->pPublisherInfo)
930         {
931             ok(info->pPublisherInfo->dwLinkChoice == SPC_URL_LINK_CHOICE,
932              "unexpected link choice %d\n",
933              info->pPublisherInfo->dwLinkChoice);
934             ok(!lstrcmpW(U(*info->pPublisherInfo).pwszUrl, winehq),
935              "unexpected link value\n");
936         }
937         LocalFree(info);
938     }
939 }
940
941 START_TEST(asn)
942 {
943     HMODULE hCrypt32 = LoadLibraryA("crypt32.dll");
944     pCryptDecodeObjectEx = (void*)GetProcAddress(hCrypt32, "CryptDecodeObjectEx");
945     pCryptEncodeObjectEx = (void*)GetProcAddress(hCrypt32, "CryptEncodeObjectEx");
946
947     test_encodeSPCFinancialCriteria();
948     test_decodeSPCFinancialCriteria();
949     test_encodeSPCLink();
950     test_decodeSPCLink();
951     test_encodeSPCPEImage();
952     test_decodeSPCPEImage();
953     test_encodeCatMemberInfo();
954     test_decodeCatMemberInfo();
955     test_encodeCatNameValue();
956     test_decodeCatNameValue();
957     test_encodeSpOpusInfo();
958     test_decodeSpOpusInfo();
959
960     FreeLibrary(hCrypt32);
961 }