user32/tests: Run tests on win95 again.
[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_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
53
54 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
55 {
56     DWORD bytesNeeded, significantBytes = 0;
57
58     if (len <= 0x7f)
59         bytesNeeded = 1;
60     else
61     {
62         DWORD temp;
63
64         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
65          temp <<= 8, significantBytes--)
66             ;
67         bytesNeeded = significantBytes + 1;
68     }
69     if (!pbEncoded)
70     {
71         *pcbEncoded = bytesNeeded;
72         return TRUE;
73     }
74     if (*pcbEncoded < bytesNeeded)
75     {
76         SetLastError(ERROR_MORE_DATA);
77         return FALSE;
78     }
79     if (len <= 0x7f)
80         *pbEncoded = (BYTE)len;
81     else
82     {
83         DWORD i;
84
85         *pbEncoded++ = significantBytes | 0x80;
86         for (i = 0; i < significantBytes; i++)
87         {
88             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
89             len >>= 8;
90         }
91     }
92     *pcbEncoded = bytesNeeded;
93     return TRUE;
94 }
95
96 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
97  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
98  DWORD *pcbEncoded)
99 {
100     BOOL ret = TRUE;
101     const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
102     DWORD bytesNeeded, lenBytes;
103
104     TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
105      *pcbEncoded);
106
107     CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
108     bytesNeeded = 1 + lenBytes + blob->cbData;
109     if (!pbEncoded)
110         *pcbEncoded = bytesNeeded;
111     else if (*pcbEncoded < bytesNeeded)
112     {
113         *pcbEncoded = bytesNeeded;
114         SetLastError(ERROR_MORE_DATA);
115         ret = FALSE;
116     }
117     else
118     {
119         *pbEncoded++ = ASN_OCTETSTRING;
120         CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
121         pbEncoded += lenBytes;
122         if (blob->cbData)
123             memcpy(pbEncoded, blob->pbData, blob->cbData);
124     }
125     TRACE("returning %d\n", ret);
126     return ret;
127 }
128
129 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
130  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
131  DWORD *pcbEncoded)
132 {
133     BOOL ret = FALSE;
134
135     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
136      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
137      pcbEncoded);
138
139     __TRY
140     {
141         const SPC_LINK *link = (const SPC_LINK *)pvStructInfo;
142         DWORD bytesNeeded, lenBytes;
143
144         switch (link->dwLinkChoice)
145         {
146         case SPC_FILE_LINK_CHOICE:
147         {
148             DWORD fileNameLen, fileNameLenBytes;
149             LPWSTR ptr;
150
151             fileNameLen = link->u.pwszFile ?
152              lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
153             CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
154             CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
155              &lenBytes);
156             bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
157             if (!pbEncoded)
158             {
159                 *pcbEncoded = bytesNeeded;
160                 ret = TRUE;
161             }
162             else if (*pcbEncoded < bytesNeeded)
163             {
164                 SetLastError(ERROR_MORE_DATA);
165                 *pcbEncoded = bytesNeeded;
166             }
167             else
168             {
169                 *pcbEncoded = bytesNeeded;
170                 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
171                 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
172                  &lenBytes);
173                 pbEncoded += lenBytes;
174                 *pbEncoded++ = ASN_CONTEXT;
175                 CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
176                 pbEncoded += fileNameLenBytes;
177                 for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
178                 {
179                     *(WCHAR *)pbEncoded = hton16(*ptr);
180                     pbEncoded += sizeof(WCHAR);
181                 }
182                 ret = TRUE;
183             }
184             break;
185         }
186         case SPC_MONIKER_LINK_CHOICE:
187         {
188             DWORD classIdLenBytes, dataLenBytes, dataLen;
189             CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
190              (BYTE *)link->u.Moniker.ClassId };
191
192             CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
193             CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
194              &dataLenBytes);
195             dataLen = 2 + classIdLenBytes + classId.cbData +
196              dataLenBytes + link->u.Moniker.SerializedData.cbData;
197             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
198             bytesNeeded = 1 + dataLen + lenBytes;
199             if (!pbEncoded)
200             {
201                 *pcbEncoded = bytesNeeded;
202                 ret = TRUE;
203             }
204             else if (*pcbEncoded < bytesNeeded)
205             {
206                 SetLastError(ERROR_MORE_DATA);
207                 *pcbEncoded = bytesNeeded;
208             }
209             else
210             {
211                 DWORD size;
212
213                 *pcbEncoded = bytesNeeded;
214                 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
215                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
216                 pbEncoded += lenBytes;
217                 size = 1 + classIdLenBytes + classId.cbData;
218                 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
219                  pbEncoded, &size);
220                 pbEncoded += size;
221                 size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
222                 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
223                  &link->u.Moniker.SerializedData, pbEncoded, &size);
224                 pbEncoded += size;
225                 ret = TRUE;
226             }
227             break;
228         }
229         case SPC_URL_LINK_CHOICE:
230         {
231             LPWSTR ptr;
232             DWORD urlLen;
233
234             /* Check for invalid characters in URL */
235             ret = TRUE;
236             urlLen = 0;
237             for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
238                 if (*ptr > 0x7f)
239                 {
240                     *pcbEncoded = 0;
241                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
242                     ret = FALSE;
243                 }
244                 else
245                     urlLen++;
246             if (ret)
247             {
248                 CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
249                 bytesNeeded = 1 + lenBytes + urlLen;
250                 if (!pbEncoded)
251                     *pcbEncoded = bytesNeeded;
252                 else if (*pcbEncoded < bytesNeeded)
253                 {
254                     SetLastError(ERROR_MORE_DATA);
255                     *pcbEncoded = bytesNeeded;
256                     ret = FALSE;
257                 }
258                 else
259                 {
260                     *pcbEncoded = bytesNeeded;
261                     *pbEncoded++ = ASN_CONTEXT;
262                     CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
263                     pbEncoded += lenBytes;
264                     for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
265                         *pbEncoded++ = (BYTE)*ptr;
266                 }
267             }
268             break;
269         }
270         default:
271             SetLastError(E_INVALIDARG);
272         }
273     }
274     __EXCEPT_PAGE_FAULT
275     {
276         SetLastError(STATUS_ACCESS_VIOLATION);
277     }
278     __ENDTRY
279     TRACE("returning %d\n", ret);
280     return ret;
281 }
282
283 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
284  BYTE *, DWORD *);
285
286 struct AsnEncodeSequenceItem
287 {
288     const void           *pvStructInfo;
289     CryptEncodeObjectFunc encodeFunc;
290     DWORD                 size; /* used during encoding, not for your use */
291 };
292
293 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
294  struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
295  DWORD *pcbEncoded)
296 {
297     BOOL ret;
298     DWORD i, dataLen = 0;
299
300     TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
301     for (i = 0, ret = TRUE; ret && i < cItem; i++)
302     {
303         ret = items[i].encodeFunc(dwCertEncodingType, NULL,
304          items[i].pvStructInfo, NULL, &items[i].size);
305         /* Some functions propagate their errors through the size */
306         if (!ret)
307             *pcbEncoded = items[i].size;
308         dataLen += items[i].size;
309     }
310     if (ret)
311     {
312         DWORD lenBytes, bytesNeeded;
313
314         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
315         bytesNeeded = 1 + lenBytes + dataLen;
316         if (!pbEncoded)
317             *pcbEncoded = bytesNeeded;
318         else if (*pcbEncoded < bytesNeeded)
319         {
320             *pcbEncoded = bytesNeeded;
321             SetLastError(ERROR_MORE_DATA);
322             ret = FALSE;
323         }
324         else
325         {
326             *pcbEncoded = bytesNeeded;
327             *pbEncoded++ = ASN_SEQUENCE;
328             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
329             pbEncoded += lenBytes;
330             for (i = 0; ret && i < cItem; i++)
331             {
332                 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
333                  items[i].pvStructInfo, pbEncoded, &items[i].size);
334                 /* Some functions propagate their errors through the size */
335                 if (!ret)
336                     *pcbEncoded = items[i].size;
337                 pbEncoded += items[i].size;
338             }
339         }
340     }
341     TRACE("returning %d\n", ret);
342     return ret;
343 }
344
345 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
346  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
347  DWORD *pcbEncoded)
348 {
349     BOOL ret = FALSE;
350
351     __TRY
352     {
353         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
354         DWORD bytesNeeded, lenBytes, dataBytes;
355         BYTE unusedBits;
356
357         /* yep, MS allows cUnusedBits to be >= 8 */
358         if (!blob->cUnusedBits)
359         {
360             dataBytes = blob->cbData;
361             unusedBits = 0;
362         }
363         else if (blob->cbData * 8 > blob->cUnusedBits)
364         {
365             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
366             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
367              blob->cUnusedBits;
368         }
369         else
370         {
371             dataBytes = 0;
372             unusedBits = 0;
373         }
374         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
375         bytesNeeded = 1 + lenBytes + dataBytes + 1;
376         if (!pbEncoded)
377         {
378             *pcbEncoded = bytesNeeded;
379             ret = TRUE;
380         }
381         else if (*pcbEncoded < bytesNeeded)
382         {
383             *pcbEncoded = bytesNeeded;
384             SetLastError(ERROR_MORE_DATA);
385         }
386         else
387         {
388             ret = TRUE;
389             *pcbEncoded = bytesNeeded;
390             *pbEncoded++ = ASN_BITSTRING;
391             CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
392             pbEncoded += lenBytes;
393             *pbEncoded++ = unusedBits;
394             if (dataBytes)
395             {
396                 BYTE mask = 0xff << unusedBits;
397
398                 if (dataBytes > 1)
399                 {
400                     memcpy(pbEncoded, blob->pbData, dataBytes - 1);
401                     pbEncoded += dataBytes - 1;
402                 }
403                 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
404             }
405         }
406     }
407     __EXCEPT_PAGE_FAULT
408     {
409         SetLastError(STATUS_ACCESS_VIOLATION);
410     }
411     __ENDTRY
412     return ret;
413 }
414
415 struct AsnConstructedItem
416 {
417     BYTE                  tag;
418     const void           *pvStructInfo;
419     CryptEncodeObjectFunc encodeFunc;
420 };
421
422 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
423  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
424  DWORD *pcbEncoded)
425 {
426     BOOL ret;
427     const struct AsnConstructedItem *item =
428      (const struct AsnConstructedItem *)pvStructInfo;
429     DWORD len;
430
431     if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
432      item->pvStructInfo, NULL, &len)))
433     {
434         DWORD dataLen, bytesNeeded;
435
436         CRYPT_EncodeLen(len, NULL, &dataLen);
437         bytesNeeded = 1 + dataLen + len;
438         if (!pbEncoded)
439             *pcbEncoded = bytesNeeded;
440         else if (*pcbEncoded < bytesNeeded)
441         {
442             *pcbEncoded = bytesNeeded;
443             SetLastError(ERROR_MORE_DATA);
444             ret = FALSE;
445         }
446         else
447         {
448             *pcbEncoded = bytesNeeded;
449             *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
450             CRYPT_EncodeLen(len, pbEncoded, &dataLen);
451             pbEncoded += dataLen;
452             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
453              item->pvStructInfo, pbEncoded, &len);
454             if (!ret)
455             {
456                 /* Some functions propagate their errors through the size */
457                 *pcbEncoded = len;
458             }
459         }
460     }
461     else
462     {
463         /* Some functions propagate their errors through the size */
464         *pcbEncoded = len;
465     }
466     return ret;
467 }
468
469
470 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
471  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
472  DWORD *pcbEncoded)
473 {
474     const SPC_PE_IMAGE_DATA *imageData =
475      (const SPC_PE_IMAGE_DATA *)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 = (LPCSTR)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         while (ret && *ptr)
542         {
543             int pos;
544
545             /* note I assume each component is at most 32-bits long in base 2 */
546             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
547             {
548                 if (val1 >= 0x10000000)
549                     bytesNeeded += 5;
550                 else if (val1 >= 0x200000)
551                     bytesNeeded += 4;
552                 else if (val1 >= 0x4000)
553                     bytesNeeded += 3;
554                 else if (val1 >= 0x80)
555                     bytesNeeded += 2;
556                 else
557                     bytesNeeded += 1;
558                 ptr += pos;
559                 if (*ptr == '.')
560                     ptr++;
561             }
562             else
563             {
564                 SetLastError(CRYPT_E_ASN1_ERROR);
565                 return FALSE;
566             }
567         }
568         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
569     }
570     else
571         lenBytes = 1;
572     bytesNeeded += 1 + lenBytes;
573     if (pbEncoded)
574     {
575         if (*pcbEncoded < bytesNeeded)
576         {
577             SetLastError(ERROR_MORE_DATA);
578             ret = FALSE;
579         }
580         else
581         {
582             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
583             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
584             pbEncoded += lenBytes;
585             if (pszObjId)
586             {
587                 const char *ptr;
588                 int val, pos;
589
590                 *pbEncoded++ = firstByte;
591                 ptr = pszObjId + firstPos;
592                 while (ret && *ptr)
593                 {
594                     sscanf(ptr, "%d%n", &val, &pos);
595                     {
596                         unsigned char outBytes[5];
597                         int numBytes, i;
598
599                         if (val >= 0x10000000)
600                             numBytes = 5;
601                         else if (val >= 0x200000)
602                             numBytes = 4;
603                         else if (val >= 0x4000)
604                             numBytes = 3;
605                         else if (val >= 0x80)
606                             numBytes = 2;
607                         else
608                             numBytes = 1;
609                         for (i = numBytes; i > 0; i--)
610                         {
611                             outBytes[i - 1] = val & 0x7f;
612                             val >>= 7;
613                         }
614                         for (i = 0; i < numBytes - 1; i++)
615                             *pbEncoded++ = outBytes[i] | 0x80;
616                         *pbEncoded++ = outBytes[i];
617                         ptr += pos;
618                         if (*ptr == '.')
619                             ptr++;
620                     }
621                 }
622             }
623         }
624     }
625     *pcbEncoded = bytesNeeded;
626     return ret;
627 }
628
629 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
630  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
631  DWORD *pcbEncoded)
632 {
633     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
634     BOOL ret = TRUE;
635
636     if (!pbEncoded)
637         *pcbEncoded = blob->cbData;
638     else if (*pcbEncoded < blob->cbData)
639     {
640         *pcbEncoded = blob->cbData;
641         SetLastError(ERROR_MORE_DATA);
642         ret = FALSE;
643     }
644     else
645     {
646         if (blob->cbData)
647             memcpy(pbEncoded, blob->pbData, blob->cbData);
648         *pcbEncoded = blob->cbData;
649     }
650     return ret;
651 }
652
653 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
654  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
655  BYTE *pbEncoded, DWORD *pcbEncoded)
656 {
657     const CRYPT_ALGORITHM_IDENTIFIER *algo =
658      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
659     static const BYTE asn1Null[] = { ASN_NULL, 0 };
660     static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
661      (LPBYTE)asn1Null };
662     BOOL ret;
663     struct AsnEncodeSequenceItem items[2] = {
664      { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
665      { NULL,           CRYPT_CopyEncodedBlob, 0 },
666     };
667
668     if (algo->Parameters.cbData)
669         items[1].pvStructInfo = &algo->Parameters;
670     else
671         items[1].pvStructInfo = &nullBlob;
672     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
673      sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
674     return ret;
675 }
676
677 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
678  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
679  DWORD *pcbEncoded)
680 {
681     const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
682      (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
683     struct AsnEncodeSequenceItem items[] = {
684      { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
685      { &typeValue->Value,    CRYPT_CopyEncodedBlob, 0 },
686     };
687
688     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
689      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
690 }
691
692 struct SPCDigest
693 {
694     CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
695     CRYPT_HASH_BLOB            Digest;
696 };
697
698 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
699  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
700  DWORD *pcbEncoded)
701 {
702     const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
703     struct AsnEncodeSequenceItem items[] = {
704      { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
705      { &digest->Digest,          CRYPT_CopyEncodedBlob, 0 },
706     };
707
708     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
709      items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
710 }
711
712 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
713  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
714  DWORD *pcbEncoded)
715 {
716     BOOL ret = FALSE;
717
718     TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
719      debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
720
721     __TRY
722     {
723         const SPC_INDIRECT_DATA_CONTENT *data =
724          (const SPC_INDIRECT_DATA_CONTENT *)pvStructInfo;
725         struct AsnEncodeSequenceItem items[] = {
726          { &data->Data,            CRYPT_AsnEncodeAttributeTypeValue, 0 },
727          { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
728         };
729
730         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
731          items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
732     }
733     __EXCEPT_PAGE_FAULT
734     {
735         SetLastError(STATUS_ACCESS_VIOLATION);
736     }
737     __ENDTRY
738     return ret;
739 }
740
741 /* Gets the number of length bytes from the given (leading) length byte */
742 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
743
744 /* Helper function to get the encoded length of the data starting at pbEncoded,
745  * where pbEncoded[0] is the tag.  If the data are too short to contain a
746  * length or if the length is too large for cbEncoded, sets an appropriate
747  * error code and returns FALSE.
748  */
749 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
750 {
751     BOOL ret;
752
753     if (cbEncoded <= 1)
754     {
755         SetLastError(CRYPT_E_ASN1_CORRUPT);
756         ret = FALSE;
757     }
758     else if (pbEncoded[1] <= 0x7f)
759     {
760         if (pbEncoded[1] + 1 > cbEncoded)
761         {
762             SetLastError(CRYPT_E_ASN1_EOD);
763             ret = FALSE;
764         }
765         else
766         {
767             *len = pbEncoded[1];
768             ret = TRUE;
769         }
770     }
771     else if (pbEncoded[1] == 0x80)
772     {
773         FIXME("unimplemented for indefinite-length encoding\n");
774         SetLastError(CRYPT_E_ASN1_CORRUPT);
775         ret = FALSE;
776     }
777     else
778     {
779         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
780
781         if (lenLen > sizeof(DWORD) + 1)
782         {
783             SetLastError(CRYPT_E_ASN1_LARGE);
784             ret = FALSE;
785         }
786         else if (lenLen + 2 > cbEncoded)
787         {
788             SetLastError(CRYPT_E_ASN1_CORRUPT);
789             ret = FALSE;
790         }
791         else
792         {
793             DWORD out = 0;
794
795             pbEncoded += 2;
796             while (--lenLen)
797             {
798                 out <<= 8;
799                 out |= *pbEncoded++;
800             }
801             if (out + lenLen + 1 > cbEncoded)
802             {
803                 SetLastError(CRYPT_E_ASN1_EOD);
804                 ret = FALSE;
805             }
806             else
807             {
808                 *len = out;
809                 ret = TRUE;
810             }
811         }
812     }
813     return ret;
814 }
815
816 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
817  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
818  void *pvStructInfo, DWORD *pcbStructInfo)
819 {
820     BOOL ret;
821     DWORD bytesNeeded, dataLen;
822
823     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
824      pvStructInfo, *pcbStructInfo);
825
826     if (!cbEncoded)
827     {
828         SetLastError(CRYPT_E_ASN1_CORRUPT);
829         ret = FALSE;
830     }
831     else if (pbEncoded[0] != ASN_OCTETSTRING)
832     {
833         SetLastError(CRYPT_E_ASN1_BADTAG);
834         ret = FALSE;
835     }
836     else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
837     {
838         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
839             bytesNeeded = sizeof(CRYPT_DATA_BLOB);
840         else
841             bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
842         if (!pvStructInfo)
843             *pcbStructInfo = bytesNeeded;
844         else if (*pcbStructInfo < bytesNeeded)
845         {
846             SetLastError(ERROR_MORE_DATA);
847             *pcbStructInfo = bytesNeeded;
848             ret = FALSE;
849         }
850         else
851         {
852             CRYPT_DATA_BLOB *blob;
853             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
854
855             blob = (CRYPT_DATA_BLOB *)pvStructInfo;
856             blob->cbData = dataLen;
857             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
858                 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
859             else
860             {
861                 assert(blob->pbData);
862                 if (blob->cbData)
863                     memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
864                      blob->cbData);
865             }
866         }
867     }
868     return ret;
869 }
870
871 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
872  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
873  void *pvStructInfo, DWORD *pcbStructInfo)
874 {
875     BOOL ret = FALSE;
876     DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
877
878     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
879      pvStructInfo, *pcbStructInfo);
880
881     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
882     {
883         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
884         DWORD realDataLen;
885
886         switch (pbEncoded[0])
887         {
888         case ASN_CONTEXT:
889             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
890             if (!pvStructInfo)
891                 *pcbStructInfo = bytesNeeded;
892             else if (*pcbStructInfo < bytesNeeded)
893             {
894                 *pcbStructInfo = bytesNeeded;
895                 SetLastError(ERROR_MORE_DATA);
896                 ret = FALSE;
897             }
898             else
899             {
900                 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
901                 DWORD i;
902
903                 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
904                 for (i = 0; i < dataLen; i++)
905                     link->u.pwszUrl[i] =
906                      *(pbEncoded + 1 + lenBytes + i);
907                 link->u.pwszUrl[i] = '\0';
908                 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
909             }
910             break;
911         case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
912         {
913             CRYPT_DATA_BLOB classId;
914             DWORD size = sizeof(classId);
915
916             if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
917              pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
918              CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
919             {
920                 if (classId.cbData != sizeof(SPC_UUID))
921                 {
922                     SetLastError(CRYPT_E_BAD_ENCODE);
923                     ret = FALSE;
924                 }
925                 else
926                 {
927                     CRYPT_DATA_BLOB data;
928
929                     /* The tag length for the classId must be 1 since the
930                      * length is correct.
931                      */
932                     size = sizeof(data);
933                     if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
934                      pbEncoded + 3 + lenBytes + classId.cbData,
935                      cbEncoded - 3 - lenBytes - classId.cbData,
936                      CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
937                     {
938                         bytesNeeded += data.cbData;
939                         if (!pvStructInfo)
940                             *pcbStructInfo = bytesNeeded;
941                         else if (*pcbStructInfo < bytesNeeded)
942                         {
943                             *pcbStructInfo = bytesNeeded;
944                             SetLastError(ERROR_MORE_DATA);
945                             ret = FALSE;
946                         }
947                         else
948                         {
949                             PSPC_LINK link = (PSPC_LINK)pvStructInfo;
950
951                             link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
952                             /* pwszFile pointer was set by caller, copy it
953                              * before overwriting it
954                              */
955                             link->u.Moniker.SerializedData.pbData =
956                              (BYTE *)link->u.pwszFile;
957                             memcpy(link->u.Moniker.ClassId, classId.pbData,
958                              classId.cbData);
959                             memcpy(link->u.Moniker.SerializedData.pbData,
960                              data.pbData, data.cbData);
961                             link->u.Moniker.SerializedData.cbData = data.cbData;
962                         }
963                     }
964                 }
965             }
966             break;
967         }
968         case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
969             if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
970                 SetLastError(CRYPT_E_ASN1_BADTAG);
971             else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
972              &realDataLen)))
973             {
974                 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
975
976                 bytesNeeded += realDataLen + sizeof(WCHAR);
977                 if (!pvStructInfo)
978                     *pcbStructInfo = bytesNeeded;
979                 else if (*pcbStructInfo < bytesNeeded)
980                 {
981                     *pcbStructInfo = bytesNeeded;
982                     SetLastError(ERROR_MORE_DATA);
983                     ret = FALSE;
984                 }
985                 else
986                 {
987                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
988                     DWORD i;
989                     const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
990
991                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
992                     for (i = 0; i < dataLen / sizeof(WCHAR); i++)
993                         link->u.pwszFile[i] =
994                          hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
995                     link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
996                     TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
997                 }
998             }
999             else
1000             {
1001                 bytesNeeded += sizeof(WCHAR);
1002                 if (!pvStructInfo)
1003                     *pcbStructInfo = bytesNeeded;
1004                 else if (*pcbStructInfo < bytesNeeded)
1005                 {
1006                     *pcbStructInfo = bytesNeeded;
1007                     SetLastError(ERROR_MORE_DATA);
1008                     ret = FALSE;
1009                 }
1010                 else
1011                 {
1012                     PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1013
1014                     link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1015                     link->u.pwszFile[0] = '\0';
1016                     ret = TRUE;
1017                 }
1018             }
1019             break;
1020         default:
1021             SetLastError(CRYPT_E_ASN1_BADTAG);
1022         }
1023     }
1024     TRACE("returning %d\n", ret);
1025     return ret;
1026 }
1027
1028 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1029  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1030  void *pvStructInfo, DWORD *pcbStructInfo)
1031 {
1032     BOOL ret = FALSE;
1033
1034     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1035      pvStructInfo, *pcbStructInfo);
1036
1037     __TRY
1038     {
1039         DWORD bytesNeeded;
1040
1041         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1042          lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1043         if (ret)
1044         {
1045             if (!pvStructInfo)
1046                 *pcbStructInfo = bytesNeeded;
1047             else if (*pcbStructInfo < bytesNeeded)
1048             {
1049                 *pcbStructInfo = bytesNeeded;
1050                 SetLastError(ERROR_MORE_DATA);
1051                 ret = FALSE;
1052             }
1053             else
1054             {
1055                 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1056
1057                 link->u.pwszFile =
1058                  (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1059                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1060                  lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1061                  pcbStructInfo);
1062             }
1063         }
1064     }
1065     __EXCEPT_PAGE_FAULT
1066     {
1067         SetLastError(STATUS_ACCESS_VIOLATION);
1068     }
1069     __ENDTRY
1070     TRACE("returning %d\n", ret);
1071     return ret;
1072 }
1073
1074 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1075  DWORD, DWORD, void *, DWORD *);
1076
1077 /* tag:
1078  *     The expected tag of the item.  If tag is 0, decodeFunc is called
1079  *     regardless of the tag value seen.
1080  * offset:
1081  *     A sequence is decoded into a struct.  The offset member is the
1082  *     offset of this item within that struct.
1083  * decodeFunc:
1084  *     The decoder function to use.  If this is NULL, then the member isn't
1085  *     decoded, but minSize space is reserved for it.
1086  * minSize:
1087  *     The minimum amount of space occupied after decoding.  You must set this.
1088  * optional:
1089  *     If true, and the tag doesn't match the expected tag for this item,
1090  *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1091  *     filled with 0 for this member.
1092  * hasPointer, pointerOffset:
1093  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1094  *     the offset within the struct of the data pointer (or to the
1095  *     first data pointer, if more than one exist).
1096  * size:
1097  *     Used by CRYPT_AsnDecodeSequence, not for your use.
1098  */
1099 struct AsnDecodeSequenceItem
1100 {
1101     BYTE                  tag;
1102     DWORD                 offset;
1103     CryptDecodeObjectFunc decodeFunc;
1104     DWORD                 minSize;
1105     BOOL                  optional;
1106     BOOL                  hasPointer;
1107     DWORD                 pointerOffset;
1108     DWORD                 size;
1109 };
1110
1111 /* Decodes the items in a sequence, where the items are described in items,
1112  * the encoded data are in pbEncoded with length cbEncoded.  Decodes into
1113  * pvStructInfo.  nextData is a pointer to the memory location at which the
1114  * first decoded item with a dynamic pointer should point.
1115  * Upon decoding, *cbDecoded is the total number of bytes decoded.
1116  */
1117 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1118  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1119  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1120  DWORD *cbDecoded)
1121 {
1122     BOOL ret;
1123     DWORD i, decoded = 0;
1124     const BYTE *ptr = pbEncoded;
1125
1126     TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1127      cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1128
1129     for (i = 0, ret = TRUE; ret && i < cItem; i++)
1130     {
1131         if (cbEncoded - (ptr - pbEncoded) != 0)
1132         {
1133             DWORD nextItemLen;
1134
1135             if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1136              &nextItemLen)))
1137             {
1138                 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1139
1140                 if (ptr[0] == items[i].tag || !items[i].tag)
1141                 {
1142                     if (nextData && pvStructInfo && items[i].hasPointer)
1143                     {
1144                         TRACE("Setting next pointer to %p\n",
1145                          nextData);
1146                         *(BYTE **)((BYTE *)pvStructInfo +
1147                          items[i].pointerOffset) = nextData;
1148                     }
1149                     if (items[i].decodeFunc)
1150                     {
1151                         if (pvStructInfo)
1152                             TRACE("decoding item %d\n", i);
1153                         else
1154                             TRACE("sizing item %d\n", i);
1155                         ret = items[i].decodeFunc(dwCertEncodingType,
1156                          NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1157                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1158                          pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
1159                          : NULL, &items[i].size);
1160                         if (ret)
1161                         {
1162                             /* Account for alignment padding */
1163                             if (items[i].size % sizeof(DWORD))
1164                                 items[i].size += sizeof(DWORD) -
1165                                  items[i].size % sizeof(DWORD);
1166                             TRACE("item %d size: %d\n", i, items[i].size);
1167                             if (nextData && items[i].hasPointer &&
1168                              items[i].size > items[i].minSize)
1169                                 nextData += items[i].size - items[i].minSize;
1170                             ptr += 1 + nextItemLenBytes + nextItemLen;
1171                             decoded += 1 + nextItemLenBytes + nextItemLen;
1172                             TRACE("item %d: decoded %d bytes\n", i,
1173                              1 + nextItemLenBytes + nextItemLen);
1174                         }
1175                         else if (items[i].optional &&
1176                          GetLastError() == CRYPT_E_ASN1_BADTAG)
1177                         {
1178                             TRACE("skipping optional item %d\n", i);
1179                             items[i].size = items[i].minSize;
1180                             SetLastError(NOERROR);
1181                             ret = TRUE;
1182                         }
1183                         else
1184                             TRACE("item %d failed: %08x\n", i,
1185                              GetLastError());
1186                     }
1187                     else
1188                     {
1189                         TRACE("item %d: decoded %d bytes\n", i,
1190                          1 + nextItemLenBytes + nextItemLen);
1191                         ptr += 1 + nextItemLenBytes + nextItemLen;
1192                         decoded += 1 + nextItemLenBytes + nextItemLen;
1193                         items[i].size = items[i].minSize;
1194                     }
1195                 }
1196                 else if (items[i].optional)
1197                 {
1198                     TRACE("skipping optional item %d\n", i);
1199                     items[i].size = items[i].minSize;
1200                 }
1201                 else
1202                 {
1203                     TRACE("item %d: tag %02x doesn't match expected %02x\n",
1204                      i, ptr[0], items[i].tag);
1205                     SetLastError(CRYPT_E_ASN1_BADTAG);
1206                     ret = FALSE;
1207                 }
1208             }
1209         }
1210         else if (items[i].optional)
1211         {
1212             TRACE("missing optional item %d, skipping\n", i);
1213             items[i].size = items[i].minSize;
1214         }
1215         else
1216         {
1217             TRACE("not enough bytes for item %d, failing\n", i);
1218             SetLastError(CRYPT_E_ASN1_CORRUPT);
1219             ret = FALSE;
1220         }
1221     }
1222     if (ret)
1223         *cbDecoded = decoded;
1224     TRACE("returning %d\n", ret);
1225     return ret;
1226 }
1227
1228 /* This decodes an arbitrary sequence into a contiguous block of memory
1229  * (basically, a struct.)  Each element being decoded is described by a struct
1230  * AsnDecodeSequenceItem, see above.
1231  * startingPointer is an optional pointer to the first place where dynamic
1232  * data will be stored.  If you know the starting offset, you may pass it
1233  * here.  Otherwise, pass NULL, and one will be inferred from the items.
1234  */
1235 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1236  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1237  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1238  void *startingPointer)
1239 {
1240     BOOL ret;
1241
1242     TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1243      cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1244
1245     if (pbEncoded[0] == ASN_SEQUENCE)
1246     {
1247         DWORD dataLen;
1248
1249         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1250         {
1251             DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1252             const BYTE *ptr = pbEncoded + 1 + lenBytes;
1253
1254             cbEncoded -= 1 + lenBytes;
1255             if (cbEncoded < dataLen)
1256             {
1257                 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1258                  cbEncoded);
1259                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1260                 ret = FALSE;
1261             }
1262             else
1263                 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1264                  cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1265             if (ret && cbDecoded != dataLen)
1266             {
1267                 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1268                  cbDecoded);
1269                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1270                 ret = FALSE;
1271             }
1272             if (ret)
1273             {
1274                 DWORD i, bytesNeeded = 0, structSize = 0;
1275
1276                 for (i = 0; i < cItem; i++)
1277                 {
1278                     bytesNeeded += items[i].size;
1279                     structSize += items[i].minSize;
1280                 }
1281                 if (!pvStructInfo)
1282                     *pcbStructInfo = bytesNeeded;
1283                 else if (*pcbStructInfo < bytesNeeded)
1284                 {
1285                     SetLastError(ERROR_MORE_DATA);
1286                     *pcbStructInfo = bytesNeeded;
1287                     ret = FALSE;
1288                 }
1289                 else
1290                 {
1291                     BYTE *nextData;
1292
1293                     *pcbStructInfo = bytesNeeded;
1294                     if (startingPointer)
1295                         nextData = (BYTE *)startingPointer;
1296                     else
1297                         nextData = (BYTE *)pvStructInfo + structSize;
1298                     memset(pvStructInfo, 0, structSize);
1299                     ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1300                      ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1301                      &cbDecoded);
1302                 }
1303             }
1304         }
1305     }
1306     else
1307     {
1308         SetLastError(CRYPT_E_ASN1_BADTAG);
1309         ret = FALSE;
1310     }
1311     TRACE("returning %d (%08x)\n", ret, GetLastError());
1312     return ret;
1313 }
1314
1315 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1316  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1317  void *pvStructInfo, DWORD *pcbStructInfo)
1318 {
1319     BOOL ret;
1320
1321     TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1322      pvStructInfo, *pcbStructInfo);
1323
1324     if (pbEncoded[0] == ASN_BITSTRING)
1325     {
1326         DWORD bytesNeeded, dataLen;
1327
1328         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1329         {
1330             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1331                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1332             else
1333                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
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                 CRYPT_BIT_BLOB *blob;
1345
1346                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1347                 blob->cbData = dataLen - 1;
1348                 blob->cUnusedBits = *(pbEncoded + 1 +
1349                  GET_LEN_BYTES(pbEncoded[1]));
1350                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1351                 {
1352                     blob->pbData = (BYTE *)pbEncoded + 2 +
1353                      GET_LEN_BYTES(pbEncoded[1]);
1354                 }
1355                 else
1356                 {
1357                     assert(blob->pbData);
1358                     if (blob->cbData)
1359                     {
1360                         BYTE mask = 0xff << blob->cUnusedBits;
1361
1362                         memcpy(blob->pbData, pbEncoded + 2 +
1363                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1364                         blob->pbData[blob->cbData - 1] &= mask;
1365                     }
1366                 }
1367             }
1368         }
1369     }
1370     else
1371     {
1372         SetLastError(CRYPT_E_ASN1_BADTAG);
1373         ret = FALSE;
1374     }
1375     TRACE("returning %d (%08x)\n", ret, GetLastError());
1376     return ret;
1377 }
1378
1379 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1380  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1381  void *pvStructInfo, DWORD *pcbStructInfo)
1382 {
1383     BOOL ret = FALSE;
1384     DWORD dataLen;
1385
1386     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1387     {
1388         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1389         DWORD size;
1390         SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1391
1392         ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1393          pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1394         if (ret)
1395         {
1396             if (!pvStructInfo)
1397                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1398             else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1399             {
1400                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1401                 SetLastError(ERROR_MORE_DATA);
1402                 ret = FALSE;
1403             }
1404             else
1405             {
1406                 *pcbStructInfo = size + sizeof(PSPC_LINK);
1407                 /* Set imageData's pointer if necessary */
1408                 if (size > sizeof(SPC_LINK))
1409                 {
1410                     (*pLink)->u.pwszUrl =
1411                      (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1412                 }
1413                 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1414                  lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1415                  *pLink, pcbStructInfo);
1416             }
1417         }
1418     }
1419     return ret;
1420 }
1421
1422 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1423  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1424  void *pvStructInfo, DWORD *pcbStructInfo)
1425 {
1426     BOOL ret = FALSE;
1427
1428     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1429      pvStructInfo, *pcbStructInfo);
1430
1431     __TRY
1432     {
1433         struct AsnDecodeSequenceItem items[] = {
1434          { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1435            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1436            offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1437          { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1438            CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1439            offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1440         };
1441
1442         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1443          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1444          pvStructInfo, pcbStructInfo, NULL);
1445     }
1446     __EXCEPT_PAGE_FAULT
1447     {
1448         SetLastError(STATUS_ACCESS_VIOLATION);
1449     }
1450     __ENDTRY
1451     TRACE("returning %d\n", ret);
1452     return ret;
1453 }
1454
1455 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1456  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1457  void *pvStructInfo, DWORD *pcbStructInfo)
1458 {
1459     BOOL ret = TRUE;
1460     DWORD dataLen;
1461
1462     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1463      pvStructInfo, *pcbStructInfo);
1464
1465     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1466     {
1467         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1468         DWORD bytesNeeded = sizeof(LPSTR);
1469
1470         if (dataLen)
1471         {
1472             /* The largest possible string for the first two components
1473              * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1474              */
1475             char firstTwo[6];
1476             const BYTE *ptr;
1477
1478             snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1479              pbEncoded[1 + lenBytes] / 40,
1480              pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1481              * 40);
1482             bytesNeeded += strlen(firstTwo) + 1;
1483             for (ptr = pbEncoded + 2 + lenBytes; ret &&
1484              ptr - pbEncoded - 1 - lenBytes < dataLen; )
1485             {
1486                 /* large enough for ".4000000" */
1487                 char str[9];
1488                 int val = 0;
1489
1490                 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1491                  (*ptr & 0x80))
1492                 {
1493                     val <<= 7;
1494                     val |= *ptr & 0x7f;
1495                     ptr++;
1496                 }
1497                 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1498                  (*ptr & 0x80))
1499                 {
1500                     SetLastError(CRYPT_E_ASN1_CORRUPT);
1501                     ret = FALSE;
1502                 }
1503                 else
1504                 {
1505                     val <<= 7;
1506                     val |= *ptr++;
1507                     snprintf(str, sizeof(str), ".%d", val);
1508                     bytesNeeded += strlen(str);
1509                 }
1510             }
1511         }
1512         if (!pvStructInfo)
1513             *pcbStructInfo = bytesNeeded;
1514         else if (*pcbStructInfo < bytesNeeded)
1515         {
1516             *pcbStructInfo = bytesNeeded;
1517             SetLastError(ERROR_MORE_DATA);
1518             ret = FALSE;
1519         }
1520         else
1521         {
1522             if (dataLen)
1523             {
1524                 const BYTE *ptr;
1525                 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1526
1527                 *pszObjId = 0;
1528                 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1529                  pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1530                  40) * 40);
1531                 pszObjId += strlen(pszObjId);
1532                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1533                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
1534                 {
1535                     int val = 0;
1536
1537                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1538                      (*ptr & 0x80))
1539                     {
1540                         val <<= 7;
1541                         val |= *ptr & 0x7f;
1542                         ptr++;
1543                     }
1544                     val <<= 7;
1545                     val |= *ptr++;
1546                     sprintf(pszObjId, ".%d", val);
1547                     pszObjId += strlen(pszObjId);
1548                 }
1549             }
1550             else
1551                 *(LPSTR *)pvStructInfo = NULL;
1552             *pcbStructInfo = bytesNeeded;
1553         }
1554     }
1555     return ret;
1556 }
1557
1558 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1559  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1560  void *pvStructInfo, DWORD *pcbStructInfo)
1561 {
1562     BOOL ret = FALSE;
1563
1564     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1565      pvStructInfo, *pcbStructInfo);
1566
1567     if (!cbEncoded)
1568         SetLastError(CRYPT_E_ASN1_CORRUPT);
1569     else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1570         ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1571          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1572     else
1573         SetLastError(CRYPT_E_ASN1_BADTAG);
1574     return ret;
1575 }
1576
1577 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1578  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1579  void *pvStructInfo, DWORD *pcbStructInfo)
1580 {
1581     BOOL ret = TRUE;
1582     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1583
1584     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1585      pvStructInfo, *pcbStructInfo);
1586
1587     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1588         bytesNeeded += cbEncoded;
1589     if (!pvStructInfo)
1590         *pcbStructInfo = bytesNeeded;
1591     else if (*pcbStructInfo < bytesNeeded)
1592     {
1593         SetLastError(ERROR_MORE_DATA);
1594         *pcbStructInfo = bytesNeeded;
1595         ret = FALSE;
1596     }
1597     else
1598     {
1599         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1600
1601         *pcbStructInfo = bytesNeeded;
1602         blob->cbData = cbEncoded;
1603         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1604             blob->pbData = (LPBYTE)pbEncoded;
1605         else
1606         {
1607             assert(blob->pbData);
1608             memcpy(blob->pbData, pbEncoded, blob->cbData);
1609         }
1610     }
1611     return ret;
1612 }
1613
1614 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1615  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1616  void *pvStructInfo, DWORD *pcbStructInfo)
1617 {
1618     CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1619      (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1620     struct AsnDecodeSequenceItem items[] = {
1621      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1622        CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1623        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1624      { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1625        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1626        offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1627     };
1628
1629     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1630      pvStructInfo, *pcbStructInfo);
1631
1632     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1633      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1634      pvStructInfo, pcbStructInfo,
1635      typeValue ? typeValue->pszObjId : NULL);
1636 }
1637
1638 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1639  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1640  void *pvStructInfo, DWORD *pcbStructInfo)
1641 {
1642     CRYPT_ALGORITHM_IDENTIFIER *algo =
1643      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
1644     BOOL ret = TRUE;
1645     struct AsnDecodeSequenceItem items[] = {
1646      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
1647        CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
1648        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
1649      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
1650        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
1651        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
1652     };
1653
1654     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1655      pvStructInfo, *pcbStructInfo);
1656
1657     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1658      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1659      pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
1660     if (ret && pvStructInfo)
1661     {
1662         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
1663          debugstr_a(algo->pszObjId));
1664     }
1665     return ret;
1666 }
1667
1668 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
1669  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1670  void *pvStructInfo, DWORD *pcbStructInfo)
1671 {
1672     struct SPCDigest *digest =
1673      (struct SPCDigest *)pvStructInfo;
1674     struct AsnDecodeSequenceItem items[] = {
1675      { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
1676        CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
1677        FALSE, TRUE,
1678        offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
1679      { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
1680        CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
1681        FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
1682     };
1683
1684     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1685      pvStructInfo, *pcbStructInfo);
1686
1687     return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1688      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1689      pvStructInfo, pcbStructInfo,
1690      digest ? digest->DigestAlgorithm.pszObjId : NULL);
1691 }
1692
1693 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
1694  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1695  void *pvStructInfo, DWORD *pcbStructInfo)
1696 {
1697     BOOL ret = FALSE;
1698
1699     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1700      pvStructInfo, *pcbStructInfo);
1701
1702     __TRY
1703     {
1704         struct AsnDecodeSequenceItem items[] = {
1705          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
1706            CRYPT_AsnDecodeAttributeTypeValue,
1707            sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
1708            offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
1709          { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
1710            CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
1711            FALSE, TRUE,
1712            offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
1713         };
1714
1715         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1716          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1717          pvStructInfo, pcbStructInfo, NULL);
1718     }
1719     __EXCEPT_PAGE_FAULT
1720     {
1721         SetLastError(STATUS_ACCESS_VIOLATION);
1722     }
1723     __ENDTRY
1724     TRACE("returning %d\n", ret);
1725     return ret;
1726 }
1727
1728 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
1729  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1730  void *pvStructInfo, DWORD *pcbStructInfo)
1731 {
1732     FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1733      pvStructInfo, *pcbStructInfo);
1734     return FALSE;
1735 }