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