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