netapi32: Fix tests when the machine is on DOMAIN.
[wine.git] / dlls / wintrust / asn.c
blob2b0bde1cf45839ac712d13afd8254f8b0f57e00f
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)
54 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
56 DWORD bytesNeeded, significantBytes = 0;
58 if (len <= 0x7f)
59 bytesNeeded = 1;
60 else
62 DWORD temp;
64 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
65 temp <<= 8, significantBytes--)
67 bytesNeeded = significantBytes + 1;
69 if (!pbEncoded)
71 *pcbEncoded = bytesNeeded;
72 return TRUE;
74 if (*pcbEncoded < bytesNeeded)
76 SetLastError(ERROR_MORE_DATA);
77 return FALSE;
79 if (len <= 0x7f)
80 *pbEncoded = (BYTE)len;
81 else
83 DWORD i;
85 *pbEncoded++ = significantBytes | 0x80;
86 for (i = 0; i < significantBytes; i++)
88 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
89 len >>= 8;
92 *pcbEncoded = bytesNeeded;
93 return TRUE;
96 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
97 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
98 DWORD *pcbEncoded)
100 BOOL ret = TRUE;
101 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
102 DWORD bytesNeeded, lenBytes;
104 TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
105 *pcbEncoded);
107 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
108 bytesNeeded = 1 + lenBytes + blob->cbData;
109 if (!pbEncoded)
110 *pcbEncoded = bytesNeeded;
111 else if (*pcbEncoded < bytesNeeded)
113 *pcbEncoded = bytesNeeded;
114 SetLastError(ERROR_MORE_DATA);
115 ret = FALSE;
117 else
119 *pbEncoded++ = ASN_OCTETSTRING;
120 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
121 pbEncoded += lenBytes;
122 if (blob->cbData)
123 memcpy(pbEncoded, blob->pbData, blob->cbData);
125 TRACE("returning %d\n", ret);
126 return ret;
129 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
130 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
131 DWORD *pcbEncoded)
133 BOOL ret = FALSE;
135 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
136 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
137 pcbEncoded);
139 __TRY
141 const SPC_LINK *link = (const SPC_LINK *)pvStructInfo;
142 DWORD bytesNeeded, lenBytes;
144 switch (link->dwLinkChoice)
146 case SPC_FILE_LINK_CHOICE:
148 DWORD fileNameLen, fileNameLenBytes;
149 LPWSTR ptr;
151 fileNameLen = link->u.pwszFile ?
152 lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
153 CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
154 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
155 &lenBytes);
156 bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
157 if (!pbEncoded)
159 *pcbEncoded = bytesNeeded;
160 ret = TRUE;
162 else if (*pcbEncoded < bytesNeeded)
164 SetLastError(ERROR_MORE_DATA);
165 *pcbEncoded = bytesNeeded;
167 else
169 *pcbEncoded = bytesNeeded;
170 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
171 CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
172 &lenBytes);
173 pbEncoded += lenBytes;
174 *pbEncoded++ = ASN_CONTEXT;
175 CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
176 pbEncoded += fileNameLenBytes;
177 for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
179 *(WCHAR *)pbEncoded = hton16(*ptr);
180 pbEncoded += sizeof(WCHAR);
182 ret = TRUE;
184 break;
186 case SPC_MONIKER_LINK_CHOICE:
188 DWORD classIdLenBytes, dataLenBytes, dataLen;
189 CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
190 (BYTE *)&link->u.Moniker.ClassId };
192 CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
193 CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
194 &dataLenBytes);
195 dataLen = 2 + classIdLenBytes + classId.cbData +
196 dataLenBytes + link->u.Moniker.SerializedData.cbData;
197 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
198 bytesNeeded = 1 + dataLen + lenBytes;
199 if (!pbEncoded)
201 *pcbEncoded = bytesNeeded;
202 ret = TRUE;
204 else if (*pcbEncoded < bytesNeeded)
206 SetLastError(ERROR_MORE_DATA);
207 *pcbEncoded = bytesNeeded;
209 else
211 DWORD size;
213 *pcbEncoded = bytesNeeded;
214 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
215 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
216 pbEncoded += lenBytes;
217 size = 1 + classIdLenBytes + classId.cbData;
218 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
219 pbEncoded, &size);
220 pbEncoded += size;
221 size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
222 CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
223 &link->u.Moniker.SerializedData, pbEncoded, &size);
224 pbEncoded += size;
225 ret = TRUE;
227 break;
229 case SPC_URL_LINK_CHOICE:
231 LPWSTR ptr;
232 DWORD urlLen;
234 /* Check for invalid characters in URL */
235 ret = TRUE;
236 urlLen = 0;
237 for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
238 if (*ptr > 0x7f)
240 *pcbEncoded = 0;
241 SetLastError(CRYPT_E_INVALID_IA5_STRING);
242 ret = FALSE;
244 else
245 urlLen++;
246 if (ret)
248 CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
249 bytesNeeded = 1 + lenBytes + urlLen;
250 if (!pbEncoded)
251 *pcbEncoded = bytesNeeded;
252 else if (*pcbEncoded < bytesNeeded)
254 SetLastError(ERROR_MORE_DATA);
255 *pcbEncoded = bytesNeeded;
256 ret = FALSE;
258 else
260 *pcbEncoded = bytesNeeded;
261 *pbEncoded++ = ASN_CONTEXT;
262 CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
263 pbEncoded += lenBytes;
264 for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
265 *pbEncoded++ = (BYTE)*ptr;
268 break;
270 default:
271 SetLastError(E_INVALIDARG);
274 __EXCEPT_PAGE_FAULT
276 SetLastError(STATUS_ACCESS_VIOLATION);
278 __ENDTRY
279 TRACE("returning %d\n", ret);
280 return ret;
283 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
284 BYTE *, DWORD *);
286 struct AsnEncodeSequenceItem
288 const void *pvStructInfo;
289 CryptEncodeObjectFunc encodeFunc;
290 DWORD size; /* used during encoding, not for your use */
293 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
294 struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
295 DWORD *pcbEncoded)
297 BOOL ret;
298 DWORD i, dataLen = 0;
300 TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
301 for (i = 0, ret = TRUE; ret && i < cItem; i++)
303 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
304 items[i].pvStructInfo, NULL, &items[i].size);
305 /* Some functions propagate their errors through the size */
306 if (!ret)
307 *pcbEncoded = items[i].size;
308 dataLen += items[i].size;
310 if (ret)
312 DWORD lenBytes, bytesNeeded;
314 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
315 bytesNeeded = 1 + lenBytes + dataLen;
316 if (!pbEncoded)
317 *pcbEncoded = bytesNeeded;
318 else if (*pcbEncoded < bytesNeeded)
320 *pcbEncoded = bytesNeeded;
321 SetLastError(ERROR_MORE_DATA);
322 ret = FALSE;
324 else
326 *pcbEncoded = bytesNeeded;
327 *pbEncoded++ = ASN_SEQUENCE;
328 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
329 pbEncoded += lenBytes;
330 for (i = 0; ret && i < cItem; i++)
332 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
333 items[i].pvStructInfo, pbEncoded, &items[i].size);
334 /* Some functions propagate their errors through the size */
335 if (!ret)
336 *pcbEncoded = items[i].size;
337 pbEncoded += items[i].size;
341 TRACE("returning %d\n", ret);
342 return ret;
345 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
346 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
347 DWORD *pcbEncoded)
349 BOOL ret = FALSE;
351 __TRY
353 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
354 DWORD bytesNeeded, lenBytes, dataBytes;
355 BYTE unusedBits;
357 /* yep, MS allows cUnusedBits to be >= 8 */
358 if (!blob->cUnusedBits)
360 dataBytes = blob->cbData;
361 unusedBits = 0;
363 else if (blob->cbData * 8 > blob->cUnusedBits)
365 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
366 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
367 blob->cUnusedBits;
369 else
371 dataBytes = 0;
372 unusedBits = 0;
374 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
375 bytesNeeded = 1 + lenBytes + dataBytes + 1;
376 if (!pbEncoded)
378 *pcbEncoded = bytesNeeded;
379 ret = TRUE;
381 else if (*pcbEncoded < bytesNeeded)
383 *pcbEncoded = bytesNeeded;
384 SetLastError(ERROR_MORE_DATA);
386 else
388 ret = TRUE;
389 *pcbEncoded = bytesNeeded;
390 *pbEncoded++ = ASN_BITSTRING;
391 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
392 pbEncoded += lenBytes;
393 *pbEncoded++ = unusedBits;
394 if (dataBytes)
396 BYTE mask = 0xff << unusedBits;
398 if (dataBytes > 1)
400 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
401 pbEncoded += dataBytes - 1;
403 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
407 __EXCEPT_PAGE_FAULT
409 SetLastError(STATUS_ACCESS_VIOLATION);
411 __ENDTRY
412 return ret;
415 struct AsnConstructedItem
417 BYTE tag;
418 const void *pvStructInfo;
419 CryptEncodeObjectFunc encodeFunc;
422 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
423 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
424 DWORD *pcbEncoded)
426 BOOL ret;
427 const struct AsnConstructedItem *item =
428 (const struct AsnConstructedItem *)pvStructInfo;
429 DWORD len;
431 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
432 item->pvStructInfo, NULL, &len)))
434 DWORD dataLen, bytesNeeded;
436 CRYPT_EncodeLen(len, NULL, &dataLen);
437 bytesNeeded = 1 + dataLen + len;
438 if (!pbEncoded)
439 *pcbEncoded = bytesNeeded;
440 else if (*pcbEncoded < bytesNeeded)
442 *pcbEncoded = bytesNeeded;
443 SetLastError(ERROR_MORE_DATA);
444 ret = FALSE;
446 else
448 *pcbEncoded = bytesNeeded;
449 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
450 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
451 pbEncoded += dataLen;
452 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
453 item->pvStructInfo, pbEncoded, &len);
454 if (!ret)
456 /* Some functions propagate their errors through the size */
457 *pcbEncoded = len;
461 else
463 /* Some functions propagate their errors through the size */
464 *pcbEncoded = len;
466 return ret;
470 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
471 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
472 DWORD *pcbEncoded)
474 const SPC_PE_IMAGE_DATA *imageData =
475 (const SPC_PE_IMAGE_DATA *)pvStructInfo;
476 BOOL ret = FALSE;
478 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
479 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
480 pcbEncoded);
482 __TRY
484 struct AsnEncodeSequenceItem items[2] = {
485 { 0 }
487 struct AsnConstructedItem constructed = { 0, imageData->pFile,
488 WVTAsn1SpcLinkEncode };
489 DWORD cItem = 0;
491 if (imageData->Flags.cbData)
493 items[cItem].pvStructInfo = &imageData->Flags;
494 items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
495 cItem++;
497 if (imageData->pFile)
499 items[cItem].pvStructInfo = &constructed;
500 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
501 cItem++;
504 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
505 pbEncoded, pcbEncoded);
507 __EXCEPT_PAGE_FAULT
509 SetLastError(STATUS_ACCESS_VIOLATION);
511 __ENDTRY
512 TRACE("returning %d\n", ret);
513 return ret;
516 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
517 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
518 DWORD *pcbEncoded)
520 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
521 DWORD bytesNeeded = 0, lenBytes;
522 BOOL ret = TRUE;
523 int firstPos = 0;
524 BYTE firstByte = 0;
526 TRACE("%s\n", debugstr_a(pszObjId));
528 if (pszObjId)
530 const char *ptr;
531 int val1, val2;
533 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
535 SetLastError(CRYPT_E_ASN1_ERROR);
536 return FALSE;
538 bytesNeeded++;
539 firstByte = val1 * 40 + val2;
540 ptr = pszObjId + firstPos;
541 while (ret && *ptr)
543 int pos;
545 /* note I assume each component is at most 32-bits long in base 2 */
546 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
548 if (val1 >= 0x10000000)
549 bytesNeeded += 5;
550 else if (val1 >= 0x200000)
551 bytesNeeded += 4;
552 else if (val1 >= 0x4000)
553 bytesNeeded += 3;
554 else if (val1 >= 0x80)
555 bytesNeeded += 2;
556 else
557 bytesNeeded += 1;
558 ptr += pos;
559 if (*ptr == '.')
560 ptr++;
562 else
564 SetLastError(CRYPT_E_ASN1_ERROR);
565 return FALSE;
568 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
570 else
571 lenBytes = 1;
572 bytesNeeded += 1 + lenBytes;
573 if (pbEncoded)
575 if (*pcbEncoded < bytesNeeded)
577 SetLastError(ERROR_MORE_DATA);
578 ret = FALSE;
580 else
582 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
583 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
584 pbEncoded += lenBytes;
585 if (pszObjId)
587 const char *ptr;
588 int val, pos;
590 *pbEncoded++ = firstByte;
591 ptr = pszObjId + firstPos;
592 while (ret && *ptr)
594 sscanf(ptr, "%d%n", &val, &pos);
596 unsigned char outBytes[5];
597 int numBytes, i;
599 if (val >= 0x10000000)
600 numBytes = 5;
601 else if (val >= 0x200000)
602 numBytes = 4;
603 else if (val >= 0x4000)
604 numBytes = 3;
605 else if (val >= 0x80)
606 numBytes = 2;
607 else
608 numBytes = 1;
609 for (i = numBytes; i > 0; i--)
611 outBytes[i - 1] = val & 0x7f;
612 val >>= 7;
614 for (i = 0; i < numBytes - 1; i++)
615 *pbEncoded++ = outBytes[i] | 0x80;
616 *pbEncoded++ = outBytes[i];
617 ptr += pos;
618 if (*ptr == '.')
619 ptr++;
625 *pcbEncoded = bytesNeeded;
626 return ret;
629 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
630 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
631 DWORD *pcbEncoded)
633 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
634 BOOL ret = TRUE;
636 if (!pbEncoded)
637 *pcbEncoded = blob->cbData;
638 else if (*pcbEncoded < blob->cbData)
640 *pcbEncoded = blob->cbData;
641 SetLastError(ERROR_MORE_DATA);
642 ret = FALSE;
644 else
646 if (blob->cbData)
647 memcpy(pbEncoded, blob->pbData, blob->cbData);
648 *pcbEncoded = blob->cbData;
650 return ret;
653 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
654 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
655 BYTE *pbEncoded, DWORD *pcbEncoded)
657 const CRYPT_ALGORITHM_IDENTIFIER *algo =
658 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
659 static const BYTE asn1Null[] = { ASN_NULL, 0 };
660 static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
661 (LPBYTE)asn1Null };
662 BOOL ret;
663 struct AsnEncodeSequenceItem items[2] = {
664 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
665 { NULL, CRYPT_CopyEncodedBlob, 0 },
668 if (algo->Parameters.cbData)
669 items[1].pvStructInfo = &algo->Parameters;
670 else
671 items[1].pvStructInfo = &nullBlob;
672 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
673 sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
674 return ret;
677 static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType,
678 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
679 DWORD *pcbEncoded)
681 const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
682 (const CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
683 struct AsnEncodeSequenceItem items[] = {
684 { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 },
685 { &typeValue->Value, CRYPT_CopyEncodedBlob, 0 },
688 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
689 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
692 struct SPCDigest
694 CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
695 CRYPT_HASH_BLOB Digest;
698 static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType,
699 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
700 DWORD *pcbEncoded)
702 const struct SPCDigest *digest = (const struct SPCDigest *)pvStructInfo;
703 struct AsnEncodeSequenceItem items[] = {
704 { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 },
705 { &digest->Digest, CRYPT_CopyEncodedBlob, 0 },
708 return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
709 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
712 BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType,
713 LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
714 DWORD *pcbEncoded)
716 BOOL ret = FALSE;
718 TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
719 debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded);
721 __TRY
723 const SPC_INDIRECT_DATA_CONTENT *data =
724 (const SPC_INDIRECT_DATA_CONTENT *)pvStructInfo;
725 struct AsnEncodeSequenceItem items[] = {
726 { &data->Data, CRYPT_AsnEncodeAttributeTypeValue, 0 },
727 { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 },
730 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING,
731 items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded);
733 __EXCEPT_PAGE_FAULT
735 SetLastError(STATUS_ACCESS_VIOLATION);
737 __ENDTRY
738 return ret;
741 /* Gets the number of length bytes from the given (leading) length byte */
742 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
744 /* Helper function to get the encoded length of the data starting at pbEncoded,
745 * where pbEncoded[0] is the tag. If the data are too short to contain a
746 * length or if the length is too large for cbEncoded, sets an appropriate
747 * error code and returns FALSE.
749 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
751 BOOL ret;
753 if (cbEncoded <= 1)
755 SetLastError(CRYPT_E_ASN1_CORRUPT);
756 ret = FALSE;
758 else if (pbEncoded[1] <= 0x7f)
760 if (pbEncoded[1] + 1 > cbEncoded)
762 SetLastError(CRYPT_E_ASN1_EOD);
763 ret = FALSE;
765 else
767 *len = pbEncoded[1];
768 ret = TRUE;
771 else if (pbEncoded[1] == 0x80)
773 FIXME("unimplemented for indefinite-length encoding\n");
774 SetLastError(CRYPT_E_ASN1_CORRUPT);
775 ret = FALSE;
777 else
779 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
781 if (lenLen > sizeof(DWORD) + 1)
783 SetLastError(CRYPT_E_ASN1_LARGE);
784 ret = FALSE;
786 else if (lenLen + 2 > cbEncoded)
788 SetLastError(CRYPT_E_ASN1_CORRUPT);
789 ret = FALSE;
791 else
793 DWORD out = 0;
795 pbEncoded += 2;
796 while (--lenLen)
798 out <<= 8;
799 out |= *pbEncoded++;
801 if (out + lenLen + 1 > cbEncoded)
803 SetLastError(CRYPT_E_ASN1_EOD);
804 ret = FALSE;
806 else
808 *len = out;
809 ret = TRUE;
813 return ret;
816 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
817 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
818 void *pvStructInfo, DWORD *pcbStructInfo)
820 BOOL ret;
821 DWORD bytesNeeded, dataLen;
823 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
824 pvStructInfo, *pcbStructInfo);
826 if (!cbEncoded)
828 SetLastError(CRYPT_E_ASN1_CORRUPT);
829 ret = FALSE;
831 else if (pbEncoded[0] != ASN_OCTETSTRING)
833 SetLastError(CRYPT_E_ASN1_BADTAG);
834 ret = FALSE;
836 else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
838 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
839 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
840 else
841 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
842 if (!pvStructInfo)
843 *pcbStructInfo = bytesNeeded;
844 else if (*pcbStructInfo < bytesNeeded)
846 SetLastError(ERROR_MORE_DATA);
847 *pcbStructInfo = bytesNeeded;
848 ret = FALSE;
850 else
852 CRYPT_DATA_BLOB *blob;
853 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
855 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
856 blob->cbData = dataLen;
857 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
858 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
859 else
861 assert(blob->pbData);
862 if (blob->cbData)
863 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
864 blob->cbData);
868 return ret;
871 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
872 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
873 void *pvStructInfo, DWORD *pcbStructInfo)
875 BOOL ret = FALSE;
876 DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
878 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
879 pvStructInfo, *pcbStructInfo);
881 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
883 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
884 DWORD realDataLen;
886 switch (pbEncoded[0])
888 case ASN_CONTEXT:
889 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
890 if (!pvStructInfo)
891 *pcbStructInfo = bytesNeeded;
892 else if (*pcbStructInfo < bytesNeeded)
894 *pcbStructInfo = bytesNeeded;
895 SetLastError(ERROR_MORE_DATA);
896 ret = FALSE;
898 else
900 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
901 DWORD i;
903 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
904 for (i = 0; i < dataLen; i++)
905 link->u.pwszUrl[i] =
906 *(pbEncoded + 1 + lenBytes + i);
907 link->u.pwszUrl[i] = '\0';
908 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
910 break;
911 case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
913 CRYPT_DATA_BLOB classId;
914 DWORD size = sizeof(classId);
916 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
917 pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
918 CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
920 if (classId.cbData != sizeof(SPC_UUID))
922 SetLastError(CRYPT_E_BAD_ENCODE);
923 ret = FALSE;
925 else
927 CRYPT_DATA_BLOB data;
929 /* The tag length for the classId must be 1 since the
930 * length is correct.
932 size = sizeof(data);
933 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
934 pbEncoded + 3 + lenBytes + classId.cbData,
935 cbEncoded - 3 - lenBytes - classId.cbData,
936 CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
938 bytesNeeded += data.cbData;
939 if (!pvStructInfo)
940 *pcbStructInfo = bytesNeeded;
941 else if (*pcbStructInfo < bytesNeeded)
943 *pcbStructInfo = bytesNeeded;
944 SetLastError(ERROR_MORE_DATA);
945 ret = FALSE;
947 else
949 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
951 link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
952 /* pwszFile pointer was set by caller, copy it
953 * before overwriting it
955 link->u.Moniker.SerializedData.pbData =
956 (BYTE *)link->u.pwszFile;
957 memcpy(&link->u.Moniker.ClassId, classId.pbData,
958 classId.cbData);
959 memcpy(link->u.Moniker.SerializedData.pbData,
960 data.pbData, data.cbData);
961 link->u.Moniker.SerializedData.cbData = data.cbData;
966 break;
968 case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
969 if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
970 SetLastError(CRYPT_E_ASN1_BADTAG);
971 else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
972 &realDataLen)))
974 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
976 bytesNeeded += realDataLen + sizeof(WCHAR);
977 if (!pvStructInfo)
978 *pcbStructInfo = bytesNeeded;
979 else if (*pcbStructInfo < bytesNeeded)
981 *pcbStructInfo = bytesNeeded;
982 SetLastError(ERROR_MORE_DATA);
983 ret = FALSE;
985 else
987 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
988 DWORD i;
989 const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
991 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
992 for (i = 0; i < dataLen / sizeof(WCHAR); i++)
993 link->u.pwszFile[i] =
994 hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
995 link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
996 TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
999 else
1001 bytesNeeded += sizeof(WCHAR);
1002 if (!pvStructInfo)
1003 *pcbStructInfo = bytesNeeded;
1004 else if (*pcbStructInfo < bytesNeeded)
1006 *pcbStructInfo = bytesNeeded;
1007 SetLastError(ERROR_MORE_DATA);
1008 ret = FALSE;
1010 else
1012 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1014 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1015 link->u.pwszFile[0] = '\0';
1016 ret = TRUE;
1019 break;
1020 default:
1021 SetLastError(CRYPT_E_ASN1_BADTAG);
1024 TRACE("returning %d\n", ret);
1025 return ret;
1028 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1029 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1030 void *pvStructInfo, DWORD *pcbStructInfo)
1032 BOOL ret = FALSE;
1034 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1035 pvStructInfo, *pcbStructInfo);
1037 __TRY
1039 DWORD bytesNeeded;
1041 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1042 lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1043 if (ret)
1045 if (!pvStructInfo)
1046 *pcbStructInfo = bytesNeeded;
1047 else if (*pcbStructInfo < bytesNeeded)
1049 *pcbStructInfo = bytesNeeded;
1050 SetLastError(ERROR_MORE_DATA);
1051 ret = FALSE;
1053 else
1055 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1057 link->u.pwszFile =
1058 (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1059 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1060 lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1061 pcbStructInfo);
1065 __EXCEPT_PAGE_FAULT
1067 SetLastError(STATUS_ACCESS_VIOLATION);
1069 __ENDTRY
1070 TRACE("returning %d\n", ret);
1071 return ret;
1074 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1075 DWORD, DWORD, void *, DWORD *);
1077 /* tag:
1078 * The expected tag of the item. If tag is 0, decodeFunc is called
1079 * regardless of the tag value seen.
1080 * offset:
1081 * A sequence is decoded into a struct. The offset member is the
1082 * offset of this item within that struct.
1083 * decodeFunc:
1084 * The decoder function to use. If this is NULL, then the member isn't
1085 * decoded, but minSize space is reserved for it.
1086 * minSize:
1087 * The minimum amount of space occupied after decoding. You must set this.
1088 * optional:
1089 * If true, and the tag doesn't match the expected tag for this item,
1090 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1091 * filled with 0 for this member.
1092 * hasPointer, pointerOffset:
1093 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1094 * the offset within the struct of the data pointer (or to the
1095 * first data pointer, if more than one exist).
1096 * size:
1097 * Used by CRYPT_AsnDecodeSequence, not for your use.
1099 struct AsnDecodeSequenceItem
1101 BYTE tag;
1102 DWORD offset;
1103 CryptDecodeObjectFunc decodeFunc;
1104 DWORD minSize;
1105 BOOL optional;
1106 BOOL hasPointer;
1107 DWORD pointerOffset;
1108 DWORD size;
1111 /* Decodes the items in a sequence, where the items are described in items,
1112 * the encoded data are in pbEncoded with length cbEncoded. Decodes into
1113 * pvStructInfo. nextData is a pointer to the memory location at which the
1114 * first decoded item with a dynamic pointer should point.
1115 * Upon decoding, *cbDecoded is the total number of bytes decoded.
1117 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1118 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1119 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1120 DWORD *cbDecoded)
1122 BOOL ret;
1123 DWORD i, decoded = 0;
1124 const BYTE *ptr = pbEncoded;
1126 TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1127 cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1129 for (i = 0, ret = TRUE; ret && i < cItem; i++)
1131 if (cbEncoded - (ptr - pbEncoded) != 0)
1133 DWORD nextItemLen;
1135 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1136 &nextItemLen)))
1138 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1140 if (ptr[0] == items[i].tag || !items[i].tag)
1142 if (nextData && pvStructInfo && items[i].hasPointer)
1144 TRACE("Setting next pointer to %p\n",
1145 nextData);
1146 *(BYTE **)((BYTE *)pvStructInfo +
1147 items[i].pointerOffset) = nextData;
1149 if (items[i].decodeFunc)
1151 if (pvStructInfo)
1152 TRACE("decoding item %d\n", i);
1153 else
1154 TRACE("sizing item %d\n", i);
1155 ret = items[i].decodeFunc(dwCertEncodingType,
1156 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1157 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1158 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
1159 : NULL, &items[i].size);
1160 if (ret)
1162 /* Account for alignment padding */
1163 if (items[i].size % sizeof(DWORD))
1164 items[i].size += sizeof(DWORD) -
1165 items[i].size % sizeof(DWORD);
1166 TRACE("item %d size: %d\n", i, items[i].size);
1167 if (nextData && items[i].hasPointer &&
1168 items[i].size > items[i].minSize)
1169 nextData += items[i].size - items[i].minSize;
1170 ptr += 1 + nextItemLenBytes + nextItemLen;
1171 decoded += 1 + nextItemLenBytes + nextItemLen;
1172 TRACE("item %d: decoded %d bytes\n", i,
1173 1 + nextItemLenBytes + nextItemLen);
1175 else if (items[i].optional &&
1176 GetLastError() == CRYPT_E_ASN1_BADTAG)
1178 TRACE("skipping optional item %d\n", i);
1179 items[i].size = items[i].minSize;
1180 SetLastError(NOERROR);
1181 ret = TRUE;
1183 else
1184 TRACE("item %d failed: %08x\n", i,
1185 GetLastError());
1187 else
1189 TRACE("item %d: decoded %d bytes\n", i,
1190 1 + nextItemLenBytes + nextItemLen);
1191 ptr += 1 + nextItemLenBytes + nextItemLen;
1192 decoded += 1 + nextItemLenBytes + nextItemLen;
1193 items[i].size = items[i].minSize;
1196 else if (items[i].optional)
1198 TRACE("skipping optional item %d\n", i);
1199 items[i].size = items[i].minSize;
1201 else
1203 TRACE("item %d: tag %02x doesn't match expected %02x\n",
1204 i, ptr[0], items[i].tag);
1205 SetLastError(CRYPT_E_ASN1_BADTAG);
1206 ret = FALSE;
1210 else if (items[i].optional)
1212 TRACE("missing optional item %d, skipping\n", i);
1213 items[i].size = items[i].minSize;
1215 else
1217 TRACE("not enough bytes for item %d, failing\n", i);
1218 SetLastError(CRYPT_E_ASN1_CORRUPT);
1219 ret = FALSE;
1222 if (ret)
1223 *cbDecoded = decoded;
1224 TRACE("returning %d\n", ret);
1225 return ret;
1228 /* This decodes an arbitrary sequence into a contiguous block of memory
1229 * (basically, a struct.) Each element being decoded is described by a struct
1230 * AsnDecodeSequenceItem, see above.
1231 * startingPointer is an optional pointer to the first place where dynamic
1232 * data will be stored. If you know the starting offset, you may pass it
1233 * here. Otherwise, pass NULL, and one will be inferred from the items.
1235 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1236 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1237 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1238 void *startingPointer)
1240 BOOL ret;
1242 TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1243 cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1245 if (pbEncoded[0] == ASN_SEQUENCE)
1247 DWORD dataLen;
1249 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1251 DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1252 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1254 cbEncoded -= 1 + lenBytes;
1255 if (cbEncoded < dataLen)
1257 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1258 cbEncoded);
1259 SetLastError(CRYPT_E_ASN1_CORRUPT);
1260 ret = FALSE;
1262 else
1263 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1264 cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1265 if (ret && cbDecoded != dataLen)
1267 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1268 cbDecoded);
1269 SetLastError(CRYPT_E_ASN1_CORRUPT);
1270 ret = FALSE;
1272 if (ret)
1274 DWORD i, bytesNeeded = 0, structSize = 0;
1276 for (i = 0; i < cItem; i++)
1278 bytesNeeded += items[i].size;
1279 structSize += items[i].minSize;
1281 if (!pvStructInfo)
1282 *pcbStructInfo = bytesNeeded;
1283 else if (*pcbStructInfo < bytesNeeded)
1285 SetLastError(ERROR_MORE_DATA);
1286 *pcbStructInfo = bytesNeeded;
1287 ret = FALSE;
1289 else
1291 BYTE *nextData;
1293 *pcbStructInfo = bytesNeeded;
1294 if (startingPointer)
1295 nextData = (BYTE *)startingPointer;
1296 else
1297 nextData = (BYTE *)pvStructInfo + structSize;
1298 memset(pvStructInfo, 0, structSize);
1299 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1300 ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1301 &cbDecoded);
1306 else
1308 SetLastError(CRYPT_E_ASN1_BADTAG);
1309 ret = FALSE;
1311 TRACE("returning %d (%08x)\n", ret, GetLastError());
1312 return ret;
1315 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1316 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1317 void *pvStructInfo, DWORD *pcbStructInfo)
1319 BOOL ret;
1321 TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1322 pvStructInfo, *pcbStructInfo);
1324 if (pbEncoded[0] == ASN_BITSTRING)
1326 DWORD bytesNeeded, dataLen;
1328 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1330 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1331 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1332 else
1333 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1334 if (!pvStructInfo)
1335 *pcbStructInfo = bytesNeeded;
1336 else if (*pcbStructInfo < bytesNeeded)
1338 *pcbStructInfo = bytesNeeded;
1339 SetLastError(ERROR_MORE_DATA);
1340 ret = FALSE;
1342 else
1344 CRYPT_BIT_BLOB *blob;
1346 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1347 blob->cbData = dataLen - 1;
1348 blob->cUnusedBits = *(pbEncoded + 1 +
1349 GET_LEN_BYTES(pbEncoded[1]));
1350 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1352 blob->pbData = (BYTE *)pbEncoded + 2 +
1353 GET_LEN_BYTES(pbEncoded[1]);
1355 else
1357 assert(blob->pbData);
1358 if (blob->cbData)
1360 BYTE mask = 0xff << blob->cUnusedBits;
1362 memcpy(blob->pbData, pbEncoded + 2 +
1363 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1364 blob->pbData[blob->cbData - 1] &= mask;
1370 else
1372 SetLastError(CRYPT_E_ASN1_BADTAG);
1373 ret = FALSE;
1375 TRACE("returning %d (%08x)\n", ret, GetLastError());
1376 return ret;
1379 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1380 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1381 void *pvStructInfo, DWORD *pcbStructInfo)
1383 BOOL ret = FALSE;
1384 DWORD dataLen;
1386 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1388 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1389 DWORD size;
1390 SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1392 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1393 pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1394 if (ret)
1396 if (!pvStructInfo)
1397 *pcbStructInfo = size + sizeof(PSPC_LINK);
1398 else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1400 *pcbStructInfo = size + sizeof(PSPC_LINK);
1401 SetLastError(ERROR_MORE_DATA);
1402 ret = FALSE;
1404 else
1406 *pcbStructInfo = size + sizeof(PSPC_LINK);
1407 /* Set imageData's pointer if necessary */
1408 if (size > sizeof(SPC_LINK))
1410 (*pLink)->u.pwszUrl =
1411 (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1413 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1414 lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1415 *pLink, pcbStructInfo);
1419 return ret;
1422 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1423 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1424 void *pvStructInfo, DWORD *pcbStructInfo)
1426 BOOL ret = FALSE;
1428 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1429 pvStructInfo, *pcbStructInfo);
1431 __TRY
1433 struct AsnDecodeSequenceItem items[] = {
1434 { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1435 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1436 offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1437 { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1438 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1439 offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1442 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1443 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1444 pvStructInfo, pcbStructInfo, NULL);
1446 __EXCEPT_PAGE_FAULT
1448 SetLastError(STATUS_ACCESS_VIOLATION);
1450 __ENDTRY
1451 TRACE("returning %d\n", ret);
1452 return ret;
1455 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1456 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1457 void *pvStructInfo, DWORD *pcbStructInfo)
1459 BOOL ret = TRUE;
1460 DWORD dataLen;
1462 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1463 pvStructInfo, *pcbStructInfo);
1465 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1467 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1468 DWORD bytesNeeded = sizeof(LPSTR);
1470 if (dataLen)
1472 /* The largest possible string for the first two components
1473 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1475 char firstTwo[6];
1476 const BYTE *ptr;
1478 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1479 pbEncoded[1 + lenBytes] / 40,
1480 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1481 * 40);
1482 bytesNeeded += strlen(firstTwo) + 1;
1483 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1484 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1486 /* large enough for ".4000000" */
1487 char str[9];
1488 int val = 0;
1490 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1491 (*ptr & 0x80))
1493 val <<= 7;
1494 val |= *ptr & 0x7f;
1495 ptr++;
1497 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1498 (*ptr & 0x80))
1500 SetLastError(CRYPT_E_ASN1_CORRUPT);
1501 ret = FALSE;
1503 else
1505 val <<= 7;
1506 val |= *ptr++;
1507 snprintf(str, sizeof(str), ".%d", val);
1508 bytesNeeded += strlen(str);
1512 if (!pvStructInfo)
1513 *pcbStructInfo = bytesNeeded;
1514 else if (*pcbStructInfo < bytesNeeded)
1516 *pcbStructInfo = bytesNeeded;
1517 SetLastError(ERROR_MORE_DATA);
1518 ret = FALSE;
1520 else
1522 if (dataLen)
1524 const BYTE *ptr;
1525 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1527 *pszObjId = 0;
1528 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1529 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1530 40) * 40);
1531 pszObjId += strlen(pszObjId);
1532 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1533 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1535 int val = 0;
1537 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1538 (*ptr & 0x80))
1540 val <<= 7;
1541 val |= *ptr & 0x7f;
1542 ptr++;
1544 val <<= 7;
1545 val |= *ptr++;
1546 sprintf(pszObjId, ".%d", val);
1547 pszObjId += strlen(pszObjId);
1550 else
1551 *(LPSTR *)pvStructInfo = NULL;
1552 *pcbStructInfo = bytesNeeded;
1555 return ret;
1558 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1559 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1560 void *pvStructInfo, DWORD *pcbStructInfo)
1562 BOOL ret = FALSE;
1564 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1565 pvStructInfo, *pcbStructInfo);
1567 if (!cbEncoded)
1568 SetLastError(CRYPT_E_ASN1_CORRUPT);
1569 else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1570 ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1571 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1572 else
1573 SetLastError(CRYPT_E_ASN1_BADTAG);
1574 return ret;
1577 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1578 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1579 void *pvStructInfo, DWORD *pcbStructInfo)
1581 BOOL ret = TRUE;
1582 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1584 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1585 pvStructInfo, *pcbStructInfo);
1587 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1588 bytesNeeded += cbEncoded;
1589 if (!pvStructInfo)
1590 *pcbStructInfo = bytesNeeded;
1591 else if (*pcbStructInfo < bytesNeeded)
1593 SetLastError(ERROR_MORE_DATA);
1594 *pcbStructInfo = bytesNeeded;
1595 ret = FALSE;
1597 else
1599 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1601 *pcbStructInfo = bytesNeeded;
1602 blob->cbData = cbEncoded;
1603 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1604 blob->pbData = (LPBYTE)pbEncoded;
1605 else
1607 assert(blob->pbData);
1608 memcpy(blob->pbData, pbEncoded, blob->cbData);
1611 return ret;
1614 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1615 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1616 void *pvStructInfo, DWORD *pcbStructInfo)
1618 CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1619 (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1620 struct AsnDecodeSequenceItem items[] = {
1621 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1622 CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1623 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1624 { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1625 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1626 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1629 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1630 pvStructInfo, *pcbStructInfo);
1632 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1633 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1634 pvStructInfo, pcbStructInfo,
1635 typeValue ? typeValue->pszObjId : NULL);
1638 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1639 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1640 void *pvStructInfo, DWORD *pcbStructInfo)
1642 CRYPT_ALGORITHM_IDENTIFIER *algo =
1643 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
1644 BOOL ret = TRUE;
1645 struct AsnDecodeSequenceItem items[] = {
1646 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
1647 CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
1648 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
1649 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
1650 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
1651 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
1654 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1655 pvStructInfo, *pcbStructInfo);
1657 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1658 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1659 pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
1660 if (ret && pvStructInfo)
1662 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
1663 debugstr_a(algo->pszObjId));
1665 return ret;
1668 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
1669 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1670 void *pvStructInfo, DWORD *pcbStructInfo)
1672 struct SPCDigest *digest =
1673 (struct SPCDigest *)pvStructInfo;
1674 struct AsnDecodeSequenceItem items[] = {
1675 { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
1676 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
1677 FALSE, TRUE,
1678 offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
1679 { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
1680 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
1681 FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
1684 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1685 pvStructInfo, *pcbStructInfo);
1687 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1688 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1689 pvStructInfo, pcbStructInfo,
1690 digest ? digest->DigestAlgorithm.pszObjId : NULL);
1693 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
1694 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1695 void *pvStructInfo, DWORD *pcbStructInfo)
1697 BOOL ret = FALSE;
1699 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1700 pvStructInfo, *pcbStructInfo);
1702 __TRY
1704 struct AsnDecodeSequenceItem items[] = {
1705 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
1706 CRYPT_AsnDecodeAttributeTypeValue,
1707 sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
1708 offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
1709 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
1710 CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
1711 FALSE, TRUE,
1712 offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
1715 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1716 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1717 pvStructInfo, pcbStructInfo, NULL);
1719 __EXCEPT_PAGE_FAULT
1721 SetLastError(STATUS_ACCESS_VIOLATION);
1723 __ENDTRY
1724 TRACE("returning %d\n", ret);
1725 return ret;
1728 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
1729 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1730 void *pvStructInfo, DWORD *pcbStructInfo)
1732 FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1733 pvStructInfo, *pcbStructInfo);
1734 return FALSE;