winecfg: Renamed 'Shell Folder' to 'Folder'.
[wine/multimedia.git] / dlls / wintrust / asn.c
blobcc877dc58be0fff63dab332fa667d437d0945a80
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 "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #define NONAMELESSUNION
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "wincrypt.h"
32 #include "wintrust.h"
33 #include "snmp.h"
34 #include "winternl.h"
35 #include "wine/debug.h"
36 #include "wine/exception.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
40 #ifdef WORDS_BIGENDIAN
42 #define hton16(x) (x)
43 #define n16toh(x) (x)
45 #else
47 #define hton16(x) RtlUshortByteSwap(x)
48 #define n16toh(x) RtlUshortByteSwap(x)
50 #endif
52 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
53 #define ASN_BMPSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e)
55 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
57 DWORD bytesNeeded, significantBytes = 0;
59 if (len <= 0x7f)
60 bytesNeeded = 1;
61 else
63 DWORD temp;
65 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
66 temp <<= 8, significantBytes--)
68 bytesNeeded = significantBytes + 1;
70 if (!pbEncoded)
72 *pcbEncoded = bytesNeeded;
73 return TRUE;
75 if (*pcbEncoded < bytesNeeded)
77 SetLastError(ERROR_MORE_DATA);
78 return FALSE;
80 if (len <= 0x7f)
81 *pbEncoded = (BYTE)len;
82 else
84 DWORD i;
86 *pbEncoded++ = significantBytes | 0x80;
87 for (i = 0; i < significantBytes; i++)
89 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
90 len >>= 8;
93 *pcbEncoded = bytesNeeded;
94 return TRUE;
97 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
99 DWORD *pcbEncoded)
101 BOOL ret = TRUE;
102 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
103 DWORD bytesNeeded, lenBytes;
105 TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
106 *pcbEncoded);
108 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
109 bytesNeeded = 1 + lenBytes + blob->cbData;
110 if (!pbEncoded)
111 *pcbEncoded = bytesNeeded;
112 else if (*pcbEncoded < bytesNeeded)
114 *pcbEncoded = bytesNeeded;
115 SetLastError(ERROR_MORE_DATA);
116 ret = FALSE;
118 else
120 *pbEncoded++ = ASN_OCTETSTRING;
121 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
122 pbEncoded += lenBytes;
123 if (blob->cbData)
124 memcpy(pbEncoded, blob->pbData, blob->cbData);
126 TRACE("returning %d\n", ret);
127 return ret;
130 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
131 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
132 DWORD *pcbEncoded)
134 BOOL ret = FALSE;
136 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
137 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
138 pcbEncoded);
140 __TRY
142 const SPC_LINK *link = (const SPC_LINK *)pvStructInfo;
143 DWORD bytesNeeded, lenBytes;
145 switch (link->dwLinkChoice)
147 case SPC_FILE_LINK_CHOICE:
149 DWORD fileNameLen, fileNameLenBytes;
150 LPWSTR ptr;
152 fileNameLen = link->u.pwszFile ?
153 lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
154 CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
155 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
156 &lenBytes);
157 bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
158 if (!pbEncoded)
160 *pcbEncoded = bytesNeeded;
161 ret = TRUE;
163 else if (*pcbEncoded < bytesNeeded)
165 SetLastError(ERROR_MORE_DATA);
166 *pcbEncoded = bytesNeeded;
168 else
170 *pcbEncoded = bytesNeeded;
171 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
172 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
173 &lenBytes);
174 pbEncoded += lenBytes;
175 *pbEncoded++ = ASN_CONTEXT;
176 CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
177 pbEncoded += fileNameLenBytes;
178 for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
180 *(WCHAR *)pbEncoded = hton16(*ptr);
181 pbEncoded += sizeof(WCHAR);
183 ret = TRUE;
185 break;
187 case SPC_MONIKER_LINK_CHOICE:
189 DWORD classIdLenBytes, dataLenBytes, dataLen;
190 CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
191 (BYTE *)link->u.Moniker.ClassId };
193 CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
194 CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
195 &dataLenBytes);
196 dataLen = 2 + classIdLenBytes + classId.cbData +
197 dataLenBytes + link->u.Moniker.SerializedData.cbData;
198 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
199 bytesNeeded = 1 + dataLen + lenBytes;
200 if (!pbEncoded)
202 *pcbEncoded = bytesNeeded;
203 ret = TRUE;
205 else if (*pcbEncoded < bytesNeeded)
207 SetLastError(ERROR_MORE_DATA);
208 *pcbEncoded = bytesNeeded;
210 else
212 DWORD size;
214 *pcbEncoded = bytesNeeded;
215 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
216 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
217 pbEncoded += lenBytes;
218 size = 1 + classIdLenBytes + classId.cbData;
219 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
220 pbEncoded, &size);
221 pbEncoded += size;
222 size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
223 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
224 &link->u.Moniker.SerializedData, pbEncoded, &size);
225 pbEncoded += size;
226 ret = TRUE;
228 break;
230 case SPC_URL_LINK_CHOICE:
232 LPWSTR ptr;
233 DWORD urlLen;
235 /* Check for invalid characters in URL */
236 ret = TRUE;
237 urlLen = 0;
238 for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
239 if (*ptr > 0x7f)
241 *pcbEncoded = 0;
242 SetLastError(CRYPT_E_INVALID_IA5_STRING);
243 ret = FALSE;
245 else
246 urlLen++;
247 if (ret)
249 CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
250 bytesNeeded = 1 + lenBytes + urlLen;
251 if (!pbEncoded)
252 *pcbEncoded = bytesNeeded;
253 else if (*pcbEncoded < bytesNeeded)
255 SetLastError(ERROR_MORE_DATA);
256 *pcbEncoded = bytesNeeded;
257 ret = FALSE;
259 else
261 *pcbEncoded = bytesNeeded;
262 *pbEncoded++ = ASN_CONTEXT;
263 CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
264 pbEncoded += lenBytes;
265 for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
266 *pbEncoded++ = (BYTE)*ptr;
269 break;
271 default:
272 SetLastError(E_INVALIDARG);
275 __EXCEPT_PAGE_FAULT
277 SetLastError(STATUS_ACCESS_VIOLATION);
279 __ENDTRY
280 TRACE("returning %d\n", ret);
281 return ret;
284 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
285 BYTE *, DWORD *);
287 struct AsnEncodeSequenceItem
289 const void *pvStructInfo;
290 CryptEncodeObjectFunc encodeFunc;
291 DWORD size; /* used during encoding, not for your use */
294 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
295 struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
296 DWORD *pcbEncoded)
298 BOOL ret;
299 DWORD i, dataLen = 0;
301 TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
302 for (i = 0, ret = TRUE; ret && i < cItem; i++)
304 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
305 items[i].pvStructInfo, NULL, &items[i].size);
306 /* Some functions propagate their errors through the size */
307 if (!ret)
308 *pcbEncoded = items[i].size;
309 dataLen += items[i].size;
311 if (ret)
313 DWORD lenBytes, bytesNeeded;
315 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
316 bytesNeeded = 1 + lenBytes + dataLen;
317 if (!pbEncoded)
318 *pcbEncoded = bytesNeeded;
319 else if (*pcbEncoded < bytesNeeded)
321 *pcbEncoded = bytesNeeded;
322 SetLastError(ERROR_MORE_DATA);
323 ret = FALSE;
325 else
327 *pcbEncoded = bytesNeeded;
328 *pbEncoded++ = ASN_SEQUENCE;
329 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
330 pbEncoded += lenBytes;
331 for (i = 0; ret && i < cItem; i++)
333 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
334 items[i].pvStructInfo, pbEncoded, &items[i].size);
335 /* Some functions propagate their errors through the size */
336 if (!ret)
337 *pcbEncoded = items[i].size;
338 pbEncoded += items[i].size;
342 TRACE("returning %d\n", ret);
343 return ret;
346 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
347 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
348 DWORD *pcbEncoded)
350 BOOL ret = FALSE;
352 __TRY
354 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
355 DWORD bytesNeeded, lenBytes, dataBytes;
356 BYTE unusedBits;
358 /* yep, MS allows cUnusedBits to be >= 8 */
359 if (!blob->cUnusedBits)
361 dataBytes = blob->cbData;
362 unusedBits = 0;
364 else if (blob->cbData * 8 > blob->cUnusedBits)
366 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
367 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
368 blob->cUnusedBits;
370 else
372 dataBytes = 0;
373 unusedBits = 0;
375 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
376 bytesNeeded = 1 + lenBytes + dataBytes + 1;
377 if (!pbEncoded)
379 *pcbEncoded = bytesNeeded;
380 ret = TRUE;
382 else if (*pcbEncoded < bytesNeeded)
384 *pcbEncoded = bytesNeeded;
385 SetLastError(ERROR_MORE_DATA);
387 else
389 ret = TRUE;
390 *pcbEncoded = bytesNeeded;
391 *pbEncoded++ = ASN_BITSTRING;
392 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
393 pbEncoded += lenBytes;
394 *pbEncoded++ = unusedBits;
395 if (dataBytes)
397 BYTE mask = 0xff << unusedBits;
399 if (dataBytes > 1)
401 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
402 pbEncoded += dataBytes - 1;
404 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
408 __EXCEPT_PAGE_FAULT
410 SetLastError(STATUS_ACCESS_VIOLATION);
412 __ENDTRY
413 return ret;
416 struct AsnConstructedItem
418 BYTE tag;
419 const void *pvStructInfo;
420 CryptEncodeObjectFunc encodeFunc;
423 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
424 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
425 DWORD *pcbEncoded)
427 BOOL ret;
428 const struct AsnConstructedItem *item =
429 (const struct AsnConstructedItem *)pvStructInfo;
430 DWORD len;
432 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
433 item->pvStructInfo, NULL, &len)))
435 DWORD dataLen, bytesNeeded;
437 CRYPT_EncodeLen(len, NULL, &dataLen);
438 bytesNeeded = 1 + dataLen + len;
439 if (!pbEncoded)
440 *pcbEncoded = bytesNeeded;
441 else if (*pcbEncoded < bytesNeeded)
443 *pcbEncoded = bytesNeeded;
444 SetLastError(ERROR_MORE_DATA);
445 ret = FALSE;
447 else
449 *pcbEncoded = bytesNeeded;
450 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
451 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
452 pbEncoded += dataLen;
453 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
454 item->pvStructInfo, pbEncoded, &len);
455 if (!ret)
457 /* Some functions propagate their errors through the size */
458 *pcbEncoded = len;
462 else
464 /* Some functions propagate their errors through the size */
465 *pcbEncoded = len;
467 return ret;
471 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
472 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
473 DWORD *pcbEncoded)
475 const SPC_PE_IMAGE_DATA *imageData =
476 (const SPC_PE_IMAGE_DATA *)pvStructInfo;
477 BOOL ret = FALSE;
479 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
480 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
481 pcbEncoded);
483 __TRY
485 struct AsnEncodeSequenceItem items[2] = {
486 { 0 }
488 struct AsnConstructedItem constructed = { 0, imageData->pFile,
489 WVTAsn1SpcLinkEncode };
490 DWORD cItem = 0;
492 if (imageData->Flags.cbData)
494 items[cItem].pvStructInfo = &imageData->Flags;
495 items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
496 cItem++;
498 if (imageData->pFile)
500 items[cItem].pvStructInfo = &constructed;
501 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
502 cItem++;
505 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
506 pbEncoded, pcbEncoded);
508 __EXCEPT_PAGE_FAULT
510 SetLastError(STATUS_ACCESS_VIOLATION);
512 __ENDTRY
513 TRACE("returning %d\n", ret);
514 return ret;
517 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
518 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
519 DWORD *pcbEncoded)
521 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
522 DWORD bytesNeeded = 0, lenBytes;
523 BOOL ret = TRUE;
524 int firstPos = 0;
525 BYTE firstByte = 0;
527 TRACE("%s\n", debugstr_a(pszObjId));
529 if (pszObjId)
531 const char *ptr;
532 int val1, val2;
534 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
536 SetLastError(CRYPT_E_ASN1_ERROR);
537 return FALSE;
539 bytesNeeded++;
540 firstByte = val1 * 40 + val2;
541 ptr = pszObjId + firstPos;
542 while (ret && *ptr)
544 int pos;
546 /* note I assume each component is at most 32-bits long in base 2 */
547 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
549 if (val1 >= 0x10000000)
550 bytesNeeded += 5;
551 else if (val1 >= 0x200000)
552 bytesNeeded += 4;
553 else if (val1 >= 0x4000)
554 bytesNeeded += 3;
555 else if (val1 >= 0x80)
556 bytesNeeded += 2;
557 else
558 bytesNeeded += 1;
559 ptr += pos;
560 if (*ptr == '.')
561 ptr++;
563 else
565 SetLastError(CRYPT_E_ASN1_ERROR);
566 return FALSE;
569 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
571 else
572 lenBytes = 1;
573 bytesNeeded += 1 + lenBytes;
574 if (pbEncoded)
576 if (*pcbEncoded < bytesNeeded)
578 SetLastError(ERROR_MORE_DATA);
579 ret = FALSE;
581 else
583 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
584 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
585 pbEncoded += lenBytes;
586 if (pszObjId)
588 const char *ptr;
589 int val, pos;
591 *pbEncoded++ = firstByte;
592 ptr = pszObjId + firstPos;
593 while (ret && *ptr)
595 sscanf(ptr, "%d%n", &val, &pos);
597 unsigned char outBytes[5];
598 int numBytes, i;
600 if (val >= 0x10000000)
601 numBytes = 5;
602 else if (val >= 0x200000)
603 numBytes = 4;
604 else if (val >= 0x4000)
605 numBytes = 3;
606 else if (val >= 0x80)
607 numBytes = 2;
608 else
609 numBytes = 1;
610 for (i = numBytes; i > 0; i--)
612 outBytes[i - 1] = val & 0x7f;
613 val >>= 7;
615 for (i = 0; i < numBytes - 1; i++)
616 *pbEncoded++ = outBytes[i] | 0x80;
617 *pbEncoded++ = outBytes[i];
618 ptr += pos;
619 if (*ptr == '.')
620 ptr++;
626 *pcbEncoded = bytesNeeded;
627 return ret;
630 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
631 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
632 DWORD *pcbEncoded)
634 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
635 BOOL ret = TRUE;
637 if (!pbEncoded)
638 *pcbEncoded = blob->cbData;
639 else if (*pcbEncoded < blob->cbData)
641 *pcbEncoded = blob->cbData;
642 SetLastError(ERROR_MORE_DATA);
643 ret = FALSE;
645 else
647 if (blob->cbData)
648 memcpy(pbEncoded, blob->pbData, blob->cbData);
649 *pcbEncoded = blob->cbData;
651 return ret;
654 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
655 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
656 BYTE *pbEncoded, DWORD *pcbEncoded)
658 const CRYPT_ALGORITHM_IDENTIFIER *algo =
659 (const CRYPT_ALGORITHM_IDENTIFIER *)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,
674 sizeof(items) / sizeof(items[0]), 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 =
683 (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
684 struct AsnEncodeSequenceItem items[] = {
685 { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
686 { &typeValue->Value, CRYPT_CopyEncodedBlob, 0 },
689 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
690 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
693 struct SPCDigest
695 CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
696 CRYPT_HASH_BLOB Digest;
699 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
700 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
701 DWORD *pcbEncoded)
703 const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
704 struct AsnEncodeSequenceItem items[] = {
705 { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
706 { &digest->Digest, CRYPT_CopyEncodedBlob, 0 },
709 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
710 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
713 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
714 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
715 DWORD *pcbEncoded)
717 BOOL ret = FALSE;
719 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
720 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
722 __TRY
724 const SPC_INDIRECT_DATA_CONTENT *data =
725 (const SPC_INDIRECT_DATA_CONTENT *)pvStructInfo;
726 struct AsnEncodeSequenceItem items[] = {
727 { &data->Data, CRYPT_AsnEncodeAttributeTypeValue, 0 },
728 { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
731 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
732 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
734 __EXCEPT_PAGE_FAULT
736 SetLastError(STATUS_ACCESS_VIOLATION);
738 __ENDTRY
739 return ret;
742 static BOOL WINAPI CRYPT_AsnEncodeBMPString(DWORD dwCertEncodingType,
743 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
744 DWORD *pcbEncoded)
746 BOOL ret = TRUE;
747 LPCWSTR str = (LPCWSTR)pvStructInfo;
748 DWORD bytesNeeded, lenBytes, strLen;
750 if (str)
751 strLen = lstrlenW(str);
752 else
753 strLen = 0;
754 CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
755 bytesNeeded = 1 + lenBytes + strLen * 2;
756 if (!pbEncoded)
757 *pcbEncoded = bytesNeeded;
758 else if (*pcbEncoded < bytesNeeded)
760 *pcbEncoded = bytesNeeded;
761 SetLastError(ERROR_MORE_DATA);
762 ret = FALSE;
764 else
766 DWORD i;
768 *pcbEncoded = bytesNeeded;
769 *pbEncoded++ = ASN_BMPSTRING;
770 CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
771 pbEncoded += lenBytes;
772 for (i = 0; i < strLen; i++)
774 *pbEncoded++ = (str[i] & 0xff00) >> 8;
775 *pbEncoded++ = str[i] & 0x00ff;
778 return ret;
781 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
782 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
783 DWORD *pcbEncoded)
785 BOOL ret;
787 __TRY
789 DWORD significantBytes, lenBytes, bytesNeeded;
790 BYTE padByte = 0;
791 BOOL pad = FALSE;
792 const CRYPT_INTEGER_BLOB *blob =
793 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
795 significantBytes = blob->cbData;
796 if (significantBytes)
798 if (blob->pbData[significantBytes - 1] & 0x80)
800 /* negative, lop off leading (little-endian) 0xffs */
801 for (; significantBytes > 0 &&
802 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
804 if (blob->pbData[significantBytes - 1] < 0x80)
806 padByte = 0xff;
807 pad = TRUE;
810 else
812 /* positive, lop off leading (little-endian) zeroes */
813 for (; significantBytes > 0 &&
814 !blob->pbData[significantBytes - 1]; significantBytes--)
816 if (significantBytes == 0)
817 significantBytes = 1;
818 if (blob->pbData[significantBytes - 1] > 0x7f)
820 padByte = 0;
821 pad = TRUE;
825 if (pad)
826 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
827 else
828 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
829 bytesNeeded = 1 + lenBytes + significantBytes;
830 if (pad)
831 bytesNeeded++;
832 if (!pbEncoded)
834 *pcbEncoded = bytesNeeded;
835 ret = TRUE;
837 else if (*pcbEncoded < bytesNeeded)
839 *pcbEncoded = bytesNeeded;
840 SetLastError(ERROR_MORE_DATA);
841 ret = FALSE;
843 else
845 *pcbEncoded = bytesNeeded;
846 *pbEncoded++ = ASN_INTEGER;
847 if (pad)
849 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
850 pbEncoded += lenBytes;
851 *pbEncoded++ = padByte;
853 else
855 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
856 pbEncoded += lenBytes;
858 for (; significantBytes > 0; significantBytes--)
859 *(pbEncoded++) = blob->pbData[significantBytes - 1];
860 ret = TRUE;
863 __EXCEPT_PAGE_FAULT
865 SetLastError(STATUS_ACCESS_VIOLATION);
866 ret = FALSE;
868 __ENDTRY
869 return ret;
872 BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
873 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
874 DWORD *pcbEncoded)
876 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
878 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
879 &blob, pbEncoded, pcbEncoded);
882 BOOL WINAPI WVTAsn1CatMemberInfoEncode(DWORD dwCertEncodingType,
883 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
884 DWORD *pcbEncoded)
886 BOOL ret = FALSE;
888 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
889 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
891 __TRY
893 const CAT_MEMBERINFO *info = (const CAT_MEMBERINFO *)pvStructInfo;
894 struct AsnEncodeSequenceItem items[] = {
895 { info->pwszSubjGuid, CRYPT_AsnEncodeBMPString, 0 },
896 { &info->dwCertVersion, CRYPT_AsnEncodeInt, 0 },
899 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
900 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
902 __EXCEPT_PAGE_FAULT
904 SetLastError(STATUS_ACCESS_VIOLATION);
906 __ENDTRY
907 return ret;
910 BOOL WINAPI WVTAsn1CatNameValueEncode(DWORD dwCertEncodingType,
911 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
912 DWORD *pcbEncoded)
914 BOOL ret = FALSE;
916 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
917 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
919 __TRY
921 const CAT_NAMEVALUE *value = (const CAT_NAMEVALUE *)pvStructInfo;
922 struct AsnEncodeSequenceItem items[] = {
923 { value->pwszTag, CRYPT_AsnEncodeBMPString, 0 },
924 { &value->fdwFlags, CRYPT_AsnEncodeInt, 0 },
925 { &value->Value, CRYPT_AsnEncodeOctets, 0 },
928 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
929 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
931 __EXCEPT_PAGE_FAULT
933 SetLastError(STATUS_ACCESS_VIOLATION);
935 __ENDTRY
936 return ret;
939 /* Gets the number of length bytes from the given (leading) length byte */
940 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
942 /* Helper function to get the encoded length of the data starting at pbEncoded,
943 * where pbEncoded[0] is the tag. If the data are too short to contain a
944 * length or if the length is too large for cbEncoded, sets an appropriate
945 * error code and returns FALSE.
947 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
949 BOOL ret;
951 if (cbEncoded <= 1)
953 SetLastError(CRYPT_E_ASN1_CORRUPT);
954 ret = FALSE;
956 else if (pbEncoded[1] <= 0x7f)
958 if (pbEncoded[1] + 1 > cbEncoded)
960 SetLastError(CRYPT_E_ASN1_EOD);
961 ret = FALSE;
963 else
965 *len = pbEncoded[1];
966 ret = TRUE;
969 else if (pbEncoded[1] == 0x80)
971 FIXME("unimplemented for indefinite-length encoding\n");
972 SetLastError(CRYPT_E_ASN1_CORRUPT);
973 ret = FALSE;
975 else
977 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
979 if (lenLen > sizeof(DWORD) + 1)
981 SetLastError(CRYPT_E_ASN1_LARGE);
982 ret = FALSE;
984 else if (lenLen + 2 > cbEncoded)
986 SetLastError(CRYPT_E_ASN1_CORRUPT);
987 ret = FALSE;
989 else
991 DWORD out = 0;
993 pbEncoded += 2;
994 while (--lenLen)
996 out <<= 8;
997 out |= *pbEncoded++;
999 if (out + lenLen + 1 > cbEncoded)
1001 SetLastError(CRYPT_E_ASN1_EOD);
1002 ret = FALSE;
1004 else
1006 *len = out;
1007 ret = TRUE;
1011 return ret;
1014 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1015 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1016 void *pvStructInfo, DWORD *pcbStructInfo)
1018 BOOL ret;
1019 DWORD bytesNeeded, dataLen;
1021 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1022 pvStructInfo, *pcbStructInfo);
1024 if (!cbEncoded)
1026 SetLastError(CRYPT_E_ASN1_CORRUPT);
1027 ret = FALSE;
1029 else if (pbEncoded[0] != ASN_OCTETSTRING)
1031 SetLastError(CRYPT_E_ASN1_BADTAG);
1032 ret = FALSE;
1034 else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1036 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1037 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1038 else
1039 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1040 if (!pvStructInfo)
1041 *pcbStructInfo = bytesNeeded;
1042 else if (*pcbStructInfo < bytesNeeded)
1044 SetLastError(ERROR_MORE_DATA);
1045 *pcbStructInfo = bytesNeeded;
1046 ret = FALSE;
1048 else
1050 CRYPT_DATA_BLOB *blob;
1051 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1053 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1054 blob->cbData = dataLen;
1055 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1056 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1057 else
1059 assert(blob->pbData);
1060 if (blob->cbData)
1061 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
1062 blob->cbData);
1066 return ret;
1069 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
1070 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1071 void *pvStructInfo, DWORD *pcbStructInfo)
1073 BOOL ret = FALSE;
1074 DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
1076 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1077 pvStructInfo, *pcbStructInfo);
1079 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1081 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1082 DWORD realDataLen;
1084 switch (pbEncoded[0])
1086 case ASN_CONTEXT:
1087 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
1088 if (!pvStructInfo)
1089 *pcbStructInfo = bytesNeeded;
1090 else if (*pcbStructInfo < bytesNeeded)
1092 *pcbStructInfo = bytesNeeded;
1093 SetLastError(ERROR_MORE_DATA);
1094 ret = FALSE;
1096 else
1098 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1099 DWORD i;
1101 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
1102 for (i = 0; i < dataLen; i++)
1103 link->u.pwszUrl[i] =
1104 *(pbEncoded + 1 + lenBytes + i);
1105 link->u.pwszUrl[i] = '\0';
1106 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
1108 break;
1109 case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
1111 CRYPT_DATA_BLOB classId;
1112 DWORD size = sizeof(classId);
1114 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1115 pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
1116 CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
1118 if (classId.cbData != sizeof(SPC_UUID))
1120 SetLastError(CRYPT_E_BAD_ENCODE);
1121 ret = FALSE;
1123 else
1125 CRYPT_DATA_BLOB data;
1127 /* The tag length for the classId must be 1 since the
1128 * length is correct.
1130 size = sizeof(data);
1131 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1132 pbEncoded + 3 + lenBytes + classId.cbData,
1133 cbEncoded - 3 - lenBytes - classId.cbData,
1134 CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
1136 bytesNeeded += data.cbData;
1137 if (!pvStructInfo)
1138 *pcbStructInfo = bytesNeeded;
1139 else if (*pcbStructInfo < bytesNeeded)
1141 *pcbStructInfo = bytesNeeded;
1142 SetLastError(ERROR_MORE_DATA);
1143 ret = FALSE;
1145 else
1147 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1149 link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
1150 /* pwszFile pointer was set by caller, copy it
1151 * before overwriting it
1153 link->u.Moniker.SerializedData.pbData =
1154 (BYTE *)link->u.pwszFile;
1155 memcpy(link->u.Moniker.ClassId, classId.pbData,
1156 classId.cbData);
1157 memcpy(link->u.Moniker.SerializedData.pbData,
1158 data.pbData, data.cbData);
1159 link->u.Moniker.SerializedData.cbData = data.cbData;
1164 break;
1166 case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
1167 if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
1168 SetLastError(CRYPT_E_ASN1_BADTAG);
1169 else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
1170 &realDataLen)))
1172 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
1174 bytesNeeded += realDataLen + sizeof(WCHAR);
1175 if (!pvStructInfo)
1176 *pcbStructInfo = bytesNeeded;
1177 else if (*pcbStructInfo < bytesNeeded)
1179 *pcbStructInfo = bytesNeeded;
1180 SetLastError(ERROR_MORE_DATA);
1181 ret = FALSE;
1183 else
1185 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1186 DWORD i;
1187 const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
1189 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1190 for (i = 0; i < dataLen / sizeof(WCHAR); i++)
1191 link->u.pwszFile[i] =
1192 hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
1193 link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
1194 TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
1197 else
1199 bytesNeeded += sizeof(WCHAR);
1200 if (!pvStructInfo)
1201 *pcbStructInfo = bytesNeeded;
1202 else if (*pcbStructInfo < bytesNeeded)
1204 *pcbStructInfo = bytesNeeded;
1205 SetLastError(ERROR_MORE_DATA);
1206 ret = FALSE;
1208 else
1210 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1212 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1213 link->u.pwszFile[0] = '\0';
1214 ret = TRUE;
1217 break;
1218 default:
1219 SetLastError(CRYPT_E_ASN1_BADTAG);
1222 TRACE("returning %d\n", ret);
1223 return ret;
1226 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1227 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1228 void *pvStructInfo, DWORD *pcbStructInfo)
1230 BOOL ret = FALSE;
1232 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1233 pvStructInfo, *pcbStructInfo);
1235 __TRY
1237 DWORD bytesNeeded;
1239 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1240 lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1241 if (ret)
1243 if (!pvStructInfo)
1244 *pcbStructInfo = bytesNeeded;
1245 else if (*pcbStructInfo < bytesNeeded)
1247 *pcbStructInfo = bytesNeeded;
1248 SetLastError(ERROR_MORE_DATA);
1249 ret = FALSE;
1251 else
1253 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1255 link->u.pwszFile =
1256 (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1257 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1258 lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1259 pcbStructInfo);
1263 __EXCEPT_PAGE_FAULT
1265 SetLastError(STATUS_ACCESS_VIOLATION);
1267 __ENDTRY
1268 TRACE("returning %d\n", ret);
1269 return ret;
1272 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1273 DWORD, DWORD, void *, DWORD *);
1275 /* tag:
1276 * The expected tag of the item. If tag is 0, decodeFunc is called
1277 * regardless of the tag value seen.
1278 * offset:
1279 * A sequence is decoded into a struct. The offset member is the
1280 * offset of this item within that struct.
1281 * decodeFunc:
1282 * The decoder function to use. If this is NULL, then the member isn't
1283 * decoded, but minSize space is reserved for it.
1284 * minSize:
1285 * The minimum amount of space occupied after decoding. You must set this.
1286 * optional:
1287 * If true, and the tag doesn't match the expected tag for this item,
1288 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1289 * filled with 0 for this member.
1290 * hasPointer, pointerOffset:
1291 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1292 * the offset within the struct of the data pointer (or to the
1293 * first data pointer, if more than one exist).
1294 * size:
1295 * Used by CRYPT_AsnDecodeSequence, not for your use.
1297 struct AsnDecodeSequenceItem
1299 BYTE tag;
1300 DWORD offset;
1301 CryptDecodeObjectFunc decodeFunc;
1302 DWORD minSize;
1303 BOOL optional;
1304 BOOL hasPointer;
1305 DWORD pointerOffset;
1306 DWORD size;
1309 /* Decodes the items in a sequence, where the items are described in items,
1310 * the encoded data are in pbEncoded with length cbEncoded. Decodes into
1311 * pvStructInfo. nextData is a pointer to the memory location at which the
1312 * first decoded item with a dynamic pointer should point.
1313 * Upon decoding, *cbDecoded is the total number of bytes decoded.
1315 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1316 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1317 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1318 DWORD *cbDecoded)
1320 BOOL ret;
1321 DWORD i, decoded = 0;
1322 const BYTE *ptr = pbEncoded;
1324 TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1325 cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1327 for (i = 0, ret = TRUE; ret && i < cItem; i++)
1329 if (cbEncoded - (ptr - pbEncoded) != 0)
1331 DWORD nextItemLen;
1333 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1334 &nextItemLen)))
1336 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1338 if (ptr[0] == items[i].tag || !items[i].tag)
1340 if (nextData && pvStructInfo && items[i].hasPointer)
1342 TRACE("Setting next pointer to %p\n",
1343 nextData);
1344 *(BYTE **)((BYTE *)pvStructInfo +
1345 items[i].pointerOffset) = nextData;
1347 if (items[i].decodeFunc)
1349 if (pvStructInfo)
1350 TRACE("decoding item %d\n", i);
1351 else
1352 TRACE("sizing item %d\n", i);
1353 ret = items[i].decodeFunc(dwCertEncodingType,
1354 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1355 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1356 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
1357 : NULL, &items[i].size);
1358 if (ret)
1360 /* Account for alignment padding */
1361 if (items[i].size % sizeof(DWORD))
1362 items[i].size += sizeof(DWORD) -
1363 items[i].size % sizeof(DWORD);
1364 TRACE("item %d size: %d\n", i, items[i].size);
1365 if (nextData && items[i].hasPointer &&
1366 items[i].size > items[i].minSize)
1367 nextData += items[i].size - items[i].minSize;
1368 ptr += 1 + nextItemLenBytes + nextItemLen;
1369 decoded += 1 + nextItemLenBytes + nextItemLen;
1370 TRACE("item %d: decoded %d bytes\n", i,
1371 1 + nextItemLenBytes + nextItemLen);
1373 else if (items[i].optional &&
1374 GetLastError() == CRYPT_E_ASN1_BADTAG)
1376 TRACE("skipping optional item %d\n", i);
1377 items[i].size = items[i].minSize;
1378 SetLastError(NOERROR);
1379 ret = TRUE;
1381 else
1382 TRACE("item %d failed: %08x\n", i,
1383 GetLastError());
1385 else
1387 TRACE("item %d: decoded %d bytes\n", i,
1388 1 + nextItemLenBytes + nextItemLen);
1389 ptr += 1 + nextItemLenBytes + nextItemLen;
1390 decoded += 1 + nextItemLenBytes + nextItemLen;
1391 items[i].size = items[i].minSize;
1394 else if (items[i].optional)
1396 TRACE("skipping optional item %d\n", i);
1397 items[i].size = items[i].minSize;
1399 else
1401 TRACE("item %d: tag %02x doesn't match expected %02x\n",
1402 i, ptr[0], items[i].tag);
1403 SetLastError(CRYPT_E_ASN1_BADTAG);
1404 ret = FALSE;
1408 else if (items[i].optional)
1410 TRACE("missing optional item %d, skipping\n", i);
1411 items[i].size = items[i].minSize;
1413 else
1415 TRACE("not enough bytes for item %d, failing\n", i);
1416 SetLastError(CRYPT_E_ASN1_CORRUPT);
1417 ret = FALSE;
1420 if (ret)
1421 *cbDecoded = decoded;
1422 TRACE("returning %d\n", ret);
1423 return ret;
1426 /* This decodes an arbitrary sequence into a contiguous block of memory
1427 * (basically, a struct.) Each element being decoded is described by a struct
1428 * AsnDecodeSequenceItem, see above.
1429 * startingPointer is an optional pointer to the first place where dynamic
1430 * data will be stored. If you know the starting offset, you may pass it
1431 * here. Otherwise, pass NULL, and one will be inferred from the items.
1433 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1434 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1435 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1436 void *startingPointer)
1438 BOOL ret;
1440 TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1441 cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1443 if (pbEncoded[0] == ASN_SEQUENCE)
1445 DWORD dataLen;
1447 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1449 DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1450 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1452 cbEncoded -= 1 + lenBytes;
1453 if (cbEncoded < dataLen)
1455 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1456 cbEncoded);
1457 SetLastError(CRYPT_E_ASN1_CORRUPT);
1458 ret = FALSE;
1460 else
1461 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1462 cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1463 if (ret && cbDecoded != dataLen)
1465 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1466 cbDecoded);
1467 SetLastError(CRYPT_E_ASN1_CORRUPT);
1468 ret = FALSE;
1470 if (ret)
1472 DWORD i, bytesNeeded = 0, structSize = 0;
1474 for (i = 0; i < cItem; i++)
1476 bytesNeeded += items[i].size;
1477 structSize += items[i].minSize;
1479 if (!pvStructInfo)
1480 *pcbStructInfo = bytesNeeded;
1481 else if (*pcbStructInfo < bytesNeeded)
1483 SetLastError(ERROR_MORE_DATA);
1484 *pcbStructInfo = bytesNeeded;
1485 ret = FALSE;
1487 else
1489 BYTE *nextData;
1491 *pcbStructInfo = bytesNeeded;
1492 if (startingPointer)
1493 nextData = (BYTE *)startingPointer;
1494 else
1495 nextData = (BYTE *)pvStructInfo + structSize;
1496 memset(pvStructInfo, 0, structSize);
1497 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1498 ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1499 &cbDecoded);
1504 else
1506 SetLastError(CRYPT_E_ASN1_BADTAG);
1507 ret = FALSE;
1509 TRACE("returning %d (%08x)\n", ret, GetLastError());
1510 return ret;
1513 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1514 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1515 void *pvStructInfo, DWORD *pcbStructInfo)
1517 BOOL ret;
1519 TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1520 pvStructInfo, *pcbStructInfo);
1522 if (pbEncoded[0] == ASN_BITSTRING)
1524 DWORD bytesNeeded, dataLen;
1526 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1528 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1529 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1530 else
1531 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1532 if (!pvStructInfo)
1533 *pcbStructInfo = bytesNeeded;
1534 else if (*pcbStructInfo < bytesNeeded)
1536 *pcbStructInfo = bytesNeeded;
1537 SetLastError(ERROR_MORE_DATA);
1538 ret = FALSE;
1540 else
1542 CRYPT_BIT_BLOB *blob;
1544 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1545 blob->cbData = dataLen - 1;
1546 blob->cUnusedBits = *(pbEncoded + 1 +
1547 GET_LEN_BYTES(pbEncoded[1]));
1548 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1550 blob->pbData = (BYTE *)pbEncoded + 2 +
1551 GET_LEN_BYTES(pbEncoded[1]);
1553 else
1555 assert(blob->pbData);
1556 if (blob->cbData)
1558 BYTE mask = 0xff << blob->cUnusedBits;
1560 memcpy(blob->pbData, pbEncoded + 2 +
1561 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1562 blob->pbData[blob->cbData - 1] &= mask;
1568 else
1570 SetLastError(CRYPT_E_ASN1_BADTAG);
1571 ret = FALSE;
1573 TRACE("returning %d (%08x)\n", ret, GetLastError());
1574 return ret;
1577 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1578 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1579 void *pvStructInfo, DWORD *pcbStructInfo)
1581 BOOL ret = FALSE;
1582 DWORD dataLen;
1584 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1586 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1587 DWORD size;
1588 SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1590 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1591 pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1592 if (ret)
1594 if (!pvStructInfo)
1595 *pcbStructInfo = size + sizeof(PSPC_LINK);
1596 else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1598 *pcbStructInfo = size + sizeof(PSPC_LINK);
1599 SetLastError(ERROR_MORE_DATA);
1600 ret = FALSE;
1602 else
1604 *pcbStructInfo = size + sizeof(PSPC_LINK);
1605 /* Set imageData's pointer if necessary */
1606 if (size > sizeof(SPC_LINK))
1608 (*pLink)->u.pwszUrl =
1609 (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1611 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1612 lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1613 *pLink, pcbStructInfo);
1617 return ret;
1620 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1621 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1622 void *pvStructInfo, DWORD *pcbStructInfo)
1624 BOOL ret = FALSE;
1626 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1627 pvStructInfo, *pcbStructInfo);
1629 __TRY
1631 struct AsnDecodeSequenceItem items[] = {
1632 { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1633 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1634 offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1635 { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1636 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1637 offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1640 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1641 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1642 pvStructInfo, pcbStructInfo, NULL);
1644 __EXCEPT_PAGE_FAULT
1646 SetLastError(STATUS_ACCESS_VIOLATION);
1648 __ENDTRY
1649 TRACE("returning %d\n", ret);
1650 return ret;
1653 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1654 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1655 void *pvStructInfo, DWORD *pcbStructInfo)
1657 BOOL ret = TRUE;
1658 DWORD dataLen;
1660 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1661 pvStructInfo, *pcbStructInfo);
1663 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1665 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1666 DWORD bytesNeeded = sizeof(LPSTR);
1668 if (dataLen)
1670 /* The largest possible string for the first two components
1671 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1673 char firstTwo[6];
1674 const BYTE *ptr;
1676 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1677 pbEncoded[1 + lenBytes] / 40,
1678 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1679 * 40);
1680 bytesNeeded += strlen(firstTwo) + 1;
1681 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1682 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1684 /* large enough for ".4000000" */
1685 char str[9];
1686 int val = 0;
1688 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1689 (*ptr & 0x80))
1691 val <<= 7;
1692 val |= *ptr & 0x7f;
1693 ptr++;
1695 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1696 (*ptr & 0x80))
1698 SetLastError(CRYPT_E_ASN1_CORRUPT);
1699 ret = FALSE;
1701 else
1703 val <<= 7;
1704 val |= *ptr++;
1705 snprintf(str, sizeof(str), ".%d", val);
1706 bytesNeeded += strlen(str);
1710 if (!pvStructInfo)
1711 *pcbStructInfo = bytesNeeded;
1712 else if (*pcbStructInfo < bytesNeeded)
1714 *pcbStructInfo = bytesNeeded;
1715 SetLastError(ERROR_MORE_DATA);
1716 ret = FALSE;
1718 else
1720 if (dataLen)
1722 const BYTE *ptr;
1723 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1725 *pszObjId = 0;
1726 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1727 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1728 40) * 40);
1729 pszObjId += strlen(pszObjId);
1730 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1731 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1733 int val = 0;
1735 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1736 (*ptr & 0x80))
1738 val <<= 7;
1739 val |= *ptr & 0x7f;
1740 ptr++;
1742 val <<= 7;
1743 val |= *ptr++;
1744 sprintf(pszObjId, ".%d", val);
1745 pszObjId += strlen(pszObjId);
1748 else
1749 *(LPSTR *)pvStructInfo = NULL;
1750 *pcbStructInfo = bytesNeeded;
1753 return ret;
1756 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1757 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1758 void *pvStructInfo, DWORD *pcbStructInfo)
1760 BOOL ret = FALSE;
1762 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1763 pvStructInfo, *pcbStructInfo);
1765 if (!cbEncoded)
1766 SetLastError(CRYPT_E_ASN1_CORRUPT);
1767 else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1768 ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1769 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1770 else
1771 SetLastError(CRYPT_E_ASN1_BADTAG);
1772 return ret;
1775 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1776 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1777 void *pvStructInfo, DWORD *pcbStructInfo)
1779 BOOL ret = TRUE;
1780 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1782 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1783 pvStructInfo, *pcbStructInfo);
1785 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1786 bytesNeeded += cbEncoded;
1787 if (!pvStructInfo)
1788 *pcbStructInfo = bytesNeeded;
1789 else if (*pcbStructInfo < bytesNeeded)
1791 SetLastError(ERROR_MORE_DATA);
1792 *pcbStructInfo = bytesNeeded;
1793 ret = FALSE;
1795 else
1797 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1799 *pcbStructInfo = bytesNeeded;
1800 blob->cbData = cbEncoded;
1801 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1802 blob->pbData = (LPBYTE)pbEncoded;
1803 else
1805 assert(blob->pbData);
1806 memcpy(blob->pbData, pbEncoded, blob->cbData);
1809 return ret;
1812 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1813 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1814 void *pvStructInfo, DWORD *pcbStructInfo)
1816 CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1817 (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1818 struct AsnDecodeSequenceItem items[] = {
1819 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1820 CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1821 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1822 { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1823 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1824 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1827 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1828 pvStructInfo, *pcbStructInfo);
1830 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1831 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1832 pvStructInfo, pcbStructInfo,
1833 typeValue ? typeValue->pszObjId : NULL);
1836 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1837 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1838 void *pvStructInfo, DWORD *pcbStructInfo)
1840 CRYPT_ALGORITHM_IDENTIFIER *algo =
1841 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
1842 BOOL ret = TRUE;
1843 struct AsnDecodeSequenceItem items[] = {
1844 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
1845 CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
1846 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
1847 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
1848 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
1849 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
1852 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1853 pvStructInfo, *pcbStructInfo);
1855 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1856 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1857 pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
1858 if (ret && pvStructInfo)
1860 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
1861 debugstr_a(algo->pszObjId));
1863 return ret;
1866 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
1867 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1868 void *pvStructInfo, DWORD *pcbStructInfo)
1870 struct SPCDigest *digest =
1871 (struct SPCDigest *)pvStructInfo;
1872 struct AsnDecodeSequenceItem items[] = {
1873 { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
1874 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
1875 FALSE, TRUE,
1876 offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
1877 { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
1878 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
1879 FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
1882 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1883 pvStructInfo, *pcbStructInfo);
1885 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1886 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1887 pvStructInfo, pcbStructInfo,
1888 digest ? digest->DigestAlgorithm.pszObjId : NULL);
1891 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
1892 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1893 void *pvStructInfo, DWORD *pcbStructInfo)
1895 BOOL ret = FALSE;
1897 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1898 pvStructInfo, *pcbStructInfo);
1900 __TRY
1902 struct AsnDecodeSequenceItem items[] = {
1903 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
1904 CRYPT_AsnDecodeAttributeTypeValue,
1905 sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
1906 offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
1907 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
1908 CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
1909 FALSE, TRUE,
1910 offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
1913 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1914 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1915 pvStructInfo, pcbStructInfo, NULL);
1917 __EXCEPT_PAGE_FAULT
1919 SetLastError(STATUS_ACCESS_VIOLATION);
1921 __ENDTRY
1922 TRACE("returning %d\n", ret);
1923 return ret;
1926 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
1927 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1928 void *pvStructInfo, DWORD *pcbStructInfo)
1930 FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1931 pvStructInfo, *pcbStructInfo);
1932 return FALSE;
1935 static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType,
1936 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1937 void *pvStructInfo, DWORD *pcbStructInfo)
1939 BOOL ret;
1940 DWORD bytesNeeded, dataLen;
1942 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1944 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1946 bytesNeeded = dataLen + 2 + sizeof(LPWSTR);
1947 if (!pvStructInfo)
1948 *pcbStructInfo = bytesNeeded;
1949 else if (*pcbStructInfo < bytesNeeded)
1951 *pcbStructInfo = bytesNeeded;
1952 SetLastError(ERROR_MORE_DATA);
1953 ret = FALSE;
1955 else
1957 LPWSTR str;
1958 DWORD i;
1960 *pcbStructInfo = bytesNeeded;
1961 assert(pvStructInfo);
1962 str = *(LPWSTR *)pvStructInfo;
1963 for (i = 0; i < dataLen / 2; i++)
1964 str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) |
1965 pbEncoded[1 + lenBytes + 2 * i + 1];
1966 /* Decoded string is always NULL-terminated */
1967 str[i] = '\0';
1970 return ret;
1973 static BOOL CRYPT_AsnDecodeInteger(const BYTE *pbEncoded,
1974 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo)
1976 BOOL ret;
1977 DWORD bytesNeeded, dataLen;
1979 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1981 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1983 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
1984 if (!pvStructInfo)
1985 *pcbStructInfo = bytesNeeded;
1986 else if (*pcbStructInfo < bytesNeeded)
1988 *pcbStructInfo = bytesNeeded;
1989 SetLastError(ERROR_MORE_DATA);
1990 ret = FALSE;
1992 else
1994 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1996 *pcbStructInfo = bytesNeeded;
1997 blob->cbData = dataLen;
1998 assert(blob->pbData);
1999 if (blob->cbData)
2001 DWORD i;
2003 for (i = 0; i < blob->cbData; i++)
2005 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2006 dataLen - i - 1);
2011 return ret;
2014 /* Ignores tag. Only allows integers 4 bytes or smaller in size. */
2015 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2016 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2017 void *pvStructInfo, DWORD *pcbStructInfo)
2019 BOOL ret;
2020 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
2021 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
2022 DWORD size = sizeof(buf);
2024 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
2025 ret = CRYPT_AsnDecodeInteger(pbEncoded, cbEncoded, 0, buf, &size);
2026 if (ret)
2028 if (!pvStructInfo)
2029 *pcbStructInfo = sizeof(int);
2030 else if (*pcbStructInfo < sizeof(int))
2032 *pcbStructInfo = sizeof(int);
2033 SetLastError(ERROR_MORE_DATA);
2034 ret = FALSE;
2036 else
2038 int val, i;
2040 *pcbStructInfo = sizeof(int);
2041 if (blob->pbData[blob->cbData - 1] & 0x80)
2043 /* initialize to a negative value to sign-extend */
2044 val = -1;
2046 else
2047 val = 0;
2048 for (i = 0; i < blob->cbData; i++)
2050 val <<= 8;
2051 val |= blob->pbData[blob->cbData - i - 1];
2053 memcpy(pvStructInfo, &val, sizeof(int));
2056 else if (GetLastError() == ERROR_MORE_DATA)
2057 SetLastError(CRYPT_E_ASN1_LARGE);
2058 return ret;
2061 BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType,
2062 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2063 void *pvStructInfo, DWORD *pcbStructInfo)
2065 BOOL ret = FALSE;
2067 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2068 pvStructInfo, *pcbStructInfo);
2070 __TRY
2072 struct AsnDecodeSequenceItem items[] = {
2073 { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid),
2074 CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2075 offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 },
2076 { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion),
2077 CRYPT_AsnDecodeInt, sizeof(DWORD),
2078 FALSE, FALSE, 0, 0 },
2081 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2082 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2083 pvStructInfo, pcbStructInfo, NULL);
2085 __EXCEPT_PAGE_FAULT
2087 SetLastError(STATUS_ACCESS_VIOLATION);
2089 __ENDTRY
2090 TRACE("returning %d\n", ret);
2091 return ret;
2094 BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType,
2095 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2096 void *pvStructInfo, DWORD *pcbStructInfo)
2098 BOOL ret = FALSE;
2100 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
2101 pvStructInfo, *pcbStructInfo);
2103 __TRY
2105 struct AsnDecodeSequenceItem items[] = {
2106 { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag),
2107 CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE,
2108 offsetof(CAT_NAMEVALUE, pwszTag), 0 },
2109 { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags),
2110 CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
2111 { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value),
2112 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2113 offsetof(CAT_NAMEVALUE, Value.pbData), 0 },
2116 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2117 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2118 pvStructInfo, pcbStructInfo, NULL);
2120 __EXCEPT_PAGE_FAULT
2122 SetLastError(STATUS_ACCESS_VIOLATION);
2124 __ENDTRY
2125 TRACE("returning %d\n", ret);
2126 return ret;