xref: /reactos/dll/win32/wintrust/asn.c (revision 19b18ce2)
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[8];
1845             const BYTE *ptr;
1846 
1847             sprintf(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                 pszObjId += sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1898                  pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1899                  40) * 40);
1900                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1901                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
1902                 {
1903                     int val = 0;
1904 
1905                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1906                      (*ptr & 0x80))
1907                     {
1908                         val <<= 7;
1909                         val |= *ptr & 0x7f;
1910                         ptr++;
1911                     }
1912                     val <<= 7;
1913                     val |= *ptr++;
1914                     pszObjId += sprintf(pszObjId, ".%d", val);
1915                 }
1916             }
1917             else
1918                 *(LPSTR *)pvStructInfo = NULL;
1919             *pcbStructInfo = bytesNeeded;
1920         }
1921     }
1922     return ret;
1923 }
1924 
1925 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1926  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1927  void *pvStructInfo, DWORD *pcbStructInfo)
1928 {
1929     BOOL ret = FALSE;
1930 
1931     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1932      pvStructInfo, *pcbStructInfo);
1933 
1934     if (!cbEncoded)
1935         SetLastError(CRYPT_E_ASN1_CORRUPT);
1936     else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1937         ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1938          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1939     else
1940         SetLastError(CRYPT_E_ASN1_BADTAG);
1941     return ret;
1942 }
1943 
1944 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1945  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1946  void *pvStructInfo, DWORD *pcbStructInfo)
1947 {
1948     BOOL ret = TRUE;
1949     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1950 
1951     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1952      pvStructInfo, *pcbStructInfo);
1953 
1954     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1955         bytesNeeded += cbEncoded;
1956     if (!pvStructInfo)
1957         *pcbStructInfo = bytesNeeded;
1958     else if (*pcbStructInfo < bytesNeeded)
1959     {
1960         SetLastError(ERROR_MORE_DATA);
1961         *pcbStructInfo = bytesNeeded;
1962         ret = FALSE;
1963     }
1964     else
1965     {
1966         PCRYPT_OBJID_BLOB blob = pvStructInfo;
1967 
1968         *pcbStructInfo = bytesNeeded;
1969         blob->cbData = cbEncoded;
1970         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1971             blob->pbData = (LPBYTE)pbEncoded;
1972         else
1973         {
1974             assert(blob->pbData);
1975             memcpy(blob->pbData, pbEncoded, blob->cbData);
1976         }
1977     }
1978     return ret;
1979 }
1980 
1981 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1982  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1983  void *pvStructInfo, DWORD *pcbStructInfo)
1984 {
1985     CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue = pvStructInfo;
1986     struct AsnDecodeSequenceItem items[] = {
1987      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1988        CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1989        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1990      { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1991        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1992        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1993     };
1994 
1995     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1996      pvStructInfo, *pcbStructInfo);
1997 
1998     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1999      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2000      pvStructInfo, pcbStructInfo,
2001      typeValue ? typeValue->pszObjId : NULL);
2002 }
2003 
2004 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
2005  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2006  void *pvStructInfo, DWORD *pcbStructInfo)
2007 {
2008     CRYPT_ALGORITHM_IDENTIFIER *algo = pvStructInfo;
2009     BOOL ret = TRUE;
2010     struct AsnDecodeSequenceItem items[] = {
2011      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
2012        CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
2013        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
2014      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
2015        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
2016        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
2017     };
2018 
2019     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2020      pvStructInfo, *pcbStructInfo);
2021 
2022     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2023      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2024      pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
2025     if (ret && pvStructInfo)
2026     {
2027         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
2028          debugstr_a(algo->pszObjId));
2029     }
2030     return ret;
2031 }
2032 
2033 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
2034  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2035  void *pvStructInfo, DWORD *pcbStructInfo)
2036 {
2037     struct SPCDigest *digest = pvStructInfo;
2038     struct AsnDecodeSequenceItem items[] = {
2039      { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
2040        CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2041        FALSE, TRUE,
2042        offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
2043      { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
2044        CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
2045        FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
2046     };
2047 
2048     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2049      pvStructInfo, *pcbStructInfo);
2050 
2051     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2052      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2053      pvStructInfo, pcbStructInfo,
2054      digest ? digest->DigestAlgorithm.pszObjId : NULL);
2055 }
2056 
2057 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
2058  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2059  void *pvStructInfo, DWORD *pcbStructInfo)
2060 {
2061     BOOL ret = FALSE;
2062 
2063     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2064      pvStructInfo, *pcbStructInfo);
2065 
2066     __TRY
2067     {
2068         struct AsnDecodeSequenceItem items[] = {
2069          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
2070            CRYPT_AsnDecodeAttributeTypeValue,
2071            sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
2072            offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
2073          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
2074            CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
2075            FALSE, TRUE,
2076            offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
2077         };
2078 
2079         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2080          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2081          pvStructInfo, pcbStructInfo, NULL);
2082     }
2083     __EXCEPT_PAGE_FAULT
2084     {
2085         SetLastError(STATUS_ACCESS_VIOLATION);
2086     }
2087     __ENDTRY
2088     TRACE("returning %d\n", ret);
2089     return ret;
2090 }
2091 
2092 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
2093  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2094  void *pvStructInfo, DWORD *pcbStructInfo)
2095 {
2096     BOOL ret;
2097     DWORD bytesNeeded, dataLen;
2098 
2099     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2100     {
2101         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2102 
2103         bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
2104         if (!pvStructInfo)
2105             *pcbStructInfo = bytesNeeded;
2106         else if (*pcbStructInfo < bytesNeeded)
2107         {
2108             *pcbStructInfo = bytesNeeded;
2109             SetLastError(ERROR_MORE_DATA);
2110             ret = FALSE;
2111         }
2112         else
2113         {
2114             LPWSTR str;
2115             DWORD i;
2116 
2117             *pcbStructInfo = bytesNeeded;
2118             assert(pvStructInfo);
2119             str = *(LPWSTR *)pvStructInfo;
2120             for (i = 0; i < dataLen / 2; i++)
2121                 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
2122                  pbEncoded[1 + lenBytes + 2 * i + 1];
2123             /* Decoded string is always NULL-terminated */
2124             str[i] = '\0';
2125         }
2126     }
2127     return ret;
2128 }
2129 
2130 static BOOL WINAPI CRYPT_AsnDecodeProgramName(DWORD dwCertEncodingType,
2131  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2132  void *pvStructInfo, DWORD *pcbStructInfo)
2133 {
2134     BOOL ret = FALSE;
2135     DWORD dataLen;
2136 
2137     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2138      pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
2139 
2140     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2141     {
2142         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2143 
2144         ret = CRYPT_AsnDecodeBMPString(dwCertEncodingType, lpszStructType,
2145          pbEncoded + 1 + lenBytes, dataLen, dwFlags, pvStructInfo,
2146          pcbStructInfo);
2147     }
2148     return ret;
2149 }
2150 
2151 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
2152  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2153  void *pvStructInfo, DWORD *pcbStructInfo)
2154 {
2155     BOOL ret = FALSE;
2156 
2157     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2158      pvStructInfo, *pcbStructInfo);
2159 
2160     __TRY
2161     {
2162         struct AsnDecodeSequenceItem items[] = {
2163          { ASN_CONSTRUCTOR | ASN_CONTEXT,
2164            offsetof(SPC_SP_OPUS_INFO, pwszProgramName),
2165            CRYPT_AsnDecodeProgramName, sizeof(LPCWSTR), TRUE, TRUE,
2166            offsetof(SPC_SP_OPUS_INFO, pwszProgramName), 0 },
2167          { ASN_CONSTRUCTOR | ASN_CONTEXT | 1,
2168            offsetof(SPC_SP_OPUS_INFO, pMoreInfo),
2169            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
2170            offsetof(SPC_SP_OPUS_INFO, pMoreInfo), 0 },
2171          { ASN_CONSTRUCTOR | ASN_CONTEXT | 2,
2172            offsetof(SPC_SP_OPUS_INFO, pPublisherInfo),
2173            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
2174            offsetof(SPC_SP_OPUS_INFO, pPublisherInfo), 0 },
2175         };
2176 
2177         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2178          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2179          pvStructInfo, pcbStructInfo, NULL);
2180     }
2181     __EXCEPT_PAGE_FAULT
2182     {
2183         SetLastError(STATUS_ACCESS_VIOLATION);
2184     }
2185     __ENDTRY
2186     TRACE("returning %d\n", ret);
2187     return ret;
2188 }
2189 
2190 /* Ignores tag.  Only allows integers 4 bytes or smaller in size. */
2191 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2192  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2193  void *pvStructInfo, DWORD *pcbStructInfo)
2194 {
2195     BOOL ret;
2196     DWORD dataLen;
2197 
2198     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2199     {
2200         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2201 
2202         if (dataLen > sizeof(int))
2203         {
2204             SetLastError(CRYPT_E_ASN1_LARGE);
2205             ret = FALSE;
2206         }
2207         else if (!pvStructInfo)
2208             *pcbStructInfo = sizeof(int);
2209         else if (*pcbStructInfo < sizeof(int))
2210         {
2211             *pcbStructInfo = sizeof(int);
2212             SetLastError(ERROR_MORE_DATA);
2213             ret = FALSE;
2214         }
2215         else
2216         {
2217             int val;
2218             DWORD i;
2219 
2220             *pcbStructInfo = sizeof(int);
2221             if (dataLen && pbEncoded[1 + lenBytes] & 0x80)
2222             {
2223                 /* initialize to a negative value to sign-extend */
2224                 val = -1;
2225             }
2226             else
2227                 val = 0;
2228             for (i = 0; i < dataLen; i++)
2229             {
2230                 val <<= 8;
2231                 val |= pbEncoded[1 + lenBytes + i];
2232             }
2233             memcpy(pvStructInfo, &val, sizeof(int));
2234         }
2235     }
2236     return ret;
2237 }
2238 
2239 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2240  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2241  void *pvStructInfo, DWORD *pcbStructInfo)
2242 {
2243     BOOL ret = FALSE;
2244 
2245     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2246      pvStructInfo, *pcbStructInfo);
2247 
2248     __TRY
2249     {
2250         struct AsnDecodeSequenceItem items[] = {
2251          { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2252            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2253            offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2254          { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2255            CRYPT_AsnDecodeInt, FINALMEMBERSIZE(CAT_MEMBERINFO, dwCertVersion),
2256            FALSE, FALSE, 0, 0 },
2257         };
2258 
2259         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2260          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2261          pvStructInfo, pcbStructInfo, NULL);
2262     }
2263     __EXCEPT_PAGE_FAULT
2264     {
2265         SetLastError(STATUS_ACCESS_VIOLATION);
2266     }
2267     __ENDTRY
2268     TRACE("returning %d\n", ret);
2269     return ret;
2270 }
2271 
2272 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2273  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2274  void *pvStructInfo, DWORD *pcbStructInfo)
2275 {
2276     BOOL ret = FALSE;
2277 
2278     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2279      pvStructInfo, *pcbStructInfo);
2280 
2281     __TRY
2282     {
2283         struct AsnDecodeSequenceItem items[] = {
2284          { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2285            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2286            offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2287          { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2288            CRYPT_AsnDecodeInt, MEMBERSIZE(CAT_NAMEVALUE, fdwFlags, Value),
2289            FALSE, FALSE, 0, 0 },
2290          { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2291            CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2292            offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2293         };
2294 
2295         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2296          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2297          pvStructInfo, pcbStructInfo, NULL);
2298     }
2299     __EXCEPT_PAGE_FAULT
2300     {
2301         SetLastError(STATUS_ACCESS_VIOLATION);
2302     }
2303     __ENDTRY
2304     TRACE("returning %d\n", ret);
2305     return ret;
2306 }
2307 
2308 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
2309  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2310  void *pvStructInfo, DWORD *pcbStructInfo)
2311 {
2312     BOOL ret;
2313 
2314     if (cbEncoded < 3)
2315     {
2316         SetLastError(CRYPT_E_ASN1_CORRUPT);
2317         return FALSE;
2318     }
2319     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2320     {
2321         SetLastError(CRYPT_E_ASN1_CORRUPT);
2322         return FALSE;
2323     }
2324     if (pbEncoded[1] > 1)
2325     {
2326         SetLastError(CRYPT_E_ASN1_CORRUPT);
2327         return FALSE;
2328     }
2329     if (!pvStructInfo)
2330     {
2331         *pcbStructInfo = sizeof(BOOL);
2332         ret = TRUE;
2333     }
2334     else if (*pcbStructInfo < sizeof(BOOL))
2335     {
2336         *pcbStructInfo = sizeof(BOOL);
2337         SetLastError(ERROR_MORE_DATA);
2338         ret = FALSE;
2339     }
2340     else
2341     {
2342         *pcbStructInfo = sizeof(BOOL);
2343         *(BOOL *)pvStructInfo = pbEncoded[2] != 0;
2344         ret = TRUE;
2345     }
2346     TRACE("returning %d (%08x)\n", ret, GetLastError());
2347     return ret;
2348 }
2349 
2350 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType,
2351  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2352  void *pvStructInfo, DWORD *pcbStructInfo)
2353 {
2354     BOOL ret = FALSE;
2355 
2356     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2357      pvStructInfo, *pcbStructInfo);
2358 
2359     __TRY
2360     {
2361         struct AsnDecodeSequenceItem items[] = {
2362          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable),
2363            CRYPT_AsnDecodeBool, MEMBERSIZE(SPC_FINANCIAL_CRITERIA,
2364            fFinancialInfoAvailable, fMeetsCriteria), FALSE, FALSE, 0, 0 },
2365          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria),
2366            CRYPT_AsnDecodeBool, FINALMEMBERSIZE(SPC_FINANCIAL_CRITERIA,
2367            fMeetsCriteria), FALSE, FALSE, 0, 0 },
2368         };
2369 
2370         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2371          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2372          pvStructInfo, pcbStructInfo, NULL);
2373     }
2374     __EXCEPT_PAGE_FAULT
2375     {
2376         SetLastError(STATUS_ACCESS_VIOLATION);
2377     }
2378     __ENDTRY
2379     TRACE("returning %d\n", ret);
2380     return ret;
2381 }
2382