wintrust: Implement WVTAsn1CatMemberInfoEncode.
[wine/wine64.git] / dlls / wintrust / asn.c
blob364e7c2dc8827f7f37bd0cf22490669ddadb13b6
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 /* Gets the number of length bytes from the given (leading) length byte */
911 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
913 /* Helper function to get the encoded length of the data starting at pbEncoded,
914 * where pbEncoded[0] is the tag. If the data are too short to contain a
915 * length or if the length is too large for cbEncoded, sets an appropriate
916 * error code and returns FALSE.
918 static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
920 BOOL ret;
922 if (cbEncoded <= 1)
924 SetLastError(CRYPT_E_ASN1_CORRUPT);
925 ret = FALSE;
927 else if (pbEncoded[1] <= 0x7f)
929 if (pbEncoded[1] + 1 > cbEncoded)
931 SetLastError(CRYPT_E_ASN1_EOD);
932 ret = FALSE;
934 else
936 *len = pbEncoded[1];
937 ret = TRUE;
940 else if (pbEncoded[1] == 0x80)
942 FIXME("unimplemented for indefinite-length encoding\n");
943 SetLastError(CRYPT_E_ASN1_CORRUPT);
944 ret = FALSE;
946 else
948 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
950 if (lenLen > sizeof(DWORD) + 1)
952 SetLastError(CRYPT_E_ASN1_LARGE);
953 ret = FALSE;
955 else if (lenLen + 2 > cbEncoded)
957 SetLastError(CRYPT_E_ASN1_CORRUPT);
958 ret = FALSE;
960 else
962 DWORD out = 0;
964 pbEncoded += 2;
965 while (--lenLen)
967 out <<= 8;
968 out |= *pbEncoded++;
970 if (out + lenLen + 1 > cbEncoded)
972 SetLastError(CRYPT_E_ASN1_EOD);
973 ret = FALSE;
975 else
977 *len = out;
978 ret = TRUE;
982 return ret;
985 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
986 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
987 void *pvStructInfo, DWORD *pcbStructInfo)
989 BOOL ret;
990 DWORD bytesNeeded, dataLen;
992 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
993 pvStructInfo, *pcbStructInfo);
995 if (!cbEncoded)
997 SetLastError(CRYPT_E_ASN1_CORRUPT);
998 ret = FALSE;
1000 else if (pbEncoded[0] != ASN_OCTETSTRING)
1002 SetLastError(CRYPT_E_ASN1_BADTAG);
1003 ret = FALSE;
1005 else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1007 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1008 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1009 else
1010 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1011 if (!pvStructInfo)
1012 *pcbStructInfo = bytesNeeded;
1013 else if (*pcbStructInfo < bytesNeeded)
1015 SetLastError(ERROR_MORE_DATA);
1016 *pcbStructInfo = bytesNeeded;
1017 ret = FALSE;
1019 else
1021 CRYPT_DATA_BLOB *blob;
1022 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1024 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1025 blob->cbData = dataLen;
1026 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1027 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1028 else
1030 assert(blob->pbData);
1031 if (blob->cbData)
1032 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
1033 blob->cbData);
1037 return ret;
1040 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType,
1041 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1042 void *pvStructInfo, DWORD *pcbStructInfo)
1044 BOOL ret = FALSE;
1045 DWORD bytesNeeded = sizeof(SPC_LINK), dataLen;
1047 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1048 pvStructInfo, *pcbStructInfo);
1050 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1052 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1053 DWORD realDataLen;
1055 switch (pbEncoded[0])
1057 case ASN_CONTEXT:
1058 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
1059 if (!pvStructInfo)
1060 *pcbStructInfo = bytesNeeded;
1061 else if (*pcbStructInfo < bytesNeeded)
1063 *pcbStructInfo = bytesNeeded;
1064 SetLastError(ERROR_MORE_DATA);
1065 ret = FALSE;
1067 else
1069 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1070 DWORD i;
1072 link->dwLinkChoice = SPC_URL_LINK_CHOICE;
1073 for (i = 0; i < dataLen; i++)
1074 link->u.pwszUrl[i] =
1075 *(pbEncoded + 1 + lenBytes + i);
1076 link->u.pwszUrl[i] = '\0';
1077 TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl));
1079 break;
1080 case ASN_CONSTRUCTOR | ASN_CONTEXT | 1:
1082 CRYPT_DATA_BLOB classId;
1083 DWORD size = sizeof(classId);
1085 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1086 pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes,
1087 CRYPT_DECODE_NOCOPY_FLAG, &classId, &size)))
1089 if (classId.cbData != sizeof(SPC_UUID))
1091 SetLastError(CRYPT_E_BAD_ENCODE);
1092 ret = FALSE;
1094 else
1096 CRYPT_DATA_BLOB data;
1098 /* The tag length for the classId must be 1 since the
1099 * length is correct.
1101 size = sizeof(data);
1102 if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL,
1103 pbEncoded + 3 + lenBytes + classId.cbData,
1104 cbEncoded - 3 - lenBytes - classId.cbData,
1105 CRYPT_DECODE_NOCOPY_FLAG, &data, &size)))
1107 bytesNeeded += data.cbData;
1108 if (!pvStructInfo)
1109 *pcbStructInfo = bytesNeeded;
1110 else if (*pcbStructInfo < bytesNeeded)
1112 *pcbStructInfo = bytesNeeded;
1113 SetLastError(ERROR_MORE_DATA);
1114 ret = FALSE;
1116 else
1118 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1120 link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE;
1121 /* pwszFile pointer was set by caller, copy it
1122 * before overwriting it
1124 link->u.Moniker.SerializedData.pbData =
1125 (BYTE *)link->u.pwszFile;
1126 memcpy(link->u.Moniker.ClassId, classId.pbData,
1127 classId.cbData);
1128 memcpy(link->u.Moniker.SerializedData.pbData,
1129 data.pbData, data.cbData);
1130 link->u.Moniker.SerializedData.cbData = data.cbData;
1135 break;
1137 case ASN_CONSTRUCTOR | ASN_CONTEXT | 2:
1138 if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT)
1139 SetLastError(CRYPT_E_ASN1_BADTAG);
1140 else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen,
1141 &realDataLen)))
1143 BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]);
1145 bytesNeeded += realDataLen + sizeof(WCHAR);
1146 if (!pvStructInfo)
1147 *pcbStructInfo = bytesNeeded;
1148 else if (*pcbStructInfo < bytesNeeded)
1150 *pcbStructInfo = bytesNeeded;
1151 SetLastError(ERROR_MORE_DATA);
1152 ret = FALSE;
1154 else
1156 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1157 DWORD i;
1158 const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes;
1160 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1161 for (i = 0; i < dataLen / sizeof(WCHAR); i++)
1162 link->u.pwszFile[i] =
1163 hton16(*(WORD *)(ptr + i * sizeof(WCHAR)));
1164 link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0';
1165 TRACE("returning file %s\n", debugstr_w(link->u.pwszFile));
1168 else
1170 bytesNeeded += sizeof(WCHAR);
1171 if (!pvStructInfo)
1172 *pcbStructInfo = bytesNeeded;
1173 else if (*pcbStructInfo < bytesNeeded)
1175 *pcbStructInfo = bytesNeeded;
1176 SetLastError(ERROR_MORE_DATA);
1177 ret = FALSE;
1179 else
1181 PSPC_LINK link = (PSPC_LINK)pvStructInfo;
1183 link->dwLinkChoice = SPC_FILE_LINK_CHOICE;
1184 link->u.pwszFile[0] = '\0';
1185 ret = TRUE;
1188 break;
1189 default:
1190 SetLastError(CRYPT_E_ASN1_BADTAG);
1193 TRACE("returning %d\n", ret);
1194 return ret;
1197 BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType,
1198 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1199 void *pvStructInfo, DWORD *pcbStructInfo)
1201 BOOL ret = FALSE;
1203 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1204 pvStructInfo, *pcbStructInfo);
1206 __TRY
1208 DWORD bytesNeeded;
1210 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1211 lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded);
1212 if (ret)
1214 if (!pvStructInfo)
1215 *pcbStructInfo = bytesNeeded;
1216 else if (*pcbStructInfo < bytesNeeded)
1218 *pcbStructInfo = bytesNeeded;
1219 SetLastError(ERROR_MORE_DATA);
1220 ret = FALSE;
1222 else
1224 SPC_LINK *link = (SPC_LINK *)pvStructInfo;
1226 link->u.pwszFile =
1227 (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK));
1228 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1229 lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1230 pcbStructInfo);
1234 __EXCEPT_PAGE_FAULT
1236 SetLastError(STATUS_ACCESS_VIOLATION);
1238 __ENDTRY
1239 TRACE("returning %d\n", ret);
1240 return ret;
1243 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1244 DWORD, DWORD, void *, DWORD *);
1246 /* tag:
1247 * The expected tag of the item. If tag is 0, decodeFunc is called
1248 * regardless of the tag value seen.
1249 * offset:
1250 * A sequence is decoded into a struct. The offset member is the
1251 * offset of this item within that struct.
1252 * decodeFunc:
1253 * The decoder function to use. If this is NULL, then the member isn't
1254 * decoded, but minSize space is reserved for it.
1255 * minSize:
1256 * The minimum amount of space occupied after decoding. You must set this.
1257 * optional:
1258 * If true, and the tag doesn't match the expected tag for this item,
1259 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
1260 * filled with 0 for this member.
1261 * hasPointer, pointerOffset:
1262 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
1263 * the offset within the struct of the data pointer (or to the
1264 * first data pointer, if more than one exist).
1265 * size:
1266 * Used by CRYPT_AsnDecodeSequence, not for your use.
1268 struct AsnDecodeSequenceItem
1270 BYTE tag;
1271 DWORD offset;
1272 CryptDecodeObjectFunc decodeFunc;
1273 DWORD minSize;
1274 BOOL optional;
1275 BOOL hasPointer;
1276 DWORD pointerOffset;
1277 DWORD size;
1280 /* Decodes the items in a sequence, where the items are described in items,
1281 * the encoded data are in pbEncoded with length cbEncoded. Decodes into
1282 * pvStructInfo. nextData is a pointer to the memory location at which the
1283 * first decoded item with a dynamic pointer should point.
1284 * Upon decoding, *cbDecoded is the total number of bytes decoded.
1286 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
1287 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1288 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData,
1289 DWORD *cbDecoded)
1291 BOOL ret;
1292 DWORD i, decoded = 0;
1293 const BYTE *ptr = pbEncoded;
1295 TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
1296 cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
1298 for (i = 0, ret = TRUE; ret && i < cItem; i++)
1300 if (cbEncoded - (ptr - pbEncoded) != 0)
1302 DWORD nextItemLen;
1304 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1305 &nextItemLen)))
1307 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
1309 if (ptr[0] == items[i].tag || !items[i].tag)
1311 if (nextData && pvStructInfo && items[i].hasPointer)
1313 TRACE("Setting next pointer to %p\n",
1314 nextData);
1315 *(BYTE **)((BYTE *)pvStructInfo +
1316 items[i].pointerOffset) = nextData;
1318 if (items[i].decodeFunc)
1320 if (pvStructInfo)
1321 TRACE("decoding item %d\n", i);
1322 else
1323 TRACE("sizing item %d\n", i);
1324 ret = items[i].decodeFunc(dwCertEncodingType,
1325 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
1326 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1327 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
1328 : NULL, &items[i].size);
1329 if (ret)
1331 /* Account for alignment padding */
1332 if (items[i].size % sizeof(DWORD))
1333 items[i].size += sizeof(DWORD) -
1334 items[i].size % sizeof(DWORD);
1335 TRACE("item %d size: %d\n", i, items[i].size);
1336 if (nextData && items[i].hasPointer &&
1337 items[i].size > items[i].minSize)
1338 nextData += items[i].size - items[i].minSize;
1339 ptr += 1 + nextItemLenBytes + nextItemLen;
1340 decoded += 1 + nextItemLenBytes + nextItemLen;
1341 TRACE("item %d: decoded %d bytes\n", i,
1342 1 + nextItemLenBytes + nextItemLen);
1344 else if (items[i].optional &&
1345 GetLastError() == CRYPT_E_ASN1_BADTAG)
1347 TRACE("skipping optional item %d\n", i);
1348 items[i].size = items[i].minSize;
1349 SetLastError(NOERROR);
1350 ret = TRUE;
1352 else
1353 TRACE("item %d failed: %08x\n", i,
1354 GetLastError());
1356 else
1358 TRACE("item %d: decoded %d bytes\n", i,
1359 1 + nextItemLenBytes + nextItemLen);
1360 ptr += 1 + nextItemLenBytes + nextItemLen;
1361 decoded += 1 + nextItemLenBytes + nextItemLen;
1362 items[i].size = items[i].minSize;
1365 else if (items[i].optional)
1367 TRACE("skipping optional item %d\n", i);
1368 items[i].size = items[i].minSize;
1370 else
1372 TRACE("item %d: tag %02x doesn't match expected %02x\n",
1373 i, ptr[0], items[i].tag);
1374 SetLastError(CRYPT_E_ASN1_BADTAG);
1375 ret = FALSE;
1379 else if (items[i].optional)
1381 TRACE("missing optional item %d, skipping\n", i);
1382 items[i].size = items[i].minSize;
1384 else
1386 TRACE("not enough bytes for item %d, failing\n", i);
1387 SetLastError(CRYPT_E_ASN1_CORRUPT);
1388 ret = FALSE;
1391 if (ret)
1392 *cbDecoded = decoded;
1393 TRACE("returning %d\n", ret);
1394 return ret;
1397 /* This decodes an arbitrary sequence into a contiguous block of memory
1398 * (basically, a struct.) Each element being decoded is described by a struct
1399 * AsnDecodeSequenceItem, see above.
1400 * startingPointer is an optional pointer to the first place where dynamic
1401 * data will be stored. If you know the starting offset, you may pass it
1402 * here. Otherwise, pass NULL, and one will be inferred from the items.
1404 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
1405 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
1406 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
1407 void *startingPointer)
1409 BOOL ret;
1411 TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded,
1412 cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer);
1414 if (pbEncoded[0] == ASN_SEQUENCE)
1416 DWORD dataLen;
1418 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1420 DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
1421 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1423 cbEncoded -= 1 + lenBytes;
1424 if (cbEncoded < dataLen)
1426 TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
1427 cbEncoded);
1428 SetLastError(CRYPT_E_ASN1_CORRUPT);
1429 ret = FALSE;
1431 else
1432 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr,
1433 cbEncoded, dwFlags, NULL, NULL, &cbDecoded);
1434 if (ret && cbDecoded != dataLen)
1436 TRACE("expected %d decoded, got %d, failing\n", dataLen,
1437 cbDecoded);
1438 SetLastError(CRYPT_E_ASN1_CORRUPT);
1439 ret = FALSE;
1441 if (ret)
1443 DWORD i, bytesNeeded = 0, structSize = 0;
1445 for (i = 0; i < cItem; i++)
1447 bytesNeeded += items[i].size;
1448 structSize += items[i].minSize;
1450 if (!pvStructInfo)
1451 *pcbStructInfo = bytesNeeded;
1452 else if (*pcbStructInfo < bytesNeeded)
1454 SetLastError(ERROR_MORE_DATA);
1455 *pcbStructInfo = bytesNeeded;
1456 ret = FALSE;
1458 else
1460 BYTE *nextData;
1462 *pcbStructInfo = bytesNeeded;
1463 if (startingPointer)
1464 nextData = (BYTE *)startingPointer;
1465 else
1466 nextData = (BYTE *)pvStructInfo + structSize;
1467 memset(pvStructInfo, 0, structSize);
1468 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
1469 ptr, cbEncoded, dwFlags, pvStructInfo, nextData,
1470 &cbDecoded);
1475 else
1477 SetLastError(CRYPT_E_ASN1_BADTAG);
1478 ret = FALSE;
1480 TRACE("returning %d (%08x)\n", ret, GetLastError());
1481 return ret;
1484 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
1485 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1486 void *pvStructInfo, DWORD *pcbStructInfo)
1488 BOOL ret;
1490 TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
1491 pvStructInfo, *pcbStructInfo);
1493 if (pbEncoded[0] == ASN_BITSTRING)
1495 DWORD bytesNeeded, dataLen;
1497 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1499 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1500 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1501 else
1502 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1503 if (!pvStructInfo)
1504 *pcbStructInfo = bytesNeeded;
1505 else if (*pcbStructInfo < bytesNeeded)
1507 *pcbStructInfo = bytesNeeded;
1508 SetLastError(ERROR_MORE_DATA);
1509 ret = FALSE;
1511 else
1513 CRYPT_BIT_BLOB *blob;
1515 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1516 blob->cbData = dataLen - 1;
1517 blob->cUnusedBits = *(pbEncoded + 1 +
1518 GET_LEN_BYTES(pbEncoded[1]));
1519 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1521 blob->pbData = (BYTE *)pbEncoded + 2 +
1522 GET_LEN_BYTES(pbEncoded[1]);
1524 else
1526 assert(blob->pbData);
1527 if (blob->cbData)
1529 BYTE mask = 0xff << blob->cUnusedBits;
1531 memcpy(blob->pbData, pbEncoded + 2 +
1532 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
1533 blob->pbData[blob->cbData - 1] &= mask;
1539 else
1541 SetLastError(CRYPT_E_ASN1_BADTAG);
1542 ret = FALSE;
1544 TRACE("returning %d (%08x)\n", ret, GetLastError());
1545 return ret;
1548 static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType,
1549 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1550 void *pvStructInfo, DWORD *pcbStructInfo)
1552 BOOL ret = FALSE;
1553 DWORD dataLen;
1555 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1557 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1558 DWORD size;
1559 SPC_LINK **pLink = (SPC_LINK **)pvStructInfo;
1561 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType,
1562 pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size);
1563 if (ret)
1565 if (!pvStructInfo)
1566 *pcbStructInfo = size + sizeof(PSPC_LINK);
1567 else if (*pcbStructInfo < size + sizeof(PSPC_LINK))
1569 *pcbStructInfo = size + sizeof(PSPC_LINK);
1570 SetLastError(ERROR_MORE_DATA);
1571 ret = FALSE;
1573 else
1575 *pcbStructInfo = size + sizeof(PSPC_LINK);
1576 /* Set imageData's pointer if necessary */
1577 if (size > sizeof(SPC_LINK))
1579 (*pLink)->u.pwszUrl =
1580 (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK));
1582 ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType,
1583 lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
1584 *pLink, pcbStructInfo);
1588 return ret;
1591 BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
1592 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1593 void *pvStructInfo, DWORD *pcbStructInfo)
1595 BOOL ret = FALSE;
1597 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1598 pvStructInfo, *pcbStructInfo);
1600 __TRY
1602 struct AsnDecodeSequenceItem items[] = {
1603 { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags),
1604 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
1605 offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 },
1606 { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile),
1607 CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE,
1608 offsetof(SPC_PE_IMAGE_DATA, pFile), 0 },
1611 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1612 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1613 pvStructInfo, pcbStructInfo, NULL);
1615 __EXCEPT_PAGE_FAULT
1617 SetLastError(STATUS_ACCESS_VIOLATION);
1619 __ENDTRY
1620 TRACE("returning %d\n", ret);
1621 return ret;
1624 static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType,
1625 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1626 void *pvStructInfo, DWORD *pcbStructInfo)
1628 BOOL ret = TRUE;
1629 DWORD dataLen;
1631 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1632 pvStructInfo, *pcbStructInfo);
1634 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1636 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1637 DWORD bytesNeeded = sizeof(LPSTR);
1639 if (dataLen)
1641 /* The largest possible string for the first two components
1642 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1644 char firstTwo[6];
1645 const BYTE *ptr;
1647 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1648 pbEncoded[1 + lenBytes] / 40,
1649 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1650 * 40);
1651 bytesNeeded += strlen(firstTwo) + 1;
1652 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1653 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1655 /* large enough for ".4000000" */
1656 char str[9];
1657 int val = 0;
1659 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1660 (*ptr & 0x80))
1662 val <<= 7;
1663 val |= *ptr & 0x7f;
1664 ptr++;
1666 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1667 (*ptr & 0x80))
1669 SetLastError(CRYPT_E_ASN1_CORRUPT);
1670 ret = FALSE;
1672 else
1674 val <<= 7;
1675 val |= *ptr++;
1676 snprintf(str, sizeof(str), ".%d", val);
1677 bytesNeeded += strlen(str);
1681 if (!pvStructInfo)
1682 *pcbStructInfo = bytesNeeded;
1683 else if (*pcbStructInfo < bytesNeeded)
1685 *pcbStructInfo = bytesNeeded;
1686 SetLastError(ERROR_MORE_DATA);
1687 ret = FALSE;
1689 else
1691 if (dataLen)
1693 const BYTE *ptr;
1694 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
1696 *pszObjId = 0;
1697 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1698 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
1699 40) * 40);
1700 pszObjId += strlen(pszObjId);
1701 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1702 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1704 int val = 0;
1706 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1707 (*ptr & 0x80))
1709 val <<= 7;
1710 val |= *ptr & 0x7f;
1711 ptr++;
1713 val <<= 7;
1714 val |= *ptr++;
1715 sprintf(pszObjId, ".%d", val);
1716 pszObjId += strlen(pszObjId);
1719 else
1720 *(LPSTR *)pvStructInfo = NULL;
1721 *pcbStructInfo = bytesNeeded;
1724 return ret;
1727 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1728 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1729 void *pvStructInfo, DWORD *pcbStructInfo)
1731 BOOL ret = FALSE;
1733 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1734 pvStructInfo, *pcbStructInfo);
1736 if (!cbEncoded)
1737 SetLastError(CRYPT_E_ASN1_CORRUPT);
1738 else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1739 ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType,
1740 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1741 else
1742 SetLastError(CRYPT_E_ASN1_BADTAG);
1743 return ret;
1746 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
1747 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1748 void *pvStructInfo, DWORD *pcbStructInfo)
1750 BOOL ret = TRUE;
1751 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
1753 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1754 pvStructInfo, *pcbStructInfo);
1756 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1757 bytesNeeded += cbEncoded;
1758 if (!pvStructInfo)
1759 *pcbStructInfo = bytesNeeded;
1760 else if (*pcbStructInfo < bytesNeeded)
1762 SetLastError(ERROR_MORE_DATA);
1763 *pcbStructInfo = bytesNeeded;
1764 ret = FALSE;
1766 else
1768 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
1770 *pcbStructInfo = bytesNeeded;
1771 blob->cbData = cbEncoded;
1772 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1773 blob->pbData = (LPBYTE)pbEncoded;
1774 else
1776 assert(blob->pbData);
1777 memcpy(blob->pbData, pbEncoded, blob->cbData);
1780 return ret;
1783 static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType,
1784 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1785 void *pvStructInfo, DWORD *pcbStructInfo)
1787 CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue =
1788 (CRYPT_ATTRIBUTE_TYPE_VALUE *)pvStructInfo;
1789 struct AsnDecodeSequenceItem items[] = {
1790 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId),
1791 CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE,
1792 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 },
1793 { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value),
1794 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE,
1795 offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 },
1798 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1799 pvStructInfo, *pcbStructInfo);
1801 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1802 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1803 pvStructInfo, pcbStructInfo,
1804 typeValue ? typeValue->pszObjId : NULL);
1807 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
1808 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1809 void *pvStructInfo, DWORD *pcbStructInfo)
1811 CRYPT_ALGORITHM_IDENTIFIER *algo =
1812 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
1813 BOOL ret = TRUE;
1814 struct AsnDecodeSequenceItem items[] = {
1815 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
1816 CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
1817 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
1818 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
1819 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
1820 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
1823 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1824 pvStructInfo, *pcbStructInfo);
1826 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1827 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1828 pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
1829 if (ret && pvStructInfo)
1831 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
1832 debugstr_a(algo->pszObjId));
1834 return ret;
1837 static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType,
1838 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1839 void *pvStructInfo, DWORD *pcbStructInfo)
1841 struct SPCDigest *digest =
1842 (struct SPCDigest *)pvStructInfo;
1843 struct AsnDecodeSequenceItem items[] = {
1844 { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm),
1845 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
1846 FALSE, TRUE,
1847 offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 },
1848 { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest),
1849 CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB),
1850 FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 },
1853 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1854 pvStructInfo, *pcbStructInfo);
1856 return CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1857 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1858 pvStructInfo, pcbStructInfo,
1859 digest ? digest->DigestAlgorithm.pszObjId : NULL);
1862 BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType,
1863 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1864 void *pvStructInfo, DWORD *pcbStructInfo)
1866 BOOL ret = FALSE;
1868 TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1869 pvStructInfo, *pcbStructInfo);
1871 __TRY
1873 struct AsnDecodeSequenceItem items[] = {
1874 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data),
1875 CRYPT_AsnDecodeAttributeTypeValue,
1876 sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE,
1877 offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 },
1878 { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm),
1879 CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest),
1880 FALSE, TRUE,
1881 offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 },
1884 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
1885 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
1886 pvStructInfo, pcbStructInfo, NULL);
1888 __EXCEPT_PAGE_FAULT
1890 SetLastError(STATUS_ACCESS_VIOLATION);
1892 __ENDTRY
1893 TRACE("returning %d\n", ret);
1894 return ret;
1897 BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType,
1898 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1899 void *pvStructInfo, DWORD *pcbStructInfo)
1901 FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
1902 pvStructInfo, *pcbStructInfo);
1903 return FALSE;