dinput: Clear action mapping with SetDataFormat().
[wine.git] / dlls / wintrust / asn.c
blob72536e8b5b09ac0c466d9fc51c797e8d9ea3888d
1 /* wintrust asn functions
3 * Copyright 2007 Juan Lang
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.
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.
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
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wincrypt.h"
29 #include "wintrust.h"
30 #include "snmp.h"
31 #include "winternl.h"
32 #include "wine/debug.h"
33 #include "wine/exception.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
37 #ifdef WORDS_BIGENDIAN
39 #define hton16(x) (x)
40 #define n16toh(x) (x)
42 #else
44 #define hton16(x) RtlUshortByteSwap(x)
45 #define n16toh(x) RtlUshortByteSwap(x)
47 #endif
49 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
50 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
51 #define ASN_BMPSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e)
53 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
55 DWORD bytesNeeded, significantBytes = 0;
57 if (len <= 0x7f)
58 bytesNeeded = 1;
59 else
61 DWORD temp;
63 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
64 temp <<= 8, significantBytes--)
66 bytesNeeded = significantBytes + 1;
68 if (!pbEncoded)
70 *pcbEncoded = bytesNeeded;
71 return TRUE;
73 if (*pcbEncoded < bytesNeeded)
75 SetLastError(ERROR_MORE_DATA);
76 return FALSE;
78 if (len <= 0x7f)
79 *pbEncoded = (BYTE)len;
80 else
82 DWORD i;
84 *pbEncoded++ = significantBytes | 0x80;
85 for (i = 0; i < significantBytes; i++)
87 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
88 len >>= 8;
91 *pcbEncoded = bytesNeeded;
92 return TRUE;
95 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
96 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
97 DWORD *pcbEncoded)
99 BOOL ret = TRUE;
100 const CRYPT_DATA_BLOB *blob = pvStructInfo;
101 DWORD bytesNeeded, lenBytes;
103 TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
104 *pcbEncoded);
106 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
107 bytesNeeded = 1 + lenBytes + blob->cbData;
108 if (!pbEncoded)
109 *pcbEncoded = bytesNeeded;
110 else if (*pcbEncoded < bytesNeeded)
112 *pcbEncoded = bytesNeeded;
113 SetLastError(ERROR_MORE_DATA);
114 ret = FALSE;
116 else
118 *pbEncoded++ = ASN_OCTETSTRING;
119 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
120 pbEncoded += lenBytes;
121 if (blob->cbData)
122 memcpy(pbEncoded, blob->pbData, blob->cbData);
124 TRACE("returning %d\n", ret);
125 return ret;
128 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
129 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
130 DWORD *pcbEncoded)
132 BOOL ret = FALSE;
134 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
135 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
136 pcbEncoded);
138 __TRY
140 const SPC_LINK *link = pvStructInfo;
141 DWORD bytesNeeded, lenBytes;
143 switch (link->dwLinkChoice)
145 case SPC_FILE_LINK_CHOICE:
147 DWORD fileNameLen, fileNameLenBytes;
148 LPWSTR ptr;
150 fileNameLen = link->u.pwszFile ?
151 lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
152 CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
153 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
154 &lenBytes);
155 bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
156 if (!pbEncoded)
158 *pcbEncoded = bytesNeeded;
159 ret = TRUE;
161 else if (*pcbEncoded < bytesNeeded)
163 SetLastError(ERROR_MORE_DATA);
164 *pcbEncoded = bytesNeeded;
166 else
168 *pcbEncoded = bytesNeeded;
169 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
170 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
171 &lenBytes);
172 pbEncoded += lenBytes;
173 *pbEncoded++ = ASN_CONTEXT;
174 CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
175 pbEncoded += fileNameLenBytes;
176 for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
178 *(WCHAR *)pbEncoded = hton16(*ptr);
179 pbEncoded += sizeof(WCHAR);
181 ret = TRUE;
183 break;
185 case SPC_MONIKER_LINK_CHOICE:
187 DWORD classIdLenBytes, dataLenBytes, dataLen;
188 CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
189 (BYTE *)link->u.Moniker.ClassId };
191 CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
192 CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
193 &dataLenBytes);
194 dataLen = 2 + classIdLenBytes + classId.cbData +
195 dataLenBytes + link->u.Moniker.SerializedData.cbData;
196 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
197 bytesNeeded = 1 + dataLen + lenBytes;
198 if (!pbEncoded)
200 *pcbEncoded = bytesNeeded;
201 ret = TRUE;
203 else if (*pcbEncoded < bytesNeeded)
205 SetLastError(ERROR_MORE_DATA);
206 *pcbEncoded = bytesNeeded;
208 else
210 DWORD size;
212 *pcbEncoded = bytesNeeded;
213 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
214 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
215 pbEncoded += lenBytes;
216 size = 1 + classIdLenBytes + classId.cbData;
217 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
218 pbEncoded, &size);
219 pbEncoded += size;
220 size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
221 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
222 &link->u.Moniker.SerializedData, pbEncoded, &size);
223 pbEncoded += size;
224 ret = TRUE;
226 break;
228 case SPC_URL_LINK_CHOICE:
230 LPWSTR ptr;
231 DWORD urlLen;
233 /* Check for invalid characters in URL */
234 ret = TRUE;
235 urlLen = 0;
236 for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
237 if (*ptr > 0x7f)
239 *pcbEncoded = 0;
240 SetLastError(CRYPT_E_INVALID_IA5_STRING);
241 ret = FALSE;
243 else
244 urlLen++;
245 if (ret)
247 CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
248 bytesNeeded = 1 + lenBytes + urlLen;
249 if (!pbEncoded)
250 *pcbEncoded = bytesNeeded;
251 else if (*pcbEncoded < bytesNeeded)
253 SetLastError(ERROR_MORE_DATA);
254 *pcbEncoded = bytesNeeded;
255 ret = FALSE;
257 else
259 *pcbEncoded = bytesNeeded;
260 *pbEncoded++ = ASN_CONTEXT;
261 CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
262 pbEncoded += lenBytes;
263 for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
264 *pbEncoded++ = (BYTE)*ptr;
267 break;
269 default:
270 SetLastError(E_INVALIDARG);
273 __EXCEPT_PAGE_FAULT
275 SetLastError(STATUS_ACCESS_VIOLATION);
277 __ENDTRY
278 TRACE("returning %d\n", ret);
279 return ret;
282 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
283 BYTE *, DWORD *);
285 struct AsnEncodeSequenceItem
287 const void *pvStructInfo;
288 CryptEncodeObjectFunc encodeFunc;
289 DWORD size; /* used during encoding, not for your use */
292 static BOOL CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
293 struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
294 DWORD *pcbEncoded)
296 BOOL ret;
297 DWORD i, dataLen = 0;
299 TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
300 for (i = 0, ret = TRUE; ret && i < cItem; i++)
302 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
303 items[i].pvStructInfo, NULL, &items[i].size);
304 /* Some functions propagate their errors through the size */
305 if (!ret)
306 *pcbEncoded = items[i].size;
307 dataLen += items[i].size;
309 if (ret)
311 DWORD lenBytes, bytesNeeded;
313 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
314 bytesNeeded = 1 + lenBytes + dataLen;
315 if (!pbEncoded)
316 *pcbEncoded = bytesNeeded;
317 else if (*pcbEncoded < bytesNeeded)
319 *pcbEncoded = bytesNeeded;
320 SetLastError(ERROR_MORE_DATA);
321 ret = FALSE;
323 else
325 *pcbEncoded = bytesNeeded;
326 *pbEncoded++ = ASN_SEQUENCE;
327 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
328 pbEncoded += lenBytes;
329 for (i = 0; ret && i < cItem; i++)
331 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
332 items[i].pvStructInfo, pbEncoded, &items[i].size);
333 /* Some functions propagate their errors through the size */
334 if (!ret)
335 *pcbEncoded = items[i].size;
336 pbEncoded += items[i].size;
340 TRACE("returning %d\n", ret);
341 return ret;
344 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
345 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
346 DWORD *pcbEncoded)
348 BOOL ret = FALSE;
350 __TRY
352 const CRYPT_BIT_BLOB *blob = pvStructInfo;
353 DWORD bytesNeeded, lenBytes, dataBytes;
354 BYTE unusedBits;
356 /* yep, MS allows cUnusedBits to be >= 8 */
357 if (!blob->cUnusedBits)
359 dataBytes = blob->cbData;
360 unusedBits = 0;
362 else if (blob->cbData * 8 > blob->cUnusedBits)
364 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
365 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
366 blob->cUnusedBits;
368 else
370 dataBytes = 0;
371 unusedBits = 0;
373 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
374 bytesNeeded = 1 + lenBytes + dataBytes + 1;
375 if (!pbEncoded)
377 *pcbEncoded = bytesNeeded;
378 ret = TRUE;
380 else if (*pcbEncoded < bytesNeeded)
382 *pcbEncoded = bytesNeeded;
383 SetLastError(ERROR_MORE_DATA);
385 else
387 ret = TRUE;
388 *pcbEncoded = bytesNeeded;
389 *pbEncoded++ = ASN_BITSTRING;
390 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
391 pbEncoded += lenBytes;
392 *pbEncoded++ = unusedBits;
393 if (dataBytes)
395 BYTE mask = 0xff << unusedBits;
397 if (dataBytes > 1)
399 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
400 pbEncoded += dataBytes - 1;
402 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
406 __EXCEPT_PAGE_FAULT
408 SetLastError(STATUS_ACCESS_VIOLATION);
410 __ENDTRY
411 return ret;
414 struct AsnConstructedItem
416 BYTE tag;
417 const void *pvStructInfo;
418 CryptEncodeObjectFunc encodeFunc;
421 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
422 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
423 DWORD *pcbEncoded)
425 BOOL ret;
426 const struct AsnConstructedItem *item = pvStructInfo;
427 DWORD len;
429 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
430 item->pvStructInfo, NULL, &len)))
432 DWORD dataLen, bytesNeeded;
434 CRYPT_EncodeLen(len, NULL, &dataLen);
435 bytesNeeded = 1 + dataLen + len;
436 if (!pbEncoded)
437 *pcbEncoded = bytesNeeded;
438 else if (*pcbEncoded < bytesNeeded)
440 *pcbEncoded = bytesNeeded;
441 SetLastError(ERROR_MORE_DATA);
442 ret = FALSE;
444 else
446 *pcbEncoded = bytesNeeded;
447 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
448 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
449 pbEncoded += dataLen;
450 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
451 item->pvStructInfo, pbEncoded, &len);
452 if (!ret)
454 /* Some functions propagate their errors through the size */
455 *pcbEncoded = len;
459 else
461 /* Some functions propagate their errors through the size */
462 *pcbEncoded = len;
464 return ret;
468 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
469 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
470 DWORD *pcbEncoded)
472 const SPC_PE_IMAGE_DATA *imageData = pvStructInfo;
473 BOOL ret = FALSE;
475 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
476 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
477 pcbEncoded);
479 __TRY
481 struct AsnEncodeSequenceItem items[2] = {
482 { 0 }
484 struct AsnConstructedItem constructed = { 0, imageData->pFile,
485 WVTAsn1SpcLinkEncode };
486 DWORD cItem = 0;
488 if (imageData->Flags.cbData)
490 items[cItem].pvStructInfo = &imageData->Flags;
491 items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
492 cItem++;
494 if (imageData->pFile)
496 items[cItem].pvStructInfo = &constructed;
497 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
498 cItem++;
501 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
502 pbEncoded, pcbEncoded);
504 __EXCEPT_PAGE_FAULT
506 SetLastError(STATUS_ACCESS_VIOLATION);
508 __ENDTRY
509 TRACE("returning %d\n", ret);
510 return ret;
513 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
514 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
515 DWORD *pcbEncoded)
517 LPCSTR pszObjId = pvStructInfo;
518 DWORD bytesNeeded = 0, lenBytes;
519 BOOL ret = TRUE;
520 int firstPos = 0;
521 BYTE firstByte = 0;
523 TRACE("%s\n", debugstr_a(pszObjId));
525 if (pszObjId)
527 const char *ptr;
528 int val1, val2;
530 if (sscanf(pszObjId, "%d.%d%n", &val1, &val2, &firstPos) != 2)
532 SetLastError(CRYPT_E_ASN1_ERROR);
533 return FALSE;
535 bytesNeeded++;
536 firstByte = val1 * 40 + val2;
537 ptr = pszObjId + firstPos;
538 if (*ptr == '.')
540 ptr++;
541 firstPos++;
543 while (ret && *ptr)
545 int pos;
547 /* note I assume each component is at most 32-bits long in base 2 */
548 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
550 if (val1 >= 0x10000000)
551 bytesNeeded += 5;
552 else if (val1 >= 0x200000)
553 bytesNeeded += 4;
554 else if (val1 >= 0x4000)
555 bytesNeeded += 3;
556 else if (val1 >= 0x80)
557 bytesNeeded += 2;
558 else
559 bytesNeeded += 1;
560 ptr += pos;
561 if (*ptr == '.')
562 ptr++;
564 else
566 SetLastError(CRYPT_E_ASN1_ERROR);
567 return FALSE;
570 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
572 else
573 lenBytes = 1;
574 bytesNeeded += 1 + lenBytes;
575 if (pbEncoded)
577 if (*pcbEncoded < bytesNeeded)
579 SetLastError(ERROR_MORE_DATA);
580 ret = FALSE;
582 else
584 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
585 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
586 pbEncoded += lenBytes;
587 if (pszObjId)
589 const char *ptr;
590 int val, pos;
592 *pbEncoded++ = firstByte;
593 ptr = pszObjId + firstPos;
594 while (ret && *ptr)
596 sscanf(ptr, "%d%n", &val, &pos);
598 unsigned char outBytes[5];
599 int numBytes, i;
601 if (val >= 0x10000000)
602 numBytes = 5;
603 else if (val >= 0x200000)
604 numBytes = 4;
605 else if (val >= 0x4000)
606 numBytes = 3;
607 else if (val >= 0x80)
608 numBytes = 2;
609 else
610 numBytes = 1;
611 for (i = numBytes; i > 0; i--)
613 outBytes[i - 1] = val & 0x7f;
614 val >>= 7;
616 for (i = 0; i < numBytes - 1; i++)
617 *pbEncoded++ = outBytes[i] | 0x80;
618 *pbEncoded++ = outBytes[i];
619 ptr += pos;
620 if (*ptr == '.')
621 ptr++;
627 *pcbEncoded = bytesNeeded;
628 return ret;
631 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
632 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
633 DWORD *pcbEncoded)
635 const CRYPT_DER_BLOB *blob = pvStructInfo;
636 BOOL ret = TRUE;
638 if (!pbEncoded)
639 *pcbEncoded = blob->cbData;
640 else if (*pcbEncoded < blob->cbData)
642 *pcbEncoded = blob->cbData;
643 SetLastError(ERROR_MORE_DATA);
644 ret = FALSE;
646 else
648 if (blob->cbData)
649 memcpy(pbEncoded, blob->pbData, blob->cbData);
650 *pcbEncoded = blob->cbData;
652 return ret;
655 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
656 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
657 BYTE *pbEncoded, DWORD *pcbEncoded)
659 const CRYPT_ALGORITHM_IDENTIFIER *algo = pvStructInfo;
660 static const BYTE asn1Null[] = { ASN_NULL, 0 };
661 static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
662 (LPBYTE)asn1Null };
663 BOOL ret;
664 struct AsnEncodeSequenceItem items[2] = {
665 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
666 { NULL, CRYPT_CopyEncodedBlob, 0 },
669 if (algo->Parameters.cbData)
670 items[1].pvStructInfo = &algo->Parameters;
671 else
672 items[1].pvStructInfo = &nullBlob;
673 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
674 pbEncoded, pcbEncoded);
675 return ret;
678 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
679 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
680 DWORD *pcbEncoded)
682 const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue = pvStructInfo;
683 struct AsnEncodeSequenceItem items[] = {
684 { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
685 { &typeValue->Value, CRYPT_CopyEncodedBlob, 0 },
688 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items),
689 pbEncoded, pcbEncoded);
692 struct SPCDigest
694 CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
695 CRYPT_HASH_BLOB Digest;
698 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
699 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
700 DWORD *pcbEncoded)
702 const struct SPCDigest *digest = pvStructInfo;
703 struct AsnEncodeSequenceItem items[] = {
704 { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
705 { &digest->Digest, CRYPT_CopyEncodedBlob, 0 },
708 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items),
709 pbEncoded, pcbEncoded);
712 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
713 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
714 DWORD *pcbEncoded)
716 BOOL ret = FALSE;
718 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
719 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
721 __TRY
723 const SPC_INDIRECT_DATA_CONTENT *data = pvStructInfo;
724 struct AsnEncodeSequenceItem items[] = {
725 { &data->Data, CRYPT_AsnEncodeAttributeTypeValue, 0 },
726 { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
729 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items),
730 pbEncoded, pcbEncoded);
732 __EXCEPT_PAGE_FAULT
734 SetLastError(STATUS_ACCESS_VIOLATION);
736 __ENDTRY
737 return ret;
740 static BOOL WINAPI CRYPT_AsnEncodeBMPString(DWORD dwCertEncodingType,
741 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
742 DWORD *pcbEncoded)
744 BOOL ret = TRUE;
745 LPCWSTR str = pvStructInfo;
746 DWORD bytesNeeded, lenBytes, strLen;
748 if (str)
749 strLen = lstrlenW(str);
750 else
751 strLen = 0;
752 CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
753 bytesNeeded = 1 + lenBytes + strLen * 2;
754 if (!pbEncoded)
755 *pcbEncoded = bytesNeeded;
756 else if (*pcbEncoded < bytesNeeded)
758 *pcbEncoded = bytesNeeded;
759 SetLastError(ERROR_MORE_DATA);
760 ret = FALSE;
762 else
764 DWORD i;
766 *pcbEncoded = bytesNeeded;
767 *pbEncoded++ = ASN_BMPSTRING;
768 CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
769 pbEncoded += lenBytes;
770 for (i = 0; i < strLen; i++)
772 *pbEncoded++ = (str[i] & 0xff00) >> 8;
773 *pbEncoded++ = str[i] & 0x00ff;
776 return ret;
779 struct AsnEncodeTagSwappedItem
781 BYTE tag;
782 const void *pvStructInfo;
783 CryptEncodeObjectFunc encodeFunc;
786 /* Sort of a wacky hack, it encodes something using the struct
787 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
788 * given in the struct AsnEncodeTagSwappedItem.
790 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
791 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
792 DWORD *pcbEncoded)
794 BOOL ret;
795 const struct AsnEncodeTagSwappedItem *item = pvStructInfo;
797 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
798 item->pvStructInfo, pbEncoded, pcbEncoded);
799 if (ret && pbEncoded)
800 *pbEncoded = item->tag;
801 return ret;
804 BOOL WINAPI WVTAsn1SpcSpOpusInfoEncode(DWORD dwCertEncodingType,
805 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
806 DWORD *pcbEncoded)
808 BOOL ret = FALSE;
810 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
811 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
813 __TRY
815 const SPC_SP_OPUS_INFO *info = pvStructInfo;
817 if (info->pMoreInfo &&
818 info->pMoreInfo->dwLinkChoice != SPC_URL_LINK_CHOICE &&
819 info->pMoreInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE &&
820 info->pMoreInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE)
821 SetLastError(E_INVALIDARG);
822 else if (info->pPublisherInfo &&
823 info->pPublisherInfo->dwLinkChoice != SPC_URL_LINK_CHOICE &&
824 info->pPublisherInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE &&
825 info->pPublisherInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE)
826 SetLastError(E_INVALIDARG);
827 else
829 struct AsnEncodeSequenceItem items[3] = { { 0 } };
830 struct AsnConstructedItem constructed[3] = { { 0 } };
831 struct AsnEncodeTagSwappedItem swapped;
832 DWORD cItem = 0, cConstructed = 0;
834 if (info->pwszProgramName)
836 swapped.tag = ASN_CONTEXT;
837 swapped.pvStructInfo = info->pwszProgramName;
838 swapped.encodeFunc = CRYPT_AsnEncodeBMPString;
839 constructed[cConstructed].tag = 0;
840 constructed[cConstructed].pvStructInfo = &swapped;
841 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeSwapTag;
842 items[cItem].pvStructInfo = &constructed[cConstructed];
843 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
844 cConstructed++;
845 cItem++;
847 if (info->pMoreInfo)
849 constructed[cConstructed].tag = 1;
850 constructed[cConstructed].pvStructInfo = info->pMoreInfo;
851 constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode;
852 items[cItem].pvStructInfo = &constructed[cConstructed];
853 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
854 cConstructed++;
855 cItem++;
857 if (info->pPublisherInfo)
859 constructed[cConstructed].tag = 2;
860 constructed[cConstructed].pvStructInfo = info->pPublisherInfo;
861 constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode;
862 items[cItem].pvStructInfo = &constructed[cConstructed];
863 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
864 cConstructed++;
865 cItem++;
867 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
868 items, cItem, pbEncoded, pcbEncoded);
871 __EXCEPT_PAGE_FAULT
873 SetLastError(STATUS_ACCESS_VIOLATION);
875 __ENDTRY
876 return ret;
879 static BOOL CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
880 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
881 DWORD *pcbEncoded)
883 BOOL ret;
885 __TRY
887 DWORD significantBytes, lenBytes, bytesNeeded;
888 BYTE padByte = 0;
889 BOOL pad = FALSE;
890 const CRYPT_INTEGER_BLOB *blob = pvStructInfo;
892 significantBytes = blob->cbData;
893 if (significantBytes)
895 if (blob->pbData[significantBytes - 1] & 0x80)
897 /* negative, lop off leading (little-endian) 0xffs */
898 for (; significantBytes > 0 &&
899 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
901 if (blob->pbData[significantBytes - 1] < 0x80)
903 padByte = 0xff;
904 pad = TRUE;
907 else
909 /* positive, lop off leading (little-endian) zeroes */
910 for (; significantBytes > 0 &&
911 !blob->pbData[significantBytes - 1]; significantBytes--)
913 if (significantBytes == 0)
914 significantBytes = 1;
915 if (blob->pbData[significantBytes - 1] > 0x7f)
917 padByte = 0;
918 pad = TRUE;
922 if (pad)
923 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
924 else
925 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
926 bytesNeeded = 1 + lenBytes + significantBytes;
927 if (pad)
928 bytesNeeded++;
929 if (!pbEncoded)
931 *pcbEncoded = bytesNeeded;
932 ret = TRUE;
934 else if (*pcbEncoded < bytesNeeded)
936 *pcbEncoded = bytesNeeded;
937 SetLastError(ERROR_MORE_DATA);
938 ret = FALSE;
940 else
942 *pcbEncoded = bytesNeeded;
943 *pbEncoded++ = ASN_INTEGER;
944 if (pad)
946 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
947 pbEncoded += lenBytes;
948 *pbEncoded++ = padByte;
950 else
952 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
953 pbEncoded += lenBytes;
955 for (; significantBytes > 0; significantBytes--)
956 *(pbEncoded++) = blob->pbData[significantBytes - 1];
957 ret = TRUE;
960 __EXCEPT_PAGE_FAULT
962 SetLastError(STATUS_ACCESS_VIOLATION);
963 ret = FALSE;
965 __ENDTRY
966 return ret;
969 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
970 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
971 DWORD *pcbEncoded)
973 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
975 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
976 &blob, pbEncoded, pcbEncoded);
979 BOOL WINAPI WVTAsn1CatMemberInfoEncode(DWORD dwCertEncodingType,
980 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
981 DWORD *pcbEncoded)
983 BOOL ret = FALSE;
985 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
986 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
988 __TRY
990 const CAT_MEMBERINFO *info = pvStructInfo;
991 struct AsnEncodeSequenceItem items[] = {
992 { info->pwszSubjGuid, CRYPT_AsnEncodeBMPString, 0 },
993 { &info->dwCertVersion, CRYPT_AsnEncodeInt, 0 },
996 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items),
997 pbEncoded, pcbEncoded);
999 __EXCEPT_PAGE_FAULT
1001 SetLastError(STATUS_ACCESS_VIOLATION);
1003 __ENDTRY
1004 return ret;
1007 BOOL WINAPI WVTAsn1CatNameValueEncode(DWORD dwCertEncodingType,
1008 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1009 DWORD *pcbEncoded)
1011 BOOL ret = FALSE;
1013 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
1014 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
1016 __TRY
1018 const CAT_NAMEVALUE *value = pvStructInfo;
1019 struct AsnEncodeSequenceItem items[] = {
1020 { value->pwszTag, CRYPT_AsnEncodeBMPString, 0 },
1021 { &value->fdwFlags, CRYPT_AsnEncodeInt, 0 },
1022 { &value->Value, CRYPT_AsnEncodeOctets, 0 },
1025 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items),
1026 pbEncoded, pcbEncoded);
1028 __EXCEPT_PAGE_FAULT
1030 SetLastError(STATUS_ACCESS_VIOLATION);
1032 __ENDTRY
1033 return ret;
1036 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1037 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1038 DWORD *pcbEncoded)
1040 BOOL val = *(const BOOL *)pvStructInfo, ret;
1042 TRACE("%d\n", val);
1044 if (!pbEncoded)
1046 *pcbEncoded = 3;
1047 ret = TRUE;
1049 else if (*pcbEncoded < 3)
1051 *pcbEncoded = 3;
1052 SetLastError(ERROR_MORE_DATA);
1053 ret = FALSE;
1055 else
1057 *pcbEncoded = 3;
1058 *pbEncoded++ = ASN_BOOL;
1059 *pbEncoded++ = 1;
1060 *pbEncoded++ = val ? 0xff : 0;
1061 ret = TRUE;
1063 TRACE("returning %d (%08x)\n", ret, GetLastError());
1064 return ret;
1067 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoEncode(DWORD dwCertEncodingType,
1068 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
1069 DWORD *pcbEncoded)
1071 BOOL ret = FALSE;
1073 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
1074 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
1076 __TRY
1078 const SPC_FINANCIAL_CRITERIA *criteria = pvStructInfo;
1079 struct AsnEncodeSequenceItem items[] = {
1080 { &criteria->fFinancialInfoAvailable, CRYPT_AsnEncodeBool, 0 },
1081 { &criteria->fMeetsCriteria, CRYPT_AsnEncodeBool, 0 },
1084 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items),
1085 pbEncoded, pcbEncoded);
1087 __EXCEPT_PAGE_FAULT
1089 SetLastError(STATUS_ACCESS_VIOLATION);
1091 __ENDTRY
1092 return ret;
1095 /* Gets the number of length bytes from the given (leading) length byte */
1096 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1098 /* Helper function to get the encoded length of the data starting at pbEncoded,
1099 * where pbEncoded[0] is the tag. If the data are too short to contain a
1100 * length or if the length is too large for cbEncoded, sets an appropriate
1101 * error code and returns FALSE.
1103 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
1105 BOOL ret;
1107 if (cbEncoded <= 1)
1109 SetLastError(CRYPT_E_ASN1_CORRUPT);
1110 ret = FALSE;
1112 else if (pbEncoded[1] <= 0x7f)
1114 if (pbEncoded[1] + 1 > cbEncoded)
1116 SetLastError(CRYPT_E_ASN1_EOD);
1117 ret = FALSE;
1119 else
1121 *len = pbEncoded[1];
1122 ret = TRUE;
1125 else if (pbEncoded[1] == 0x80)
1127 FIXME("unimplemented for indefinite-length encoding\n");
1128 SetLastError(CRYPT_E_ASN1_CORRUPT);
1129 ret = FALSE;
1131 else
1133 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1135 if (lenLen > sizeof(DWORD) + 1)
1137 SetLastError(CRYPT_E_ASN1_LARGE);
1138 ret = FALSE;
1140 else if (lenLen + 2 > cbEncoded)
1142 SetLastError(CRYPT_E_ASN1_CORRUPT);
1143 ret = FALSE;
1145 else
1147 DWORD out = 0;
1149 pbEncoded += 2;
1150 while (--lenLen)
1152 out <<= 8;
1153 out |= *pbEncoded++;
1155 if (out + lenLen + 1 > cbEncoded)
1157 SetLastError(CRYPT_E_ASN1_EOD);
1158 ret = FALSE;
1160 else
1162 *len = out;
1163 ret = TRUE;
1167 return ret;
1170 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1171 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1172 void *pvStructInfo, DWORD *pcbStructInfo)
1174 BOOL ret;
1175 DWORD bytesNeeded, dataLen;
1177 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1178 pvStructInfo, *pcbStructInfo);
1180 if (!cbEncoded)
1182 SetLastError(CRYPT_E_ASN1_CORRUPT);
1183 ret = FALSE;
1185 else if (pbEncoded[0] != ASN_OCTETSTRING)
1187 SetLastError(CRYPT_E_ASN1_BADTAG);
1188 ret = FALSE;
1190 else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1192 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1193 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1194 else
1195 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1196 if (!pvStructInfo)
1197 *pcbStructInfo = bytesNeeded;
1198 else if (*pcbStructInfo < bytesNeeded)
1200 SetLastError(ERROR_MORE_DATA);
1201 *pcbStructInfo = bytesNeeded;
1202 ret = FALSE;
1204 else
1206 CRYPT_DATA_BLOB *blob;
1207 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1209 blob = pvStructInfo;
1210 blob->cbData = dataLen;
1211 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1212 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1213 else
1215 assert(blob->pbData);
1216 if (blob->cbData)
1217 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
1218 blob->cbData);
1222 return ret;
1225 static BOOL CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
1226 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1227 void *pvStructInfo, DWORD *pcbStructInfo)
1229 BOOL ret = FALSE;
1230 DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
1232 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1233 pvStructInfo, *pcbStructInfo);
1235 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1237 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1238 DWORD realDataLen;
1240 switch (pbEncoded[0])
1242 case ASN_CONTEXT:
1243 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
1244 if (!pvStructInfo)
1245 *pcbStructInfo = bytesNeeded;
1246 else if (*pcbStructInfo < bytesNeeded)
1248 *pcbStructInfo = bytesNeeded;
1249 SetLastError(ERROR_MORE_DATA);
1250 ret = FALSE;
1252 else
1254 PSPC_LINK link = pvStructInfo;
1255 DWORD i;
1257 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
1258 for (i = 0; i < dataLen; i++)
1259 link->u.pwszUrl[i] =
1260 *(pbEncoded + 1 + lenBytes + i);
1261 link->u.pwszUrl[i] = '\0';
1262 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
1264 break;
1265 case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
1267 CRYPT_DATA_BLOB classId;
1268 DWORD size = sizeof(classId);
1270 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1271 pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
1272 CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
1274 if (classId.cbData != sizeof(SPC_UUID))
1276 SetLastError(CRYPT_E_BAD_ENCODE);
1277 ret = FALSE;
1279 else
1281 CRYPT_DATA_BLOB data;
1283 /* The tag length for the classId must be 1 since the
1284 * length is correct.
1286 size = sizeof(data);
1287 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1288 pbEncoded + 3 + lenBytes + classId.cbData,
1289 cbEncoded - 3 - lenBytes - classId.cbData,
1290 CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
1292 bytesNeeded += data.cbData;
1293 if (!pvStructInfo)
1294 *pcbStructInfo = bytesNeeded;
1295 else if (*pcbStructInfo < bytesNeeded)
1297 *pcbStructInfo = bytesNeeded;
1298 SetLastError(ERROR_MORE_DATA);
1299 ret = FALSE;
1301 else
1303 PSPC_LINK link = pvStructInfo;
1305 link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
1306 /* pwszFile pointer was set by caller, copy it
1307 * before overwriting it
1309 link->u.Moniker.SerializedData.pbData =
1310 (BYTE *)link->u.pwszFile;
1311 memcpy(link->u.Moniker.ClassId, classId.pbData,
1312 classId.cbData);
1313 memcpy(link->u.Moniker.SerializedData.pbData,
1314 data.pbData, data.cbData);
1315 link->u.Moniker.SerializedData.cbData = data.cbData;
1320 break;
1322 case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
1323 if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
1324 SetLastError(CRYPT_E_ASN1_BADTAG);
1325 else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
1326 &realDataLen)))
1328 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
1330 bytesNeeded += realDataLen + sizeof(WCHAR);
1331 if (!pvStructInfo)
1332 *pcbStructInfo = bytesNeeded;
1333 else if (*pcbStructInfo < bytesNeeded)
1335 *pcbStructInfo = bytesNeeded;
1336 SetLastError(ERROR_MORE_DATA);
1337 ret = FALSE;
1339 else
1341 PSPC_LINK link = pvStructInfo;
1342 DWORD i;
1343 const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
1345 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1346 for (i = 0; i < dataLen / sizeof(WCHAR); i++)
1347 link->u.pwszFile[i] =
1348 hton16(*(const WORD *)(ptr + i * sizeof(WCHAR)));
1349 link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
1350 TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
1353 else
1355 bytesNeeded += sizeof(WCHAR);
1356 if (!pvStructInfo)
1357 *pcbStructInfo = bytesNeeded;
1358 else if (*pcbStructInfo < bytesNeeded)
1360 *pcbStructInfo = bytesNeeded;
1361 SetLastError(ERROR_MORE_DATA);
1362 ret = FALSE;
1364 else
1366 PSPC_LINK link = pvStructInfo;
1368 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1369 link->u.pwszFile[0] = '\0';
1370 ret = TRUE;
1373 break;
1374 default:
1375 SetLastError(CRYPT_E_ASN1_BADTAG);
1378 TRACE("returning %d\n", ret);
1379 return ret;
1382 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1383 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1384 void *pvStructInfo, DWORD *pcbStructInfo)
1386 BOOL ret = FALSE;
1388 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1389 pvStructInfo, *pcbStructInfo);
1391 __TRY
1393 DWORD bytesNeeded;
1395 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1396 lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1397 if (ret)
1399 if (!pvStructInfo)
1400 *pcbStructInfo = bytesNeeded;
1401 else if (*pcbStructInfo < bytesNeeded)
1403 *pcbStructInfo = bytesNeeded;
1404 SetLastError(ERROR_MORE_DATA);
1405 ret = FALSE;
1407 else
1409 SPC_LINK *link = pvStructInfo;
1411 link->u.pwszFile =
1412 (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1413 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1414 lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1415 pcbStructInfo);
1419 __EXCEPT_PAGE_FAULT
1421 SetLastError(STATUS_ACCESS_VIOLATION);
1423 __ENDTRY
1424 TRACE("returning %d\n", ret);
1425 return ret;
1428 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1429 DWORD, DWORD, void *, DWORD *);
1431 /* tag:
1432 * The expected tag of the item. If tag is 0, decodeFunc is called
1433 * regardless of the tag value seen.
1434 * offset:
1435 * A sequence is decoded into a struct. The offset member is the
1436 * offset of this item within that struct.
1437 * decodeFunc:
1438 * The decoder function to use. If this is NULL, then the member isn't
1439 * decoded, but minSize space is reserved for it.
1440 * minSize:
1441 * The minimum amount of space occupied after decoding. You must set this.
1442 * optional:
1443 * If true, and the tag doesn't match the expected tag for this item,
1444 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1445 * filled with 0 for this member.
1446 * hasPointer, pointerOffset:
1447 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1448 * the offset within the struct of the data pointer (or to the
1449 * first data pointer, if more than one exist).
1450 * size:
1451 * Used by CRYPT_AsnDecodeSequence, not for your use.
1453 struct AsnDecodeSequenceItem
1455 BYTE tag;
1456 DWORD offset;
1457 CryptDecodeObjectFunc decodeFunc;
1458 DWORD minSize;
1459 BOOL optional;
1460 BOOL hasPointer;
1461 DWORD pointerOffset;
1462 DWORD size;
1465 /* Align up to a DWORD_PTR boundary
1467 #define ALIGN_DWORD_PTR(x) (((x) + sizeof(DWORD_PTR) - 1) & ~(sizeof(DWORD_PTR) - 1))
1469 #define FINALMEMBERSIZE(s, member) (sizeof(s) - offsetof(s, member))
1470 #define MEMBERSIZE(s, member, nextmember) \
1471 (offsetof(s, nextmember) - offsetof(s, member))
1474 /* Decodes the items in a sequence, where the items are described in items,
1475 * the encoded data are in pbEncoded with length cbEncoded. Decodes into
1476 * pvStructInfo. nextData is a pointer to the memory location at which the
1477 * first decoded item with a dynamic pointer should point.
1478 * Upon decoding, *cbDecoded is the total number of bytes decoded.
1480 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1481 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1482 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1483 DWORD *cbDecoded)
1485 BOOL ret;
1486 DWORD i, decoded = 0;
1487 const BYTE *ptr = pbEncoded;
1489 TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1490 cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1492 for (i = 0, ret = TRUE; ret && i < cItem; i++)
1494 if (cbEncoded - (ptr - pbEncoded) != 0)
1496 DWORD nextItemLen;
1498 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1499 &nextItemLen)))
1501 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1503 if (ptr[0] == items[i].tag || !items[i].tag)
1505 if (nextData && pvStructInfo && items[i].hasPointer)
1507 TRACE("Setting next pointer to %p\n",
1508 nextData);
1509 *(BYTE **)((BYTE *)pvStructInfo +
1510 items[i].pointerOffset) = nextData;
1512 if (items[i].decodeFunc)
1514 if (pvStructInfo)
1515 TRACE("decoding item %d\n", i);
1516 else
1517 TRACE("sizing item %d\n", i);
1518 ret = items[i].decodeFunc(dwCertEncodingType,
1519 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1520 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1521 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
1522 : NULL, &items[i].size);
1523 if (ret)
1525 if (items[i].size < items[i].minSize)
1526 items[i].size = items[i].minSize;
1527 else if (items[i].size > items[i].minSize)
1529 /* Account for alignment padding */
1530 items[i].size = ALIGN_DWORD_PTR(items[i].size);
1532 TRACE("item %d size: %d\n", i, items[i].size);
1533 if (nextData && items[i].hasPointer &&
1534 items[i].size > items[i].minSize)
1535 nextData += items[i].size - items[i].minSize;
1536 ptr += 1 + nextItemLenBytes + nextItemLen;
1537 decoded += 1 + nextItemLenBytes + nextItemLen;
1538 TRACE("item %d: decoded %d bytes\n", i,
1539 1 + nextItemLenBytes + nextItemLen);
1541 else if (items[i].optional &&
1542 GetLastError() == CRYPT_E_ASN1_BADTAG)
1544 TRACE("skipping optional item %d\n", i);
1545 items[i].size = items[i].minSize;
1546 SetLastError(NOERROR);
1547 ret = TRUE;
1549 else
1550 TRACE("item %d failed: %08x\n", i,
1551 GetLastError());
1553 else
1555 TRACE("item %d: decoded %d bytes\n", i,
1556 1 + nextItemLenBytes + nextItemLen);
1557 ptr += 1 + nextItemLenBytes + nextItemLen;
1558 decoded += 1 + nextItemLenBytes + nextItemLen;
1559 items[i].size = items[i].minSize;
1562 else if (items[i].optional)
1564 TRACE("skipping optional item %d\n", i);
1565 items[i].size = items[i].minSize;
1567 else
1569 TRACE("item %d: tag %02x doesn't match expected %02x\n",
1570 i, ptr[0], items[i].tag);
1571 SetLastError(CRYPT_E_ASN1_BADTAG);
1572 ret = FALSE;
1576 else if (items[i].optional)
1578 TRACE("missing optional item %d, skipping\n", i);
1579 items[i].size = items[i].minSize;
1581 else
1583 TRACE("not enough bytes for item %d, failing\n", i);
1584 SetLastError(CRYPT_E_ASN1_CORRUPT);
1585 ret = FALSE;
1588 if (ret)
1589 *cbDecoded = decoded;
1590 TRACE("returning %d\n", ret);
1591 return ret;
1594 /* This decodes an arbitrary sequence into a contiguous block of memory
1595 * (basically, a struct.) Each element being decoded is described by a struct
1596 * AsnDecodeSequenceItem, see above.
1597 * startingPointer is an optional pointer to the first place where dynamic
1598 * data will be stored. If you know the starting offset, you may pass it
1599 * here. Otherwise, pass NULL, and one will be inferred from the items.
1601 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1602 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1603 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1604 void *startingPointer)
1606 BOOL ret;
1608 TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1609 cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1611 if (pbEncoded[0] == ASN_SEQUENCE)
1613 DWORD dataLen;
1615 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1617 DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1618 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1620 cbEncoded -= 1 + lenBytes;
1621 if (cbEncoded < dataLen)
1623 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1624 cbEncoded);
1625 SetLastError(CRYPT_E_ASN1_CORRUPT);
1626 ret = FALSE;
1628 else
1629 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1630 cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1631 if (ret && cbDecoded != dataLen)
1633 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1634 cbDecoded);
1635 SetLastError(CRYPT_E_ASN1_CORRUPT);
1636 ret = FALSE;
1638 if (ret)
1640 DWORD i, bytesNeeded = 0, structSize = 0;
1642 for (i = 0; i < cItem; i++)
1644 bytesNeeded += items[i].size;
1645 structSize += items[i].minSize;
1647 if (!pvStructInfo)
1648 *pcbStructInfo = bytesNeeded;
1649 else if (*pcbStructInfo < bytesNeeded)
1651 SetLastError(ERROR_MORE_DATA);
1652 *pcbStructInfo = bytesNeeded;
1653 ret = FALSE;
1655 else
1657 BYTE *nextData;
1659 *pcbStructInfo = bytesNeeded;
1660 if (startingPointer)
1661 nextData = startingPointer;
1662 else
1663 nextData = (BYTE *)pvStructInfo + structSize;
1664 memset(pvStructInfo, 0, structSize);
1665 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1666 ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1667 &cbDecoded);
1672 else
1674 SetLastError(CRYPT_E_ASN1_BADTAG);
1675 ret = FALSE;
1677 TRACE("returning %d (%08x)\n", ret, GetLastError());
1678 return ret;
1681 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1682 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1683 void *pvStructInfo, DWORD *pcbStructInfo)
1685 BOOL ret;
1687 TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1688 pvStructInfo, *pcbStructInfo);
1690 if (pbEncoded[0] == ASN_BITSTRING)
1692 DWORD bytesNeeded, dataLen;
1694 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1696 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1697 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1698 else
1699 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1700 if (!pvStructInfo)
1701 *pcbStructInfo = bytesNeeded;
1702 else if (*pcbStructInfo < bytesNeeded)
1704 *pcbStructInfo = bytesNeeded;
1705 SetLastError(ERROR_MORE_DATA);
1706 ret = FALSE;
1708 else
1710 CRYPT_BIT_BLOB *blob;
1712 blob = pvStructInfo;
1713 blob->cbData = dataLen - 1;
1714 blob->cUnusedBits = *(pbEncoded + 1 +
1715 GET_LEN_BYTES(pbEncoded[1]));
1716 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1718 blob->pbData = (BYTE *)pbEncoded + 2 +
1719 GET_LEN_BYTES(pbEncoded[1]);
1721 else
1723 assert(blob->pbData);
1724 if (blob->cbData)
1726 BYTE mask = 0xff << blob->cUnusedBits;
1728 memcpy(blob->pbData, pbEncoded + 2 +
1729 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1730 blob->pbData[blob->cbData - 1] &= mask;
1736 else
1738 SetLastError(CRYPT_E_ASN1_BADTAG);
1739 ret = FALSE;
1741 TRACE("returning %d (%08x)\n", ret, GetLastError());
1742 return ret;
1745 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1746 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1747 void *pvStructInfo, DWORD *pcbStructInfo)
1749 BOOL ret = FALSE;
1750 DWORD dataLen;
1752 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1754 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1755 DWORD size;
1756 SPC_LINK **pLink = pvStructInfo;
1758 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1759 pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1760 if (ret)
1762 if (!pvStructInfo)
1763 *pcbStructInfo = size + sizeof(PSPC_LINK);
1764 else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1766 *pcbStructInfo = size + sizeof(PSPC_LINK);
1767 SetLastError(ERROR_MORE_DATA);
1768 ret = FALSE;
1770 else
1772 *pcbStructInfo = size + sizeof(PSPC_LINK);
1773 /* Set imageData's pointer if necessary */
1774 if (size > sizeof(SPC_LINK))
1776 (*pLink)->u.pwszUrl =
1777 (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1779 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1780 lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1781 *pLink, pcbStructInfo);
1785 return ret;
1788 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1789 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1790 void *pvStructInfo, DWORD *pcbStructInfo)
1792 BOOL ret = FALSE;
1794 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1795 pvStructInfo, *pcbStructInfo);
1797 __TRY
1799 struct AsnDecodeSequenceItem items[] = {
1800 { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1801 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1802 offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1803 { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1804 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1805 offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1808 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
1809 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, NULL);
1811 __EXCEPT_PAGE_FAULT
1813 SetLastError(STATUS_ACCESS_VIOLATION);
1815 __ENDTRY
1816 TRACE("returning %d\n", ret);
1817 return ret;
1820 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1821 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1822 void *pvStructInfo, DWORD *pcbStructInfo)
1824 BOOL ret = TRUE;
1825 DWORD dataLen;
1827 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1828 pvStructInfo, *pcbStructInfo);
1830 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1832 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1833 DWORD bytesNeeded = sizeof(LPSTR);
1835 if (dataLen)
1837 /* The largest possible string for the first two components
1838 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1840 char firstTwo[8];
1841 const BYTE *ptr;
1843 sprintf(firstTwo, "%d.%d",
1844 pbEncoded[1 + lenBytes] / 40,
1845 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1846 * 40);
1847 bytesNeeded += strlen(firstTwo) + 1;
1848 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1849 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1851 /* large enough for ".4000000" */
1852 char str[9];
1853 int val = 0;
1855 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1856 (*ptr & 0x80))
1858 val <<= 7;
1859 val |= *ptr & 0x7f;
1860 ptr++;
1862 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1863 (*ptr & 0x80))
1865 SetLastError(CRYPT_E_ASN1_CORRUPT);
1866 ret = FALSE;
1868 else
1870 val <<= 7;
1871 val |= *ptr++;
1872 snprintf(str, sizeof(str), ".%d", val);
1873 bytesNeeded += strlen(str);
1877 if (!pvStructInfo)
1878 *pcbStructInfo = bytesNeeded;
1879 else if (*pcbStructInfo < bytesNeeded)
1881 *pcbStructInfo = bytesNeeded;
1882 SetLastError(ERROR_MORE_DATA);
1883 ret = FALSE;
1885 else
1887 if (dataLen)
1889 const BYTE *ptr;
1890 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1892 *pszObjId = 0;
1893 pszObjId += sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1894 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1895 40) * 40);
1896 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1897 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1899 int val = 0;
1901 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1902 (*ptr & 0x80))
1904 val <<= 7;
1905 val |= *ptr & 0x7f;
1906 ptr++;
1908 val <<= 7;
1909 val |= *ptr++;
1910 pszObjId += sprintf(pszObjId, ".%d", val);
1913 else
1914 *(LPSTR *)pvStructInfo = NULL;
1915 *pcbStructInfo = bytesNeeded;
1918 return ret;
1921 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1922 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1923 void *pvStructInfo, DWORD *pcbStructInfo)
1925 BOOL ret = FALSE;
1927 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1928 pvStructInfo, *pcbStructInfo);
1930 if (!cbEncoded)
1931 SetLastError(CRYPT_E_ASN1_CORRUPT);
1932 else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1933 ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1934 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1935 else
1936 SetLastError(CRYPT_E_ASN1_BADTAG);
1937 return ret;
1940 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1941 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1942 void *pvStructInfo, DWORD *pcbStructInfo)
1944 BOOL ret = TRUE;
1945 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1947 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1948 pvStructInfo, *pcbStructInfo);
1950 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1951 bytesNeeded += cbEncoded;
1952 if (!pvStructInfo)
1953 *pcbStructInfo = bytesNeeded;
1954 else if (*pcbStructInfo < bytesNeeded)
1956 SetLastError(ERROR_MORE_DATA);
1957 *pcbStructInfo = bytesNeeded;
1958 ret = FALSE;
1960 else
1962 PCRYPT_OBJID_BLOB blob = pvStructInfo;
1964 *pcbStructInfo = bytesNeeded;
1965 blob->cbData = cbEncoded;
1966 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1967 blob->pbData = (LPBYTE)pbEncoded;
1968 else
1970 assert(blob->pbData);
1971 memcpy(blob->pbData, pbEncoded, blob->cbData);
1974 return ret;
1977 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1978 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1979 void *pvStructInfo, DWORD *pcbStructInfo)
1981 CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue = pvStructInfo;
1982 struct AsnDecodeSequenceItem items[] = {
1983 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1984 CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1985 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1986 { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1987 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1988 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1991 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1992 pvStructInfo, *pcbStructInfo);
1994 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
1995 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo,
1996 typeValue ? typeValue->pszObjId : NULL);
1999 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
2000 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2001 void *pvStructInfo, DWORD *pcbStructInfo)
2003 CRYPT_ALGORITHM_IDENTIFIER *algo = pvStructInfo;
2004 BOOL ret = TRUE;
2005 struct AsnDecodeSequenceItem items[] = {
2006 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
2007 CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
2008 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
2009 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
2010 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
2011 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
2014 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2015 pvStructInfo, *pcbStructInfo);
2017 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2018 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
2019 if (ret && pvStructInfo)
2021 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
2022 debugstr_a(algo->pszObjId));
2024 return ret;
2027 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
2028 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2029 void *pvStructInfo, DWORD *pcbStructInfo)
2031 struct SPCDigest *digest = pvStructInfo;
2032 struct AsnDecodeSequenceItem items[] = {
2033 { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
2034 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2035 FALSE, TRUE,
2036 offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
2037 { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
2038 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
2039 FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
2042 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2043 pvStructInfo, *pcbStructInfo);
2045 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2046 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo,
2047 digest ? digest->DigestAlgorithm.pszObjId : NULL);
2050 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
2051 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2052 void *pvStructInfo, DWORD *pcbStructInfo)
2054 BOOL ret = FALSE;
2056 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2057 pvStructInfo, *pcbStructInfo);
2059 __TRY
2061 struct AsnDecodeSequenceItem items[] = {
2062 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
2063 CRYPT_AsnDecodeAttributeTypeValue,
2064 sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
2065 offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
2066 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
2067 CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
2068 FALSE, TRUE,
2069 offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
2072 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2073 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, NULL);
2075 __EXCEPT_PAGE_FAULT
2077 SetLastError(STATUS_ACCESS_VIOLATION);
2079 __ENDTRY
2080 TRACE("returning %d\n", ret);
2081 return ret;
2084 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
2085 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2086 void *pvStructInfo, DWORD *pcbStructInfo)
2088 BOOL ret;
2089 DWORD bytesNeeded, dataLen;
2091 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2093 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2095 bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
2096 if (!pvStructInfo)
2097 *pcbStructInfo = bytesNeeded;
2098 else if (*pcbStructInfo < bytesNeeded)
2100 *pcbStructInfo = bytesNeeded;
2101 SetLastError(ERROR_MORE_DATA);
2102 ret = FALSE;
2104 else
2106 LPWSTR str;
2107 DWORD i;
2109 *pcbStructInfo = bytesNeeded;
2110 assert(pvStructInfo);
2111 str = *(LPWSTR *)pvStructInfo;
2112 for (i = 0; i < dataLen / 2; i++)
2113 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
2114 pbEncoded[1 + lenBytes + 2 * i + 1];
2115 /* Decoded string is always NULL-terminated */
2116 str[i] = '\0';
2119 return ret;
2122 static BOOL WINAPI CRYPT_AsnDecodeProgramName(DWORD dwCertEncodingType,
2123 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2124 void *pvStructInfo, DWORD *pcbStructInfo)
2126 BOOL ret = FALSE;
2127 DWORD dataLen;
2129 TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2130 pvStructInfo, pvStructInfo ? *pcbStructInfo : 0);
2132 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2134 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2136 ret = CRYPT_AsnDecodeBMPString(dwCertEncodingType, lpszStructType,
2137 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pvStructInfo,
2138 pcbStructInfo);
2140 return ret;
2143 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
2144 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2145 void *pvStructInfo, DWORD *pcbStructInfo)
2147 BOOL ret = FALSE;
2149 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2150 pvStructInfo, *pcbStructInfo);
2152 __TRY
2154 struct AsnDecodeSequenceItem items[] = {
2155 { ASN_CONSTRUCTOR | ASN_CONTEXT,
2156 offsetof(SPC_SP_OPUS_INFO, pwszProgramName),
2157 CRYPT_AsnDecodeProgramName, sizeof(LPCWSTR), TRUE, TRUE,
2158 offsetof(SPC_SP_OPUS_INFO, pwszProgramName), 0 },
2159 { ASN_CONSTRUCTOR | ASN_CONTEXT | 1,
2160 offsetof(SPC_SP_OPUS_INFO, pMoreInfo),
2161 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
2162 offsetof(SPC_SP_OPUS_INFO, pMoreInfo), 0 },
2163 { ASN_CONSTRUCTOR | ASN_CONTEXT | 2,
2164 offsetof(SPC_SP_OPUS_INFO, pPublisherInfo),
2165 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
2166 offsetof(SPC_SP_OPUS_INFO, pPublisherInfo), 0 },
2169 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2170 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, NULL);
2172 __EXCEPT_PAGE_FAULT
2174 SetLastError(STATUS_ACCESS_VIOLATION);
2176 __ENDTRY
2177 TRACE("returning %d\n", ret);
2178 return ret;
2181 /* Ignores tag. Only allows integers 4 bytes or smaller in size. */
2182 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2183 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2184 void *pvStructInfo, DWORD *pcbStructInfo)
2186 BOOL ret;
2187 DWORD dataLen;
2189 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2191 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2193 if (dataLen > sizeof(int))
2195 SetLastError(CRYPT_E_ASN1_LARGE);
2196 ret = FALSE;
2198 else if (!pvStructInfo)
2199 *pcbStructInfo = sizeof(int);
2200 else if (*pcbStructInfo < sizeof(int))
2202 *pcbStructInfo = sizeof(int);
2203 SetLastError(ERROR_MORE_DATA);
2204 ret = FALSE;
2206 else
2208 int val;
2209 DWORD i;
2211 *pcbStructInfo = sizeof(int);
2212 if (dataLen && pbEncoded[1 + lenBytes] & 0x80)
2214 /* initialize to a negative value to sign-extend */
2215 val = -1;
2217 else
2218 val = 0;
2219 for (i = 0; i < dataLen; i++)
2221 val <<= 8;
2222 val |= pbEncoded[1 + lenBytes + i];
2224 memcpy(pvStructInfo, &val, sizeof(int));
2227 return ret;
2230 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2231 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2232 void *pvStructInfo, DWORD *pcbStructInfo)
2234 BOOL ret = FALSE;
2236 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2237 pvStructInfo, *pcbStructInfo);
2239 __TRY
2241 struct AsnDecodeSequenceItem items[] = {
2242 { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2243 CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2244 offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2245 { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2246 CRYPT_AsnDecodeInt, FINALMEMBERSIZE(CAT_MEMBERINFO, dwCertVersion),
2247 FALSE, FALSE, 0, 0 },
2250 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2251 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, NULL);
2253 __EXCEPT_PAGE_FAULT
2255 SetLastError(STATUS_ACCESS_VIOLATION);
2257 __ENDTRY
2258 TRACE("returning %d\n", ret);
2259 return ret;
2262 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2263 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2264 void *pvStructInfo, DWORD *pcbStructInfo)
2266 BOOL ret = FALSE;
2268 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2269 pvStructInfo, *pcbStructInfo);
2271 __TRY
2273 struct AsnDecodeSequenceItem items[] = {
2274 { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2275 CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2276 offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2277 { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2278 CRYPT_AsnDecodeInt, MEMBERSIZE(CAT_NAMEVALUE, fdwFlags, Value),
2279 FALSE, FALSE, 0, 0 },
2280 { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2281 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2282 offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2285 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2286 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, NULL);
2288 __EXCEPT_PAGE_FAULT
2290 SetLastError(STATUS_ACCESS_VIOLATION);
2292 __ENDTRY
2293 TRACE("returning %d\n", ret);
2294 return ret;
2297 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
2298 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2299 void *pvStructInfo, DWORD *pcbStructInfo)
2301 BOOL ret;
2303 if (cbEncoded < 3)
2305 SetLastError(CRYPT_E_ASN1_CORRUPT);
2306 return FALSE;
2308 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2310 SetLastError(CRYPT_E_ASN1_CORRUPT);
2311 return FALSE;
2313 if (pbEncoded[1] > 1)
2315 SetLastError(CRYPT_E_ASN1_CORRUPT);
2316 return FALSE;
2318 if (!pvStructInfo)
2320 *pcbStructInfo = sizeof(BOOL);
2321 ret = TRUE;
2323 else if (*pcbStructInfo < sizeof(BOOL))
2325 *pcbStructInfo = sizeof(BOOL);
2326 SetLastError(ERROR_MORE_DATA);
2327 ret = FALSE;
2329 else
2331 *pcbStructInfo = sizeof(BOOL);
2332 *(BOOL *)pvStructInfo = pbEncoded[2] != 0;
2333 ret = TRUE;
2335 TRACE("returning %d (%08x)\n", ret, GetLastError());
2336 return ret;
2339 BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType,
2340 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2341 void *pvStructInfo, DWORD *pcbStructInfo)
2343 BOOL ret = FALSE;
2345 TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
2346 pvStructInfo, *pcbStructInfo);
2348 __TRY
2350 struct AsnDecodeSequenceItem items[] = {
2351 { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable),
2352 CRYPT_AsnDecodeBool, MEMBERSIZE(SPC_FINANCIAL_CRITERIA,
2353 fFinancialInfoAvailable, fMeetsCriteria), FALSE, FALSE, 0, 0 },
2354 { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria),
2355 CRYPT_AsnDecodeBool, FINALMEMBERSIZE(SPC_FINANCIAL_CRITERIA,
2356 fMeetsCriteria), FALSE, FALSE, 0, 0 },
2359 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, ARRAY_SIZE(items),
2360 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo, NULL);
2362 __EXCEPT_PAGE_FAULT
2364 SetLastError(STATUS_ACCESS_VIOLATION);
2366 __ENDTRY
2367 TRACE("returning %d\n", ret);
2368 return ret;