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