ntdsapi: Fix building the tests with MSVC headers.
[wine/wine64.git] / dlls / wintrust / asn.c
blobaf7a266091b5c5d264f22cd62e18d0855bcc80c7
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
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <assert.h>
23 #define NONAMELESSUNION
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wincrypt.h"
28 #include "wintrust.h"
29 #include "snmp.h"
30 #include "winternl.h"
31 #include "wine/debug.h"
32 #include "wine/exception.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
36 #ifdef WORDS_BIGENDIAN
38 #define hton16(x) (x)
39 #define n16toh(x) (x)
41 #else
43 #define hton16(x) RtlUshortByteSwap(x)
44 #define n16toh(x) RtlUshortByteSwap(x)
46 #endif
48 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
50 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
52 DWORD bytesNeeded, significantBytes = 0;
54 if (len <= 0x7f)
55 bytesNeeded = 1;
56 else
58 DWORD temp;
60 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
61 temp <<= 8, significantBytes--)
63 bytesNeeded = significantBytes + 1;
65 if (!pbEncoded)
67 *pcbEncoded = bytesNeeded;
68 return TRUE;
70 if (*pcbEncoded < bytesNeeded)
72 SetLastError(ERROR_MORE_DATA);
73 return FALSE;
75 if (len <= 0x7f)
76 *pbEncoded = (BYTE)len;
77 else
79 DWORD i;
81 *pbEncoded++ = significantBytes | 0x80;
82 for (i = 0; i < significantBytes; i++)
84 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
85 len >>= 8;
88 *pcbEncoded = bytesNeeded;
89 return TRUE;
92 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
93 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
94 DWORD *pcbEncoded)
96 BOOL ret = TRUE;
97 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
98 DWORD bytesNeeded, lenBytes;
100 TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
101 *pcbEncoded);
103 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
104 bytesNeeded = 1 + lenBytes + blob->cbData;
105 if (!pbEncoded)
106 *pcbEncoded = bytesNeeded;
107 else if (*pcbEncoded < bytesNeeded)
109 *pcbEncoded = bytesNeeded;
110 SetLastError(ERROR_MORE_DATA);
111 ret = FALSE;
113 else
115 *pbEncoded++ = ASN_OCTETSTRING;
116 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
117 pbEncoded += lenBytes;
118 if (blob->cbData)
119 memcpy(pbEncoded, blob->pbData, blob->cbData);
121 TRACE("returning %d\n", ret);
122 return ret;
125 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
126 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
127 DWORD *pcbEncoded)
129 BOOL ret = FALSE;
131 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
132 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
133 pcbEncoded);
135 __TRY
137 const SPC_LINK *link = (const SPC_LINK *)pvStructInfo;
138 DWORD bytesNeeded, lenBytes;
140 switch (link->dwLinkChoice)
142 case SPC_FILE_LINK_CHOICE:
144 DWORD fileNameLen, fileNameLenBytes;
145 LPWSTR ptr;
147 fileNameLen = link->u.pwszFile ?
148 lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
149 CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
150 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
151 &lenBytes);
152 bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
153 if (!pbEncoded)
155 *pcbEncoded = bytesNeeded;
156 ret = TRUE;
158 else if (*pcbEncoded < bytesNeeded)
160 SetLastError(ERROR_MORE_DATA);
161 *pcbEncoded = bytesNeeded;
163 else
165 *pcbEncoded = bytesNeeded;
166 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
167 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
168 &lenBytes);
169 pbEncoded += lenBytes;
170 *pbEncoded++ = ASN_CONTEXT;
171 CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
172 pbEncoded += fileNameLenBytes;
173 for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
175 *(WCHAR *)pbEncoded = hton16(*ptr);
176 pbEncoded += sizeof(WCHAR);
178 ret = TRUE;
180 break;
182 case SPC_MONIKER_LINK_CHOICE:
184 DWORD classIdLenBytes, dataLenBytes, dataLen;
185 CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
186 (BYTE *)&link->u.Moniker.ClassId };
188 CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
189 CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
190 &dataLenBytes);
191 dataLen = 2 + classIdLenBytes + classId.cbData +
192 dataLenBytes + link->u.Moniker.SerializedData.cbData;
193 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
194 bytesNeeded = 1 + dataLen + lenBytes;
195 if (!pbEncoded)
197 *pcbEncoded = bytesNeeded;
198 ret = TRUE;
200 else if (*pcbEncoded < bytesNeeded)
202 SetLastError(ERROR_MORE_DATA);
203 *pcbEncoded = bytesNeeded;
205 else
207 DWORD size;
209 *pcbEncoded = bytesNeeded;
210 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
211 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
212 pbEncoded += lenBytes;
213 size = 1 + classIdLenBytes + classId.cbData;
214 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
215 pbEncoded, &size);
216 pbEncoded += size;
217 size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
218 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
219 &link->u.Moniker.SerializedData, pbEncoded, &size);
220 pbEncoded += size;
221 ret = TRUE;
223 break;
225 case SPC_URL_LINK_CHOICE:
227 LPWSTR ptr;
228 DWORD urlLen;
230 /* Check for invalid characters in URL */
231 ret = TRUE;
232 urlLen = 0;
233 for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
234 if (*ptr > 0x7f)
236 *pcbEncoded = 0;
237 SetLastError(CRYPT_E_INVALID_IA5_STRING);
238 ret = FALSE;
240 else
241 urlLen++;
242 if (ret)
244 CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
245 bytesNeeded = 1 + lenBytes + urlLen;
246 if (!pbEncoded)
247 *pcbEncoded = bytesNeeded;
248 else if (*pcbEncoded < bytesNeeded)
250 SetLastError(ERROR_MORE_DATA);
251 *pcbEncoded = bytesNeeded;
252 ret = FALSE;
254 else
256 *pcbEncoded = bytesNeeded;
257 *pbEncoded++ = ASN_CONTEXT;
258 CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
259 pbEncoded += lenBytes;
260 for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
261 *pbEncoded++ = (BYTE)*ptr;
264 break;
266 default:
267 SetLastError(E_INVALIDARG);
270 __EXCEPT_PAGE_FAULT
272 SetLastError(STATUS_ACCESS_VIOLATION);
274 __ENDTRY
275 TRACE("returning %d\n", ret);
276 return ret;
279 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
280 BYTE *, DWORD *);
282 struct AsnEncodeSequenceItem
284 const void *pvStructInfo;
285 CryptEncodeObjectFunc encodeFunc;
286 DWORD size; /* used during encoding, not for your use */
289 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
290 struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
291 DWORD *pcbEncoded)
293 BOOL ret;
294 DWORD i, dataLen = 0;
296 TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
297 for (i = 0, ret = TRUE; ret && i < cItem; i++)
299 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
300 items[i].pvStructInfo, NULL, &items[i].size);
301 /* Some functions propagate their errors through the size */
302 if (!ret)
303 *pcbEncoded = items[i].size;
304 dataLen += items[i].size;
306 if (ret)
308 DWORD lenBytes, bytesNeeded;
310 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
311 bytesNeeded = 1 + lenBytes + dataLen;
312 if (!pbEncoded)
313 *pcbEncoded = bytesNeeded;
314 else if (*pcbEncoded < bytesNeeded)
316 *pcbEncoded = bytesNeeded;
317 SetLastError(ERROR_MORE_DATA);
318 ret = FALSE;
320 else
322 *pcbEncoded = bytesNeeded;
323 *pbEncoded++ = ASN_SEQUENCE;
324 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
325 pbEncoded += lenBytes;
326 for (i = 0; ret && i < cItem; i++)
328 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
329 items[i].pvStructInfo, pbEncoded, &items[i].size);
330 /* Some functions propagate their errors through the size */
331 if (!ret)
332 *pcbEncoded = items[i].size;
333 pbEncoded += items[i].size;
337 TRACE("returning %d\n", ret);
338 return ret;
341 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
342 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
343 DWORD *pcbEncoded)
345 BOOL ret = FALSE;
347 __TRY
349 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
350 DWORD bytesNeeded, lenBytes, dataBytes;
351 BYTE unusedBits;
353 /* yep, MS allows cUnusedBits to be >= 8 */
354 if (!blob->cUnusedBits)
356 dataBytes = blob->cbData;
357 unusedBits = 0;
359 else if (blob->cbData * 8 > blob->cUnusedBits)
361 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
362 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
363 blob->cUnusedBits;
365 else
367 dataBytes = 0;
368 unusedBits = 0;
370 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
371 bytesNeeded = 1 + lenBytes + dataBytes + 1;
372 if (!pbEncoded)
374 *pcbEncoded = bytesNeeded;
375 ret = TRUE;
377 else if (*pcbEncoded < bytesNeeded)
379 *pcbEncoded = bytesNeeded;
380 SetLastError(ERROR_MORE_DATA);
382 else
384 ret = TRUE;
385 *pcbEncoded = bytesNeeded;
386 *pbEncoded++ = ASN_BITSTRING;
387 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
388 pbEncoded += lenBytes;
389 *pbEncoded++ = unusedBits;
390 if (dataBytes)
392 BYTE mask = 0xff << unusedBits;
394 if (dataBytes > 1)
396 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
397 pbEncoded += dataBytes - 1;
399 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
403 __EXCEPT_PAGE_FAULT
405 SetLastError(STATUS_ACCESS_VIOLATION);
407 __ENDTRY
408 return ret;
411 struct AsnConstructedItem
413 BYTE tag;
414 const void *pvStructInfo;
415 CryptEncodeObjectFunc encodeFunc;
418 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
419 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
420 DWORD *pcbEncoded)
422 BOOL ret;
423 const struct AsnConstructedItem *item =
424 (const struct AsnConstructedItem *)pvStructInfo;
425 DWORD len;
427 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
428 item->pvStructInfo, NULL, &len)))
430 DWORD dataLen, bytesNeeded;
432 CRYPT_EncodeLen(len, NULL, &dataLen);
433 bytesNeeded = 1 + dataLen + len;
434 if (!pbEncoded)
435 *pcbEncoded = bytesNeeded;
436 else if (*pcbEncoded < bytesNeeded)
438 *pcbEncoded = bytesNeeded;
439 SetLastError(ERROR_MORE_DATA);
440 ret = FALSE;
442 else
444 *pcbEncoded = bytesNeeded;
445 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
446 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
447 pbEncoded += dataLen;
448 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
449 item->pvStructInfo, pbEncoded, &len);
450 if (!ret)
452 /* Some functions propagate their errors through the size */
453 *pcbEncoded = len;
457 else
459 /* Some functions propagate their errors through the size */
460 *pcbEncoded = len;
462 return ret;
466 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
467 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
468 DWORD *pcbEncoded)
470 const SPC_PE_IMAGE_DATA *imageData =
471 (const SPC_PE_IMAGE_DATA *)pvStructInfo;
472 BOOL ret = FALSE;
474 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
475 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
476 pcbEncoded);
478 __TRY
480 struct AsnEncodeSequenceItem items[2] = {
481 { 0 }
483 struct AsnConstructedItem constructed = { 0, imageData->pFile,
484 WVTAsn1SpcLinkEncode };
485 DWORD cItem = 0;
487 if (imageData->Flags.cbData)
489 items[cItem].pvStructInfo = &imageData->Flags;
490 items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
491 cItem++;
493 if (imageData->pFile)
495 items[cItem].pvStructInfo = &constructed;
496 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
497 cItem++;
500 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
501 pbEncoded, pcbEncoded);
503 __EXCEPT_PAGE_FAULT
505 SetLastError(STATUS_ACCESS_VIOLATION);
507 __ENDTRY
508 TRACE("returning %d\n", ret);
509 return ret;
512 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
513 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
514 DWORD *pcbEncoded)
516 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
517 DWORD bytesNeeded = 0, lenBytes;
518 BOOL ret = TRUE;
519 int firstPos = 0;
520 BYTE firstByte = 0;
522 TRACE("%s\n", debugstr_a(pszObjId));
524 if (pszObjId)
526 const char *ptr;
527 int val1, val2;
529 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
531 SetLastError(CRYPT_E_ASN1_ERROR);
532 return FALSE;
534 bytesNeeded++;
535 firstByte = val1 * 40 + val2;
536 ptr = pszObjId + firstPos;
537 while (ret && *ptr)
539 int pos;
541 /* note I assume each component is at most 32-bits long in base 2 */
542 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
544 if (val1 >= 0x10000000)
545 bytesNeeded += 5;
546 else if (val1 >= 0x200000)
547 bytesNeeded += 4;
548 else if (val1 >= 0x4000)
549 bytesNeeded += 3;
550 else if (val1 >= 0x80)
551 bytesNeeded += 2;
552 else
553 bytesNeeded += 1;
554 ptr += pos;
555 if (*ptr == '.')
556 ptr++;
558 else
560 SetLastError(CRYPT_E_ASN1_ERROR);
561 return FALSE;
564 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
566 else
567 lenBytes = 1;
568 bytesNeeded += 1 + lenBytes;
569 if (pbEncoded)
571 if (*pcbEncoded < bytesNeeded)
573 SetLastError(ERROR_MORE_DATA);
574 ret = FALSE;
576 else
578 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
579 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
580 pbEncoded += lenBytes;
581 if (pszObjId)
583 const char *ptr;
584 int val, pos;
586 *pbEncoded++ = firstByte;
587 ptr = pszObjId + firstPos;
588 while (ret && *ptr)
590 sscanf(ptr, "%d%n", &val, &pos);
592 unsigned char outBytes[5];
593 int numBytes, i;
595 if (val >= 0x10000000)
596 numBytes = 5;
597 else if (val >= 0x200000)
598 numBytes = 4;
599 else if (val >= 0x4000)
600 numBytes = 3;
601 else if (val >= 0x80)
602 numBytes = 2;
603 else
604 numBytes = 1;
605 for (i = numBytes; i > 0; i--)
607 outBytes[i - 1] = val & 0x7f;
608 val >>= 7;
610 for (i = 0; i < numBytes - 1; i++)
611 *pbEncoded++ = outBytes[i] | 0x80;
612 *pbEncoded++ = outBytes[i];
613 ptr += pos;
614 if (*ptr == '.')
615 ptr++;
621 *pcbEncoded = bytesNeeded;
622 return ret;
625 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
626 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
627 DWORD *pcbEncoded)
629 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
630 BOOL ret = TRUE;
632 if (!pbEncoded)
633 *pcbEncoded = blob->cbData;
634 else if (*pcbEncoded < blob->cbData)
636 *pcbEncoded = blob->cbData;
637 SetLastError(ERROR_MORE_DATA);
638 ret = FALSE;
640 else
642 if (blob->cbData)
643 memcpy(pbEncoded, blob->pbData, blob->cbData);
644 *pcbEncoded = blob->cbData;
646 return ret;
649 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
650 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
651 BYTE *pbEncoded, DWORD *pcbEncoded)
653 const CRYPT_ALGORITHM_IDENTIFIER *algo =
654 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
655 static const BYTE asn1Null[] = { ASN_NULL, 0 };
656 static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
657 (LPBYTE)asn1Null };
658 BOOL ret;
659 struct AsnEncodeSequenceItem items[2] = {
660 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
661 { NULL, CRYPT_CopyEncodedBlob, 0 },
664 if (algo->Parameters.cbData)
665 items[1].pvStructInfo = &algo->Parameters;
666 else
667 items[1].pvStructInfo = &nullBlob;
668 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
669 sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
670 return ret;
673 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
674 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
675 DWORD *pcbEncoded)
677 const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
678 (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
679 struct AsnEncodeSequenceItem items[] = {
680 { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
681 { &typeValue->Value, CRYPT_CopyEncodedBlob, 0 },
684 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
685 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
688 struct SPCDigest
690 CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
691 CRYPT_HASH_BLOB Digest;
694 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
695 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
696 DWORD *pcbEncoded)
698 const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
699 struct AsnEncodeSequenceItem items[] = {
700 { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
701 { &digest->Digest, CRYPT_CopyEncodedBlob, 0 },
704 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
705 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
708 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
709 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
710 DWORD *pcbEncoded)
712 BOOL ret = FALSE;
714 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
715 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
717 __TRY
719 const SPC_INDIRECT_DATA_CONTENT *data =
720 (const SPC_INDIRECT_DATA_CONTENT *)pvStructInfo;
721 struct AsnEncodeSequenceItem items[] = {
722 { &data->Data, CRYPT_AsnEncodeAttributeTypeValue, 0 },
723 { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
726 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
727 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
729 __EXCEPT_PAGE_FAULT
731 SetLastError(STATUS_ACCESS_VIOLATION);
733 __ENDTRY
734 return ret;
737 /* Gets the number of length bytes from the given (leading) length byte */
738 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
740 /* Helper function to get the encoded length of the data starting at pbEncoded,
741 * where pbEncoded[0] is the tag. If the data are too short to contain a
742 * length or if the length is too large for cbEncoded, sets an appropriate
743 * error code and returns FALSE.
745 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
747 BOOL ret;
749 if (cbEncoded <= 1)
751 SetLastError(CRYPT_E_ASN1_CORRUPT);
752 ret = FALSE;
754 else if (pbEncoded[1] <= 0x7f)
756 if (pbEncoded[1] + 1 > cbEncoded)
758 SetLastError(CRYPT_E_ASN1_EOD);
759 ret = FALSE;
761 else
763 *len = pbEncoded[1];
764 ret = TRUE;
767 else if (pbEncoded[1] == 0x80)
769 FIXME("unimplemented for indefinite-length encoding\n");
770 SetLastError(CRYPT_E_ASN1_CORRUPT);
771 ret = FALSE;
773 else
775 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
777 if (lenLen > sizeof(DWORD) + 1)
779 SetLastError(CRYPT_E_ASN1_LARGE);
780 ret = FALSE;
782 else if (lenLen + 2 > cbEncoded)
784 SetLastError(CRYPT_E_ASN1_CORRUPT);
785 ret = FALSE;
787 else
789 DWORD out = 0;
791 pbEncoded += 2;
792 while (--lenLen)
794 out <<= 8;
795 out |= *pbEncoded++;
797 if (out + lenLen + 1 > cbEncoded)
799 SetLastError(CRYPT_E_ASN1_EOD);
800 ret = FALSE;
802 else
804 *len = out;
805 ret = TRUE;
809 return ret;
812 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
813 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
814 void *pvStructInfo, DWORD *pcbStructInfo)
816 BOOL ret;
817 DWORD bytesNeeded, dataLen;
819 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
820 pvStructInfo, *pcbStructInfo);
822 if (!cbEncoded)
824 SetLastError(CRYPT_E_ASN1_CORRUPT);
825 ret = FALSE;
827 else if (pbEncoded[0] != ASN_OCTETSTRING)
829 SetLastError(CRYPT_E_ASN1_BADTAG);
830 ret = FALSE;
832 else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
834 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
835 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
836 else
837 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
838 if (!pvStructInfo)
839 *pcbStructInfo = bytesNeeded;
840 else if (*pcbStructInfo < bytesNeeded)
842 SetLastError(ERROR_MORE_DATA);
843 *pcbStructInfo = bytesNeeded;
844 ret = FALSE;
846 else
848 CRYPT_DATA_BLOB *blob;
849 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
851 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
852 blob->cbData = dataLen;
853 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
854 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
855 else
857 assert(blob->pbData);
858 if (blob->cbData)
859 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
860 blob->cbData);
864 return ret;
867 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
868 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
869 void *pvStructInfo, DWORD *pcbStructInfo)
871 BOOL ret = FALSE;
872 DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
874 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
875 pvStructInfo, *pcbStructInfo);
877 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
879 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
880 DWORD realDataLen;
882 switch (pbEncoded[0])
884 case ASN_CONTEXT:
885 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
886 if (!pvStructInfo)
887 *pcbStructInfo = bytesNeeded;
888 else if (*pcbStructInfo < bytesNeeded)
890 *pcbStructInfo = bytesNeeded;
891 SetLastError(ERROR_MORE_DATA);
892 ret = FALSE;
894 else
896 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
897 DWORD i;
899 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
900 for (i = 0; i < dataLen; i++)
901 link->u.pwszUrl[i] =
902 *(pbEncoded + 1 + lenBytes + i);
903 link->u.pwszUrl[i] = '\0';
904 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
906 break;
907 case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
909 CRYPT_DATA_BLOB classId;
910 DWORD size = sizeof(classId);
912 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
913 pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
914 CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
916 if (classId.cbData != sizeof(SPC_UUID))
918 SetLastError(CRYPT_E_BAD_ENCODE);
919 ret = FALSE;
921 else
923 CRYPT_DATA_BLOB data;
925 /* The tag length for the classId must be 1 since the
926 * length is correct.
928 size = sizeof(data);
929 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
930 pbEncoded + 3 + lenBytes + classId.cbData,
931 cbEncoded - 3 - lenBytes - classId.cbData,
932 CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
934 bytesNeeded += data.cbData;
935 if (!pvStructInfo)
936 *pcbStructInfo = bytesNeeded;
937 else if (*pcbStructInfo < bytesNeeded)
939 *pcbStructInfo = bytesNeeded;
940 SetLastError(ERROR_MORE_DATA);
941 ret = FALSE;
943 else
945 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
947 link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
948 /* pwszFile pointer was set by caller, copy it
949 * before overwriting it
951 link->u.Moniker.SerializedData.pbData =
952 (BYTE *)link->u.pwszFile;
953 memcpy(&link->u.Moniker.ClassId, classId.pbData,
954 classId.cbData);
955 memcpy(link->u.Moniker.SerializedData.pbData,
956 data.pbData, data.cbData);
957 link->u.Moniker.SerializedData.cbData = data.cbData;
962 break;
964 case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
965 if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
966 SetLastError(CRYPT_E_ASN1_BADTAG);
967 else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
968 &realDataLen)))
970 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
972 bytesNeeded += realDataLen + sizeof(WCHAR);
973 if (!pvStructInfo)
974 *pcbStructInfo = bytesNeeded;
975 else if (*pcbStructInfo < bytesNeeded)
977 *pcbStructInfo = bytesNeeded;
978 SetLastError(ERROR_MORE_DATA);
979 ret = FALSE;
981 else
983 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
984 DWORD i;
985 const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
987 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
988 for (i = 0; i < dataLen / sizeof(WCHAR); i++)
989 link->u.pwszFile[i] =
990 hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
991 link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
992 TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
995 else
997 bytesNeeded += sizeof(WCHAR);
998 if (!pvStructInfo)
999 *pcbStructInfo = bytesNeeded;
1000 else if (*pcbStructInfo < bytesNeeded)
1002 *pcbStructInfo = bytesNeeded;
1003 SetLastError(ERROR_MORE_DATA);
1004 ret = FALSE;
1006 else
1008 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1010 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1011 link->u.pwszFile[0] = '\0';
1012 ret = TRUE;
1015 break;
1016 default:
1017 SetLastError(CRYPT_E_ASN1_BADTAG);
1020 TRACE("returning %d\n", ret);
1021 return ret;
1024 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1025 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1026 void *pvStructInfo, DWORD *pcbStructInfo)
1028 BOOL ret = FALSE;
1030 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1031 pvStructInfo, *pcbStructInfo);
1033 __TRY
1035 DWORD bytesNeeded;
1037 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1038 lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1039 if (ret)
1041 if (!pvStructInfo)
1042 *pcbStructInfo = bytesNeeded;
1043 else if (*pcbStructInfo < bytesNeeded)
1045 *pcbStructInfo = bytesNeeded;
1046 SetLastError(ERROR_MORE_DATA);
1047 ret = FALSE;
1049 else
1051 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1053 link->u.pwszFile =
1054 (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1055 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1056 lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1057 pcbStructInfo);
1061 __EXCEPT_PAGE_FAULT
1063 SetLastError(STATUS_ACCESS_VIOLATION);
1065 __ENDTRY
1066 TRACE("returning %d\n", ret);
1067 return ret;
1070 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1071 DWORD, DWORD, void *, DWORD *);
1073 /* tag:
1074 * The expected tag of the item. If tag is 0, decodeFunc is called
1075 * regardless of the tag value seen.
1076 * offset:
1077 * A sequence is decoded into a struct. The offset member is the
1078 * offset of this item within that struct.
1079 * decodeFunc:
1080 * The decoder function to use. If this is NULL, then the member isn't
1081 * decoded, but minSize space is reserved for it.
1082 * minSize:
1083 * The minimum amount of space occupied after decoding. You must set this.
1084 * optional:
1085 * If true, and the tag doesn't match the expected tag for this item,
1086 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1087 * filled with 0 for this member.
1088 * hasPointer, pointerOffset:
1089 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1090 * the offset within the struct of the data pointer (or to the
1091 * first data pointer, if more than one exist).
1092 * size:
1093 * Used by CRYPT_AsnDecodeSequence, not for your use.
1095 struct AsnDecodeSequenceItem
1097 BYTE tag;
1098 DWORD offset;
1099 CryptDecodeObjectFunc decodeFunc;
1100 DWORD minSize;
1101 BOOL optional;
1102 BOOL hasPointer;
1103 DWORD pointerOffset;
1104 DWORD size;
1107 /* Decodes the items in a sequence, where the items are described in items,
1108 * the encoded data are in pbEncoded with length cbEncoded. Decodes into
1109 * pvStructInfo. nextData is a pointer to the memory location at which the
1110 * first decoded item with a dynamic pointer should point.
1111 * Upon decoding, *cbDecoded is the total number of bytes decoded.
1113 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1114 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1115 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1116 DWORD *cbDecoded)
1118 BOOL ret;
1119 DWORD i, decoded = 0;
1120 const BYTE *ptr = pbEncoded;
1122 TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1123 cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1125 for (i = 0, ret = TRUE; ret && i < cItem; i++)
1127 if (cbEncoded - (ptr - pbEncoded) != 0)
1129 DWORD nextItemLen;
1131 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1132 &nextItemLen)))
1134 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1136 if (ptr[0] == items[i].tag || !items[i].tag)
1138 if (nextData && pvStructInfo && items[i].hasPointer)
1140 TRACE("Setting next pointer to %p\n",
1141 nextData);
1142 *(BYTE **)((BYTE *)pvStructInfo +
1143 items[i].pointerOffset) = nextData;
1145 if (items[i].decodeFunc)
1147 if (pvStructInfo)
1148 TRACE("decoding item %d\n", i);
1149 else
1150 TRACE("sizing item %d\n", i);
1151 ret = items[i].decodeFunc(dwCertEncodingType,
1152 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1153 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1154 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
1155 : NULL, &items[i].size);
1156 if (ret)
1158 /* Account for alignment padding */
1159 if (items[i].size % sizeof(DWORD))
1160 items[i].size += sizeof(DWORD) -
1161 items[i].size % sizeof(DWORD);
1162 TRACE("item %d size: %d\n", i, items[i].size);
1163 if (nextData && items[i].hasPointer &&
1164 items[i].size > items[i].minSize)
1165 nextData += items[i].size - items[i].minSize;
1166 ptr += 1 + nextItemLenBytes + nextItemLen;
1167 decoded += 1 + nextItemLenBytes + nextItemLen;
1168 TRACE("item %d: decoded %d bytes\n", i,
1169 1 + nextItemLenBytes + nextItemLen);
1171 else if (items[i].optional &&
1172 GetLastError() == CRYPT_E_ASN1_BADTAG)
1174 TRACE("skipping optional item %d\n", i);
1175 items[i].size = items[i].minSize;
1176 SetLastError(NOERROR);
1177 ret = TRUE;
1179 else
1180 TRACE("item %d failed: %08x\n", i,
1181 GetLastError());
1183 else
1185 TRACE("item %d: decoded %d bytes\n", i,
1186 1 + nextItemLenBytes + nextItemLen);
1187 ptr += 1 + nextItemLenBytes + nextItemLen;
1188 decoded += 1 + nextItemLenBytes + nextItemLen;
1189 items[i].size = items[i].minSize;
1192 else if (items[i].optional)
1194 TRACE("skipping optional item %d\n", i);
1195 items[i].size = items[i].minSize;
1197 else
1199 TRACE("item %d: tag %02x doesn't match expected %02x\n",
1200 i, ptr[0], items[i].tag);
1201 SetLastError(CRYPT_E_ASN1_BADTAG);
1202 ret = FALSE;
1206 else if (items[i].optional)
1208 TRACE("missing optional item %d, skipping\n", i);
1209 items[i].size = items[i].minSize;
1211 else
1213 TRACE("not enough bytes for item %d, failing\n", i);
1214 SetLastError(CRYPT_E_ASN1_CORRUPT);
1215 ret = FALSE;
1218 if (ret)
1219 *cbDecoded = decoded;
1220 TRACE("returning %d\n", ret);
1221 return ret;
1224 /* This decodes an arbitrary sequence into a contiguous block of memory
1225 * (basically, a struct.) Each element being decoded is described by a struct
1226 * AsnDecodeSequenceItem, see above.
1227 * startingPointer is an optional pointer to the first place where dynamic
1228 * data will be stored. If you know the starting offset, you may pass it
1229 * here. Otherwise, pass NULL, and one will be inferred from the items.
1231 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1232 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1233 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1234 void *startingPointer)
1236 BOOL ret;
1238 TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1239 cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1241 if (pbEncoded[0] == ASN_SEQUENCE)
1243 DWORD dataLen;
1245 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1247 DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1248 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1250 cbEncoded -= 1 + lenBytes;
1251 if (cbEncoded < dataLen)
1253 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1254 cbEncoded);
1255 SetLastError(CRYPT_E_ASN1_CORRUPT);
1256 ret = FALSE;
1258 else
1259 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1260 cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1261 if (ret && cbDecoded != dataLen)
1263 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1264 cbDecoded);
1265 SetLastError(CRYPT_E_ASN1_CORRUPT);
1266 ret = FALSE;
1268 if (ret)
1270 DWORD i, bytesNeeded = 0, structSize = 0;
1272 for (i = 0; i < cItem; i++)
1274 bytesNeeded += items[i].size;
1275 structSize += items[i].minSize;
1277 if (!pvStructInfo)
1278 *pcbStructInfo = bytesNeeded;
1279 else if (*pcbStructInfo < bytesNeeded)
1281 SetLastError(ERROR_MORE_DATA);
1282 *pcbStructInfo = bytesNeeded;
1283 ret = FALSE;
1285 else
1287 BYTE *nextData;
1289 *pcbStructInfo = bytesNeeded;
1290 if (startingPointer)
1291 nextData = (BYTE *)startingPointer;
1292 else
1293 nextData = (BYTE *)pvStructInfo + structSize;
1294 memset(pvStructInfo, 0, structSize);
1295 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1296 ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1297 &cbDecoded);
1302 else
1304 SetLastError(CRYPT_E_ASN1_BADTAG);
1305 ret = FALSE;
1307 TRACE("returning %d (%08x)\n", ret, GetLastError());
1308 return ret;
1311 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1312 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1313 void *pvStructInfo, DWORD *pcbStructInfo)
1315 BOOL ret;
1317 TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1318 pvStructInfo, *pcbStructInfo);
1320 if (pbEncoded[0] == ASN_BITSTRING)
1322 DWORD bytesNeeded, dataLen;
1324 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1326 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1327 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1328 else
1329 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1330 if (!pvStructInfo)
1331 *pcbStructInfo = bytesNeeded;
1332 else if (*pcbStructInfo < bytesNeeded)
1334 *pcbStructInfo = bytesNeeded;
1335 SetLastError(ERROR_MORE_DATA);
1336 ret = FALSE;
1338 else
1340 CRYPT_BIT_BLOB *blob;
1342 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1343 blob->cbData = dataLen - 1;
1344 blob->cUnusedBits = *(pbEncoded + 1 +
1345 GET_LEN_BYTES(pbEncoded[1]));
1346 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1348 blob->pbData = (BYTE *)pbEncoded + 2 +
1349 GET_LEN_BYTES(pbEncoded[1]);
1351 else
1353 assert(blob->pbData);
1354 if (blob->cbData)
1356 BYTE mask = 0xff << blob->cUnusedBits;
1358 memcpy(blob->pbData, pbEncoded + 2 +
1359 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1360 blob->pbData[blob->cbData - 1] &= mask;
1366 else
1368 SetLastError(CRYPT_E_ASN1_BADTAG);
1369 ret = FALSE;
1371 TRACE("returning %d (%08x)\n", ret, GetLastError());
1372 return ret;
1375 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1376 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1377 void *pvStructInfo, DWORD *pcbStructInfo)
1379 BOOL ret = FALSE;
1380 DWORD dataLen;
1382 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1384 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1385 DWORD size;
1386 SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1388 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1389 pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1390 if (ret)
1392 if (!pvStructInfo)
1393 *pcbStructInfo = size + sizeof(PSPC_LINK);
1394 else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1396 *pcbStructInfo = size + sizeof(PSPC_LINK);
1397 SetLastError(ERROR_MORE_DATA);
1398 ret = FALSE;
1400 else
1402 *pcbStructInfo = size + sizeof(PSPC_LINK);
1403 /* Set imageData's pointer if necessary */
1404 if (size > sizeof(SPC_LINK))
1406 (*pLink)->u.pwszUrl =
1407 (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1409 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1410 lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1411 *pLink, pcbStructInfo);
1415 return ret;
1418 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1419 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1420 void *pvStructInfo, DWORD *pcbStructInfo)
1422 BOOL ret = FALSE;
1424 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1425 pvStructInfo, *pcbStructInfo);
1427 __TRY
1429 struct AsnDecodeSequenceItem items[] = {
1430 { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1431 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1432 offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1433 { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1434 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1435 offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1438 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1439 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1440 pvStructInfo, pcbStructInfo, NULL);
1442 __EXCEPT_PAGE_FAULT
1444 SetLastError(STATUS_ACCESS_VIOLATION);
1446 __ENDTRY
1447 TRACE("returning %d\n", ret);
1448 return ret;
1451 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1452 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1453 void *pvStructInfo, DWORD *pcbStructInfo)
1455 BOOL ret = TRUE;
1456 DWORD dataLen;
1458 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1459 pvStructInfo, *pcbStructInfo);
1461 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1463 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1464 DWORD bytesNeeded = sizeof(LPSTR);
1466 if (dataLen)
1468 /* The largest possible string for the first two components
1469 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1471 char firstTwo[6];
1472 const BYTE *ptr;
1474 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1475 pbEncoded[1 + lenBytes] / 40,
1476 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1477 * 40);
1478 bytesNeeded += strlen(firstTwo) + 1;
1479 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1480 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1482 /* large enough for ".4000000" */
1483 char str[9];
1484 int val = 0;
1486 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1487 (*ptr & 0x80))
1489 val <<= 7;
1490 val |= *ptr & 0x7f;
1491 ptr++;
1493 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1494 (*ptr & 0x80))
1496 SetLastError(CRYPT_E_ASN1_CORRUPT);
1497 ret = FALSE;
1499 else
1501 val <<= 7;
1502 val |= *ptr++;
1503 snprintf(str, sizeof(str), ".%d", val);
1504 bytesNeeded += strlen(str);
1508 if (!pvStructInfo)
1509 *pcbStructInfo = bytesNeeded;
1510 else if (*pcbStructInfo < bytesNeeded)
1512 *pcbStructInfo = bytesNeeded;
1513 SetLastError(ERROR_MORE_DATA);
1514 ret = FALSE;
1516 else
1518 if (dataLen)
1520 const BYTE *ptr;
1521 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1523 *pszObjId = 0;
1524 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1525 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1526 40) * 40);
1527 pszObjId += strlen(pszObjId);
1528 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1529 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1531 int val = 0;
1533 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1534 (*ptr & 0x80))
1536 val <<= 7;
1537 val |= *ptr & 0x7f;
1538 ptr++;
1540 val <<= 7;
1541 val |= *ptr++;
1542 sprintf(pszObjId, ".%d", val);
1543 pszObjId += strlen(pszObjId);
1546 else
1547 *(LPSTR *)pvStructInfo = NULL;
1548 *pcbStructInfo = bytesNeeded;
1551 return ret;
1554 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1555 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1556 void *pvStructInfo, DWORD *pcbStructInfo)
1558 BOOL ret = FALSE;
1560 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1561 pvStructInfo, *pcbStructInfo);
1563 if (!cbEncoded)
1564 SetLastError(CRYPT_E_ASN1_CORRUPT);
1565 else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1566 ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1567 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1568 else
1569 SetLastError(CRYPT_E_ASN1_BADTAG);
1570 return ret;
1573 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1574 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1575 void *pvStructInfo, DWORD *pcbStructInfo)
1577 BOOL ret = TRUE;
1578 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1580 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1581 pvStructInfo, *pcbStructInfo);
1583 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1584 bytesNeeded += cbEncoded;
1585 if (!pvStructInfo)
1586 *pcbStructInfo = bytesNeeded;
1587 else if (*pcbStructInfo < bytesNeeded)
1589 SetLastError(ERROR_MORE_DATA);
1590 *pcbStructInfo = bytesNeeded;
1591 ret = FALSE;
1593 else
1595 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1597 *pcbStructInfo = bytesNeeded;
1598 blob->cbData = cbEncoded;
1599 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1600 blob->pbData = (LPBYTE)pbEncoded;
1601 else
1603 assert(blob->pbData);
1604 memcpy(blob->pbData, pbEncoded, blob->cbData);
1607 return ret;
1610 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1611 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1612 void *pvStructInfo, DWORD *pcbStructInfo)
1614 CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1615 (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1616 struct AsnDecodeSequenceItem items[] = {
1617 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1618 CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1619 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1620 { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1621 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1622 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1625 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1626 pvStructInfo, *pcbStructInfo);
1628 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1629 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1630 pvStructInfo, pcbStructInfo,
1631 typeValue ? typeValue->pszObjId : NULL);
1634 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1635 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1636 void *pvStructInfo, DWORD *pcbStructInfo)
1638 CRYPT_ALGORITHM_IDENTIFIER *algo =
1639 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
1640 BOOL ret = TRUE;
1641 struct AsnDecodeSequenceItem items[] = {
1642 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
1643 CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
1644 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
1645 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
1646 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
1647 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
1650 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1651 pvStructInfo, *pcbStructInfo);
1653 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1654 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1655 pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
1656 if (ret && pvStructInfo)
1658 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
1659 debugstr_a(algo->pszObjId));
1661 return ret;
1664 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
1665 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1666 void *pvStructInfo, DWORD *pcbStructInfo)
1668 struct SPCDigest *digest =
1669 (struct SPCDigest *)pvStructInfo;
1670 struct AsnDecodeSequenceItem items[] = {
1671 { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
1672 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
1673 FALSE, TRUE,
1674 offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
1675 { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
1676 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
1677 FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
1680 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1681 pvStructInfo, *pcbStructInfo);
1683 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1684 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1685 pvStructInfo, pcbStructInfo,
1686 digest ? digest->DigestAlgorithm.pszObjId : NULL);
1689 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
1690 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1691 void *pvStructInfo, DWORD *pcbStructInfo)
1693 BOOL ret = FALSE;
1695 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1696 pvStructInfo, *pcbStructInfo);
1698 __TRY
1700 struct AsnDecodeSequenceItem items[] = {
1701 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
1702 CRYPT_AsnDecodeAttributeTypeValue,
1703 sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
1704 offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
1705 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
1706 CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
1707 FALSE, TRUE,
1708 offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
1711 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1712 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1713 pvStructInfo, pcbStructInfo, NULL);
1715 __EXCEPT_PAGE_FAULT
1717 SetLastError(STATUS_ACCESS_VIOLATION);
1719 __ENDTRY
1720 TRACE("returning %d\n", ret);
1721 return ret;
1724 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
1725 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1726 void *pvStructInfo, DWORD *pcbStructInfo)
1728 FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1729 pvStructInfo, *pcbStructInfo);
1730 return FALSE;