jscript: Added SCRIPTITEM_ISVISIBLE flag implementation.
[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 = (const CRYPT_DATA_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 = (const SPC_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 WINAPI 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 = (const CRYPT_BIT_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 =
430      (const struct AsnConstructedItem *)pvStructInfo;
431     DWORD len;
432
433     if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
434      item->pvStructInfo, NULL, &len)))
435     {
436         DWORD dataLen, bytesNeeded;
437
438         CRYPT_EncodeLen(len, NULL, &dataLen);
439         bytesNeeded = 1 + dataLen + len;
440         if (!pbEncoded)
441             *pcbEncoded = bytesNeeded;
442         else if (*pcbEncoded < bytesNeeded)
443         {
444             *pcbEncoded = bytesNeeded;
445             SetLastError(ERROR_MORE_DATA);
446             ret = FALSE;
447         }
448         else
449         {
450             *pcbEncoded = bytesNeeded;
451             *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
452             CRYPT_EncodeLen(len, pbEncoded, &dataLen);
453             pbEncoded += dataLen;
454             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
455              item->pvStructInfo, pbEncoded, &len);
456             if (!ret)
457             {
458                 /* Some functions propagate their errors through the size */
459                 *pcbEncoded = len;
460             }
461         }
462     }
463     else
464     {
465         /* Some functions propagate their errors through the size */
466         *pcbEncoded = len;
467     }
468     return ret;
469 }
470
471
472 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
473  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
474  DWORD *pcbEncoded)
475 {
476     const SPC_PE_IMAGE_DATA *imageData =
477      (const SPC_PE_IMAGE_DATA *)pvStructInfo;
478     BOOL ret = FALSE;
479
480     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
481      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
482      pcbEncoded);
483
484     __TRY
485     {
486         struct AsnEncodeSequenceItem items[2] = {
487          { 0 }
488         };
489         struct AsnConstructedItem constructed = { 0, imageData->pFile,
490          WVTAsn1SpcLinkEncode };
491         DWORD cItem = 0;
492
493         if (imageData->Flags.cbData)
494         {
495             items[cItem].pvStructInfo = &imageData->Flags;
496             items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
497             cItem++;
498         }
499         if (imageData->pFile)
500         {
501             items[cItem].pvStructInfo = &constructed;
502             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
503             cItem++;
504         }
505
506         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
507          pbEncoded, pcbEncoded);
508     }
509     __EXCEPT_PAGE_FAULT
510     {
511         SetLastError(STATUS_ACCESS_VIOLATION);
512     }
513     __ENDTRY
514     TRACE("returning %d\n", ret);
515     return ret;
516 }
517
518 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
519  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
520  DWORD *pcbEncoded)
521 {
522     LPCSTR pszObjId = (LPCSTR)pvStructInfo;
523     DWORD bytesNeeded = 0, lenBytes;
524     BOOL ret = TRUE;
525     int firstPos = 0;
526     BYTE firstByte = 0;
527
528     TRACE("%s\n", debugstr_a(pszObjId));
529
530     if (pszObjId)
531     {
532         const char *ptr;
533         int val1, val2;
534
535         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
536         {
537             SetLastError(CRYPT_E_ASN1_ERROR);
538             return FALSE;
539         }
540         bytesNeeded++;
541         firstByte = val1 * 40 + val2;
542         ptr = pszObjId + firstPos;
543         while (ret && *ptr)
544         {
545             int pos;
546
547             /* note I assume each component is at most 32-bits long in base 2 */
548             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
549             {
550                 if (val1 >= 0x10000000)
551                     bytesNeeded += 5;
552                 else if (val1 >= 0x200000)
553                     bytesNeeded += 4;
554                 else if (val1 >= 0x4000)
555                     bytesNeeded += 3;
556                 else if (val1 >= 0x80)
557                     bytesNeeded += 2;
558                 else
559                     bytesNeeded += 1;
560                 ptr += pos;
561                 if (*ptr == '.')
562                     ptr++;
563             }
564             else
565             {
566                 SetLastError(CRYPT_E_ASN1_ERROR);
567                 return FALSE;
568             }
569         }
570         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
571     }
572     else
573         lenBytes = 1;
574     bytesNeeded += 1 + lenBytes;
575     if (pbEncoded)
576     {
577         if (*pcbEncoded < bytesNeeded)
578         {
579             SetLastError(ERROR_MORE_DATA);
580             ret = FALSE;
581         }
582         else
583         {
584             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
585             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
586             pbEncoded += lenBytes;
587             if (pszObjId)
588             {
589                 const char *ptr;
590                 int val, pos;
591
592                 *pbEncoded++ = firstByte;
593                 ptr = pszObjId + firstPos;
594                 while (ret && *ptr)
595                 {
596                     sscanf(ptr, "%d%n", &val, &pos);
597                     {
598                         unsigned char outBytes[5];
599                         int numBytes, i;
600
601                         if (val >= 0x10000000)
602                             numBytes = 5;
603                         else if (val >= 0x200000)
604                             numBytes = 4;
605                         else if (val >= 0x4000)
606                             numBytes = 3;
607                         else if (val >= 0x80)
608                             numBytes = 2;
609                         else
610                             numBytes = 1;
611                         for (i = numBytes; i > 0; i--)
612                         {
613                             outBytes[i - 1] = val & 0x7f;
614                             val >>= 7;
615                         }
616                         for (i = 0; i < numBytes - 1; i++)
617                             *pbEncoded++ = outBytes[i] | 0x80;
618                         *pbEncoded++ = outBytes[i];
619                         ptr += pos;
620                         if (*ptr == '.')
621                             ptr++;
622                     }
623                 }
624             }
625         }
626     }
627     *pcbEncoded = bytesNeeded;
628     return ret;
629 }
630
631 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
632  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
633  DWORD *pcbEncoded)
634 {
635     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
636     BOOL ret = TRUE;
637
638     if (!pbEncoded)
639         *pcbEncoded = blob->cbData;
640     else if (*pcbEncoded < blob->cbData)
641     {
642         *pcbEncoded = blob->cbData;
643         SetLastError(ERROR_MORE_DATA);
644         ret = FALSE;
645     }
646     else
647     {
648         if (blob->cbData)
649             memcpy(pbEncoded, blob->pbData, blob->cbData);
650         *pcbEncoded = blob->cbData;
651     }
652     return ret;
653 }
654
655 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
656  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
657  BYTE *pbEncoded, DWORD *pcbEncoded)
658 {
659     const CRYPT_ALGORITHM_IDENTIFIER *algo =
660      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
661     static const BYTE asn1Null[] = { ASN_NULL, 0 };
662     static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
663      (LPBYTE)asn1Null };
664     BOOL ret;
665     struct AsnEncodeSequenceItem items[2] = {
666      { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
667      { NULL,           CRYPT_CopyEncodedBlob, 0 },
668     };
669
670     if (algo->Parameters.cbData)
671         items[1].pvStructInfo = &algo->Parameters;
672     else
673         items[1].pvStructInfo = &nullBlob;
674     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
675      sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
676     return ret;
677 }
678
679 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
680  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
681  DWORD *pcbEncoded)
682 {
683     const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
684      (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
685     struct AsnEncodeSequenceItem items[] = {
686      { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
687      { &typeValue->Value,    CRYPT_CopyEncodedBlob, 0 },
688     };
689
690     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
691      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
692 }
693
694 struct SPCDigest
695 {
696     CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
697     CRYPT_HASH_BLOB            Digest;
698 };
699
700 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
701  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
702  DWORD *pcbEncoded)
703 {
704     const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
705     struct AsnEncodeSequenceItem items[] = {
706      { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
707      { &digest->Digest,          CRYPT_CopyEncodedBlob, 0 },
708     };
709
710     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
711      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
712 }
713
714 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
715  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
716  DWORD *pcbEncoded)
717 {
718     BOOL ret = FALSE;
719
720     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
721      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
722
723     __TRY
724     {
725         const SPC_INDIRECT_DATA_CONTENT *data =
726          (const SPC_INDIRECT_DATA_CONTENT *)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 = (LPCWSTR)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 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
783  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
784  DWORD *pcbEncoded)
785 {
786     BOOL ret;
787
788     __TRY
789     {
790         DWORD significantBytes, lenBytes, bytesNeeded;
791         BYTE padByte = 0;
792         BOOL pad = FALSE;
793         const CRYPT_INTEGER_BLOB *blob =
794          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
795
796         significantBytes = blob->cbData;
797         if (significantBytes)
798         {
799             if (blob->pbData[significantBytes - 1] & 0x80)
800             {
801                 /* negative, lop off leading (little-endian) 0xffs */
802                 for (; significantBytes > 0 &&
803                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
804                     ;
805                 if (blob->pbData[significantBytes - 1] < 0x80)
806                 {
807                     padByte = 0xff;
808                     pad = TRUE;
809                 }
810             }
811             else
812             {
813                 /* positive, lop off leading (little-endian) zeroes */
814                 for (; significantBytes > 0 &&
815                  !blob->pbData[significantBytes - 1]; significantBytes--)
816                     ;
817                 if (significantBytes == 0)
818                     significantBytes = 1;
819                 if (blob->pbData[significantBytes - 1] > 0x7f)
820                 {
821                     padByte = 0;
822                     pad = TRUE;
823                 }
824             }
825         }
826         if (pad)
827             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
828         else
829             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
830         bytesNeeded = 1 + lenBytes + significantBytes;
831         if (pad)
832             bytesNeeded++;
833         if (!pbEncoded)
834         {
835             *pcbEncoded = bytesNeeded;
836             ret = TRUE;
837         }
838         else if (*pcbEncoded < bytesNeeded)
839         {
840             *pcbEncoded = bytesNeeded;
841             SetLastError(ERROR_MORE_DATA);
842             ret = FALSE;
843         }
844         else
845         {
846             *pcbEncoded = bytesNeeded;
847             *pbEncoded++ = ASN_INTEGER;
848             if (pad)
849             {
850                 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
851                 pbEncoded += lenBytes;
852                 *pbEncoded++ = padByte;
853             }
854             else
855             {
856                 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
857                 pbEncoded += lenBytes;
858             }
859             for (; significantBytes > 0; significantBytes--)
860                 *(pbEncoded++) = blob->pbData[significantBytes - 1];
861             ret = TRUE;
862         }
863     }
864     __EXCEPT_PAGE_FAULT
865     {
866         SetLastError(STATUS_ACCESS_VIOLATION);
867         ret = FALSE;
868     }
869     __ENDTRY
870     return ret;
871 }
872
873 BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
874  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
875  DWORD *pcbEncoded)
876 {
877     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
878
879     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
880      &blob, pbEncoded, pcbEncoded);
881 }
882
883 BOOL WINAPI WVTAsn1CatMemberInfoEncode(DWORD dwCertEncodingType,
884  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
885  DWORD *pcbEncoded)
886 {
887     BOOL ret = FALSE;
888
889     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
890      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
891
892     __TRY
893     {
894         const CAT_MEMBERINFO *info = (const CAT_MEMBERINFO *)pvStructInfo;
895         struct AsnEncodeSequenceItem items[] = {
896          { info->pwszSubjGuid, CRYPT_AsnEncodeBMPString, 0 },
897          { &info->dwCertVersion, CRYPT_AsnEncodeInt, 0 },
898         };
899
900         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
901          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
902     }
903     __EXCEPT_PAGE_FAULT
904     {
905         SetLastError(STATUS_ACCESS_VIOLATION);
906     }
907     __ENDTRY
908     return ret;
909 }
910
911 BOOL WINAPI WVTAsn1CatNameValueEncode(DWORD dwCertEncodingType,
912  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
913  DWORD *pcbEncoded)
914 {
915     BOOL ret = FALSE;
916
917     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
918      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
919
920     __TRY
921     {
922         const CAT_NAMEVALUE *value = (const CAT_NAMEVALUE *)pvStructInfo;
923         struct AsnEncodeSequenceItem items[] = {
924          { value->pwszTag,   CRYPT_AsnEncodeBMPString, 0 },
925          { &value->fdwFlags, CRYPT_AsnEncodeInt, 0 },
926          { &value->Value,    CRYPT_AsnEncodeOctets, 0 },
927         };
928
929         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
930          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
931     }
932     __EXCEPT_PAGE_FAULT
933     {
934         SetLastError(STATUS_ACCESS_VIOLATION);
935     }
936     __ENDTRY
937     return ret;
938 }
939
940 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
941  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
942  DWORD *pcbEncoded)
943 {
944     BOOL val = *(const BOOL *)pvStructInfo, ret;
945
946     TRACE("%d\n", val);
947
948     if (!pbEncoded)
949     {
950         *pcbEncoded = 3;
951         ret = TRUE;
952     }
953     else if (*pcbEncoded < 3)
954     {
955         *pcbEncoded = 3;
956         SetLastError(ERROR_MORE_DATA);
957         ret = FALSE;
958     }
959     else
960     {
961         *pcbEncoded = 3;
962         *pbEncoded++ = ASN_BOOL;
963         *pbEncoded++ = 1;
964         *pbEncoded++ = val ? 0xff : 0;
965         ret = TRUE;
966     }
967     TRACE("returning %d (%08x)\n", ret, GetLastError());
968     return ret;
969 }
970
971 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoEncode(DWORD dwCertEncodingType,
972  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
973  DWORD *pcbEncoded)
974 {
975     BOOL ret = FALSE;
976
977     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
978      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
979
980     __TRY
981     {
982         const SPC_FINANCIAL_CRITERIA *criteria = pvStructInfo;
983         struct AsnEncodeSequenceItem items[] = {
984          { &criteria->fFinancialInfoAvailable, CRYPT_AsnEncodeBool, 0 },
985          { &criteria->fMeetsCriteria,          CRYPT_AsnEncodeBool, 0 },
986         };
987
988         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
989          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
990     }
991     __EXCEPT_PAGE_FAULT
992     {
993         SetLastError(STATUS_ACCESS_VIOLATION);
994     }
995     __ENDTRY
996     return ret;
997 }
998
999 /* Gets the number of length bytes from the given (leading) length byte */
1000 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1001
1002 /* Helper function to get the encoded length of the data starting at pbEncoded,
1003  * where pbEncoded[0] is the tag.  If the data are too short to contain a
1004  * length or if the length is too large for cbEncoded, sets an appropriate
1005  * error code and returns FALSE.
1006  */
1007 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
1008 {
1009     BOOL ret;
1010
1011     if (cbEncoded <= 1)
1012     {
1013         SetLastError(CRYPT_E_ASN1_CORRUPT);
1014         ret = FALSE;
1015     }
1016     else if (pbEncoded[1] <= 0x7f)
1017     {
1018         if (pbEncoded[1] + 1 > cbEncoded)
1019         {
1020             SetLastError(CRYPT_E_ASN1_EOD);
1021             ret = FALSE;
1022         }
1023         else
1024         {
1025             *len = pbEncoded[1];
1026             ret = TRUE;
1027         }
1028     }
1029     else if (pbEncoded[1] == 0x80)
1030     {
1031         FIXME("unimplemented for indefinite-length encoding\n");
1032         SetLastError(CRYPT_E_ASN1_CORRUPT);
1033         ret = FALSE;
1034     }
1035     else
1036     {
1037         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1038
1039         if (lenLen > sizeof(DWORD) + 1)
1040         {
1041             SetLastError(CRYPT_E_ASN1_LARGE);
1042             ret = FALSE;
1043         }
1044         else if (lenLen + 2 > cbEncoded)
1045         {
1046             SetLastError(CRYPT_E_ASN1_CORRUPT);
1047             ret = FALSE;
1048         }
1049         else
1050         {
1051             DWORD out = 0;
1052
1053             pbEncoded += 2;
1054             while (--lenLen)
1055             {
1056                 out <<= 8;
1057                 out |= *pbEncoded++;
1058             }
1059             if (out + lenLen + 1 > cbEncoded)
1060             {
1061                 SetLastError(CRYPT_E_ASN1_EOD);
1062                 ret = FALSE;
1063             }
1064             else
1065             {
1066                 *len = out;
1067                 ret = TRUE;
1068             }
1069         }
1070     }
1071     return ret;
1072 }
1073
1074 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1075  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1076  void *pvStructInfo, DWORD *pcbStructInfo)
1077 {
1078     BOOL ret;
1079     DWORD bytesNeeded, dataLen;
1080
1081     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1082      pvStructInfo, *pcbStructInfo);
1083
1084     if (!cbEncoded)
1085     {
1086         SetLastError(CRYPT_E_ASN1_CORRUPT);
1087         ret = FALSE;
1088     }
1089     else if (pbEncoded[0] != ASN_OCTETSTRING)
1090     {
1091         SetLastError(CRYPT_E_ASN1_BADTAG);
1092         ret = FALSE;
1093     }
1094     else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1095     {
1096         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1097             bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1098         else
1099             bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1100         if (!pvStructInfo)
1101             *pcbStructInfo = bytesNeeded;
1102         else if (*pcbStructInfo < bytesNeeded)
1103         {
1104             SetLastError(ERROR_MORE_DATA);
1105             *pcbStructInfo = bytesNeeded;
1106             ret = FALSE;
1107         }
1108         else
1109         {
1110             CRYPT_DATA_BLOB *blob;
1111             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1112
1113             blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1114             blob->cbData = dataLen;
1115             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1116                 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1117             else
1118             {
1119                 assert(blob->pbData);
1120                 if (blob->cbData)
1121                     memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
1122                      blob->cbData);
1123             }
1124         }
1125     }
1126     return ret;
1127 }
1128
1129 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
1130  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1131  void *pvStructInfo, DWORD *pcbStructInfo)
1132 {
1133     BOOL ret = FALSE;
1134     DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
1135
1136     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1137      pvStructInfo, *pcbStructInfo);
1138
1139     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1140     {
1141         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1142         DWORD realDataLen;
1143
1144         switch (pbEncoded[0])
1145         {
1146         case ASN_CONTEXT:
1147             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
1148             if (!pvStructInfo)
1149                 *pcbStructInfo = bytesNeeded;
1150             else if (*pcbStructInfo < bytesNeeded)
1151             {
1152                 *pcbStructInfo = bytesNeeded;
1153                 SetLastError(ERROR_MORE_DATA);
1154                 ret = FALSE;
1155             }
1156             else
1157             {
1158                 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1159                 DWORD i;
1160
1161                 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
1162                 for (i = 0; i < dataLen; i++)
1163                     link->u.pwszUrl[i] =
1164                      *(pbEncoded + 1 + lenBytes + i);
1165                 link->u.pwszUrl[i] = '\0';
1166                 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
1167             }
1168             break;
1169         case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
1170         {
1171             CRYPT_DATA_BLOB classId;
1172             DWORD size = sizeof(classId);
1173
1174             if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1175              pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
1176              CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
1177             {
1178                 if (classId.cbData != sizeof(SPC_UUID))
1179                 {
1180                     SetLastError(CRYPT_E_BAD_ENCODE);
1181                     ret = FALSE;
1182                 }
1183                 else
1184                 {
1185                     CRYPT_DATA_BLOB data;
1186
1187                     /* The tag length for the classId must be 1 since the
1188                      * length is correct.
1189                      */
1190                     size = sizeof(data);
1191                     if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1192                      pbEncoded + 3 + lenBytes + classId.cbData,
1193                      cbEncoded - 3 - lenBytes - classId.cbData,
1194                      CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
1195                     {
1196                         bytesNeeded += data.cbData;
1197                         if (!pvStructInfo)
1198                             *pcbStructInfo = bytesNeeded;
1199                         else if (*pcbStructInfo < bytesNeeded)
1200                         {
1201                             *pcbStructInfo = bytesNeeded;
1202                             SetLastError(ERROR_MORE_DATA);
1203                             ret = FALSE;
1204                         }
1205                         else
1206                         {
1207                             PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1208
1209                             link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
1210                             /* pwszFile pointer was set by caller, copy it
1211                              * before overwriting it
1212                              */
1213                             link->u.Moniker.SerializedData.pbData =
1214                              (BYTE *)link->u.pwszFile;
1215                             memcpy(link->u.Moniker.ClassId, classId.pbData,
1216                              classId.cbData);
1217                             memcpy(link->u.Moniker.SerializedData.pbData,
1218                              data.pbData, data.cbData);
1219                             link->u.Moniker.SerializedData.cbData = data.cbData;
1220                         }
1221                     }
1222                 }
1223             }
1224             break;
1225         }
1226         case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
1227             if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
1228                 SetLastError(CRYPT_E_ASN1_BADTAG);
1229             else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
1230              &realDataLen)))
1231             {
1232                 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
1233
1234                 bytesNeeded += realDataLen + sizeof(WCHAR);
1235                 if (!pvStructInfo)
1236                     *pcbStructInfo = bytesNeeded;
1237                 else if (*pcbStructInfo < bytesNeeded)
1238                 {
1239                     *pcbStructInfo = bytesNeeded;
1240                     SetLastError(ERROR_MORE_DATA);
1241                     ret = FALSE;
1242                 }
1243                 else
1244                 {
1245                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1246                     DWORD i;
1247                     const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
1248
1249                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1250                     for (i = 0; i < dataLen / sizeof(WCHAR); i++)
1251                         link->u.pwszFile[i] =
1252                          hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
1253                     link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
1254                     TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
1255                 }
1256             }
1257             else
1258             {
1259                 bytesNeeded += sizeof(WCHAR);
1260                 if (!pvStructInfo)
1261                     *pcbStructInfo = bytesNeeded;
1262                 else if (*pcbStructInfo < bytesNeeded)
1263                 {
1264                     *pcbStructInfo = bytesNeeded;
1265                     SetLastError(ERROR_MORE_DATA);
1266                     ret = FALSE;
1267                 }
1268                 else
1269                 {
1270                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1271
1272                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1273                     link->u.pwszFile[0] = '\0';
1274                     ret = TRUE;
1275                 }
1276             }
1277             break;
1278         default:
1279             SetLastError(CRYPT_E_ASN1_BADTAG);
1280         }
1281     }
1282     TRACE("returning %d\n", ret);
1283     return ret;
1284 }
1285
1286 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1287  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1288  void *pvStructInfo, DWORD *pcbStructInfo)
1289 {
1290     BOOL ret = FALSE;
1291
1292     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1293      pvStructInfo, *pcbStructInfo);
1294
1295     __TRY
1296     {
1297         DWORD bytesNeeded;
1298
1299         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1300          lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1301         if (ret)
1302         {
1303             if (!pvStructInfo)
1304                 *pcbStructInfo = bytesNeeded;
1305             else if (*pcbStructInfo < bytesNeeded)
1306             {
1307                 *pcbStructInfo = bytesNeeded;
1308                 SetLastError(ERROR_MORE_DATA);
1309                 ret = FALSE;
1310             }
1311             else
1312             {
1313                 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1314
1315                 link->u.pwszFile =
1316                  (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1317                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1318                  lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1319                  pcbStructInfo);
1320             }
1321         }
1322     }
1323     __EXCEPT_PAGE_FAULT
1324     {
1325         SetLastError(STATUS_ACCESS_VIOLATION);
1326     }
1327     __ENDTRY
1328     TRACE("returning %d\n", ret);
1329     return ret;
1330 }
1331
1332 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1333  DWORD, DWORD, void *, DWORD *);
1334
1335 /* tag:
1336  *     The expected tag of the item.  If tag is 0, decodeFunc is called
1337  *     regardless of the tag value seen.
1338  * offset:
1339  *     A sequence is decoded into a struct.  The offset member is the
1340  *     offset of this item within that struct.
1341  * decodeFunc:
1342  *     The decoder function to use.  If this is NULL, then the member isn't
1343  *     decoded, but minSize space is reserved for it.
1344  * minSize:
1345  *     The minimum amount of space occupied after decoding.  You must set this.
1346  * optional:
1347  *     If true, and the tag doesn't match the expected tag for this item,
1348  *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1349  *     filled with 0 for this member.
1350  * hasPointer, pointerOffset:
1351  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1352  *     the offset within the struct of the data pointer (or to the
1353  *     first data pointer, if more than one exist).
1354  * size:
1355  *     Used by CRYPT_AsnDecodeSequence, not for your use.
1356  */
1357 struct AsnDecodeSequenceItem
1358 {
1359     BYTE                  tag;
1360     DWORD                 offset;
1361     CryptDecodeObjectFunc decodeFunc;
1362     DWORD                 minSize;
1363     BOOL                  optional;
1364     BOOL                  hasPointer;
1365     DWORD                 pointerOffset;
1366     DWORD                 size;
1367 };
1368
1369 /* Decodes the items in a sequence, where the items are described in items,
1370  * the encoded data are in pbEncoded with length cbEncoded.  Decodes into
1371  * pvStructInfo.  nextData is a pointer to the memory location at which the
1372  * first decoded item with a dynamic pointer should point.
1373  * Upon decoding, *cbDecoded is the total number of bytes decoded.
1374  */
1375 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1376  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1377  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1378  DWORD *cbDecoded)
1379 {
1380     BOOL ret;
1381     DWORD i, decoded = 0;
1382     const BYTE *ptr = pbEncoded;
1383
1384     TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1385      cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1386
1387     for (i = 0, ret = TRUE; ret && i < cItem; i++)
1388     {
1389         if (cbEncoded - (ptr - pbEncoded) != 0)
1390         {
1391             DWORD nextItemLen;
1392
1393             if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1394              &nextItemLen)))
1395             {
1396                 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1397
1398                 if (ptr[0] == items[i].tag || !items[i].tag)
1399                 {
1400                     if (nextData && pvStructInfo && items[i].hasPointer)
1401                     {
1402                         TRACE("Setting next pointer to %p\n",
1403                          nextData);
1404                         *(BYTE **)((BYTE *)pvStructInfo +
1405                          items[i].pointerOffset) = nextData;
1406                     }
1407                     if (items[i].decodeFunc)
1408                     {
1409                         if (pvStructInfo)
1410                             TRACE("decoding item %d\n", i);
1411                         else
1412                             TRACE("sizing item %d\n", i);
1413                         ret = items[i].decodeFunc(dwCertEncodingType,
1414                          NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1415                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1416                          pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
1417                          : NULL, &items[i].size);
1418                         if (ret)
1419                         {
1420                             /* Account for alignment padding */
1421                             if (items[i].size % sizeof(DWORD))
1422                                 items[i].size += sizeof(DWORD) -
1423                                  items[i].size % sizeof(DWORD);
1424                             TRACE("item %d size: %d\n", i, items[i].size);
1425                             if (nextData && items[i].hasPointer &&
1426                              items[i].size > items[i].minSize)
1427                                 nextData += items[i].size - items[i].minSize;
1428                             ptr += 1 + nextItemLenBytes + nextItemLen;
1429                             decoded += 1 + nextItemLenBytes + nextItemLen;
1430                             TRACE("item %d: decoded %d bytes\n", i,
1431                              1 + nextItemLenBytes + nextItemLen);
1432                         }
1433                         else if (items[i].optional &&
1434                          GetLastError() == CRYPT_E_ASN1_BADTAG)
1435                         {
1436                             TRACE("skipping optional item %d\n", i);
1437                             items[i].size = items[i].minSize;
1438                             SetLastError(NOERROR);
1439                             ret = TRUE;
1440                         }
1441                         else
1442                             TRACE("item %d failed: %08x\n", i,
1443                              GetLastError());
1444                     }
1445                     else
1446                     {
1447                         TRACE("item %d: decoded %d bytes\n", i,
1448                          1 + nextItemLenBytes + nextItemLen);
1449                         ptr += 1 + nextItemLenBytes + nextItemLen;
1450                         decoded += 1 + nextItemLenBytes + nextItemLen;
1451                         items[i].size = items[i].minSize;
1452                     }
1453                 }
1454                 else if (items[i].optional)
1455                 {
1456                     TRACE("skipping optional item %d\n", i);
1457                     items[i].size = items[i].minSize;
1458                 }
1459                 else
1460                 {
1461                     TRACE("item %d: tag %02x doesn't match expected %02x\n",
1462                      i, ptr[0], items[i].tag);
1463                     SetLastError(CRYPT_E_ASN1_BADTAG);
1464                     ret = FALSE;
1465                 }
1466             }
1467         }
1468         else if (items[i].optional)
1469         {
1470             TRACE("missing optional item %d, skipping\n", i);
1471             items[i].size = items[i].minSize;
1472         }
1473         else
1474         {
1475             TRACE("not enough bytes for item %d, failing\n", i);
1476             SetLastError(CRYPT_E_ASN1_CORRUPT);
1477             ret = FALSE;
1478         }
1479     }
1480     if (ret)
1481         *cbDecoded = decoded;
1482     TRACE("returning %d\n", ret);
1483     return ret;
1484 }
1485
1486 /* This decodes an arbitrary sequence into a contiguous block of memory
1487  * (basically, a struct.)  Each element being decoded is described by a struct
1488  * AsnDecodeSequenceItem, see above.
1489  * startingPointer is an optional pointer to the first place where dynamic
1490  * data will be stored.  If you know the starting offset, you may pass it
1491  * here.  Otherwise, pass NULL, and one will be inferred from the items.
1492  */
1493 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1494  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1495  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1496  void *startingPointer)
1497 {
1498     BOOL ret;
1499
1500     TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1501      cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1502
1503     if (pbEncoded[0] == ASN_SEQUENCE)
1504     {
1505         DWORD dataLen;
1506
1507         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1508         {
1509             DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1510             const BYTE *ptr = pbEncoded + 1 + lenBytes;
1511
1512             cbEncoded -= 1 + lenBytes;
1513             if (cbEncoded < dataLen)
1514             {
1515                 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1516                  cbEncoded);
1517                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1518                 ret = FALSE;
1519             }
1520             else
1521                 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1522                  cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1523             if (ret && cbDecoded != dataLen)
1524             {
1525                 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1526                  cbDecoded);
1527                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1528                 ret = FALSE;
1529             }
1530             if (ret)
1531             {
1532                 DWORD i, bytesNeeded = 0, structSize = 0;
1533
1534                 for (i = 0; i < cItem; i++)
1535                 {
1536                     bytesNeeded += items[i].size;
1537                     structSize += items[i].minSize;
1538                 }
1539                 if (!pvStructInfo)
1540                     *pcbStructInfo = bytesNeeded;
1541                 else if (*pcbStructInfo < bytesNeeded)
1542                 {
1543                     SetLastError(ERROR_MORE_DATA);
1544                     *pcbStructInfo = bytesNeeded;
1545                     ret = FALSE;
1546                 }
1547                 else
1548                 {
1549                     BYTE *nextData;
1550
1551                     *pcbStructInfo = bytesNeeded;
1552                     if (startingPointer)
1553                         nextData = (BYTE *)startingPointer;
1554                     else
1555                         nextData = (BYTE *)pvStructInfo + structSize;
1556                     memset(pvStructInfo, 0, structSize);
1557                     ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1558                      ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1559                      &cbDecoded);
1560                 }
1561             }
1562         }
1563     }
1564     else
1565     {
1566         SetLastError(CRYPT_E_ASN1_BADTAG);
1567         ret = FALSE;
1568     }
1569     TRACE("returning %d (%08x)\n", ret, GetLastError());
1570     return ret;
1571 }
1572
1573 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1574  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1575  void *pvStructInfo, DWORD *pcbStructInfo)
1576 {
1577     BOOL ret;
1578
1579     TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1580      pvStructInfo, *pcbStructInfo);
1581
1582     if (pbEncoded[0] == ASN_BITSTRING)
1583     {
1584         DWORD bytesNeeded, dataLen;
1585
1586         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1587         {
1588             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1589                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1590             else
1591                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1592             if (!pvStructInfo)
1593                 *pcbStructInfo = bytesNeeded;
1594             else if (*pcbStructInfo < bytesNeeded)
1595             {
1596                 *pcbStructInfo = bytesNeeded;
1597                 SetLastError(ERROR_MORE_DATA);
1598                 ret = FALSE;
1599             }
1600             else
1601             {
1602                 CRYPT_BIT_BLOB *blob;
1603
1604                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1605                 blob->cbData = dataLen - 1;
1606                 blob->cUnusedBits = *(pbEncoded + 1 +
1607                  GET_LEN_BYTES(pbEncoded[1]));
1608                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1609                 {
1610                     blob->pbData = (BYTE *)pbEncoded + 2 +
1611                      GET_LEN_BYTES(pbEncoded[1]);
1612                 }
1613                 else
1614                 {
1615                     assert(blob->pbData);
1616                     if (blob->cbData)
1617                     {
1618                         BYTE mask = 0xff << blob->cUnusedBits;
1619
1620                         memcpy(blob->pbData, pbEncoded + 2 +
1621                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1622                         blob->pbData[blob->cbData - 1] &= mask;
1623                     }
1624                 }
1625             }
1626         }
1627     }
1628     else
1629     {
1630         SetLastError(CRYPT_E_ASN1_BADTAG);
1631         ret = FALSE;
1632     }
1633     TRACE("returning %d (%08x)\n", ret, GetLastError());
1634     return ret;
1635 }
1636
1637 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1638  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1639  void *pvStructInfo, DWORD *pcbStructInfo)
1640 {
1641     BOOL ret = FALSE;
1642     DWORD dataLen;
1643
1644     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1645     {
1646         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1647         DWORD size;
1648         SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1649
1650         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1651          pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1652         if (ret)
1653         {
1654             if (!pvStructInfo)
1655                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1656             else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1657             {
1658                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1659                 SetLastError(ERROR_MORE_DATA);
1660                 ret = FALSE;
1661             }
1662             else
1663             {
1664                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1665                 /* Set imageData's pointer if necessary */
1666                 if (size > sizeof(SPC_LINK))
1667                 {
1668                     (*pLink)->u.pwszUrl =
1669                      (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1670                 }
1671                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1672                  lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1673                  *pLink, pcbStructInfo);
1674             }
1675         }
1676     }
1677     return ret;
1678 }
1679
1680 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1681  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1682  void *pvStructInfo, DWORD *pcbStructInfo)
1683 {
1684     BOOL ret = FALSE;
1685
1686     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1687      pvStructInfo, *pcbStructInfo);
1688
1689     __TRY
1690     {
1691         struct AsnDecodeSequenceItem items[] = {
1692          { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1693            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1694            offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1695          { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1696            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1697            offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1698         };
1699
1700         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1701          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1702          pvStructInfo, pcbStructInfo, NULL);
1703     }
1704     __EXCEPT_PAGE_FAULT
1705     {
1706         SetLastError(STATUS_ACCESS_VIOLATION);
1707     }
1708     __ENDTRY
1709     TRACE("returning %d\n", ret);
1710     return ret;
1711 }
1712
1713 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1714  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1715  void *pvStructInfo, DWORD *pcbStructInfo)
1716 {
1717     BOOL ret = TRUE;
1718     DWORD dataLen;
1719
1720     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1721      pvStructInfo, *pcbStructInfo);
1722
1723     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1724     {
1725         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1726         DWORD bytesNeeded = sizeof(LPSTR);
1727
1728         if (dataLen)
1729         {
1730             /* The largest possible string for the first two components
1731              * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1732              */
1733             char firstTwo[6];
1734             const BYTE *ptr;
1735
1736             snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1737              pbEncoded[1 + lenBytes] / 40,
1738              pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1739              * 40);
1740             bytesNeeded += strlen(firstTwo) + 1;
1741             for (ptr = pbEncoded + 2 + lenBytes; ret &&
1742              ptr - pbEncoded - 1 - lenBytes < dataLen; )
1743             {
1744                 /* large enough for ".4000000" */
1745                 char str[9];
1746                 int val = 0;
1747
1748                 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1749                  (*ptr & 0x80))
1750                 {
1751                     val <<= 7;
1752                     val |= *ptr & 0x7f;
1753                     ptr++;
1754                 }
1755                 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1756                  (*ptr & 0x80))
1757                 {
1758                     SetLastError(CRYPT_E_ASN1_CORRUPT);
1759                     ret = FALSE;
1760                 }
1761                 else
1762                 {
1763                     val <<= 7;
1764                     val |= *ptr++;
1765                     snprintf(str, sizeof(str), ".%d", val);
1766                     bytesNeeded += strlen(str);
1767                 }
1768             }
1769         }
1770         if (!pvStructInfo)
1771             *pcbStructInfo = bytesNeeded;
1772         else if (*pcbStructInfo < bytesNeeded)
1773         {
1774             *pcbStructInfo = bytesNeeded;
1775             SetLastError(ERROR_MORE_DATA);
1776             ret = FALSE;
1777         }
1778         else
1779         {
1780             if (dataLen)
1781             {
1782                 const BYTE *ptr;
1783                 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1784
1785                 *pszObjId = 0;
1786                 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1787                  pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1788                  40) * 40);
1789                 pszObjId += strlen(pszObjId);
1790                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1791                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
1792                 {
1793                     int val = 0;
1794
1795                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1796                      (*ptr & 0x80))
1797                     {
1798                         val <<= 7;
1799                         val |= *ptr & 0x7f;
1800                         ptr++;
1801                     }
1802                     val <<= 7;
1803                     val |= *ptr++;
1804                     sprintf(pszObjId, ".%d", val);
1805                     pszObjId += strlen(pszObjId);
1806                 }
1807             }
1808             else
1809                 *(LPSTR *)pvStructInfo = NULL;
1810             *pcbStructInfo = bytesNeeded;
1811         }
1812     }
1813     return ret;
1814 }
1815
1816 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1817  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1818  void *pvStructInfo, DWORD *pcbStructInfo)
1819 {
1820     BOOL ret = FALSE;
1821
1822     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1823      pvStructInfo, *pcbStructInfo);
1824
1825     if (!cbEncoded)
1826         SetLastError(CRYPT_E_ASN1_CORRUPT);
1827     else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1828         ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1829          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1830     else
1831         SetLastError(CRYPT_E_ASN1_BADTAG);
1832     return ret;
1833 }
1834
1835 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1836  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1837  void *pvStructInfo, DWORD *pcbStructInfo)
1838 {
1839     BOOL ret = TRUE;
1840     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1841
1842     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1843      pvStructInfo, *pcbStructInfo);
1844
1845     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1846         bytesNeeded += cbEncoded;
1847     if (!pvStructInfo)
1848         *pcbStructInfo = bytesNeeded;
1849     else if (*pcbStructInfo < bytesNeeded)
1850     {
1851         SetLastError(ERROR_MORE_DATA);
1852         *pcbStructInfo = bytesNeeded;
1853         ret = FALSE;
1854     }
1855     else
1856     {
1857         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1858
1859         *pcbStructInfo = bytesNeeded;
1860         blob->cbData = cbEncoded;
1861         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1862             blob->pbData = (LPBYTE)pbEncoded;
1863         else
1864         {
1865             assert(blob->pbData);
1866             memcpy(blob->pbData, pbEncoded, blob->cbData);
1867         }
1868     }
1869     return ret;
1870 }
1871
1872 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1873  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1874  void *pvStructInfo, DWORD *pcbStructInfo)
1875 {
1876     CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1877      (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1878     struct AsnDecodeSequenceItem items[] = {
1879      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1880        CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1881        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1882      { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1883        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1884        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1885     };
1886
1887     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1888      pvStructInfo, *pcbStructInfo);
1889
1890     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1891      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1892      pvStructInfo, pcbStructInfo,
1893      typeValue ? typeValue->pszObjId : NULL);
1894 }
1895
1896 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1897  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1898  void *pvStructInfo, DWORD *pcbStructInfo)
1899 {
1900     CRYPT_ALGORITHM_IDENTIFIER *algo =
1901      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
1902     BOOL ret = TRUE;
1903     struct AsnDecodeSequenceItem items[] = {
1904      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
1905        CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
1906        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
1907      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
1908        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
1909        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
1910     };
1911
1912     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1913      pvStructInfo, *pcbStructInfo);
1914
1915     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1916      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1917      pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
1918     if (ret && pvStructInfo)
1919     {
1920         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
1921          debugstr_a(algo->pszObjId));
1922     }
1923     return ret;
1924 }
1925
1926 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
1927  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1928  void *pvStructInfo, DWORD *pcbStructInfo)
1929 {
1930     struct SPCDigest *digest =
1931      (struct SPCDigest *)pvStructInfo;
1932     struct AsnDecodeSequenceItem items[] = {
1933      { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
1934        CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
1935        FALSE, TRUE,
1936        offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
1937      { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
1938        CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
1939        FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
1940     };
1941
1942     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1943      pvStructInfo, *pcbStructInfo);
1944
1945     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1946      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1947      pvStructInfo, pcbStructInfo,
1948      digest ? digest->DigestAlgorithm.pszObjId : NULL);
1949 }
1950
1951 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
1952  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1953  void *pvStructInfo, DWORD *pcbStructInfo)
1954 {
1955     BOOL ret = FALSE;
1956
1957     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1958      pvStructInfo, *pcbStructInfo);
1959
1960     __TRY
1961     {
1962         struct AsnDecodeSequenceItem items[] = {
1963          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
1964            CRYPT_AsnDecodeAttributeTypeValue,
1965            sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
1966            offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
1967          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
1968            CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
1969            FALSE, TRUE,
1970            offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
1971         };
1972
1973         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1974          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1975          pvStructInfo, pcbStructInfo, NULL);
1976     }
1977     __EXCEPT_PAGE_FAULT
1978     {
1979         SetLastError(STATUS_ACCESS_VIOLATION);
1980     }
1981     __ENDTRY
1982     TRACE("returning %d\n", ret);
1983     return ret;
1984 }
1985
1986 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
1987  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1988  void *pvStructInfo, DWORD *pcbStructInfo)
1989 {
1990     FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1991      pvStructInfo, *pcbStructInfo);
1992     return FALSE;
1993 }
1994
1995 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
1996  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1997  void *pvStructInfo, DWORD *pcbStructInfo)
1998 {
1999     BOOL ret;
2000     DWORD bytesNeeded, dataLen;
2001
2002     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2003     {
2004         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2005
2006         bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
2007         if (!pvStructInfo)
2008             *pcbStructInfo = bytesNeeded;
2009         else if (*pcbStructInfo < bytesNeeded)
2010         {
2011             *pcbStructInfo = bytesNeeded;
2012             SetLastError(ERROR_MORE_DATA);
2013             ret = FALSE;
2014         }
2015         else
2016         {
2017             LPWSTR str;
2018             DWORD i;
2019
2020             *pcbStructInfo = bytesNeeded;
2021             assert(pvStructInfo);
2022             str = *(LPWSTR *)pvStructInfo;
2023             for (i = 0; i < dataLen / 2; i++)
2024                 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
2025                  pbEncoded[1 + lenBytes + 2 * i + 1];
2026             /* Decoded string is always NULL-terminated */
2027             str[i] = '\0';
2028         }
2029     }
2030     return ret;
2031 }
2032
2033 static BOOL CRYPT_AsnDecodeInteger(const BYTE *pbEncoded,
2034  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo)
2035 {
2036     BOOL ret;
2037     DWORD bytesNeeded, dataLen;
2038
2039     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2040     {
2041         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2042
2043         bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2044         if (!pvStructInfo)
2045             *pcbStructInfo = bytesNeeded;
2046         else if (*pcbStructInfo < bytesNeeded)
2047         {
2048             *pcbStructInfo = bytesNeeded;
2049             SetLastError(ERROR_MORE_DATA);
2050             ret = FALSE;
2051         }
2052         else
2053         {
2054             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2055
2056             *pcbStructInfo = bytesNeeded;
2057             blob->cbData = dataLen;
2058             assert(blob->pbData);
2059             if (blob->cbData)
2060             {
2061                 DWORD i;
2062
2063                 for (i = 0; i < blob->cbData; i++)
2064                 {
2065                     blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2066                      dataLen - i - 1);
2067                 }
2068             }
2069         }
2070     }
2071     return ret;
2072 }
2073
2074 /* Ignores tag.  Only allows integers 4 bytes or smaller in size. */
2075 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2076  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2077  void *pvStructInfo, DWORD *pcbStructInfo)
2078 {
2079     BOOL ret;
2080     BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
2081     CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
2082     DWORD size = sizeof(buf);
2083
2084     blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
2085     ret = CRYPT_AsnDecodeInteger(pbEncoded, cbEncoded, 0, buf, &size);
2086     if (ret)
2087     {
2088         if (!pvStructInfo)
2089             *pcbStructInfo = sizeof(int);
2090         else if (*pcbStructInfo < sizeof(int))
2091         {
2092             *pcbStructInfo = sizeof(int);
2093             SetLastError(ERROR_MORE_DATA);
2094             ret = FALSE;
2095         }
2096         else
2097         {
2098             int val, i;
2099
2100             *pcbStructInfo = sizeof(int);
2101             if (blob->pbData[blob->cbData - 1] & 0x80)
2102             {
2103                 /* initialize to a negative value to sign-extend */
2104                 val = -1;
2105             }
2106             else
2107                 val = 0;
2108             for (i = 0; i < blob->cbData; i++)
2109             {
2110                 val <<= 8;
2111                 val |= blob->pbData[blob->cbData - i - 1];
2112             }
2113             memcpy(pvStructInfo, &val, sizeof(int));
2114         }
2115     }
2116     else if (GetLastError() == ERROR_MORE_DATA)
2117         SetLastError(CRYPT_E_ASN1_LARGE);
2118     return ret;
2119 }
2120
2121 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2122  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2123  void *pvStructInfo, DWORD *pcbStructInfo)
2124 {
2125     BOOL ret = FALSE;
2126
2127     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2128      pvStructInfo, *pcbStructInfo);
2129
2130     __TRY
2131     {
2132         struct AsnDecodeSequenceItem items[] = {
2133          { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2134            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2135            offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2136          { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2137            CRYPT_AsnDecodeInt, sizeof(DWORD),
2138            FALSE, FALSE, 0, 0 },
2139         };
2140
2141         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2142          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2143          pvStructInfo, pcbStructInfo, NULL);
2144     }
2145     __EXCEPT_PAGE_FAULT
2146     {
2147         SetLastError(STATUS_ACCESS_VIOLATION);
2148     }
2149     __ENDTRY
2150     TRACE("returning %d\n", ret);
2151     return ret;
2152 }
2153
2154 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2155  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2156  void *pvStructInfo, DWORD *pcbStructInfo)
2157 {
2158     BOOL ret = FALSE;
2159
2160     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2161      pvStructInfo, *pcbStructInfo);
2162
2163     __TRY
2164     {
2165         struct AsnDecodeSequenceItem items[] = {
2166          { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2167            CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2168            offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2169          { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2170            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
2171          { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2172            CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2173            offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2174         };
2175
2176         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2177          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2178          pvStructInfo, pcbStructInfo, NULL);
2179     }
2180     __EXCEPT_PAGE_FAULT
2181     {
2182         SetLastError(STATUS_ACCESS_VIOLATION);
2183     }
2184     __ENDTRY
2185     TRACE("returning %d\n", ret);
2186     return ret;
2187 }
2188
2189 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
2190  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2191  void *pvStructInfo, DWORD *pcbStructInfo)
2192 {
2193     BOOL ret;
2194
2195     if (cbEncoded < 3)
2196     {
2197         SetLastError(CRYPT_E_ASN1_CORRUPT);
2198         return FALSE;
2199     }
2200     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2201     {
2202         SetLastError(CRYPT_E_ASN1_CORRUPT);
2203         return FALSE;
2204     }
2205     if (pbEncoded[1] > 1)
2206     {
2207         SetLastError(CRYPT_E_ASN1_CORRUPT);
2208         return FALSE;
2209     }
2210     if (!pvStructInfo)
2211     {
2212         *pcbStructInfo = sizeof(BOOL);
2213         ret = TRUE;
2214     }
2215     else if (*pcbStructInfo < sizeof(BOOL))
2216     {
2217         *pcbStructInfo = sizeof(BOOL);
2218         SetLastError(ERROR_MORE_DATA);
2219         ret = FALSE;
2220     }
2221     else
2222     {
2223         *pcbStructInfo = sizeof(BOOL);
2224         *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
2225         ret = TRUE;
2226     }
2227     TRACE("returning %d (%08x)\n", ret, GetLastError());
2228     return ret;
2229 }
2230
2231 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType,
2232  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2233  void *pvStructInfo, DWORD *pcbStructInfo)
2234 {
2235     BOOL ret = FALSE;
2236
2237     TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2238      pvStructInfo, *pcbStructInfo);
2239
2240     __TRY
2241     {
2242         struct AsnDecodeSequenceItem items[] = {
2243          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable),
2244            CRYPT_AsnDecodeBool, sizeof(BOOL), FALSE, FALSE, 0, 0 },
2245          { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria),
2246            CRYPT_AsnDecodeBool, sizeof(BOOL), FALSE, FALSE, 0, 0 },
2247         };
2248
2249         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2250          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2251          pvStructInfo, pcbStructInfo, NULL);
2252     }
2253     __EXCEPT_PAGE_FAULT
2254     {
2255         SetLastError(STATUS_ACCESS_VIOLATION);
2256     }
2257     __ENDTRY
2258     TRACE("returning %d\n", ret);
2259     return ret;
2260 }