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