wined3d: Reinstall the G16R16F format surface load fixup.
[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         while (ret && *ptr)
544         {
545             int pos;
546
547             /* note I assume each component is at most 32-bits long in base 2 */
548             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
549             {
550                 if (val1 >= 0x10000000)
551                     bytesNeeded += 5;
552                 else if (val1 >= 0x200000)
553                     bytesNeeded += 4;
554                 else if (val1 >= 0x4000)
555                     bytesNeeded += 3;
556                 else if (val1 >= 0x80)
557                     bytesNeeded += 2;
558                 else
559                     bytesNeeded += 1;
560                 ptr += pos;
561                 if (*ptr == '.')
562                     ptr++;
563             }
564             else
565             {
566                 SetLastError(CRYPT_E_ASN1_ERROR);
567                 return FALSE;
568             }
569         }
570         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
571     }
572     else
573         lenBytes = 1;
574     bytesNeeded += 1 + lenBytes;
575     if (pbEncoded)
576     {
577         if (*pcbEncoded < bytesNeeded)
578         {
579             SetLastError(ERROR_MORE_DATA);
580             ret = FALSE;
581         }
582         else
583         {
584             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
585             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
586             pbEncoded += lenBytes;
587             if (pszObjId)
588             {
589                 const char *ptr;
590                 int val, pos;
591
592                 *pbEncoded++ = firstByte;
593                 ptr = pszObjId + firstPos;
594                 while (ret && *ptr)
595                 {
596                     sscanf(ptr, "%d%n", &val, &pos);
597                     {
598                         unsigned char outBytes[5];
599                         int numBytes, i;
600
601                         if (val >= 0x10000000)
602                             numBytes = 5;
603                         else if (val >= 0x200000)
604                             numBytes = 4;
605                         else if (val >= 0x4000)
606                             numBytes = 3;
607                         else if (val >= 0x80)
608                             numBytes = 2;
609                         else
610                             numBytes = 1;
611                         for (i = numBytes; i > 0; i--)
612                         {
613                             outBytes[i - 1] = val & 0x7f;
614                             val >>= 7;
615                         }
616                         for (i = 0; i < numBytes - 1; i++)
617                             *pbEncoded++ = outBytes[i] | 0x80;
618                         *pbEncoded++ = outBytes[i];
619                         ptr += pos;
620                         if (*ptr == '.')
621                             ptr++;
622                     }
623                 }
624             }
625         }
626     }
627     *pcbEncoded = bytesNeeded;
628     return ret;
629 }
630
631 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
632  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
633  DWORD *pcbEncoded)
634 {
635     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
636     BOOL ret = TRUE;
637
638     if (!pbEncoded)
639         *pcbEncoded = blob->cbData;
640     else if (*pcbEncoded < blob->cbData)
641     {
642         *pcbEncoded = blob->cbData;
643         SetLastError(ERROR_MORE_DATA);
644         ret = FALSE;
645     }
646     else
647     {
648         if (blob->cbData)
649             memcpy(pbEncoded, blob->pbData, blob->cbData);
650         *pcbEncoded = blob->cbData;
651     }
652     return ret;
653 }
654
655 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
656  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
657  BYTE *pbEncoded, DWORD *pcbEncoded)
658 {
659     const CRYPT_ALGORITHM_IDENTIFIER *algo =
660      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
661     static const BYTE asn1Null[] = { ASN_NULL, 0 };
662     static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
663      (LPBYTE)asn1Null };
664     BOOL ret;
665     struct AsnEncodeSequenceItem items[2] = {
666      { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
667      { NULL,           CRYPT_CopyEncodedBlob, 0 },
668     };
669
670     if (algo->Parameters.cbData)
671         items[1].pvStructInfo = &algo->Parameters;
672     else
673         items[1].pvStructInfo = &nullBlob;
674     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
675      sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
676     return ret;
677 }
678
679 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
680  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
681  DWORD *pcbEncoded)
682 {
683     const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
684      (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
685     struct AsnEncodeSequenceItem items[] = {
686      { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
687      { &typeValue->Value,    CRYPT_CopyEncodedBlob, 0 },
688     };
689
690     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
691      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
692 }
693
694 struct SPCDigest
695 {
696     CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
697     CRYPT_HASH_BLOB            Digest;
698 };
699
700 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
701  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
702  DWORD *pcbEncoded)
703 {
704     const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
705     struct AsnEncodeSequenceItem items[] = {
706      { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
707      { &digest->Digest,          CRYPT_CopyEncodedBlob, 0 },
708     };
709
710     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
711      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
712 }
713
714 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
715  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
716  DWORD *pcbEncoded)
717 {
718     BOOL ret = FALSE;
719
720     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
721      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
722
723     __TRY
724     {
725         const SPC_INDIRECT_DATA_CONTENT *data =
726          (const SPC_INDIRECT_DATA_CONTENT *)pvStructInfo;
727         struct AsnEncodeSequenceItem items[] = {
728          { &data->Data,            CRYPT_AsnEncodeAttributeTypeValue, 0 },
729          { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
730         };
731
732         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
733          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
734     }
735     __EXCEPT_PAGE_FAULT
736     {
737         SetLastError(STATUS_ACCESS_VIOLATION);
738     }
739     __ENDTRY
740     return ret;
741 }
742
743 static BOOL WINAPI CRYPT_AsnEncodeBMPString(DWORD dwCertEncodingType,
744  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
745  DWORD *pcbEncoded)
746 {
747     BOOL ret = TRUE;
748     LPCWSTR str = (LPCWSTR)pvStructInfo;
749     DWORD bytesNeeded, lenBytes, strLen;
750
751     if (str)
752         strLen = lstrlenW(str);
753     else
754         strLen = 0;
755     CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
756     bytesNeeded = 1 + lenBytes + strLen * 2;
757     if (!pbEncoded)
758         *pcbEncoded = bytesNeeded;
759     else if (*pcbEncoded < bytesNeeded)
760     {
761         *pcbEncoded = bytesNeeded;
762         SetLastError(ERROR_MORE_DATA);
763         ret = FALSE;
764     }
765     else
766     {
767         DWORD i;
768
769         *pcbEncoded = bytesNeeded;
770         *pbEncoded++ = ASN_BMPSTRING;
771         CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
772         pbEncoded += lenBytes;
773         for (i = 0; i < strLen; i++)
774         {
775             *pbEncoded++ = (str[i] & 0xff00) >> 8;
776             *pbEncoded++ = str[i] & 0x00ff;
777         }
778     }
779     return ret;
780 }
781
782 struct AsnEncodeTagSwappedItem
783 {
784     BYTE                  tag;
785     const void           *pvStructInfo;
786     CryptEncodeObjectFunc encodeFunc;
787 };
788
789 /* Sort of a wacky hack, it encodes something using the struct
790  * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
791  * given in the struct AsnEncodeTagSwappedItem.
792  */
793 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
794  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
795  DWORD *pcbEncoded)
796 {
797     BOOL ret;
798     const struct AsnEncodeTagSwappedItem *item = pvStructInfo;
799
800     ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
801      item->pvStructInfo, pbEncoded, pcbEncoded);
802     if (ret && pbEncoded)
803         *pbEncoded = item->tag;
804     return ret;
805 }
806
807 BOOL WINAPI WVTAsn1SpcSpOpusInfoEncode(DWORD dwCertEncodingType,
808  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
809  DWORD *pcbEncoded)
810 {
811     BOOL ret = FALSE;
812
813     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
814      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
815
816     __TRY
817     {
818         const SPC_SP_OPUS_INFO *info = pvStructInfo;
819
820         if (info->pMoreInfo &&
821          info->pMoreInfo->dwLinkChoice != SPC_URL_LINK_CHOICE &&
822          info->pMoreInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE &&
823          info->pMoreInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE)
824             SetLastError(E_INVALIDARG);
825         else if (info->pPublisherInfo &&
826          info->pPublisherInfo->dwLinkChoice != SPC_URL_LINK_CHOICE &&
827          info->pPublisherInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE &&
828          info->pPublisherInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE)
829             SetLastError(E_INVALIDARG);
830         else
831         {
832             struct AsnEncodeSequenceItem items[3] = { { 0 } };
833             struct AsnConstructedItem constructed[3] = { { 0 } };
834             struct AsnEncodeTagSwappedItem swapped;
835             DWORD cItem = 0, cConstructed = 0;
836
837             if (info->pwszProgramName)
838             {
839                 swapped.tag = ASN_CONTEXT;
840                 swapped.pvStructInfo = info->pwszProgramName;
841                 swapped.encodeFunc = CRYPT_AsnEncodeBMPString;
842                 constructed[cConstructed].tag = 0;
843                 constructed[cConstructed].pvStructInfo = &swapped;
844                 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeSwapTag;
845                 items[cItem].pvStructInfo = &constructed[cConstructed];
846                 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
847                 cConstructed++;
848                 cItem++;
849             }
850             if (info->pMoreInfo)
851             {
852                 constructed[cConstructed].tag = 1;
853                 constructed[cConstructed].pvStructInfo = info->pMoreInfo;
854                 constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode;
855                 items[cItem].pvStructInfo = &constructed[cConstructed];
856                 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
857                 cConstructed++;
858                 cItem++;
859             }
860             if (info->pPublisherInfo)
861             {
862                 constructed[cConstructed].tag = 2;
863                 constructed[cConstructed].pvStructInfo = info->pPublisherInfo;
864                 constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode;
865                 items[cItem].pvStructInfo = &constructed[cConstructed];
866                 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
867                 cConstructed++;
868                 cItem++;
869             }
870             ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
871              items, cItem, pbEncoded, pcbEncoded);
872         }
873     }
874     __EXCEPT_PAGE_FAULT
875     {
876         SetLastError(STATUS_ACCESS_VIOLATION);
877     }
878     __ENDTRY
879     return ret;
880 }
881
882 static BOOL CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
883  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
884  DWORD *pcbEncoded)
885 {
886     BOOL ret;
887
888     __TRY
889     {
890         DWORD significantBytes, lenBytes, bytesNeeded;
891         BYTE padByte = 0;
892         BOOL pad = FALSE;
893         const CRYPT_INTEGER_BLOB *blob =
894          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
895
896         significantBytes = blob->cbData;
897         if (significantBytes)
898         {
899             if (blob->pbData[significantBytes - 1] & 0x80)
900             {
901                 /* negative, lop off leading (little-endian) 0xffs */
902                 for (; significantBytes > 0 &&
903                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
904                     ;
905                 if (blob->pbData[significantBytes - 1] < 0x80)
906                 {
907                     padByte = 0xff;
908                     pad = TRUE;
909                 }
910             }
911             else
912             {
913                 /* positive, lop off leading (little-endian) zeroes */
914                 for (; significantBytes > 0 &&
915                  !blob->pbData[significantBytes - 1]; significantBytes--)
916                     ;
917                 if (significantBytes == 0)
918                     significantBytes = 1;
919                 if (blob->pbData[significantBytes - 1] > 0x7f)
920                 {
921                     padByte = 0;
922                     pad = TRUE;
923                 }
924             }
925         }
926         if (pad)
927             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
928         else
929             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
930         bytesNeeded = 1 + lenBytes + significantBytes;
931         if (pad)
932             bytesNeeded++;
933         if (!pbEncoded)
934         {
935             *pcbEncoded = bytesNeeded;
936             ret = TRUE;
937         }
938         else if (*pcbEncoded < bytesNeeded)
939         {
940             *pcbEncoded = bytesNeeded;
941             SetLastError(ERROR_MORE_DATA);
942             ret = FALSE;
943         }
944         else
945         {
946             *pcbEncoded = bytesNeeded;
947             *pbEncoded++ = ASN_INTEGER;
948             if (pad)
949             {
950                 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
951                 pbEncoded += lenBytes;
952                 *pbEncoded++ = padByte;
953             }
954             else
955             {
956                 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
957                 pbEncoded += lenBytes;
958             }
959             for (; significantBytes > 0; significantBytes--)
960                 *(pbEncoded++) = blob->pbData[significantBytes - 1];
961             ret = TRUE;
962         }
963     }
964     __EXCEPT_PAGE_FAULT
965     {
966         SetLastError(STATUS_ACCESS_VIOLATION);
967         ret = FALSE;
968     }
969     __ENDTRY
970     return ret;
971 }
972
973 BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
974  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
975  DWORD *pcbEncoded)
976 {
977     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
978
979     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
980      &blob, pbEncoded, pcbEncoded);
981 }
982
983 BOOL WINAPI WVTAsn1CatMemberInfoEncode(DWORD dwCertEncodingType,
984  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
985  DWORD *pcbEncoded)
986 {
987     BOOL ret = FALSE;
988
989     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
990      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
991
992     __TRY
993     {
994         const CAT_MEMBERINFO *info = (const CAT_MEMBERINFO *)pvStructInfo;
995         struct AsnEncodeSequenceItem items[] = {
996          { info->pwszSubjGuid, CRYPT_AsnEncodeBMPString, 0 },
997          { &info->dwCertVersion, CRYPT_AsnEncodeInt, 0 },
998         };
999
1000         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
1001          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
1002     }
1003     __EXCEPT_PAGE_FAULT
1004     {
1005         SetLastError(STATUS_ACCESS_VIOLATION);
1006     }
1007     __ENDTRY
1008     return ret;
1009 }
1010
1011 BOOL WINAPI WVTAsn1CatNameValueEncode(DWORD dwCertEncodingType,
1012  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1013  DWORD *pcbEncoded)
1014 {
1015     BOOL ret = FALSE;
1016
1017     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
1018      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
1019
1020     __TRY
1021     {
1022         const CAT_NAMEVALUE *value = (const CAT_NAMEVALUE *)pvStructInfo;
1023         struct AsnEncodeSequenceItem items[] = {
1024          { value->pwszTag,   CRYPT_AsnEncodeBMPString, 0 },
1025          { &value->fdwFlags, CRYPT_AsnEncodeInt, 0 },
1026          { &value->Value,    CRYPT_AsnEncodeOctets, 0 },
1027         };
1028
1029         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
1030          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
1031     }
1032     __EXCEPT_PAGE_FAULT
1033     {
1034         SetLastError(STATUS_ACCESS_VIOLATION);
1035     }
1036     __ENDTRY
1037     return ret;
1038 }
1039
1040 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1041  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1042  DWORD *pcbEncoded)
1043 {
1044     BOOL val = *(const BOOL *)pvStructInfo, ret;
1045
1046     TRACE("%d\n", val);
1047
1048     if (!pbEncoded)
1049     {
1050         *pcbEncoded = 3;
1051         ret = TRUE;
1052     }
1053     else if (*pcbEncoded < 3)
1054     {
1055         *pcbEncoded = 3;
1056         SetLastError(ERROR_MORE_DATA);
1057         ret = FALSE;
1058     }
1059     else
1060     {
1061         *pcbEncoded = 3;
1062         *pbEncoded++ = ASN_BOOL;
1063         *pbEncoded++ = 1;
1064         *pbEncoded++ = val ? 0xff : 0;
1065         ret = TRUE;
1066     }
1067     TRACE("returning %d (%08x)\n", ret, GetLastError());
1068     return ret;
1069 }
1070
1071 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoEncode(DWORD dwCertEncodingType,
1072  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1073  DWORD *pcbEncoded)
1074 {
1075     BOOL ret = FALSE;
1076
1077     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
1078      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
1079
1080     __TRY
1081     {
1082         const SPC_FINANCIAL_CRITERIA *criteria = pvStructInfo;
1083         struct AsnEncodeSequenceItem items[] = {
1084          { &criteria->fFinancialInfoAvailable, CRYPT_AsnEncodeBool, 0 },
1085          { &criteria->fMeetsCriteria,          CRYPT_AsnEncodeBool, 0 },
1086         };
1087
1088         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
1089          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
1090     }
1091     __EXCEPT_PAGE_FAULT
1092     {
1093         SetLastError(STATUS_ACCESS_VIOLATION);
1094     }
1095     __ENDTRY
1096     return ret;
1097 }
1098
1099 /* Gets the number of length bytes from the given (leading) length byte */
1100 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1101
1102 /* Helper function to get the encoded length of the data starting at pbEncoded,
1103  * where pbEncoded[0] is the tag.  If the data are too short to contain a
1104  * length or if the length is too large for cbEncoded, sets an appropriate
1105  * error code and returns FALSE.
1106  */
1107 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
1108 {
1109     BOOL ret;
1110
1111     if (cbEncoded <= 1)
1112     {
1113         SetLastError(CRYPT_E_ASN1_CORRUPT);
1114         ret = FALSE;
1115     }
1116     else if (pbEncoded[1] <= 0x7f)
1117     {
1118         if (pbEncoded[1] + 1 > cbEncoded)
1119         {
1120             SetLastError(CRYPT_E_ASN1_EOD);
1121             ret = FALSE;
1122         }
1123         else
1124         {
1125             *len = pbEncoded[1];
1126             ret = TRUE;
1127         }
1128     }
1129     else if (pbEncoded[1] == 0x80)
1130     {
1131         FIXME("unimplemented for indefinite-length encoding\n");
1132         SetLastError(CRYPT_E_ASN1_CORRUPT);
1133         ret = FALSE;
1134     }
1135     else
1136     {
1137         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1138
1139         if (lenLen > sizeof(DWORD) + 1)
1140         {
1141             SetLastError(CRYPT_E_ASN1_LARGE);
1142             ret = FALSE;
1143         }
1144         else if (lenLen + 2 > cbEncoded)
1145         {
1146             SetLastError(CRYPT_E_ASN1_CORRUPT);
1147             ret = FALSE;
1148         }
1149         else
1150         {
1151             DWORD out = 0;
1152
1153             pbEncoded += 2;
1154             while (--lenLen)
1155             {
1156                 out <<= 8;
1157                 out |= *pbEncoded++;
1158             }
1159             if (out + lenLen + 1 > cbEncoded)
1160             {
1161                 SetLastError(CRYPT_E_ASN1_EOD);
1162                 ret = FALSE;
1163             }
1164             else
1165             {
1166                 *len = out;
1167                 ret = TRUE;
1168             }
1169         }
1170     }
1171     return ret;
1172 }
1173
1174 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1175  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1176  void *pvStructInfo, DWORD *pcbStructInfo)
1177 {
1178     BOOL ret;
1179     DWORD bytesNeeded, dataLen;
1180
1181     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1182      pvStructInfo, *pcbStructInfo);
1183
1184     if (!cbEncoded)
1185     {
1186         SetLastError(CRYPT_E_ASN1_CORRUPT);
1187         ret = FALSE;
1188     }
1189     else if (pbEncoded[0] != ASN_OCTETSTRING)
1190     {
1191         SetLastError(CRYPT_E_ASN1_BADTAG);
1192         ret = FALSE;
1193     }
1194     else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1195     {
1196         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1197             bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1198         else
1199             bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1200         if (!pvStructInfo)
1201             *pcbStructInfo = bytesNeeded;
1202         else if (*pcbStructInfo < bytesNeeded)
1203         {
1204             SetLastError(ERROR_MORE_DATA);
1205             *pcbStructInfo = bytesNeeded;
1206             ret = FALSE;
1207         }
1208         else
1209         {
1210             CRYPT_DATA_BLOB *blob;
1211             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1212
1213             blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1214             blob->cbData = dataLen;
1215             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1216                 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1217             else
1218             {
1219                 assert(blob->pbData);
1220                 if (blob->cbData)
1221                     memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
1222                      blob->cbData);
1223             }
1224         }
1225     }
1226     return ret;
1227 }
1228
1229 static BOOL CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
1230  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1231  void *pvStructInfo, DWORD *pcbStructInfo)
1232 {
1233     BOOL ret = FALSE;
1234     DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
1235
1236     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1237      pvStructInfo, *pcbStructInfo);
1238
1239     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1240     {
1241         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1242         DWORD realDataLen;
1243
1244         switch (pbEncoded[0])
1245         {
1246         case ASN_CONTEXT:
1247             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
1248             if (!pvStructInfo)
1249                 *pcbStructInfo = bytesNeeded;
1250             else if (*pcbStructInfo < bytesNeeded)
1251             {
1252                 *pcbStructInfo = bytesNeeded;
1253                 SetLastError(ERROR_MORE_DATA);
1254                 ret = FALSE;
1255             }
1256             else
1257             {
1258                 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1259                 DWORD i;
1260
1261                 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
1262                 for (i = 0; i < dataLen; i++)
1263                     link->u.pwszUrl[i] =
1264                      *(pbEncoded + 1 + lenBytes + i);
1265                 link->u.pwszUrl[i] = '\0';
1266                 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
1267             }
1268             break;
1269         case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
1270         {
1271             CRYPT_DATA_BLOB classId;
1272             DWORD size = sizeof(classId);
1273
1274             if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1275              pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
1276              CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
1277             {
1278                 if (classId.cbData != sizeof(SPC_UUID))
1279                 {
1280                     SetLastError(CRYPT_E_BAD_ENCODE);
1281                     ret = FALSE;
1282                 }
1283                 else
1284                 {
1285                     CRYPT_DATA_BLOB data;
1286
1287                     /* The tag length for the classId must be 1 since the
1288                      * length is correct.
1289                      */
1290                     size = sizeof(data);
1291                     if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1292                      pbEncoded + 3 + lenBytes + classId.cbData,
1293                      cbEncoded - 3 - lenBytes - classId.cbData,
1294                      CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
1295                     {
1296                         bytesNeeded += data.cbData;
1297                         if (!pvStructInfo)
1298                             *pcbStructInfo = bytesNeeded;
1299                         else if (*pcbStructInfo < bytesNeeded)
1300                         {
1301                             *pcbStructInfo = bytesNeeded;
1302                             SetLastError(ERROR_MORE_DATA);
1303                             ret = FALSE;
1304                         }
1305                         else
1306                         {
1307                             PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1308
1309                             link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
1310                             /* pwszFile pointer was set by caller, copy it
1311                              * before overwriting it
1312                              */
1313                             link->u.Moniker.SerializedData.pbData =
1314                              (BYTE *)link->u.pwszFile;
1315                             memcpy(link->u.Moniker.ClassId, classId.pbData,
1316                              classId.cbData);
1317                             memcpy(link->u.Moniker.SerializedData.pbData,
1318                              data.pbData, data.cbData);
1319                             link->u.Moniker.SerializedData.cbData = data.cbData;
1320                         }
1321                     }
1322                 }
1323             }
1324             break;
1325         }
1326         case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
1327             if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
1328                 SetLastError(CRYPT_E_ASN1_BADTAG);
1329             else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
1330              &realDataLen)))
1331             {
1332                 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
1333
1334                 bytesNeeded += realDataLen + sizeof(WCHAR);
1335                 if (!pvStructInfo)
1336                     *pcbStructInfo = bytesNeeded;
1337                 else if (*pcbStructInfo < bytesNeeded)
1338                 {
1339                     *pcbStructInfo = bytesNeeded;
1340                     SetLastError(ERROR_MORE_DATA);
1341                     ret = FALSE;
1342                 }
1343                 else
1344                 {
1345                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1346                     DWORD i;
1347                     const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
1348
1349                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1350                     for (i = 0; i < dataLen / sizeof(WCHAR); i++)
1351                         link->u.pwszFile[i] =
1352                          hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
1353                     link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
1354                     TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
1355                 }
1356             }
1357             else
1358             {
1359                 bytesNeeded += sizeof(WCHAR);
1360                 if (!pvStructInfo)
1361                     *pcbStructInfo = bytesNeeded;
1362                 else if (*pcbStructInfo < bytesNeeded)
1363                 {
1364                     *pcbStructInfo = bytesNeeded;
1365                     SetLastError(ERROR_MORE_DATA);
1366                     ret = FALSE;
1367                 }
1368                 else
1369                 {
1370                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1371
1372                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1373                     link->u.pwszFile[0] = '\0';
1374                     ret = TRUE;
1375                 }
1376             }
1377             break;
1378         default:
1379             SetLastError(CRYPT_E_ASN1_BADTAG);
1380         }
1381     }
1382     TRACE("returning %d\n", ret);
1383     return ret;
1384 }
1385
1386 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1387  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1388  void *pvStructInfo, DWORD *pcbStructInfo)
1389 {
1390     BOOL ret = FALSE;
1391
1392     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1393      pvStructInfo, *pcbStructInfo);
1394
1395     __TRY
1396     {
1397         DWORD bytesNeeded;
1398
1399         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1400          lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1401         if (ret)
1402         {
1403             if (!pvStructInfo)
1404                 *pcbStructInfo = bytesNeeded;
1405             else if (*pcbStructInfo < bytesNeeded)
1406             {
1407                 *pcbStructInfo = bytesNeeded;
1408                 SetLastError(ERROR_MORE_DATA);
1409                 ret = FALSE;
1410             }
1411             else
1412             {
1413                 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1414
1415                 link->u.pwszFile =
1416                  (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1417                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1418                  lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1419                  pcbStructInfo);
1420             }
1421         }
1422     }
1423     __EXCEPT_PAGE_FAULT
1424     {
1425         SetLastError(STATUS_ACCESS_VIOLATION);
1426     }
1427     __ENDTRY
1428     TRACE("returning %d\n", ret);
1429     return ret;
1430 }
1431
1432 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1433  DWORD, DWORD, void *, DWORD *);
1434
1435 /* tag:
1436  *     The expected tag of the item.  If tag is 0, decodeFunc is called
1437  *     regardless of the tag value seen.
1438  * offset:
1439  *     A sequence is decoded into a struct.  The offset member is the
1440  *     offset of this item within that struct.
1441  * decodeFunc:
1442  *     The decoder function to use.  If this is NULL, then the member isn't
1443  *     decoded, but minSize space is reserved for it.
1444  * minSize:
1445  *     The minimum amount of space occupied after decoding.  You must set this.
1446  * optional:
1447  *     If true, and the tag doesn't match the expected tag for this item,
1448  *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1449  *     filled with 0 for this member.
1450  * hasPointer, pointerOffset:
1451  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1452  *     the offset within the struct of the data pointer (or to the
1453  *     first data pointer, if more than one exist).
1454  * size:
1455  *     Used by CRYPT_AsnDecodeSequence, not for your use.
1456  */
1457 struct AsnDecodeSequenceItem
1458 {
1459     BYTE                  tag;
1460     DWORD                 offset;
1461     CryptDecodeObjectFunc decodeFunc;
1462     DWORD                 minSize;
1463     BOOL                  optional;
1464     BOOL                  hasPointer;
1465     DWORD                 pointerOffset;
1466     DWORD                 size;
1467 };
1468
1469 /* Decodes the items in a sequence, where the items are described in items,
1470  * the encoded data are in pbEncoded with length cbEncoded.  Decodes into
1471  * pvStructInfo.  nextData is a pointer to the memory location at which the
1472  * first decoded item with a dynamic pointer should point.
1473  * Upon decoding, *cbDecoded is the total number of bytes decoded.
1474  */
1475 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1476  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1477  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1478  DWORD *cbDecoded)
1479 {
1480     BOOL ret;
1481     DWORD i, decoded = 0;
1482     const BYTE *ptr = pbEncoded;
1483
1484     TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1485      cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1486
1487     for (i = 0, ret = TRUE; ret && i < cItem; i++)
1488     {
1489         if (cbEncoded - (ptr - pbEncoded) != 0)
1490         {
1491             DWORD nextItemLen;
1492
1493             if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1494              &nextItemLen)))
1495             {
1496                 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1497
1498                 if (ptr[0] == items[i].tag || !items[i].tag)
1499                 {
1500                     if (nextData && pvStructInfo && items[i].hasPointer)
1501                     {
1502                         TRACE("Setting next pointer to %p\n",
1503                          nextData);
1504                         *(BYTE **)((BYTE *)pvStructInfo +
1505                          items[i].pointerOffset) = nextData;
1506                     }
1507                     if (items[i].decodeFunc)
1508                     {
1509                         if (pvStructInfo)
1510                             TRACE("decoding item %d\n", i);
1511                         else
1512                             TRACE("sizing item %d\n", i);
1513                         ret = items[i].decodeFunc(dwCertEncodingType,
1514                          NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1515                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1516                          pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
1517                          : NULL, &items[i].size);
1518                         if (ret)
1519                         {
1520                             /* Account for alignment padding */
1521                             if (items[i].size % sizeof(DWORD))
1522                                 items[i].size += sizeof(DWORD) -
1523                                  items[i].size % sizeof(DWORD);
1524                             TRACE("item %d size: %d\n", i, items[i].size);
1525                             if (nextData && items[i].hasPointer &&
1526                              items[i].size > items[i].minSize)
1527                                 nextData += items[i].size - items[i].minSize;
1528                             ptr += 1 + nextItemLenBytes + nextItemLen;
1529                             decoded += 1 + nextItemLenBytes + nextItemLen;
1530                             TRACE("item %d: decoded %d bytes\n", i,
1531                              1 + nextItemLenBytes + nextItemLen);
1532                         }
1533                         else if (items[i].optional &&
1534                          GetLastError() == CRYPT_E_ASN1_BADTAG)
1535                         {
1536                             TRACE("skipping optional item %d\n", i);
1537                             items[i].size = items[i].minSize;
1538                             SetLastError(NOERROR);
1539                             ret = TRUE;
1540                         }
1541                         else
1542                             TRACE("item %d failed: %08x\n", i,
1543                              GetLastError());
1544                     }
1545                     else
1546                     {
1547                         TRACE("item %d: decoded %d bytes\n", i,
1548                          1 + nextItemLenBytes + nextItemLen);
1549                         ptr += 1 + nextItemLenBytes + nextItemLen;
1550                         decoded += 1 + nextItemLenBytes + nextItemLen;
1551                         items[i].size = items[i].minSize;
1552                     }
1553                 }
1554                 else if (items[i].optional)
1555                 {
1556                     TRACE("skipping optional item %d\n", i);
1557                     items[i].size = items[i].minSize;
1558                 }
1559                 else
1560                 {
1561                     TRACE("item %d: tag %02x doesn't match expected %02x\n",
1562                      i, ptr[0], items[i].tag);
1563                     SetLastError(CRYPT_E_ASN1_BADTAG);
1564                     ret = FALSE;
1565                 }
1566             }
1567         }
1568         else if (items[i].optional)
1569         {
1570             TRACE("missing optional item %d, skipping\n", i);
1571             items[i].size = items[i].minSize;
1572         }
1573         else
1574         {
1575             TRACE("not enough bytes for item %d, failing\n", i);
1576             SetLastError(CRYPT_E_ASN1_CORRUPT);
1577             ret = FALSE;
1578         }
1579     }
1580     if (ret)
1581         *cbDecoded = decoded;
1582     TRACE("returning %d\n", ret);
1583     return ret;
1584 }
1585
1586 /* This decodes an arbitrary sequence into a contiguous block of memory
1587  * (basically, a struct.)  Each element being decoded is described by a struct
1588  * AsnDecodeSequenceItem, see above.
1589  * startingPointer is an optional pointer to the first place where dynamic
1590  * data will be stored.  If you know the starting offset, you may pass it
1591  * here.  Otherwise, pass NULL, and one will be inferred from the items.
1592  */
1593 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1594  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1595  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1596  void *startingPointer)
1597 {
1598     BOOL ret;
1599
1600     TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1601      cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1602
1603     if (pbEncoded[0] == ASN_SEQUENCE)
1604     {
1605         DWORD dataLen;
1606
1607         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1608         {
1609             DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1610             const BYTE *ptr = pbEncoded + 1 + lenBytes;
1611
1612             cbEncoded -= 1 + lenBytes;
1613             if (cbEncoded < dataLen)
1614             {
1615                 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1616                  cbEncoded);
1617                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1618                 ret = FALSE;
1619             }
1620             else
1621                 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1622                  cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1623             if (ret && cbDecoded != dataLen)
1624             {
1625                 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1626                  cbDecoded);
1627                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1628                 ret = FALSE;
1629             }
1630             if (ret)
1631             {
1632                 DWORD i, bytesNeeded = 0, structSize = 0;
1633
1634                 for (i = 0; i < cItem; i++)
1635                 {
1636                     bytesNeeded += items[i].size;
1637                     structSize += items[i].minSize;
1638                 }
1639                 if (!pvStructInfo)
1640                     *pcbStructInfo = bytesNeeded;
1641                 else if (*pcbStructInfo < bytesNeeded)
1642                 {
1643                     SetLastError(ERROR_MORE_DATA);
1644                     *pcbStructInfo = bytesNeeded;
1645                     ret = FALSE;
1646                 }
1647                 else
1648                 {
1649                     BYTE *nextData;
1650
1651                     *pcbStructInfo = bytesNeeded;
1652                     if (startingPointer)
1653                         nextData = (BYTE *)startingPointer;
1654                     else
1655                         nextData = (BYTE *)pvStructInfo + structSize;
1656                     memset(pvStructInfo, 0, structSize);
1657                     ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1658                      ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1659                      &cbDecoded);
1660                 }
1661             }
1662         }
1663     }
1664     else
1665     {
1666         SetLastError(CRYPT_E_ASN1_BADTAG);
1667         ret = FALSE;
1668     }
1669     TRACE("returning %d (%08x)\n", ret, GetLastError());
1670     return ret;
1671 }
1672
1673 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1674  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1675  void *pvStructInfo, DWORD *pcbStructInfo)
1676 {
1677     BOOL ret;
1678
1679     TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1680      pvStructInfo, *pcbStructInfo);
1681
1682     if (pbEncoded[0] == ASN_BITSTRING)
1683     {
1684         DWORD bytesNeeded, dataLen;
1685
1686         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1687         {
1688             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1689                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1690             else
1691                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1692             if (!pvStructInfo)
1693                 *pcbStructInfo = bytesNeeded;
1694             else if (*pcbStructInfo < bytesNeeded)
1695             {
1696                 *pcbStructInfo = bytesNeeded;
1697                 SetLastError(ERROR_MORE_DATA);
1698                 ret = FALSE;
1699             }
1700             else
1701             {
1702                 CRYPT_BIT_BLOB *blob;
1703
1704                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1705                 blob->cbData = dataLen - 1;
1706                 blob->cUnusedBits = *(pbEncoded + 1 +
1707                  GET_LEN_BYTES(pbEncoded[1]));
1708                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1709                 {
1710                     blob->pbData = (BYTE *)pbEncoded + 2 +
1711                      GET_LEN_BYTES(pbEncoded[1]);
1712                 }
1713                 else
1714                 {
1715                     assert(blob->pbData);
1716                     if (blob->cbData)
1717                     {
1718                         BYTE mask = 0xff << blob->cUnusedBits;
1719
1720                         memcpy(blob->pbData, pbEncoded + 2 +
1721                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1722                         blob->pbData[blob->cbData - 1] &= mask;
1723                     }
1724                 }
1725             }
1726         }
1727     }
1728     else
1729     {
1730         SetLastError(CRYPT_E_ASN1_BADTAG);
1731         ret = FALSE;
1732     }
1733     TRACE("returning %d (%08x)\n", ret, GetLastError());
1734     return ret;
1735 }
1736
1737 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1738  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1739  void *pvStructInfo, DWORD *pcbStructInfo)
1740 {
1741     BOOL ret = FALSE;
1742     DWORD dataLen;
1743
1744     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1745     {
1746         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1747         DWORD size;
1748         SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1749
1750         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1751          pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1752         if (ret)
1753         {
1754             if (!pvStructInfo)
1755                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1756             else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1757             {
1758                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1759                 SetLastError(ERROR_MORE_DATA);
1760                 ret = FALSE;
1761             }
1762             else
1763             {
1764                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1765                 /* Set imageData's pointer if necessary */
1766                 if (size > sizeof(SPC_LINK))
1767                 {
1768                     (*pLink)->u.pwszUrl =
1769                      (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1770                 }
1771                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1772                  lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1773                  *pLink, pcbStructInfo);
1774             }
1775         }
1776     }
1777     return ret;
1778 }
1779
1780 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1781  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1782  void *pvStructInfo, DWORD *pcbStructInfo)
1783 {
1784     BOOL ret = FALSE;
1785
1786     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1787      pvStructInfo, *pcbStructInfo);
1788
1789     __TRY
1790     {
1791         struct AsnDecodeSequenceItem items[] = {
1792          { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1793            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1794            offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1795          { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1796            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1797            offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1798         };
1799
1800         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1801          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1802          pvStructInfo, pcbStructInfo, NULL);
1803     }
1804     __EXCEPT_PAGE_FAULT
1805     {
1806         SetLastError(STATUS_ACCESS_VIOLATION);
1807     }
1808     __ENDTRY
1809     TRACE("returning %d\n", ret);
1810     return ret;
1811 }
1812
1813 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1814  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1815  void *pvStructInfo, DWORD *pcbStructInfo)
1816 {
1817     BOOL ret = TRUE;
1818     DWORD dataLen;
1819
1820     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1821      pvStructInfo, *pcbStructInfo);
1822
1823     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1824     {
1825         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1826         DWORD bytesNeeded = sizeof(LPSTR);
1827
1828         if (dataLen)
1829         {
1830             /* The largest possible string for the first two components
1831              * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1832              */
1833             char firstTwo[6];
1834             const BYTE *ptr;
1835
1836             snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1837              pbEncoded[1 + lenBytes] / 40,
1838              pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1839              * 40);
1840             bytesNeeded += strlen(firstTwo) + 1;
1841             for (ptr = pbEncoded + 2 + lenBytes; ret &&
1842              ptr - pbEncoded - 1 - lenBytes < dataLen; )
1843             {
1844                 /* large enough for ".4000000" */
1845                 char str[9];
1846                 int val = 0;
1847
1848                 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1849                  (*ptr & 0x80))
1850                 {
1851                     val <<= 7;
1852                     val |= *ptr & 0x7f;
1853                     ptr++;
1854                 }
1855                 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1856                  (*ptr & 0x80))
1857                 {
1858                     SetLastError(CRYPT_E_ASN1_CORRUPT);
1859                     ret = FALSE;
1860                 }
1861                 else
1862                 {
1863                     val <<= 7;
1864                     val |= *ptr++;
1865                     snprintf(str, sizeof(str), ".%d", val);
1866                     bytesNeeded += strlen(str);
1867                 }
1868             }
1869         }
1870         if (!pvStructInfo)
1871             *pcbStructInfo = bytesNeeded;
1872         else if (*pcbStructInfo < bytesNeeded)
1873         {
1874             *pcbStructInfo = bytesNeeded;
1875             SetLastError(ERROR_MORE_DATA);
1876             ret = FALSE;
1877         }
1878         else
1879         {
1880             if (dataLen)
1881             {
1882                 const BYTE *ptr;
1883                 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1884
1885                 *pszObjId = 0;
1886                 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1887                  pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1888                  40) * 40);
1889                 pszObjId += strlen(pszObjId);
1890                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1891                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
1892                 {
1893                     int val = 0;
1894
1895                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1896                      (*ptr & 0x80))
1897                     {
1898                         val <<= 7;
1899                         val |= *ptr & 0x7f;
1900                         ptr++;
1901                     }
1902                     val <<= 7;
1903                     val |= *ptr++;
1904                     sprintf(pszObjId, ".%d", val);
1905                     pszObjId += strlen(pszObjId);
1906                 }
1907             }
1908             else
1909                 *(LPSTR *)pvStructInfo = NULL;
1910             *pcbStructInfo = bytesNeeded;
1911         }
1912     }
1913     return ret;
1914 }
1915
1916 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1917  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1918  void *pvStructInfo, DWORD *pcbStructInfo)
1919 {
1920     BOOL ret = FALSE;
1921
1922     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1923      pvStructInfo, *pcbStructInfo);
1924
1925     if (!cbEncoded)
1926         SetLastError(CRYPT_E_ASN1_CORRUPT);
1927     else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1928         ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1929          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1930     else
1931         SetLastError(CRYPT_E_ASN1_BADTAG);
1932     return ret;
1933 }
1934
1935 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1936  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1937  void *pvStructInfo, DWORD *pcbStructInfo)
1938 {
1939     BOOL ret = TRUE;
1940     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1941
1942     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1943      pvStructInfo, *pcbStructInfo);
1944
1945     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1946         bytesNeeded += cbEncoded;
1947     if (!pvStructInfo)
1948         *pcbStructInfo = bytesNeeded;
1949     else if (*pcbStructInfo < bytesNeeded)
1950     {
1951         SetLastError(ERROR_MORE_DATA);
1952         *pcbStructInfo = bytesNeeded;
1953         ret = FALSE;
1954     }
1955     else
1956     {
1957         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1958
1959         *pcbStructInfo = bytesNeeded;
1960         blob->cbData = cbEncoded;
1961         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1962             blob->pbData = (LPBYTE)pbEncoded;
1963         else
1964         {
1965             assert(blob->pbData);
1966             memcpy(blob->pbData, pbEncoded, blob->cbData);
1967         }
1968     }
1969     return ret;
1970 }
1971
1972 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1973  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1974  void *pvStructInfo, DWORD *pcbStructInfo)
1975 {
1976     CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1977      (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1978     struct AsnDecodeSequenceItem items[] = {
1979      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1980        CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1981        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1982      { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1983        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1984        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1985     };
1986
1987     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1988      pvStructInfo, *pcbStructInfo);
1989
1990     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1991      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1992      pvStructInfo, pcbStructInfo,
1993      typeValue ? typeValue->pszObjId : NULL);
1994 }
1995
1996 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1997  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1998  void *pvStructInfo, DWORD *pcbStructInfo)
1999 {
2000     CRYPT_ALGORITHM_IDENTIFIER *algo =
2001      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
2002     BOOL ret = TRUE;
2003     struct AsnDecodeSequenceItem items[] = {
2004      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
2005        CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
2006        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
2007      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
2008        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
2009        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
2010     };
2011
2012     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2013      pvStructInfo, *pcbStructInfo);
2014
2015     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2016      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2017      pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
2018     if (ret && pvStructInfo)
2019     {
2020         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
2021          debugstr_a(algo->pszObjId));
2022     }
2023     return ret;
2024 }
2025
2026 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
2027  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2028  void *pvStructInfo, DWORD *pcbStructInfo)
2029 {
2030     struct SPCDigest *digest =
2031      (struct SPCDigest *)pvStructInfo;
2032     struct AsnDecodeSequenceItem items[] = {
2033      { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
2034        CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2035        FALSE, TRUE,
2036        offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
2037      { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
2038        CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
2039        FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
2040     };
2041
2042     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2043      pvStructInfo, *pcbStructInfo);
2044
2045     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2046      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2047      pvStructInfo, pcbStructInfo,
2048      digest ? digest->DigestAlgorithm.pszObjId : NULL);
2049 }
2050
2051 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
2052  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2053  void *pvStructInfo, DWORD *pcbStructInfo)
2054 {
2055     BOOL ret = FALSE;
2056
2057     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2058      pvStructInfo, *pcbStructInfo);
2059
2060     __TRY
2061     {
2062         struct AsnDecodeSequenceItem items[] = {
2063          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
2064            CRYPT_AsnDecodeAttributeTypeValue,
2065            sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
2066            offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
2067          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
2068            CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
2069            FALSE, TRUE,
2070            offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
2071         };
2072
2073         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2074          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2075          pvStructInfo, pcbStructInfo, NULL);
2076     }
2077     __EXCEPT_PAGE_FAULT
2078     {
2079         SetLastError(STATUS_ACCESS_VIOLATION);
2080     }
2081     __ENDTRY
2082     TRACE("returning %d\n", ret);
2083     return ret;
2084 }
2085
2086 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
2087  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2088  void *pvStructInfo, DWORD *pcbStructInfo)
2089 {
2090     FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2091      pvStructInfo, *pcbStructInfo);
2092     return FALSE;
2093 }
2094
2095 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
2096  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2097  void *pvStructInfo, DWORD *pcbStructInfo)
2098 {
2099     BOOL ret;
2100     DWORD bytesNeeded, dataLen;
2101
2102     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2103     {
2104         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2105
2106         bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
2107         if (!pvStructInfo)
2108             *pcbStructInfo = bytesNeeded;
2109         else if (*pcbStructInfo < bytesNeeded)
2110         {
2111             *pcbStructInfo = bytesNeeded;
2112             SetLastError(ERROR_MORE_DATA);
2113             ret = FALSE;
2114         }
2115         else
2116         {
2117             LPWSTR str;
2118             DWORD i;
2119
2120             *pcbStructInfo = bytesNeeded;
2121             assert(pvStructInfo);
2122             str = *(LPWSTR *)pvStructInfo;
2123             for (i = 0; i < dataLen / 2; i++)
2124                 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
2125                  pbEncoded[1 + lenBytes + 2 * i + 1];
2126             /* Decoded string is always NULL-terminated */
2127             str[i] = '\0';
2128         }
2129     }
2130     return ret;
2131 }
2132
2133 static BOOL CRYPT_AsnDecodeInteger(const BYTE *pbEncoded,
2134  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo)
2135 {
2136     BOOL ret;
2137     DWORD bytesNeeded, dataLen;
2138
2139     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2140     {
2141         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2142
2143         bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2144         if (!pvStructInfo)
2145             *pcbStructInfo = bytesNeeded;
2146         else if (*pcbStructInfo < bytesNeeded)
2147         {
2148             *pcbStructInfo = bytesNeeded;
2149             SetLastError(ERROR_MORE_DATA);
2150             ret = FALSE;
2151         }
2152         else
2153         {
2154             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2155
2156             *pcbStructInfo = bytesNeeded;
2157             blob->cbData = dataLen;
2158             assert(blob->pbData);
2159             if (blob->cbData)
2160             {
2161                 DWORD i;
2162
2163                 for (i = 0; i < blob->cbData; i++)
2164                 {
2165                     blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2166                      dataLen - i - 1);
2167                 }
2168             }
2169         }
2170     }
2171     return ret;
2172 }
2173
2174 /* Ignores tag.  Only allows integers 4 bytes or smaller in size. */
2175 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2176  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2177  void *pvStructInfo, DWORD *pcbStructInfo)
2178 {
2179     BOOL ret;
2180     BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
2181     CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
2182     DWORD size = sizeof(buf);
2183
2184     blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
2185     ret = CRYPT_AsnDecodeInteger(pbEncoded, cbEncoded, 0, buf, &size);
2186     if (ret)
2187     {
2188         if (!pvStructInfo)
2189             *pcbStructInfo = sizeof(int);
2190         else if (*pcbStructInfo < sizeof(int))
2191         {
2192             *pcbStructInfo = sizeof(int);
2193             SetLastError(ERROR_MORE_DATA);
2194             ret = FALSE;
2195         }
2196         else
2197         {
2198             int val;
2199             DWORD i;
2200
2201             *pcbStructInfo = sizeof(int);
2202             if (blob->pbData[blob->cbData - 1] & 0x80)
2203             {
2204                 /* initialize to a negative value to sign-extend */
2205                 val = -1;
2206             }
2207             else
2208                 val = 0;
2209             for (i = 0; i < blob->cbData; i++)
2210             {
2211                 val <<= 8;
2212                 val |= blob->pbData[blob->cbData - i - 1];
2213             }
2214             memcpy(pvStructInfo, &val, sizeof(int));
2215         }
2216     }
2217     else if (GetLastError() == ERROR_MORE_DATA)
2218         SetLastError(CRYPT_E_ASN1_LARGE);
2219     return ret;
2220 }
2221
2222 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2223  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2224  void *pvStructInfo, DWORD *pcbStructInfo)
2225 {
2226     BOOL ret = FALSE;
2227
2228     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2229      pvStructInfo, *pcbStructInfo);
2230
2231     __TRY
2232     {
2233         struct AsnDecodeSequenceItem items[] = {
2234          { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2235            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2236            offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2237          { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2238            CRYPT_AsnDecodeInt, sizeof(DWORD),
2239            FALSE, FALSE, 0, 0 },
2240         };
2241
2242         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2243          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2244          pvStructInfo, pcbStructInfo, NULL);
2245     }
2246     __EXCEPT_PAGE_FAULT
2247     {
2248         SetLastError(STATUS_ACCESS_VIOLATION);
2249     }
2250     __ENDTRY
2251     TRACE("returning %d\n", ret);
2252     return ret;
2253 }
2254
2255 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2256  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2257  void *pvStructInfo, DWORD *pcbStructInfo)
2258 {
2259     BOOL ret = FALSE;
2260
2261     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2262      pvStructInfo, *pcbStructInfo);
2263
2264     __TRY
2265     {
2266         struct AsnDecodeSequenceItem items[] = {
2267          { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2268            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2269            offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2270          { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2271            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
2272          { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2273            CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2274            offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2275         };
2276
2277         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2278          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2279          pvStructInfo, pcbStructInfo, NULL);
2280     }
2281     __EXCEPT_PAGE_FAULT
2282     {
2283         SetLastError(STATUS_ACCESS_VIOLATION);
2284     }
2285     __ENDTRY
2286     TRACE("returning %d\n", ret);
2287     return ret;
2288 }
2289
2290 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
2291  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2292  void *pvStructInfo, DWORD *pcbStructInfo)
2293 {
2294     BOOL ret;
2295
2296     if (cbEncoded < 3)
2297     {
2298         SetLastError(CRYPT_E_ASN1_CORRUPT);
2299         return FALSE;
2300     }
2301     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2302     {
2303         SetLastError(CRYPT_E_ASN1_CORRUPT);
2304         return FALSE;
2305     }
2306     if (pbEncoded[1] > 1)
2307     {
2308         SetLastError(CRYPT_E_ASN1_CORRUPT);
2309         return FALSE;
2310     }
2311     if (!pvStructInfo)
2312     {
2313         *pcbStructInfo = sizeof(BOOL);
2314         ret = TRUE;
2315     }
2316     else if (*pcbStructInfo < sizeof(BOOL))
2317     {
2318         *pcbStructInfo = sizeof(BOOL);
2319         SetLastError(ERROR_MORE_DATA);
2320         ret = FALSE;
2321     }
2322     else
2323     {
2324         *pcbStructInfo = sizeof(BOOL);
2325         *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
2326         ret = TRUE;
2327     }
2328     TRACE("returning %d (%08x)\n", ret, GetLastError());
2329     return ret;
2330 }
2331
2332 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType,
2333  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2334  void *pvStructInfo, DWORD *pcbStructInfo)
2335 {
2336     BOOL ret = FALSE;
2337
2338     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2339      pvStructInfo, *pcbStructInfo);
2340
2341     __TRY
2342     {
2343         struct AsnDecodeSequenceItem items[] = {
2344          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable),
2345            CRYPT_AsnDecodeBool, sizeof(BOOL), FALSE, FALSE, 0, 0 },
2346          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria),
2347            CRYPT_AsnDecodeBool, sizeof(BOOL), FALSE, FALSE, 0, 0 },
2348         };
2349
2350         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2351          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2352          pvStructInfo, pcbStructInfo, NULL);
2353     }
2354     __EXCEPT_PAGE_FAULT
2355     {
2356         SetLastError(STATUS_ACCESS_VIOLATION);
2357     }
2358     __ENDTRY
2359     TRACE("returning %d\n", ret);
2360     return ret;
2361 }