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