d3d9/tests: Don't test for equality in d3d9's depth_blit_test.
[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(*(const 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                             if (items[i].size < items[i].minSize)
1529                                 items[i].size = items[i].minSize;
1530                             else if (items[i].size > items[i].minSize)
1531                             {
1532                                 /* Account for alignment padding */
1533                                 items[i].size = ALIGN_DWORD_PTR(items[i].size);
1534                             }
1535                             TRACE("item %d size: %d\n", i, items[i].size);
1536                             if (nextData && items[i].hasPointer &&
1537                              items[i].size > items[i].minSize)
1538                                 nextData += items[i].size - items[i].minSize;
1539                             ptr += 1 + nextItemLenBytes + nextItemLen;
1540                             decoded += 1 + nextItemLenBytes + nextItemLen;
1541                             TRACE("item %d: decoded %d bytes\n", i,
1542                              1 + nextItemLenBytes + nextItemLen);
1543                         }
1544                         else if (items[i].optional &&
1545                          GetLastError() == CRYPT_E_ASN1_BADTAG)
1546                         {
1547                             TRACE("skipping optional item %d\n", i);
1548                             items[i].size = items[i].minSize;
1549                             SetLastError(NOERROR);
1550                             ret = TRUE;
1551                         }
1552                         else
1553                             TRACE("item %d failed: %08x\n", i,
1554                              GetLastError());
1555                     }
1556                     else
1557                     {
1558                         TRACE("item %d: decoded %d bytes\n", i,
1559                          1 + nextItemLenBytes + nextItemLen);
1560                         ptr += 1 + nextItemLenBytes + nextItemLen;
1561                         decoded += 1 + nextItemLenBytes + nextItemLen;
1562                         items[i].size = items[i].minSize;
1563                     }
1564                 }
1565                 else if (items[i].optional)
1566                 {
1567                     TRACE("skipping optional item %d\n", i);
1568                     items[i].size = items[i].minSize;
1569                 }
1570                 else
1571                 {
1572                     TRACE("item %d: tag %02x doesn't match expected %02x\n",
1573                      i, ptr[0], items[i].tag);
1574                     SetLastError(CRYPT_E_ASN1_BADTAG);
1575                     ret = FALSE;
1576                 }
1577             }
1578         }
1579         else if (items[i].optional)
1580         {
1581             TRACE("missing optional item %d, skipping\n", i);
1582             items[i].size = items[i].minSize;
1583         }
1584         else
1585         {
1586             TRACE("not enough bytes for item %d, failing\n", i);
1587             SetLastError(CRYPT_E_ASN1_CORRUPT);
1588             ret = FALSE;
1589         }
1590     }
1591     if (ret)
1592         *cbDecoded = decoded;
1593     TRACE("returning %d\n", ret);
1594     return ret;
1595 }
1596
1597 /* This decodes an arbitrary sequence into a contiguous block of memory
1598  * (basically, a struct.)  Each element being decoded is described by a struct
1599  * AsnDecodeSequenceItem, see above.
1600  * startingPointer is an optional pointer to the first place where dynamic
1601  * data will be stored.  If you know the starting offset, you may pass it
1602  * here.  Otherwise, pass NULL, and one will be inferred from the items.
1603  */
1604 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1605  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1606  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1607  void *startingPointer)
1608 {
1609     BOOL ret;
1610
1611     TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1612      cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1613
1614     if (pbEncoded[0] == ASN_SEQUENCE)
1615     {
1616         DWORD dataLen;
1617
1618         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1619         {
1620             DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1621             const BYTE *ptr = pbEncoded + 1 + lenBytes;
1622
1623             cbEncoded -= 1 + lenBytes;
1624             if (cbEncoded < dataLen)
1625             {
1626                 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1627                  cbEncoded);
1628                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1629                 ret = FALSE;
1630             }
1631             else
1632                 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1633                  cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1634             if (ret && cbDecoded != dataLen)
1635             {
1636                 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1637                  cbDecoded);
1638                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1639                 ret = FALSE;
1640             }
1641             if (ret)
1642             {
1643                 DWORD i, bytesNeeded = 0, structSize = 0;
1644
1645                 for (i = 0; i < cItem; i++)
1646                 {
1647                     bytesNeeded += items[i].size;
1648                     structSize += items[i].minSize;
1649                 }
1650                 if (!pvStructInfo)
1651                     *pcbStructInfo = bytesNeeded;
1652                 else if (*pcbStructInfo < bytesNeeded)
1653                 {
1654                     SetLastError(ERROR_MORE_DATA);
1655                     *pcbStructInfo = bytesNeeded;
1656                     ret = FALSE;
1657                 }
1658                 else
1659                 {
1660                     BYTE *nextData;
1661
1662                     *pcbStructInfo = bytesNeeded;
1663                     if (startingPointer)
1664                         nextData = startingPointer;
1665                     else
1666                         nextData = (BYTE *)pvStructInfo + structSize;
1667                     memset(pvStructInfo, 0, structSize);
1668                     ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1669                      ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1670                      &cbDecoded);
1671                 }
1672             }
1673         }
1674     }
1675     else
1676     {
1677         SetLastError(CRYPT_E_ASN1_BADTAG);
1678         ret = FALSE;
1679     }
1680     TRACE("returning %d (%08x)\n", ret, GetLastError());
1681     return ret;
1682 }
1683
1684 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1685  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1686  void *pvStructInfo, DWORD *pcbStructInfo)
1687 {
1688     BOOL ret;
1689
1690     TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1691      pvStructInfo, *pcbStructInfo);
1692
1693     if (pbEncoded[0] == ASN_BITSTRING)
1694     {
1695         DWORD bytesNeeded, dataLen;
1696
1697         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1698         {
1699             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1700                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1701             else
1702                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1703             if (!pvStructInfo)
1704                 *pcbStructInfo = bytesNeeded;
1705             else if (*pcbStructInfo < bytesNeeded)
1706             {
1707                 *pcbStructInfo = bytesNeeded;
1708                 SetLastError(ERROR_MORE_DATA);
1709                 ret = FALSE;
1710             }
1711             else
1712             {
1713                 CRYPT_BIT_BLOB *blob;
1714
1715                 blob = pvStructInfo;
1716                 blob->cbData = dataLen - 1;
1717                 blob->cUnusedBits = *(pbEncoded + 1 +
1718                  GET_LEN_BYTES(pbEncoded[1]));
1719                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1720                 {
1721                     blob->pbData = (BYTE *)pbEncoded + 2 +
1722                      GET_LEN_BYTES(pbEncoded[1]);
1723                 }
1724                 else
1725                 {
1726                     assert(blob->pbData);
1727                     if (blob->cbData)
1728                     {
1729                         BYTE mask = 0xff << blob->cUnusedBits;
1730
1731                         memcpy(blob->pbData, pbEncoded + 2 +
1732                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1733                         blob->pbData[blob->cbData - 1] &= mask;
1734                     }
1735                 }
1736             }
1737         }
1738     }
1739     else
1740     {
1741         SetLastError(CRYPT_E_ASN1_BADTAG);
1742         ret = FALSE;
1743     }
1744     TRACE("returning %d (%08x)\n", ret, GetLastError());
1745     return ret;
1746 }
1747
1748 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1749  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1750  void *pvStructInfo, DWORD *pcbStructInfo)
1751 {
1752     BOOL ret = FALSE;
1753     DWORD dataLen;
1754
1755     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1756     {
1757         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1758         DWORD size;
1759         SPC_LINK **pLink = pvStructInfo;
1760
1761         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1762          pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1763         if (ret)
1764         {
1765             if (!pvStructInfo)
1766                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1767             else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1768             {
1769                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1770                 SetLastError(ERROR_MORE_DATA);
1771                 ret = FALSE;
1772             }
1773             else
1774             {
1775                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1776                 /* Set imageData's pointer if necessary */
1777                 if (size > sizeof(SPC_LINK))
1778                 {
1779                     (*pLink)->u.pwszUrl =
1780                      (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1781                 }
1782                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1783                  lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1784                  *pLink, pcbStructInfo);
1785             }
1786         }
1787     }
1788     return ret;
1789 }
1790
1791 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1792  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1793  void *pvStructInfo, DWORD *pcbStructInfo)
1794 {
1795     BOOL ret = FALSE;
1796
1797     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1798      pvStructInfo, *pcbStructInfo);
1799
1800     __TRY
1801     {
1802         struct AsnDecodeSequenceItem items[] = {
1803          { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1804            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1805            offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1806          { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1807            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1808            offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1809         };
1810
1811         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1812          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1813          pvStructInfo, pcbStructInfo, NULL);
1814     }
1815     __EXCEPT_PAGE_FAULT
1816     {
1817         SetLastError(STATUS_ACCESS_VIOLATION);
1818     }
1819     __ENDTRY
1820     TRACE("returning %d\n", ret);
1821     return ret;
1822 }
1823
1824 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1825  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1826  void *pvStructInfo, DWORD *pcbStructInfo)
1827 {
1828     BOOL ret = TRUE;
1829     DWORD dataLen;
1830
1831     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1832      pvStructInfo, *pcbStructInfo);
1833
1834     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1835     {
1836         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1837         DWORD bytesNeeded = sizeof(LPSTR);
1838
1839         if (dataLen)
1840         {
1841             /* The largest possible string for the first two components
1842              * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1843              */
1844             char firstTwo[6];
1845             const BYTE *ptr;
1846
1847             snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1848              pbEncoded[1 + lenBytes] / 40,
1849              pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1850              * 40);
1851             bytesNeeded += strlen(firstTwo) + 1;
1852             for (ptr = pbEncoded + 2 + lenBytes; ret &&
1853              ptr - pbEncoded - 1 - lenBytes < dataLen; )
1854             {
1855                 /* large enough for ".4000000" */
1856                 char str[9];
1857                 int val = 0;
1858
1859                 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1860                  (*ptr & 0x80))
1861                 {
1862                     val <<= 7;
1863                     val |= *ptr & 0x7f;
1864                     ptr++;
1865                 }
1866                 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1867                  (*ptr & 0x80))
1868                 {
1869                     SetLastError(CRYPT_E_ASN1_CORRUPT);
1870                     ret = FALSE;
1871                 }
1872                 else
1873                 {
1874                     val <<= 7;
1875                     val |= *ptr++;
1876                     snprintf(str, sizeof(str), ".%d", val);
1877                     bytesNeeded += strlen(str);
1878                 }
1879             }
1880         }
1881         if (!pvStructInfo)
1882             *pcbStructInfo = bytesNeeded;
1883         else if (*pcbStructInfo < bytesNeeded)
1884         {
1885             *pcbStructInfo = bytesNeeded;
1886             SetLastError(ERROR_MORE_DATA);
1887             ret = FALSE;
1888         }
1889         else
1890         {
1891             if (dataLen)
1892             {
1893                 const BYTE *ptr;
1894                 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1895
1896                 *pszObjId = 0;
1897                 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1898                  pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1899                  40) * 40);
1900                 pszObjId += strlen(pszObjId);
1901                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1902                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
1903                 {
1904                     int val = 0;
1905
1906                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1907                      (*ptr & 0x80))
1908                     {
1909                         val <<= 7;
1910                         val |= *ptr & 0x7f;
1911                         ptr++;
1912                     }
1913                     val <<= 7;
1914                     val |= *ptr++;
1915                     sprintf(pszObjId, ".%d", val);
1916                     pszObjId += strlen(pszObjId);
1917                 }
1918             }
1919             else
1920                 *(LPSTR *)pvStructInfo = NULL;
1921             *pcbStructInfo = bytesNeeded;
1922         }
1923     }
1924     return ret;
1925 }
1926
1927 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1928  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1929  void *pvStructInfo, DWORD *pcbStructInfo)
1930 {
1931     BOOL ret = FALSE;
1932
1933     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1934      pvStructInfo, *pcbStructInfo);
1935
1936     if (!cbEncoded)
1937         SetLastError(CRYPT_E_ASN1_CORRUPT);
1938     else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1939         ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1940          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1941     else
1942         SetLastError(CRYPT_E_ASN1_BADTAG);
1943     return ret;
1944 }
1945
1946 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1947  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1948  void *pvStructInfo, DWORD *pcbStructInfo)
1949 {
1950     BOOL ret = TRUE;
1951     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1952
1953     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1954      pvStructInfo, *pcbStructInfo);
1955
1956     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1957         bytesNeeded += cbEncoded;
1958     if (!pvStructInfo)
1959         *pcbStructInfo = bytesNeeded;
1960     else if (*pcbStructInfo < bytesNeeded)
1961     {
1962         SetLastError(ERROR_MORE_DATA);
1963         *pcbStructInfo = bytesNeeded;
1964         ret = FALSE;
1965     }
1966     else
1967     {
1968         PCRYPT_OBJID_BLOB blob = pvStructInfo;
1969
1970         *pcbStructInfo = bytesNeeded;
1971         blob->cbData = cbEncoded;
1972         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1973             blob->pbData = (LPBYTE)pbEncoded;
1974         else
1975         {
1976             assert(blob->pbData);
1977             memcpy(blob->pbData, pbEncoded, blob->cbData);
1978         }
1979     }
1980     return ret;
1981 }
1982
1983 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1984  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1985  void *pvStructInfo, DWORD *pcbStructInfo)
1986 {
1987     CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue = pvStructInfo;
1988     struct AsnDecodeSequenceItem items[] = {
1989      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1990        CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1991        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1992      { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1993        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1994        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1995     };
1996
1997     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1998      pvStructInfo, *pcbStructInfo);
1999
2000     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2001      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2002      pvStructInfo, pcbStructInfo,
2003      typeValue ? typeValue->pszObjId : NULL);
2004 }
2005
2006 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
2007  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2008  void *pvStructInfo, DWORD *pcbStructInfo)
2009 {
2010     CRYPT_ALGORITHM_IDENTIFIER *algo = pvStructInfo;
2011     BOOL ret = TRUE;
2012     struct AsnDecodeSequenceItem items[] = {
2013      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
2014        CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
2015        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
2016      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
2017        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
2018        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
2019     };
2020
2021     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2022      pvStructInfo, *pcbStructInfo);
2023
2024     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2025      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2026      pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
2027     if (ret && pvStructInfo)
2028     {
2029         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
2030          debugstr_a(algo->pszObjId));
2031     }
2032     return ret;
2033 }
2034
2035 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
2036  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2037  void *pvStructInfo, DWORD *pcbStructInfo)
2038 {
2039     struct SPCDigest *digest = pvStructInfo;
2040     struct AsnDecodeSequenceItem items[] = {
2041      { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
2042        CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2043        FALSE, TRUE,
2044        offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
2045      { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
2046        CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
2047        FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
2048     };
2049
2050     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2051      pvStructInfo, *pcbStructInfo);
2052
2053     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2054      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2055      pvStructInfo, pcbStructInfo,
2056      digest ? digest->DigestAlgorithm.pszObjId : NULL);
2057 }
2058
2059 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
2060  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2061  void *pvStructInfo, DWORD *pcbStructInfo)
2062 {
2063     BOOL ret = FALSE;
2064
2065     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2066      pvStructInfo, *pcbStructInfo);
2067
2068     __TRY
2069     {
2070         struct AsnDecodeSequenceItem items[] = {
2071          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
2072            CRYPT_AsnDecodeAttributeTypeValue,
2073            sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
2074            offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
2075          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
2076            CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
2077            FALSE, TRUE,
2078            offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
2079         };
2080
2081         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2082          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2083          pvStructInfo, pcbStructInfo, NULL);
2084     }
2085     __EXCEPT_PAGE_FAULT
2086     {
2087         SetLastError(STATUS_ACCESS_VIOLATION);
2088     }
2089     __ENDTRY
2090     TRACE("returning %d\n", ret);
2091     return ret;
2092 }
2093
2094 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
2095  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2096  void *pvStructInfo, DWORD *pcbStructInfo)
2097 {
2098     BOOL ret;
2099     DWORD bytesNeeded, dataLen;
2100
2101     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2102     {
2103         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2104
2105         bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
2106         if (!pvStructInfo)
2107             *pcbStructInfo = bytesNeeded;
2108         else if (*pcbStructInfo < bytesNeeded)
2109         {
2110             *pcbStructInfo = bytesNeeded;
2111             SetLastError(ERROR_MORE_DATA);
2112             ret = FALSE;
2113         }
2114         else
2115         {
2116             LPWSTR str;
2117             DWORD i;
2118
2119             *pcbStructInfo = bytesNeeded;
2120             assert(pvStructInfo);
2121             str = *(LPWSTR *)pvStructInfo;
2122             for (i = 0; i < dataLen / 2; i++)
2123                 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
2124                  pbEncoded[1 + lenBytes + 2 * i + 1];
2125             /* Decoded string is always NULL-terminated */
2126             str[i] = '\0';
2127         }
2128     }
2129     return ret;
2130 }
2131
2132 static BOOL WINAPI CRYPT_AsnDecodeProgramName(DWORD dwCertEncodingType,
2133  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2134  void *pvStructInfo, DWORD *pcbStructInfo)
2135 {
2136     BOOL ret = FALSE;
2137     DWORD dataLen;
2138
2139     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2140      pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
2141
2142     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2143     {
2144         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2145
2146         ret = CRYPT_AsnDecodeBMPString(dwCertEncodingType, lpszStructType,
2147          pbEncoded + 1 + lenBytes, dataLen, dwFlags, pvStructInfo,
2148          pcbStructInfo);
2149     }
2150     return ret;
2151 }
2152
2153 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
2154  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2155  void *pvStructInfo, DWORD *pcbStructInfo)
2156 {
2157     BOOL ret = FALSE;
2158
2159     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2160      pvStructInfo, *pcbStructInfo);
2161
2162     __TRY
2163     {
2164         struct AsnDecodeSequenceItem items[] = {
2165          { ASN_CONSTRUCTOR | ASN_CONTEXT,
2166            offsetof(SPC_SP_OPUS_INFO, pwszProgramName),
2167            CRYPT_AsnDecodeProgramName, sizeof(LPCWSTR), TRUE, TRUE,
2168            offsetof(SPC_SP_OPUS_INFO, pwszProgramName), 0 },
2169          { ASN_CONSTRUCTOR | ASN_CONTEXT | 1,
2170            offsetof(SPC_SP_OPUS_INFO, pMoreInfo),
2171            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
2172            offsetof(SPC_SP_OPUS_INFO, pMoreInfo), 0 },
2173          { ASN_CONSTRUCTOR | ASN_CONTEXT | 2,
2174            offsetof(SPC_SP_OPUS_INFO, pPublisherInfo),
2175            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
2176            offsetof(SPC_SP_OPUS_INFO, pPublisherInfo), 0 },
2177         };
2178
2179         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2180          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2181          pvStructInfo, pcbStructInfo, NULL);
2182     }
2183     __EXCEPT_PAGE_FAULT
2184     {
2185         SetLastError(STATUS_ACCESS_VIOLATION);
2186     }
2187     __ENDTRY
2188     TRACE("returning %d\n", ret);
2189     return ret;
2190 }
2191
2192 /* Ignores tag.  Only allows integers 4 bytes or smaller in size. */
2193 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2194  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2195  void *pvStructInfo, DWORD *pcbStructInfo)
2196 {
2197     BOOL ret;
2198     DWORD dataLen;
2199
2200     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2201     {
2202         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2203
2204         if (dataLen > sizeof(int))
2205         {
2206             SetLastError(CRYPT_E_ASN1_LARGE);
2207             ret = FALSE;
2208         }
2209         else if (!pvStructInfo)
2210             *pcbStructInfo = sizeof(int);
2211         else if (*pcbStructInfo < sizeof(int))
2212         {
2213             *pcbStructInfo = sizeof(int);
2214             SetLastError(ERROR_MORE_DATA);
2215             ret = FALSE;
2216         }
2217         else
2218         {
2219             int val;
2220             DWORD i;
2221
2222             *pcbStructInfo = sizeof(int);
2223             if (dataLen && pbEncoded[1 + lenBytes] & 0x80)
2224             {
2225                 /* initialize to a negative value to sign-extend */
2226                 val = -1;
2227             }
2228             else
2229                 val = 0;
2230             for (i = 0; i < dataLen; i++)
2231             {
2232                 val <<= 8;
2233                 val |= pbEncoded[1 + lenBytes + i];
2234             }
2235             memcpy(pvStructInfo, &val, sizeof(int));
2236         }
2237     }
2238     return ret;
2239 }
2240
2241 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2242  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2243  void *pvStructInfo, DWORD *pcbStructInfo)
2244 {
2245     BOOL ret = FALSE;
2246
2247     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2248      pvStructInfo, *pcbStructInfo);
2249
2250     __TRY
2251     {
2252         struct AsnDecodeSequenceItem items[] = {
2253          { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2254            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2255            offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2256          { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2257            CRYPT_AsnDecodeInt, FINALMEMBERSIZE(CAT_MEMBERINFO, dwCertVersion),
2258            FALSE, FALSE, 0, 0 },
2259         };
2260
2261         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2262          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2263          pvStructInfo, pcbStructInfo, NULL);
2264     }
2265     __EXCEPT_PAGE_FAULT
2266     {
2267         SetLastError(STATUS_ACCESS_VIOLATION);
2268     }
2269     __ENDTRY
2270     TRACE("returning %d\n", ret);
2271     return ret;
2272 }
2273
2274 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2275  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2276  void *pvStructInfo, DWORD *pcbStructInfo)
2277 {
2278     BOOL ret = FALSE;
2279
2280     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2281      pvStructInfo, *pcbStructInfo);
2282
2283     __TRY
2284     {
2285         struct AsnDecodeSequenceItem items[] = {
2286          { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2287            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2288            offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2289          { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2290            CRYPT_AsnDecodeInt, MEMBERSIZE(CAT_NAMEVALUE, fdwFlags, Value),
2291            FALSE, FALSE, 0, 0 },
2292          { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2293            CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2294            offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2295         };
2296
2297         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2298          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2299          pvStructInfo, pcbStructInfo, NULL);
2300     }
2301     __EXCEPT_PAGE_FAULT
2302     {
2303         SetLastError(STATUS_ACCESS_VIOLATION);
2304     }
2305     __ENDTRY
2306     TRACE("returning %d\n", ret);
2307     return ret;
2308 }
2309
2310 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
2311  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2312  void *pvStructInfo, DWORD *pcbStructInfo)
2313 {
2314     BOOL ret;
2315
2316     if (cbEncoded < 3)
2317     {
2318         SetLastError(CRYPT_E_ASN1_CORRUPT);
2319         return FALSE;
2320     }
2321     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2322     {
2323         SetLastError(CRYPT_E_ASN1_CORRUPT);
2324         return FALSE;
2325     }
2326     if (pbEncoded[1] > 1)
2327     {
2328         SetLastError(CRYPT_E_ASN1_CORRUPT);
2329         return FALSE;
2330     }
2331     if (!pvStructInfo)
2332     {
2333         *pcbStructInfo = sizeof(BOOL);
2334         ret = TRUE;
2335     }
2336     else if (*pcbStructInfo < sizeof(BOOL))
2337     {
2338         *pcbStructInfo = sizeof(BOOL);
2339         SetLastError(ERROR_MORE_DATA);
2340         ret = FALSE;
2341     }
2342     else
2343     {
2344         *pcbStructInfo = sizeof(BOOL);
2345         *(BOOL *)pvStructInfo = pbEncoded[2] != 0;
2346         ret = TRUE;
2347     }
2348     TRACE("returning %d (%08x)\n", ret, GetLastError());
2349     return ret;
2350 }
2351
2352 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType,
2353  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2354  void *pvStructInfo, DWORD *pcbStructInfo)
2355 {
2356     BOOL ret = FALSE;
2357
2358     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2359      pvStructInfo, *pcbStructInfo);
2360
2361     __TRY
2362     {
2363         struct AsnDecodeSequenceItem items[] = {
2364          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable),
2365            CRYPT_AsnDecodeBool, MEMBERSIZE(SPC_FINANCIAL_CRITERIA,
2366            fFinancialInfoAvailable, fMeetsCriteria), FALSE, FALSE, 0, 0 },
2367          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria),
2368            CRYPT_AsnDecodeBool, FINALMEMBERSIZE(SPC_FINANCIAL_CRITERIA,
2369            fMeetsCriteria), FALSE, FALSE, 0, 0 },
2370         };
2371
2372         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2373          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2374          pvStructInfo, pcbStructInfo, NULL);
2375     }
2376     __EXCEPT_PAGE_FAULT
2377     {
2378         SetLastError(STATUS_ACCESS_VIOLATION);
2379     }
2380     __ENDTRY
2381     TRACE("returning %d\n", ret);
2382     return ret;
2383 }