wintrust/tests: Add a test for enumerating catalog attributes.
[wine] / dlls / wintrust / asn.c
1 /* 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
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #define NONAMELESSUNION
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "wincrypt.h"
32 #include "wintrust.h"
33 #include "snmp.h"
34 #include "winternl.h"
35 #include "wine/debug.h"
36 #include "wine/exception.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
39
40 #ifdef WORDS_BIGENDIAN
41
42 #define hton16(x) (x)
43 #define n16toh(x) (x)
44
45 #else
46
47 #define hton16(x) RtlUshortByteSwap(x)
48 #define n16toh(x) RtlUshortByteSwap(x)
49
50 #endif
51
52 #define ASN_BOOL            (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
53 #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
54 #define ASN_BMPSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e)
55
56 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
57 {
58     DWORD bytesNeeded, significantBytes = 0;
59
60     if (len <= 0x7f)
61         bytesNeeded = 1;
62     else
63     {
64         DWORD temp;
65
66         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
67          temp <<= 8, significantBytes--)
68             ;
69         bytesNeeded = significantBytes + 1;
70     }
71     if (!pbEncoded)
72     {
73         *pcbEncoded = bytesNeeded;
74         return TRUE;
75     }
76     if (*pcbEncoded < bytesNeeded)
77     {
78         SetLastError(ERROR_MORE_DATA);
79         return FALSE;
80     }
81     if (len <= 0x7f)
82         *pbEncoded = (BYTE)len;
83     else
84     {
85         DWORD i;
86
87         *pbEncoded++ = significantBytes | 0x80;
88         for (i = 0; i < significantBytes; i++)
89         {
90             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
91             len >>= 8;
92         }
93     }
94     *pcbEncoded = bytesNeeded;
95     return TRUE;
96 }
97
98 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
99  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
100  DWORD *pcbEncoded)
101 {
102     BOOL ret = TRUE;
103     const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
104     DWORD bytesNeeded, lenBytes;
105
106     TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
107      *pcbEncoded);
108
109     CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
110     bytesNeeded = 1 + lenBytes + blob->cbData;
111     if (!pbEncoded)
112         *pcbEncoded = bytesNeeded;
113     else if (*pcbEncoded < bytesNeeded)
114     {
115         *pcbEncoded = bytesNeeded;
116         SetLastError(ERROR_MORE_DATA);
117         ret = FALSE;
118     }
119     else
120     {
121         *pbEncoded++ = ASN_OCTETSTRING;
122         CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
123         pbEncoded += lenBytes;
124         if (blob->cbData)
125             memcpy(pbEncoded, blob->pbData, blob->cbData);
126     }
127     TRACE("returning %d\n", ret);
128     return ret;
129 }
130
131 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
132  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
133  DWORD *pcbEncoded)
134 {
135     BOOL ret = FALSE;
136
137     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
138      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
139      pcbEncoded);
140
141     __TRY
142     {
143         const SPC_LINK *link = (const SPC_LINK *)pvStructInfo;
144         DWORD bytesNeeded, lenBytes;
145
146         switch (link->dwLinkChoice)
147         {
148         case SPC_FILE_LINK_CHOICE:
149         {
150             DWORD fileNameLen, fileNameLenBytes;
151             LPWSTR ptr;
152
153             fileNameLen = link->u.pwszFile ?
154              lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
155             CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
156             CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
157              &lenBytes);
158             bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
159             if (!pbEncoded)
160             {
161                 *pcbEncoded = bytesNeeded;
162                 ret = TRUE;
163             }
164             else if (*pcbEncoded < bytesNeeded)
165             {
166                 SetLastError(ERROR_MORE_DATA);
167                 *pcbEncoded = bytesNeeded;
168             }
169             else
170             {
171                 *pcbEncoded = bytesNeeded;
172                 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
173                 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
174                  &lenBytes);
175                 pbEncoded += lenBytes;
176                 *pbEncoded++ = ASN_CONTEXT;
177                 CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
178                 pbEncoded += fileNameLenBytes;
179                 for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
180                 {
181                     *(WCHAR *)pbEncoded = hton16(*ptr);
182                     pbEncoded += sizeof(WCHAR);
183                 }
184                 ret = TRUE;
185             }
186             break;
187         }
188         case SPC_MONIKER_LINK_CHOICE:
189         {
190             DWORD classIdLenBytes, dataLenBytes, dataLen;
191             CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
192              (BYTE *)link->u.Moniker.ClassId };
193
194             CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
195             CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
196              &dataLenBytes);
197             dataLen = 2 + classIdLenBytes + classId.cbData +
198              dataLenBytes + link->u.Moniker.SerializedData.cbData;
199             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
200             bytesNeeded = 1 + dataLen + lenBytes;
201             if (!pbEncoded)
202             {
203                 *pcbEncoded = bytesNeeded;
204                 ret = TRUE;
205             }
206             else if (*pcbEncoded < bytesNeeded)
207             {
208                 SetLastError(ERROR_MORE_DATA);
209                 *pcbEncoded = bytesNeeded;
210             }
211             else
212             {
213                 DWORD size;
214
215                 *pcbEncoded = bytesNeeded;
216                 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
217                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
218                 pbEncoded += lenBytes;
219                 size = 1 + classIdLenBytes + classId.cbData;
220                 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
221                  pbEncoded, &size);
222                 pbEncoded += size;
223                 size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
224                 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
225                  &link->u.Moniker.SerializedData, pbEncoded, &size);
226                 pbEncoded += size;
227                 ret = TRUE;
228             }
229             break;
230         }
231         case SPC_URL_LINK_CHOICE:
232         {
233             LPWSTR ptr;
234             DWORD urlLen;
235
236             /* Check for invalid characters in URL */
237             ret = TRUE;
238             urlLen = 0;
239             for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
240                 if (*ptr > 0x7f)
241                 {
242                     *pcbEncoded = 0;
243                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
244                     ret = FALSE;
245                 }
246                 else
247                     urlLen++;
248             if (ret)
249             {
250                 CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
251                 bytesNeeded = 1 + lenBytes + urlLen;
252                 if (!pbEncoded)
253                     *pcbEncoded = bytesNeeded;
254                 else if (*pcbEncoded < bytesNeeded)
255                 {
256                     SetLastError(ERROR_MORE_DATA);
257                     *pcbEncoded = bytesNeeded;
258                     ret = FALSE;
259                 }
260                 else
261                 {
262                     *pcbEncoded = bytesNeeded;
263                     *pbEncoded++ = ASN_CONTEXT;
264                     CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
265                     pbEncoded += lenBytes;
266                     for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
267                         *pbEncoded++ = (BYTE)*ptr;
268                 }
269             }
270             break;
271         }
272         default:
273             SetLastError(E_INVALIDARG);
274         }
275     }
276     __EXCEPT_PAGE_FAULT
277     {
278         SetLastError(STATUS_ACCESS_VIOLATION);
279     }
280     __ENDTRY
281     TRACE("returning %d\n", ret);
282     return ret;
283 }
284
285 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
286  BYTE *, DWORD *);
287
288 struct AsnEncodeSequenceItem
289 {
290     const void           *pvStructInfo;
291     CryptEncodeObjectFunc encodeFunc;
292     DWORD                 size; /* used during encoding, not for your use */
293 };
294
295 static BOOL CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
296  struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
297  DWORD *pcbEncoded)
298 {
299     BOOL ret;
300     DWORD i, dataLen = 0;
301
302     TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
303     for (i = 0, ret = TRUE; ret && i < cItem; i++)
304     {
305         ret = items[i].encodeFunc(dwCertEncodingType, NULL,
306          items[i].pvStructInfo, NULL, &items[i].size);
307         /* Some functions propagate their errors through the size */
308         if (!ret)
309             *pcbEncoded = items[i].size;
310         dataLen += items[i].size;
311     }
312     if (ret)
313     {
314         DWORD lenBytes, bytesNeeded;
315
316         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
317         bytesNeeded = 1 + lenBytes + dataLen;
318         if (!pbEncoded)
319             *pcbEncoded = bytesNeeded;
320         else if (*pcbEncoded < bytesNeeded)
321         {
322             *pcbEncoded = bytesNeeded;
323             SetLastError(ERROR_MORE_DATA);
324             ret = FALSE;
325         }
326         else
327         {
328             *pcbEncoded = bytesNeeded;
329             *pbEncoded++ = ASN_SEQUENCE;
330             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
331             pbEncoded += lenBytes;
332             for (i = 0; ret && i < cItem; i++)
333             {
334                 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
335                  items[i].pvStructInfo, pbEncoded, &items[i].size);
336                 /* Some functions propagate their errors through the size */
337                 if (!ret)
338                     *pcbEncoded = items[i].size;
339                 pbEncoded += items[i].size;
340             }
341         }
342     }
343     TRACE("returning %d\n", ret);
344     return ret;
345 }
346
347 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
348  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
349  DWORD *pcbEncoded)
350 {
351     BOOL ret = FALSE;
352
353     __TRY
354     {
355         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
356         DWORD bytesNeeded, lenBytes, dataBytes;
357         BYTE unusedBits;
358
359         /* yep, MS allows cUnusedBits to be >= 8 */
360         if (!blob->cUnusedBits)
361         {
362             dataBytes = blob->cbData;
363             unusedBits = 0;
364         }
365         else if (blob->cbData * 8 > blob->cUnusedBits)
366         {
367             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
368             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
369              blob->cUnusedBits;
370         }
371         else
372         {
373             dataBytes = 0;
374             unusedBits = 0;
375         }
376         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
377         bytesNeeded = 1 + lenBytes + dataBytes + 1;
378         if (!pbEncoded)
379         {
380             *pcbEncoded = bytesNeeded;
381             ret = TRUE;
382         }
383         else if (*pcbEncoded < bytesNeeded)
384         {
385             *pcbEncoded = bytesNeeded;
386             SetLastError(ERROR_MORE_DATA);
387         }
388         else
389         {
390             ret = TRUE;
391             *pcbEncoded = bytesNeeded;
392             *pbEncoded++ = ASN_BITSTRING;
393             CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
394             pbEncoded += lenBytes;
395             *pbEncoded++ = unusedBits;
396             if (dataBytes)
397             {
398                 BYTE mask = 0xff << unusedBits;
399
400                 if (dataBytes > 1)
401                 {
402                     memcpy(pbEncoded, blob->pbData, dataBytes - 1);
403                     pbEncoded += dataBytes - 1;
404                 }
405                 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
406             }
407         }
408     }
409     __EXCEPT_PAGE_FAULT
410     {
411         SetLastError(STATUS_ACCESS_VIOLATION);
412     }
413     __ENDTRY
414     return ret;
415 }
416
417 struct AsnConstructedItem
418 {
419     BYTE                  tag;
420     const void           *pvStructInfo;
421     CryptEncodeObjectFunc encodeFunc;
422 };
423
424 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
425  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
426  DWORD *pcbEncoded)
427 {
428     BOOL ret;
429     const struct AsnConstructedItem *item =
430      (const struct AsnConstructedItem *)pvStructInfo;
431     DWORD len;
432
433     if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
434      item->pvStructInfo, NULL, &len)))
435     {
436         DWORD dataLen, bytesNeeded;
437
438         CRYPT_EncodeLen(len, NULL, &dataLen);
439         bytesNeeded = 1 + dataLen + len;
440         if (!pbEncoded)
441             *pcbEncoded = bytesNeeded;
442         else if (*pcbEncoded < bytesNeeded)
443         {
444             *pcbEncoded = bytesNeeded;
445             SetLastError(ERROR_MORE_DATA);
446             ret = FALSE;
447         }
448         else
449         {
450             *pcbEncoded = bytesNeeded;
451             *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
452             CRYPT_EncodeLen(len, pbEncoded, &dataLen);
453             pbEncoded += dataLen;
454             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
455              item->pvStructInfo, pbEncoded, &len);
456             if (!ret)
457             {
458                 /* Some functions propagate their errors through the size */
459                 *pcbEncoded = len;
460             }
461         }
462     }
463     else
464     {
465         /* Some functions propagate their errors through the size */
466         *pcbEncoded = len;
467     }
468     return ret;
469 }
470
471
472 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
473  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
474  DWORD *pcbEncoded)
475 {
476     const SPC_PE_IMAGE_DATA *imageData =
477      (const SPC_PE_IMAGE_DATA *)pvStructInfo;
478     BOOL ret = FALSE;
479
480     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
481      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
482      pcbEncoded);
483
484     __TRY
485     {
486         struct AsnEncodeSequenceItem items[2] = {
487          { 0 }
488         };
489         struct AsnConstructedItem constructed = { 0, imageData->pFile,
490          WVTAsn1SpcLinkEncode };
491         DWORD cItem = 0;
492
493         if (imageData->Flags.cbData)
494         {
495             items[cItem].pvStructInfo = &imageData->Flags;
496             items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
497             cItem++;
498         }
499         if (imageData->pFile)
500         {
501             items[cItem].pvStructInfo = &constructed;
502             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
503             cItem++;
504         }
505
506         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
507          pbEncoded, pcbEncoded);
508     }
509     __EXCEPT_PAGE_FAULT
510     {
511         SetLastError(STATUS_ACCESS_VIOLATION);
512     }
513     __ENDTRY
514     TRACE("returning %d\n", ret);
515     return ret;
516 }
517
518 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
519  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
520  DWORD *pcbEncoded)
521 {
522     LPCSTR pszObjId = (LPCSTR)pvStructInfo;
523     DWORD bytesNeeded = 0, lenBytes;
524     BOOL ret = TRUE;
525     int firstPos = 0;
526     BYTE firstByte = 0;
527
528     TRACE("%s\n", debugstr_a(pszObjId));
529
530     if (pszObjId)
531     {
532         const char *ptr;
533         int val1, val2;
534
535         if (sscanf(pszObjId, "%d.%d%n", &val1, &val2, &firstPos) != 2)
536         {
537             SetLastError(CRYPT_E_ASN1_ERROR);
538             return FALSE;
539         }
540         bytesNeeded++;
541         firstByte = val1 * 40 + val2;
542         ptr = pszObjId + firstPos;
543         if (*ptr == '.')
544         {
545             ptr++;
546             firstPos++;
547         }
548         while (ret && *ptr)
549         {
550             int pos;
551
552             /* note I assume each component is at most 32-bits long in base 2 */
553             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
554             {
555                 if (val1 >= 0x10000000)
556                     bytesNeeded += 5;
557                 else if (val1 >= 0x200000)
558                     bytesNeeded += 4;
559                 else if (val1 >= 0x4000)
560                     bytesNeeded += 3;
561                 else if (val1 >= 0x80)
562                     bytesNeeded += 2;
563                 else
564                     bytesNeeded += 1;
565                 ptr += pos;
566                 if (*ptr == '.')
567                     ptr++;
568             }
569             else
570             {
571                 SetLastError(CRYPT_E_ASN1_ERROR);
572                 return FALSE;
573             }
574         }
575         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
576     }
577     else
578         lenBytes = 1;
579     bytesNeeded += 1 + lenBytes;
580     if (pbEncoded)
581     {
582         if (*pcbEncoded < bytesNeeded)
583         {
584             SetLastError(ERROR_MORE_DATA);
585             ret = FALSE;
586         }
587         else
588         {
589             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
590             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
591             pbEncoded += lenBytes;
592             if (pszObjId)
593             {
594                 const char *ptr;
595                 int val, pos;
596
597                 *pbEncoded++ = firstByte;
598                 ptr = pszObjId + firstPos;
599                 while (ret && *ptr)
600                 {
601                     sscanf(ptr, "%d%n", &val, &pos);
602                     {
603                         unsigned char outBytes[5];
604                         int numBytes, i;
605
606                         if (val >= 0x10000000)
607                             numBytes = 5;
608                         else if (val >= 0x200000)
609                             numBytes = 4;
610                         else if (val >= 0x4000)
611                             numBytes = 3;
612                         else if (val >= 0x80)
613                             numBytes = 2;
614                         else
615                             numBytes = 1;
616                         for (i = numBytes; i > 0; i--)
617                         {
618                             outBytes[i - 1] = val & 0x7f;
619                             val >>= 7;
620                         }
621                         for (i = 0; i < numBytes - 1; i++)
622                             *pbEncoded++ = outBytes[i] | 0x80;
623                         *pbEncoded++ = outBytes[i];
624                         ptr += pos;
625                         if (*ptr == '.')
626                             ptr++;
627                     }
628                 }
629             }
630         }
631     }
632     *pcbEncoded = bytesNeeded;
633     return ret;
634 }
635
636 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
637  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
638  DWORD *pcbEncoded)
639 {
640     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
641     BOOL ret = TRUE;
642
643     if (!pbEncoded)
644         *pcbEncoded = blob->cbData;
645     else if (*pcbEncoded < blob->cbData)
646     {
647         *pcbEncoded = blob->cbData;
648         SetLastError(ERROR_MORE_DATA);
649         ret = FALSE;
650     }
651     else
652     {
653         if (blob->cbData)
654             memcpy(pbEncoded, blob->pbData, blob->cbData);
655         *pcbEncoded = blob->cbData;
656     }
657     return ret;
658 }
659
660 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
661  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
662  BYTE *pbEncoded, DWORD *pcbEncoded)
663 {
664     const CRYPT_ALGORITHM_IDENTIFIER *algo =
665      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
666     static const BYTE asn1Null[] = { ASN_NULL, 0 };
667     static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
668      (LPBYTE)asn1Null };
669     BOOL ret;
670     struct AsnEncodeSequenceItem items[2] = {
671      { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
672      { NULL,           CRYPT_CopyEncodedBlob, 0 },
673     };
674
675     if (algo->Parameters.cbData)
676         items[1].pvStructInfo = &algo->Parameters;
677     else
678         items[1].pvStructInfo = &nullBlob;
679     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
680      sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
681     return ret;
682 }
683
684 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
685  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
686  DWORD *pcbEncoded)
687 {
688     const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
689      (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
690     struct AsnEncodeSequenceItem items[] = {
691      { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
692      { &typeValue->Value,    CRYPT_CopyEncodedBlob, 0 },
693     };
694
695     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
696      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
697 }
698
699 struct SPCDigest
700 {
701     CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
702     CRYPT_HASH_BLOB            Digest;
703 };
704
705 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
706  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
707  DWORD *pcbEncoded)
708 {
709     const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
710     struct AsnEncodeSequenceItem items[] = {
711      { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
712      { &digest->Digest,          CRYPT_CopyEncodedBlob, 0 },
713     };
714
715     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
716      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
717 }
718
719 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
720  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
721  DWORD *pcbEncoded)
722 {
723     BOOL ret = FALSE;
724
725     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
726      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
727
728     __TRY
729     {
730         const SPC_INDIRECT_DATA_CONTENT *data =
731          (const SPC_INDIRECT_DATA_CONTENT *)pvStructInfo;
732         struct AsnEncodeSequenceItem items[] = {
733          { &data->Data,            CRYPT_AsnEncodeAttributeTypeValue, 0 },
734          { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
735         };
736
737         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
738          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
739     }
740     __EXCEPT_PAGE_FAULT
741     {
742         SetLastError(STATUS_ACCESS_VIOLATION);
743     }
744     __ENDTRY
745     return ret;
746 }
747
748 static BOOL WINAPI CRYPT_AsnEncodeBMPString(DWORD dwCertEncodingType,
749  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
750  DWORD *pcbEncoded)
751 {
752     BOOL ret = TRUE;
753     LPCWSTR str = (LPCWSTR)pvStructInfo;
754     DWORD bytesNeeded, lenBytes, strLen;
755
756     if (str)
757         strLen = lstrlenW(str);
758     else
759         strLen = 0;
760     CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
761     bytesNeeded = 1 + lenBytes + strLen * 2;
762     if (!pbEncoded)
763         *pcbEncoded = bytesNeeded;
764     else if (*pcbEncoded < bytesNeeded)
765     {
766         *pcbEncoded = bytesNeeded;
767         SetLastError(ERROR_MORE_DATA);
768         ret = FALSE;
769     }
770     else
771     {
772         DWORD i;
773
774         *pcbEncoded = bytesNeeded;
775         *pbEncoded++ = ASN_BMPSTRING;
776         CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
777         pbEncoded += lenBytes;
778         for (i = 0; i < strLen; i++)
779         {
780             *pbEncoded++ = (str[i] & 0xff00) >> 8;
781             *pbEncoded++ = str[i] & 0x00ff;
782         }
783     }
784     return ret;
785 }
786
787 struct AsnEncodeTagSwappedItem
788 {
789     BYTE                  tag;
790     const void           *pvStructInfo;
791     CryptEncodeObjectFunc encodeFunc;
792 };
793
794 /* Sort of a wacky hack, it encodes something using the struct
795  * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
796  * given in the struct AsnEncodeTagSwappedItem.
797  */
798 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
799  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
800  DWORD *pcbEncoded)
801 {
802     BOOL ret;
803     const struct AsnEncodeTagSwappedItem *item = pvStructInfo;
804
805     ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
806      item->pvStructInfo, pbEncoded, pcbEncoded);
807     if (ret && pbEncoded)
808         *pbEncoded = item->tag;
809     return ret;
810 }
811
812 BOOL WINAPI WVTAsn1SpcSpOpusInfoEncode(DWORD dwCertEncodingType,
813  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
814  DWORD *pcbEncoded)
815 {
816     BOOL ret = FALSE;
817
818     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
819      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
820
821     __TRY
822     {
823         const SPC_SP_OPUS_INFO *info = pvStructInfo;
824
825         if (info->pMoreInfo &&
826          info->pMoreInfo->dwLinkChoice != SPC_URL_LINK_CHOICE &&
827          info->pMoreInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE &&
828          info->pMoreInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE)
829             SetLastError(E_INVALIDARG);
830         else if (info->pPublisherInfo &&
831          info->pPublisherInfo->dwLinkChoice != SPC_URL_LINK_CHOICE &&
832          info->pPublisherInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE &&
833          info->pPublisherInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE)
834             SetLastError(E_INVALIDARG);
835         else
836         {
837             struct AsnEncodeSequenceItem items[3] = { { 0 } };
838             struct AsnConstructedItem constructed[3] = { { 0 } };
839             struct AsnEncodeTagSwappedItem swapped;
840             DWORD cItem = 0, cConstructed = 0;
841
842             if (info->pwszProgramName)
843             {
844                 swapped.tag = ASN_CONTEXT;
845                 swapped.pvStructInfo = info->pwszProgramName;
846                 swapped.encodeFunc = CRYPT_AsnEncodeBMPString;
847                 constructed[cConstructed].tag = 0;
848                 constructed[cConstructed].pvStructInfo = &swapped;
849                 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeSwapTag;
850                 items[cItem].pvStructInfo = &constructed[cConstructed];
851                 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
852                 cConstructed++;
853                 cItem++;
854             }
855             if (info->pMoreInfo)
856             {
857                 constructed[cConstructed].tag = 1;
858                 constructed[cConstructed].pvStructInfo = info->pMoreInfo;
859                 constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode;
860                 items[cItem].pvStructInfo = &constructed[cConstructed];
861                 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
862                 cConstructed++;
863                 cItem++;
864             }
865             if (info->pPublisherInfo)
866             {
867                 constructed[cConstructed].tag = 2;
868                 constructed[cConstructed].pvStructInfo = info->pPublisherInfo;
869                 constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode;
870                 items[cItem].pvStructInfo = &constructed[cConstructed];
871                 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
872                 cConstructed++;
873                 cItem++;
874             }
875             ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
876              items, cItem, pbEncoded, pcbEncoded);
877         }
878     }
879     __EXCEPT_PAGE_FAULT
880     {
881         SetLastError(STATUS_ACCESS_VIOLATION);
882     }
883     __ENDTRY
884     return ret;
885 }
886
887 static BOOL CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
888  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
889  DWORD *pcbEncoded)
890 {
891     BOOL ret;
892
893     __TRY
894     {
895         DWORD significantBytes, lenBytes, bytesNeeded;
896         BYTE padByte = 0;
897         BOOL pad = FALSE;
898         const CRYPT_INTEGER_BLOB *blob =
899          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
900
901         significantBytes = blob->cbData;
902         if (significantBytes)
903         {
904             if (blob->pbData[significantBytes - 1] & 0x80)
905             {
906                 /* negative, lop off leading (little-endian) 0xffs */
907                 for (; significantBytes > 0 &&
908                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
909                     ;
910                 if (blob->pbData[significantBytes - 1] < 0x80)
911                 {
912                     padByte = 0xff;
913                     pad = TRUE;
914                 }
915             }
916             else
917             {
918                 /* positive, lop off leading (little-endian) zeroes */
919                 for (; significantBytes > 0 &&
920                  !blob->pbData[significantBytes - 1]; significantBytes--)
921                     ;
922                 if (significantBytes == 0)
923                     significantBytes = 1;
924                 if (blob->pbData[significantBytes - 1] > 0x7f)
925                 {
926                     padByte = 0;
927                     pad = TRUE;
928                 }
929             }
930         }
931         if (pad)
932             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
933         else
934             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
935         bytesNeeded = 1 + lenBytes + significantBytes;
936         if (pad)
937             bytesNeeded++;
938         if (!pbEncoded)
939         {
940             *pcbEncoded = bytesNeeded;
941             ret = TRUE;
942         }
943         else if (*pcbEncoded < bytesNeeded)
944         {
945             *pcbEncoded = bytesNeeded;
946             SetLastError(ERROR_MORE_DATA);
947             ret = FALSE;
948         }
949         else
950         {
951             *pcbEncoded = bytesNeeded;
952             *pbEncoded++ = ASN_INTEGER;
953             if (pad)
954             {
955                 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
956                 pbEncoded += lenBytes;
957                 *pbEncoded++ = padByte;
958             }
959             else
960             {
961                 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
962                 pbEncoded += lenBytes;
963             }
964             for (; significantBytes > 0; significantBytes--)
965                 *(pbEncoded++) = blob->pbData[significantBytes - 1];
966             ret = TRUE;
967         }
968     }
969     __EXCEPT_PAGE_FAULT
970     {
971         SetLastError(STATUS_ACCESS_VIOLATION);
972         ret = FALSE;
973     }
974     __ENDTRY
975     return ret;
976 }
977
978 BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
979  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
980  DWORD *pcbEncoded)
981 {
982     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
983
984     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
985      &blob, pbEncoded, pcbEncoded);
986 }
987
988 BOOL WINAPI WVTAsn1CatMemberInfoEncode(DWORD dwCertEncodingType,
989  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
990  DWORD *pcbEncoded)
991 {
992     BOOL ret = FALSE;
993
994     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
995      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
996
997     __TRY
998     {
999         const CAT_MEMBERINFO *info = (const CAT_MEMBERINFO *)pvStructInfo;
1000         struct AsnEncodeSequenceItem items[] = {
1001          { info->pwszSubjGuid, CRYPT_AsnEncodeBMPString, 0 },
1002          { &info->dwCertVersion, CRYPT_AsnEncodeInt, 0 },
1003         };
1004
1005         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
1006          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
1007     }
1008     __EXCEPT_PAGE_FAULT
1009     {
1010         SetLastError(STATUS_ACCESS_VIOLATION);
1011     }
1012     __ENDTRY
1013     return ret;
1014 }
1015
1016 BOOL WINAPI WVTAsn1CatNameValueEncode(DWORD dwCertEncodingType,
1017  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1018  DWORD *pcbEncoded)
1019 {
1020     BOOL ret = FALSE;
1021
1022     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
1023      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
1024
1025     __TRY
1026     {
1027         const CAT_NAMEVALUE *value = (const CAT_NAMEVALUE *)pvStructInfo;
1028         struct AsnEncodeSequenceItem items[] = {
1029          { value->pwszTag,   CRYPT_AsnEncodeBMPString, 0 },
1030          { &value->fdwFlags, CRYPT_AsnEncodeInt, 0 },
1031          { &value->Value,    CRYPT_AsnEncodeOctets, 0 },
1032         };
1033
1034         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
1035          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
1036     }
1037     __EXCEPT_PAGE_FAULT
1038     {
1039         SetLastError(STATUS_ACCESS_VIOLATION);
1040     }
1041     __ENDTRY
1042     return ret;
1043 }
1044
1045 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1046  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1047  DWORD *pcbEncoded)
1048 {
1049     BOOL val = *(const BOOL *)pvStructInfo, ret;
1050
1051     TRACE("%d\n", val);
1052
1053     if (!pbEncoded)
1054     {
1055         *pcbEncoded = 3;
1056         ret = TRUE;
1057     }
1058     else if (*pcbEncoded < 3)
1059     {
1060         *pcbEncoded = 3;
1061         SetLastError(ERROR_MORE_DATA);
1062         ret = FALSE;
1063     }
1064     else
1065     {
1066         *pcbEncoded = 3;
1067         *pbEncoded++ = ASN_BOOL;
1068         *pbEncoded++ = 1;
1069         *pbEncoded++ = val ? 0xff : 0;
1070         ret = TRUE;
1071     }
1072     TRACE("returning %d (%08x)\n", ret, GetLastError());
1073     return ret;
1074 }
1075
1076 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoEncode(DWORD dwCertEncodingType,
1077  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1078  DWORD *pcbEncoded)
1079 {
1080     BOOL ret = FALSE;
1081
1082     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
1083      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
1084
1085     __TRY
1086     {
1087         const SPC_FINANCIAL_CRITERIA *criteria = pvStructInfo;
1088         struct AsnEncodeSequenceItem items[] = {
1089          { &criteria->fFinancialInfoAvailable, CRYPT_AsnEncodeBool, 0 },
1090          { &criteria->fMeetsCriteria,          CRYPT_AsnEncodeBool, 0 },
1091         };
1092
1093         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
1094          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
1095     }
1096     __EXCEPT_PAGE_FAULT
1097     {
1098         SetLastError(STATUS_ACCESS_VIOLATION);
1099     }
1100     __ENDTRY
1101     return ret;
1102 }
1103
1104 /* Gets the number of length bytes from the given (leading) length byte */
1105 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1106
1107 /* Helper function to get the encoded length of the data starting at pbEncoded,
1108  * where pbEncoded[0] is the tag.  If the data are too short to contain a
1109  * length or if the length is too large for cbEncoded, sets an appropriate
1110  * error code and returns FALSE.
1111  */
1112 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
1113 {
1114     BOOL ret;
1115
1116     if (cbEncoded <= 1)
1117     {
1118         SetLastError(CRYPT_E_ASN1_CORRUPT);
1119         ret = FALSE;
1120     }
1121     else if (pbEncoded[1] <= 0x7f)
1122     {
1123         if (pbEncoded[1] + 1 > cbEncoded)
1124         {
1125             SetLastError(CRYPT_E_ASN1_EOD);
1126             ret = FALSE;
1127         }
1128         else
1129         {
1130             *len = pbEncoded[1];
1131             ret = TRUE;
1132         }
1133     }
1134     else if (pbEncoded[1] == 0x80)
1135     {
1136         FIXME("unimplemented for indefinite-length encoding\n");
1137         SetLastError(CRYPT_E_ASN1_CORRUPT);
1138         ret = FALSE;
1139     }
1140     else
1141     {
1142         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1143
1144         if (lenLen > sizeof(DWORD) + 1)
1145         {
1146             SetLastError(CRYPT_E_ASN1_LARGE);
1147             ret = FALSE;
1148         }
1149         else if (lenLen + 2 > cbEncoded)
1150         {
1151             SetLastError(CRYPT_E_ASN1_CORRUPT);
1152             ret = FALSE;
1153         }
1154         else
1155         {
1156             DWORD out = 0;
1157
1158             pbEncoded += 2;
1159             while (--lenLen)
1160             {
1161                 out <<= 8;
1162                 out |= *pbEncoded++;
1163             }
1164             if (out + lenLen + 1 > cbEncoded)
1165             {
1166                 SetLastError(CRYPT_E_ASN1_EOD);
1167                 ret = FALSE;
1168             }
1169             else
1170             {
1171                 *len = out;
1172                 ret = TRUE;
1173             }
1174         }
1175     }
1176     return ret;
1177 }
1178
1179 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1180  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1181  void *pvStructInfo, DWORD *pcbStructInfo)
1182 {
1183     BOOL ret;
1184     DWORD bytesNeeded, dataLen;
1185
1186     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1187      pvStructInfo, *pcbStructInfo);
1188
1189     if (!cbEncoded)
1190     {
1191         SetLastError(CRYPT_E_ASN1_CORRUPT);
1192         ret = FALSE;
1193     }
1194     else if (pbEncoded[0] != ASN_OCTETSTRING)
1195     {
1196         SetLastError(CRYPT_E_ASN1_BADTAG);
1197         ret = FALSE;
1198     }
1199     else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1200     {
1201         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1202             bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1203         else
1204             bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1205         if (!pvStructInfo)
1206             *pcbStructInfo = bytesNeeded;
1207         else if (*pcbStructInfo < bytesNeeded)
1208         {
1209             SetLastError(ERROR_MORE_DATA);
1210             *pcbStructInfo = bytesNeeded;
1211             ret = FALSE;
1212         }
1213         else
1214         {
1215             CRYPT_DATA_BLOB *blob;
1216             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1217
1218             blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1219             blob->cbData = dataLen;
1220             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1221                 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1222             else
1223             {
1224                 assert(blob->pbData);
1225                 if (blob->cbData)
1226                     memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
1227                      blob->cbData);
1228             }
1229         }
1230     }
1231     return ret;
1232 }
1233
1234 static BOOL CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
1235  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1236  void *pvStructInfo, DWORD *pcbStructInfo)
1237 {
1238     BOOL ret = FALSE;
1239     DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
1240
1241     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1242      pvStructInfo, *pcbStructInfo);
1243
1244     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1245     {
1246         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1247         DWORD realDataLen;
1248
1249         switch (pbEncoded[0])
1250         {
1251         case ASN_CONTEXT:
1252             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
1253             if (!pvStructInfo)
1254                 *pcbStructInfo = bytesNeeded;
1255             else if (*pcbStructInfo < bytesNeeded)
1256             {
1257                 *pcbStructInfo = bytesNeeded;
1258                 SetLastError(ERROR_MORE_DATA);
1259                 ret = FALSE;
1260             }
1261             else
1262             {
1263                 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1264                 DWORD i;
1265
1266                 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
1267                 for (i = 0; i < dataLen; i++)
1268                     link->u.pwszUrl[i] =
1269                      *(pbEncoded + 1 + lenBytes + i);
1270                 link->u.pwszUrl[i] = '\0';
1271                 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
1272             }
1273             break;
1274         case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
1275         {
1276             CRYPT_DATA_BLOB classId;
1277             DWORD size = sizeof(classId);
1278
1279             if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1280              pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
1281              CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
1282             {
1283                 if (classId.cbData != sizeof(SPC_UUID))
1284                 {
1285                     SetLastError(CRYPT_E_BAD_ENCODE);
1286                     ret = FALSE;
1287                 }
1288                 else
1289                 {
1290                     CRYPT_DATA_BLOB data;
1291
1292                     /* The tag length for the classId must be 1 since the
1293                      * length is correct.
1294                      */
1295                     size = sizeof(data);
1296                     if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1297                      pbEncoded + 3 + lenBytes + classId.cbData,
1298                      cbEncoded - 3 - lenBytes - classId.cbData,
1299                      CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
1300                     {
1301                         bytesNeeded += data.cbData;
1302                         if (!pvStructInfo)
1303                             *pcbStructInfo = bytesNeeded;
1304                         else if (*pcbStructInfo < bytesNeeded)
1305                         {
1306                             *pcbStructInfo = bytesNeeded;
1307                             SetLastError(ERROR_MORE_DATA);
1308                             ret = FALSE;
1309                         }
1310                         else
1311                         {
1312                             PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1313
1314                             link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
1315                             /* pwszFile pointer was set by caller, copy it
1316                              * before overwriting it
1317                              */
1318                             link->u.Moniker.SerializedData.pbData =
1319                              (BYTE *)link->u.pwszFile;
1320                             memcpy(link->u.Moniker.ClassId, classId.pbData,
1321                              classId.cbData);
1322                             memcpy(link->u.Moniker.SerializedData.pbData,
1323                              data.pbData, data.cbData);
1324                             link->u.Moniker.SerializedData.cbData = data.cbData;
1325                         }
1326                     }
1327                 }
1328             }
1329             break;
1330         }
1331         case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
1332             if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
1333                 SetLastError(CRYPT_E_ASN1_BADTAG);
1334             else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
1335              &realDataLen)))
1336             {
1337                 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
1338
1339                 bytesNeeded += realDataLen + sizeof(WCHAR);
1340                 if (!pvStructInfo)
1341                     *pcbStructInfo = bytesNeeded;
1342                 else if (*pcbStructInfo < bytesNeeded)
1343                 {
1344                     *pcbStructInfo = bytesNeeded;
1345                     SetLastError(ERROR_MORE_DATA);
1346                     ret = FALSE;
1347                 }
1348                 else
1349                 {
1350                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1351                     DWORD i;
1352                     const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
1353
1354                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1355                     for (i = 0; i < dataLen / sizeof(WCHAR); i++)
1356                         link->u.pwszFile[i] =
1357                          hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
1358                     link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
1359                     TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
1360                 }
1361             }
1362             else
1363             {
1364                 bytesNeeded += sizeof(WCHAR);
1365                 if (!pvStructInfo)
1366                     *pcbStructInfo = bytesNeeded;
1367                 else if (*pcbStructInfo < bytesNeeded)
1368                 {
1369                     *pcbStructInfo = bytesNeeded;
1370                     SetLastError(ERROR_MORE_DATA);
1371                     ret = FALSE;
1372                 }
1373                 else
1374                 {
1375                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1376
1377                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1378                     link->u.pwszFile[0] = '\0';
1379                     ret = TRUE;
1380                 }
1381             }
1382             break;
1383         default:
1384             SetLastError(CRYPT_E_ASN1_BADTAG);
1385         }
1386     }
1387     TRACE("returning %d\n", ret);
1388     return ret;
1389 }
1390
1391 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1392  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1393  void *pvStructInfo, DWORD *pcbStructInfo)
1394 {
1395     BOOL ret = FALSE;
1396
1397     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1398      pvStructInfo, *pcbStructInfo);
1399
1400     __TRY
1401     {
1402         DWORD bytesNeeded;
1403
1404         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1405          lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1406         if (ret)
1407         {
1408             if (!pvStructInfo)
1409                 *pcbStructInfo = bytesNeeded;
1410             else if (*pcbStructInfo < bytesNeeded)
1411             {
1412                 *pcbStructInfo = bytesNeeded;
1413                 SetLastError(ERROR_MORE_DATA);
1414                 ret = FALSE;
1415             }
1416             else
1417             {
1418                 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1419
1420                 link->u.pwszFile =
1421                  (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1422                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1423                  lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1424                  pcbStructInfo);
1425             }
1426         }
1427     }
1428     __EXCEPT_PAGE_FAULT
1429     {
1430         SetLastError(STATUS_ACCESS_VIOLATION);
1431     }
1432     __ENDTRY
1433     TRACE("returning %d\n", ret);
1434     return ret;
1435 }
1436
1437 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1438  DWORD, DWORD, void *, DWORD *);
1439
1440 /* tag:
1441  *     The expected tag of the item.  If tag is 0, decodeFunc is called
1442  *     regardless of the tag value seen.
1443  * offset:
1444  *     A sequence is decoded into a struct.  The offset member is the
1445  *     offset of this item within that struct.
1446  * decodeFunc:
1447  *     The decoder function to use.  If this is NULL, then the member isn't
1448  *     decoded, but minSize space is reserved for it.
1449  * minSize:
1450  *     The minimum amount of space occupied after decoding.  You must set this.
1451  * optional:
1452  *     If true, and the tag doesn't match the expected tag for this item,
1453  *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1454  *     filled with 0 for this member.
1455  * hasPointer, pointerOffset:
1456  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1457  *     the offset within the struct of the data pointer (or to the
1458  *     first data pointer, if more than one exist).
1459  * size:
1460  *     Used by CRYPT_AsnDecodeSequence, not for your use.
1461  */
1462 struct AsnDecodeSequenceItem
1463 {
1464     BYTE                  tag;
1465     DWORD                 offset;
1466     CryptDecodeObjectFunc decodeFunc;
1467     DWORD                 minSize;
1468     BOOL                  optional;
1469     BOOL                  hasPointer;
1470     DWORD                 pointerOffset;
1471     DWORD                 size;
1472 };
1473
1474 /* Decodes the items in a sequence, where the items are described in items,
1475  * the encoded data are in pbEncoded with length cbEncoded.  Decodes into
1476  * pvStructInfo.  nextData is a pointer to the memory location at which the
1477  * first decoded item with a dynamic pointer should point.
1478  * Upon decoding, *cbDecoded is the total number of bytes decoded.
1479  */
1480 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1481  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1482  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1483  DWORD *cbDecoded)
1484 {
1485     BOOL ret;
1486     DWORD i, decoded = 0;
1487     const BYTE *ptr = pbEncoded;
1488
1489     TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1490      cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1491
1492     for (i = 0, ret = TRUE; ret && i < cItem; i++)
1493     {
1494         if (cbEncoded - (ptr - pbEncoded) != 0)
1495         {
1496             DWORD nextItemLen;
1497
1498             if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1499              &nextItemLen)))
1500             {
1501                 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1502
1503                 if (ptr[0] == items[i].tag || !items[i].tag)
1504                 {
1505                     if (nextData && pvStructInfo && items[i].hasPointer)
1506                     {
1507                         TRACE("Setting next pointer to %p\n",
1508                          nextData);
1509                         *(BYTE **)((BYTE *)pvStructInfo +
1510                          items[i].pointerOffset) = nextData;
1511                     }
1512                     if (items[i].decodeFunc)
1513                     {
1514                         if (pvStructInfo)
1515                             TRACE("decoding item %d\n", i);
1516                         else
1517                             TRACE("sizing item %d\n", i);
1518                         ret = items[i].decodeFunc(dwCertEncodingType,
1519                          NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1520                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1521                          pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
1522                          : NULL, &items[i].size);
1523                         if (ret)
1524                         {
1525                             /* Account for alignment padding */
1526                             if (items[i].size % sizeof(DWORD))
1527                                 items[i].size += sizeof(DWORD) -
1528                                  items[i].size % sizeof(DWORD);
1529                             TRACE("item %d size: %d\n", i, items[i].size);
1530                             if (nextData && items[i].hasPointer &&
1531                              items[i].size > items[i].minSize)
1532                                 nextData += items[i].size - items[i].minSize;
1533                             ptr += 1 + nextItemLenBytes + nextItemLen;
1534                             decoded += 1 + nextItemLenBytes + nextItemLen;
1535                             TRACE("item %d: decoded %d bytes\n", i,
1536                              1 + nextItemLenBytes + nextItemLen);
1537                         }
1538                         else if (items[i].optional &&
1539                          GetLastError() == CRYPT_E_ASN1_BADTAG)
1540                         {
1541                             TRACE("skipping optional item %d\n", i);
1542                             items[i].size = items[i].minSize;
1543                             SetLastError(NOERROR);
1544                             ret = TRUE;
1545                         }
1546                         else
1547                             TRACE("item %d failed: %08x\n", i,
1548                              GetLastError());
1549                     }
1550                     else
1551                     {
1552                         TRACE("item %d: decoded %d bytes\n", i,
1553                          1 + nextItemLenBytes + nextItemLen);
1554                         ptr += 1 + nextItemLenBytes + nextItemLen;
1555                         decoded += 1 + nextItemLenBytes + nextItemLen;
1556                         items[i].size = items[i].minSize;
1557                     }
1558                 }
1559                 else if (items[i].optional)
1560                 {
1561                     TRACE("skipping optional item %d\n", i);
1562                     items[i].size = items[i].minSize;
1563                 }
1564                 else
1565                 {
1566                     TRACE("item %d: tag %02x doesn't match expected %02x\n",
1567                      i, ptr[0], items[i].tag);
1568                     SetLastError(CRYPT_E_ASN1_BADTAG);
1569                     ret = FALSE;
1570                 }
1571             }
1572         }
1573         else if (items[i].optional)
1574         {
1575             TRACE("missing optional item %d, skipping\n", i);
1576             items[i].size = items[i].minSize;
1577         }
1578         else
1579         {
1580             TRACE("not enough bytes for item %d, failing\n", i);
1581             SetLastError(CRYPT_E_ASN1_CORRUPT);
1582             ret = FALSE;
1583         }
1584     }
1585     if (ret)
1586         *cbDecoded = decoded;
1587     TRACE("returning %d\n", ret);
1588     return ret;
1589 }
1590
1591 /* This decodes an arbitrary sequence into a contiguous block of memory
1592  * (basically, a struct.)  Each element being decoded is described by a struct
1593  * AsnDecodeSequenceItem, see above.
1594  * startingPointer is an optional pointer to the first place where dynamic
1595  * data will be stored.  If you know the starting offset, you may pass it
1596  * here.  Otherwise, pass NULL, and one will be inferred from the items.
1597  */
1598 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1599  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1600  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1601  void *startingPointer)
1602 {
1603     BOOL ret;
1604
1605     TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1606      cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1607
1608     if (pbEncoded[0] == ASN_SEQUENCE)
1609     {
1610         DWORD dataLen;
1611
1612         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1613         {
1614             DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1615             const BYTE *ptr = pbEncoded + 1 + lenBytes;
1616
1617             cbEncoded -= 1 + lenBytes;
1618             if (cbEncoded < dataLen)
1619             {
1620                 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1621                  cbEncoded);
1622                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1623                 ret = FALSE;
1624             }
1625             else
1626                 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1627                  cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1628             if (ret && cbDecoded != dataLen)
1629             {
1630                 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1631                  cbDecoded);
1632                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1633                 ret = FALSE;
1634             }
1635             if (ret)
1636             {
1637                 DWORD i, bytesNeeded = 0, structSize = 0;
1638
1639                 for (i = 0; i < cItem; i++)
1640                 {
1641                     bytesNeeded += items[i].size;
1642                     structSize += items[i].minSize;
1643                 }
1644                 if (!pvStructInfo)
1645                     *pcbStructInfo = bytesNeeded;
1646                 else if (*pcbStructInfo < bytesNeeded)
1647                 {
1648                     SetLastError(ERROR_MORE_DATA);
1649                     *pcbStructInfo = bytesNeeded;
1650                     ret = FALSE;
1651                 }
1652                 else
1653                 {
1654                     BYTE *nextData;
1655
1656                     *pcbStructInfo = bytesNeeded;
1657                     if (startingPointer)
1658                         nextData = (BYTE *)startingPointer;
1659                     else
1660                         nextData = (BYTE *)pvStructInfo + structSize;
1661                     memset(pvStructInfo, 0, structSize);
1662                     ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1663                      ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1664                      &cbDecoded);
1665                 }
1666             }
1667         }
1668     }
1669     else
1670     {
1671         SetLastError(CRYPT_E_ASN1_BADTAG);
1672         ret = FALSE;
1673     }
1674     TRACE("returning %d (%08x)\n", ret, GetLastError());
1675     return ret;
1676 }
1677
1678 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1679  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1680  void *pvStructInfo, DWORD *pcbStructInfo)
1681 {
1682     BOOL ret;
1683
1684     TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1685      pvStructInfo, *pcbStructInfo);
1686
1687     if (pbEncoded[0] == ASN_BITSTRING)
1688     {
1689         DWORD bytesNeeded, dataLen;
1690
1691         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1692         {
1693             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1694                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1695             else
1696                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1697             if (!pvStructInfo)
1698                 *pcbStructInfo = bytesNeeded;
1699             else if (*pcbStructInfo < bytesNeeded)
1700             {
1701                 *pcbStructInfo = bytesNeeded;
1702                 SetLastError(ERROR_MORE_DATA);
1703                 ret = FALSE;
1704             }
1705             else
1706             {
1707                 CRYPT_BIT_BLOB *blob;
1708
1709                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1710                 blob->cbData = dataLen - 1;
1711                 blob->cUnusedBits = *(pbEncoded + 1 +
1712                  GET_LEN_BYTES(pbEncoded[1]));
1713                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1714                 {
1715                     blob->pbData = (BYTE *)pbEncoded + 2 +
1716                      GET_LEN_BYTES(pbEncoded[1]);
1717                 }
1718                 else
1719                 {
1720                     assert(blob->pbData);
1721                     if (blob->cbData)
1722                     {
1723                         BYTE mask = 0xff << blob->cUnusedBits;
1724
1725                         memcpy(blob->pbData, pbEncoded + 2 +
1726                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1727                         blob->pbData[blob->cbData - 1] &= mask;
1728                     }
1729                 }
1730             }
1731         }
1732     }
1733     else
1734     {
1735         SetLastError(CRYPT_E_ASN1_BADTAG);
1736         ret = FALSE;
1737     }
1738     TRACE("returning %d (%08x)\n", ret, GetLastError());
1739     return ret;
1740 }
1741
1742 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1743  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1744  void *pvStructInfo, DWORD *pcbStructInfo)
1745 {
1746     BOOL ret = FALSE;
1747     DWORD dataLen;
1748
1749     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1750     {
1751         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1752         DWORD size;
1753         SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1754
1755         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1756          pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1757         if (ret)
1758         {
1759             if (!pvStructInfo)
1760                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1761             else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1762             {
1763                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1764                 SetLastError(ERROR_MORE_DATA);
1765                 ret = FALSE;
1766             }
1767             else
1768             {
1769                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1770                 /* Set imageData's pointer if necessary */
1771                 if (size > sizeof(SPC_LINK))
1772                 {
1773                     (*pLink)->u.pwszUrl =
1774                      (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1775                 }
1776                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1777                  lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1778                  *pLink, pcbStructInfo);
1779             }
1780         }
1781     }
1782     return ret;
1783 }
1784
1785 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1786  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1787  void *pvStructInfo, DWORD *pcbStructInfo)
1788 {
1789     BOOL ret = FALSE;
1790
1791     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1792      pvStructInfo, *pcbStructInfo);
1793
1794     __TRY
1795     {
1796         struct AsnDecodeSequenceItem items[] = {
1797          { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1798            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1799            offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1800          { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1801            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1802            offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1803         };
1804
1805         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1806          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1807          pvStructInfo, pcbStructInfo, NULL);
1808     }
1809     __EXCEPT_PAGE_FAULT
1810     {
1811         SetLastError(STATUS_ACCESS_VIOLATION);
1812     }
1813     __ENDTRY
1814     TRACE("returning %d\n", ret);
1815     return ret;
1816 }
1817
1818 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1819  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1820  void *pvStructInfo, DWORD *pcbStructInfo)
1821 {
1822     BOOL ret = TRUE;
1823     DWORD dataLen;
1824
1825     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1826      pvStructInfo, *pcbStructInfo);
1827
1828     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1829     {
1830         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1831         DWORD bytesNeeded = sizeof(LPSTR);
1832
1833         if (dataLen)
1834         {
1835             /* The largest possible string for the first two components
1836              * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1837              */
1838             char firstTwo[6];
1839             const BYTE *ptr;
1840
1841             snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1842              pbEncoded[1 + lenBytes] / 40,
1843              pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1844              * 40);
1845             bytesNeeded += strlen(firstTwo) + 1;
1846             for (ptr = pbEncoded + 2 + lenBytes; ret &&
1847              ptr - pbEncoded - 1 - lenBytes < dataLen; )
1848             {
1849                 /* large enough for ".4000000" */
1850                 char str[9];
1851                 int val = 0;
1852
1853                 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1854                  (*ptr & 0x80))
1855                 {
1856                     val <<= 7;
1857                     val |= *ptr & 0x7f;
1858                     ptr++;
1859                 }
1860                 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1861                  (*ptr & 0x80))
1862                 {
1863                     SetLastError(CRYPT_E_ASN1_CORRUPT);
1864                     ret = FALSE;
1865                 }
1866                 else
1867                 {
1868                     val <<= 7;
1869                     val |= *ptr++;
1870                     snprintf(str, sizeof(str), ".%d", val);
1871                     bytesNeeded += strlen(str);
1872                 }
1873             }
1874         }
1875         if (!pvStructInfo)
1876             *pcbStructInfo = bytesNeeded;
1877         else if (*pcbStructInfo < bytesNeeded)
1878         {
1879             *pcbStructInfo = bytesNeeded;
1880             SetLastError(ERROR_MORE_DATA);
1881             ret = FALSE;
1882         }
1883         else
1884         {
1885             if (dataLen)
1886             {
1887                 const BYTE *ptr;
1888                 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1889
1890                 *pszObjId = 0;
1891                 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1892                  pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1893                  40) * 40);
1894                 pszObjId += strlen(pszObjId);
1895                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1896                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
1897                 {
1898                     int val = 0;
1899
1900                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1901                      (*ptr & 0x80))
1902                     {
1903                         val <<= 7;
1904                         val |= *ptr & 0x7f;
1905                         ptr++;
1906                     }
1907                     val <<= 7;
1908                     val |= *ptr++;
1909                     sprintf(pszObjId, ".%d", val);
1910                     pszObjId += strlen(pszObjId);
1911                 }
1912             }
1913             else
1914                 *(LPSTR *)pvStructInfo = NULL;
1915             *pcbStructInfo = bytesNeeded;
1916         }
1917     }
1918     return ret;
1919 }
1920
1921 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1922  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1923  void *pvStructInfo, DWORD *pcbStructInfo)
1924 {
1925     BOOL ret = FALSE;
1926
1927     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1928      pvStructInfo, *pcbStructInfo);
1929
1930     if (!cbEncoded)
1931         SetLastError(CRYPT_E_ASN1_CORRUPT);
1932     else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1933         ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1934          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1935     else
1936         SetLastError(CRYPT_E_ASN1_BADTAG);
1937     return ret;
1938 }
1939
1940 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1941  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1942  void *pvStructInfo, DWORD *pcbStructInfo)
1943 {
1944     BOOL ret = TRUE;
1945     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1946
1947     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1948      pvStructInfo, *pcbStructInfo);
1949
1950     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1951         bytesNeeded += cbEncoded;
1952     if (!pvStructInfo)
1953         *pcbStructInfo = bytesNeeded;
1954     else if (*pcbStructInfo < bytesNeeded)
1955     {
1956         SetLastError(ERROR_MORE_DATA);
1957         *pcbStructInfo = bytesNeeded;
1958         ret = FALSE;
1959     }
1960     else
1961     {
1962         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1963
1964         *pcbStructInfo = bytesNeeded;
1965         blob->cbData = cbEncoded;
1966         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1967             blob->pbData = (LPBYTE)pbEncoded;
1968         else
1969         {
1970             assert(blob->pbData);
1971             memcpy(blob->pbData, pbEncoded, blob->cbData);
1972         }
1973     }
1974     return ret;
1975 }
1976
1977 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1978  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1979  void *pvStructInfo, DWORD *pcbStructInfo)
1980 {
1981     CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1982      (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1983     struct AsnDecodeSequenceItem items[] = {
1984      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1985        CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1986        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1987      { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1988        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1989        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1990     };
1991
1992     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1993      pvStructInfo, *pcbStructInfo);
1994
1995     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1996      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1997      pvStructInfo, pcbStructInfo,
1998      typeValue ? typeValue->pszObjId : NULL);
1999 }
2000
2001 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
2002  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2003  void *pvStructInfo, DWORD *pcbStructInfo)
2004 {
2005     CRYPT_ALGORITHM_IDENTIFIER *algo =
2006      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
2007     BOOL ret = TRUE;
2008     struct AsnDecodeSequenceItem items[] = {
2009      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
2010        CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
2011        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
2012      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
2013        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
2014        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
2015     };
2016
2017     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2018      pvStructInfo, *pcbStructInfo);
2019
2020     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2021      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2022      pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
2023     if (ret && pvStructInfo)
2024     {
2025         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
2026          debugstr_a(algo->pszObjId));
2027     }
2028     return ret;
2029 }
2030
2031 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
2032  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2033  void *pvStructInfo, DWORD *pcbStructInfo)
2034 {
2035     struct SPCDigest *digest =
2036      (struct SPCDigest *)pvStructInfo;
2037     struct AsnDecodeSequenceItem items[] = {
2038      { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
2039        CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2040        FALSE, TRUE,
2041        offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
2042      { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
2043        CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
2044        FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
2045     };
2046
2047     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2048      pvStructInfo, *pcbStructInfo);
2049
2050     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2051      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2052      pvStructInfo, pcbStructInfo,
2053      digest ? digest->DigestAlgorithm.pszObjId : NULL);
2054 }
2055
2056 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
2057  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2058  void *pvStructInfo, DWORD *pcbStructInfo)
2059 {
2060     BOOL ret = FALSE;
2061
2062     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2063      pvStructInfo, *pcbStructInfo);
2064
2065     __TRY
2066     {
2067         struct AsnDecodeSequenceItem items[] = {
2068          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
2069            CRYPT_AsnDecodeAttributeTypeValue,
2070            sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
2071            offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
2072          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
2073            CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
2074            FALSE, TRUE,
2075            offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
2076         };
2077
2078         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2079          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2080          pvStructInfo, pcbStructInfo, NULL);
2081     }
2082     __EXCEPT_PAGE_FAULT
2083     {
2084         SetLastError(STATUS_ACCESS_VIOLATION);
2085     }
2086     __ENDTRY
2087     TRACE("returning %d\n", ret);
2088     return ret;
2089 }
2090
2091 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
2092  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2093  void *pvStructInfo, DWORD *pcbStructInfo)
2094 {
2095     FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2096      pvStructInfo, *pcbStructInfo);
2097     return FALSE;
2098 }
2099
2100 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
2101  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2102  void *pvStructInfo, DWORD *pcbStructInfo)
2103 {
2104     BOOL ret;
2105     DWORD bytesNeeded, dataLen;
2106
2107     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2108     {
2109         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2110
2111         bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
2112         if (!pvStructInfo)
2113             *pcbStructInfo = bytesNeeded;
2114         else if (*pcbStructInfo < bytesNeeded)
2115         {
2116             *pcbStructInfo = bytesNeeded;
2117             SetLastError(ERROR_MORE_DATA);
2118             ret = FALSE;
2119         }
2120         else
2121         {
2122             LPWSTR str;
2123             DWORD i;
2124
2125             *pcbStructInfo = bytesNeeded;
2126             assert(pvStructInfo);
2127             str = *(LPWSTR *)pvStructInfo;
2128             for (i = 0; i < dataLen / 2; i++)
2129                 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
2130                  pbEncoded[1 + lenBytes + 2 * i + 1];
2131             /* Decoded string is always NULL-terminated */
2132             str[i] = '\0';
2133         }
2134     }
2135     return ret;
2136 }
2137
2138 static BOOL CRYPT_AsnDecodeInteger(const BYTE *pbEncoded,
2139  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo)
2140 {
2141     BOOL ret;
2142     DWORD bytesNeeded, dataLen;
2143
2144     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2145     {
2146         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2147
2148         bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2149         if (!pvStructInfo)
2150             *pcbStructInfo = bytesNeeded;
2151         else if (*pcbStructInfo < bytesNeeded)
2152         {
2153             *pcbStructInfo = bytesNeeded;
2154             SetLastError(ERROR_MORE_DATA);
2155             ret = FALSE;
2156         }
2157         else
2158         {
2159             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2160
2161             *pcbStructInfo = bytesNeeded;
2162             blob->cbData = dataLen;
2163             assert(blob->pbData);
2164             if (blob->cbData)
2165             {
2166                 DWORD i;
2167
2168                 for (i = 0; i < blob->cbData; i++)
2169                 {
2170                     blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2171                      dataLen - i - 1);
2172                 }
2173             }
2174         }
2175     }
2176     return ret;
2177 }
2178
2179 /* Ignores tag.  Only allows integers 4 bytes or smaller in size. */
2180 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2181  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2182  void *pvStructInfo, DWORD *pcbStructInfo)
2183 {
2184     BOOL ret;
2185     BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
2186     CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
2187     DWORD size = sizeof(buf);
2188
2189     blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
2190     ret = CRYPT_AsnDecodeInteger(pbEncoded, cbEncoded, 0, buf, &size);
2191     if (ret)
2192     {
2193         if (!pvStructInfo)
2194             *pcbStructInfo = sizeof(int);
2195         else if (*pcbStructInfo < sizeof(int))
2196         {
2197             *pcbStructInfo = sizeof(int);
2198             SetLastError(ERROR_MORE_DATA);
2199             ret = FALSE;
2200         }
2201         else
2202         {
2203             int val;
2204             DWORD i;
2205
2206             *pcbStructInfo = sizeof(int);
2207             if (blob->pbData[blob->cbData - 1] & 0x80)
2208             {
2209                 /* initialize to a negative value to sign-extend */
2210                 val = -1;
2211             }
2212             else
2213                 val = 0;
2214             for (i = 0; i < blob->cbData; i++)
2215             {
2216                 val <<= 8;
2217                 val |= blob->pbData[blob->cbData - i - 1];
2218             }
2219             memcpy(pvStructInfo, &val, sizeof(int));
2220         }
2221     }
2222     else if (GetLastError() == ERROR_MORE_DATA)
2223         SetLastError(CRYPT_E_ASN1_LARGE);
2224     return ret;
2225 }
2226
2227 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2228  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2229  void *pvStructInfo, DWORD *pcbStructInfo)
2230 {
2231     BOOL ret = FALSE;
2232
2233     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2234      pvStructInfo, *pcbStructInfo);
2235
2236     __TRY
2237     {
2238         struct AsnDecodeSequenceItem items[] = {
2239          { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2240            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2241            offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2242          { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2243            CRYPT_AsnDecodeInt, sizeof(DWORD),
2244            FALSE, FALSE, 0, 0 },
2245         };
2246
2247         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2248          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2249          pvStructInfo, pcbStructInfo, NULL);
2250     }
2251     __EXCEPT_PAGE_FAULT
2252     {
2253         SetLastError(STATUS_ACCESS_VIOLATION);
2254     }
2255     __ENDTRY
2256     TRACE("returning %d\n", ret);
2257     return ret;
2258 }
2259
2260 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2261  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2262  void *pvStructInfo, DWORD *pcbStructInfo)
2263 {
2264     BOOL ret = FALSE;
2265
2266     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2267      pvStructInfo, *pcbStructInfo);
2268
2269     __TRY
2270     {
2271         struct AsnDecodeSequenceItem items[] = {
2272          { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2273            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2274            offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2275          { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2276            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
2277          { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2278            CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2279            offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2280         };
2281
2282         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2283          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2284          pvStructInfo, pcbStructInfo, NULL);
2285     }
2286     __EXCEPT_PAGE_FAULT
2287     {
2288         SetLastError(STATUS_ACCESS_VIOLATION);
2289     }
2290     __ENDTRY
2291     TRACE("returning %d\n", ret);
2292     return ret;
2293 }
2294
2295 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
2296  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2297  void *pvStructInfo, DWORD *pcbStructInfo)
2298 {
2299     BOOL ret;
2300
2301     if (cbEncoded < 3)
2302     {
2303         SetLastError(CRYPT_E_ASN1_CORRUPT);
2304         return FALSE;
2305     }
2306     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2307     {
2308         SetLastError(CRYPT_E_ASN1_CORRUPT);
2309         return FALSE;
2310     }
2311     if (pbEncoded[1] > 1)
2312     {
2313         SetLastError(CRYPT_E_ASN1_CORRUPT);
2314         return FALSE;
2315     }
2316     if (!pvStructInfo)
2317     {
2318         *pcbStructInfo = sizeof(BOOL);
2319         ret = TRUE;
2320     }
2321     else if (*pcbStructInfo < sizeof(BOOL))
2322     {
2323         *pcbStructInfo = sizeof(BOOL);
2324         SetLastError(ERROR_MORE_DATA);
2325         ret = FALSE;
2326     }
2327     else
2328     {
2329         *pcbStructInfo = sizeof(BOOL);
2330         *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
2331         ret = TRUE;
2332     }
2333     TRACE("returning %d (%08x)\n", ret, GetLastError());
2334     return ret;
2335 }
2336
2337 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType,
2338  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2339  void *pvStructInfo, DWORD *pcbStructInfo)
2340 {
2341     BOOL ret = FALSE;
2342
2343     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2344      pvStructInfo, *pcbStructInfo);
2345
2346     __TRY
2347     {
2348         struct AsnDecodeSequenceItem items[] = {
2349          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable),
2350            CRYPT_AsnDecodeBool, sizeof(BOOL), FALSE, FALSE, 0, 0 },
2351          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria),
2352            CRYPT_AsnDecodeBool, sizeof(BOOL), FALSE, FALSE, 0, 0 },
2353         };
2354
2355         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2356          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2357          pvStructInfo, pcbStructInfo, NULL);
2358     }
2359     __EXCEPT_PAGE_FAULT
2360     {
2361         SetLastError(STATUS_ACCESS_VIOLATION);
2362     }
2363     __ENDTRY
2364     TRACE("returning %d\n", ret);
2365     return ret;
2366 }