|  | /* wintrust asn functions | 
|  | * | 
|  | * Copyright 2007 Juan Lang | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  | #include <assert.h> | 
|  | #define NONAMELESSUNION | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "wincrypt.h" | 
|  | #include "wintrust.h" | 
|  | #include "snmp.h" | 
|  | #include "winternl.h" | 
|  | #include "wine/debug.h" | 
|  | #include "wine/exception.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(cryptasn); | 
|  |  | 
|  | #ifdef WORDS_BIGENDIAN | 
|  |  | 
|  | #define hton16(x) (x) | 
|  | #define n16toh(x) (x) | 
|  |  | 
|  | #else | 
|  |  | 
|  | #define hton16(x) RtlUshortByteSwap(x) | 
|  | #define n16toh(x) RtlUshortByteSwap(x) | 
|  |  | 
|  | #endif | 
|  |  | 
|  | #define ASN_BOOL            (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01) | 
|  | #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03) | 
|  | #define ASN_BMPSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e) | 
|  |  | 
|  | static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded) | 
|  | { | 
|  | DWORD bytesNeeded, significantBytes = 0; | 
|  |  | 
|  | if (len <= 0x7f) | 
|  | bytesNeeded = 1; | 
|  | else | 
|  | { | 
|  | DWORD temp; | 
|  |  | 
|  | for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000); | 
|  | temp <<= 8, significantBytes--) | 
|  | ; | 
|  | bytesNeeded = significantBytes + 1; | 
|  | } | 
|  | if (!pbEncoded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | return TRUE; | 
|  | } | 
|  | if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | return FALSE; | 
|  | } | 
|  | if (len <= 0x7f) | 
|  | *pbEncoded = (BYTE)len; | 
|  | else | 
|  | { | 
|  | DWORD i; | 
|  |  | 
|  | *pbEncoded++ = significantBytes | 0x80; | 
|  | for (i = 0; i < significantBytes; i++) | 
|  | { | 
|  | *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff); | 
|  | len >>= 8; | 
|  | } | 
|  | } | 
|  | *pcbEncoded = bytesNeeded; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = TRUE; | 
|  | const CRYPT_DATA_BLOB *blob = pvStructInfo; | 
|  | DWORD bytesNeeded, lenBytes; | 
|  |  | 
|  | TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded, | 
|  | *pcbEncoded); | 
|  |  | 
|  | CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + lenBytes + blob->cbData; | 
|  | if (!pbEncoded) | 
|  | *pcbEncoded = bytesNeeded; | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pbEncoded++ = ASN_OCTETSTRING; | 
|  | CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | if (blob->cbData) | 
|  | memcpy(pbEncoded, blob->pbData, blob->cbData); | 
|  | } | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, | 
|  | pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const SPC_LINK *link = pvStructInfo; | 
|  | DWORD bytesNeeded, lenBytes; | 
|  |  | 
|  | switch (link->dwLinkChoice) | 
|  | { | 
|  | case SPC_FILE_LINK_CHOICE: | 
|  | { | 
|  | DWORD fileNameLen, fileNameLenBytes; | 
|  | LPWSTR ptr; | 
|  |  | 
|  | fileNameLen = link->u.pwszFile ? | 
|  | lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0; | 
|  | CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes); | 
|  | CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL, | 
|  | &lenBytes); | 
|  | bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen; | 
|  | if (!pbEncoded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | ret = TRUE; | 
|  | } | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | *pcbEncoded = bytesNeeded; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2; | 
|  | CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded, | 
|  | &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | *pbEncoded++ = ASN_CONTEXT; | 
|  | CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes); | 
|  | pbEncoded += fileNameLenBytes; | 
|  | for (ptr = link->u.pwszFile; ptr && *ptr; ptr++) | 
|  | { | 
|  | *(WCHAR *)pbEncoded = hton16(*ptr); | 
|  | pbEncoded += sizeof(WCHAR); | 
|  | } | 
|  | ret = TRUE; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case SPC_MONIKER_LINK_CHOICE: | 
|  | { | 
|  | DWORD classIdLenBytes, dataLenBytes, dataLen; | 
|  | CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId), | 
|  | (BYTE *)link->u.Moniker.ClassId }; | 
|  |  | 
|  | CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes); | 
|  | CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL, | 
|  | &dataLenBytes); | 
|  | dataLen = 2 + classIdLenBytes + classId.cbData + | 
|  | dataLenBytes + link->u.Moniker.SerializedData.cbData; | 
|  | CRYPT_EncodeLen(dataLen, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + dataLen + lenBytes; | 
|  | if (!pbEncoded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | ret = TRUE; | 
|  | } | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | *pcbEncoded = bytesNeeded; | 
|  | } | 
|  | else | 
|  | { | 
|  | DWORD size; | 
|  |  | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1; | 
|  | CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | size = 1 + classIdLenBytes + classId.cbData; | 
|  | CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId, | 
|  | pbEncoded, &size); | 
|  | pbEncoded += size; | 
|  | size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData; | 
|  | CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, | 
|  | &link->u.Moniker.SerializedData, pbEncoded, &size); | 
|  | pbEncoded += size; | 
|  | ret = TRUE; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case SPC_URL_LINK_CHOICE: | 
|  | { | 
|  | LPWSTR ptr; | 
|  | DWORD urlLen; | 
|  |  | 
|  | /* Check for invalid characters in URL */ | 
|  | ret = TRUE; | 
|  | urlLen = 0; | 
|  | for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++) | 
|  | if (*ptr > 0x7f) | 
|  | { | 
|  | *pcbEncoded = 0; | 
|  | SetLastError(CRYPT_E_INVALID_IA5_STRING); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | urlLen++; | 
|  | if (ret) | 
|  | { | 
|  | CRYPT_EncodeLen(urlLen, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + lenBytes + urlLen; | 
|  | if (!pbEncoded) | 
|  | *pcbEncoded = bytesNeeded; | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | *pcbEncoded = bytesNeeded; | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_CONTEXT; | 
|  | CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++) | 
|  | *pbEncoded++ = (BYTE)*ptr; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | SetLastError(E_INVALIDARG); | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *, | 
|  | BYTE *, DWORD *); | 
|  |  | 
|  | struct AsnEncodeSequenceItem | 
|  | { | 
|  | const void           *pvStructInfo; | 
|  | CryptEncodeObjectFunc encodeFunc; | 
|  | DWORD                 size; /* used during encoding, not for your use */ | 
|  | }; | 
|  |  | 
|  | static BOOL CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType, | 
|  | struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret; | 
|  | DWORD i, dataLen = 0; | 
|  |  | 
|  | TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded); | 
|  | for (i = 0, ret = TRUE; ret && i < cItem; i++) | 
|  | { | 
|  | ret = items[i].encodeFunc(dwCertEncodingType, NULL, | 
|  | items[i].pvStructInfo, NULL, &items[i].size); | 
|  | /* Some functions propagate their errors through the size */ | 
|  | if (!ret) | 
|  | *pcbEncoded = items[i].size; | 
|  | dataLen += items[i].size; | 
|  | } | 
|  | if (ret) | 
|  | { | 
|  | DWORD lenBytes, bytesNeeded; | 
|  |  | 
|  | CRYPT_EncodeLen(dataLen, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + lenBytes + dataLen; | 
|  | if (!pbEncoded) | 
|  | *pcbEncoded = bytesNeeded; | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_SEQUENCE; | 
|  | CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | for (i = 0; ret && i < cItem; i++) | 
|  | { | 
|  | ret = items[i].encodeFunc(dwCertEncodingType, NULL, | 
|  | items[i].pvStructInfo, pbEncoded, &items[i].size); | 
|  | /* Some functions propagate their errors through the size */ | 
|  | if (!ret) | 
|  | *pcbEncoded = items[i].size; | 
|  | pbEncoded += items[i].size; | 
|  | } | 
|  | } | 
|  | } | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const CRYPT_BIT_BLOB *blob = pvStructInfo; | 
|  | DWORD bytesNeeded, lenBytes, dataBytes; | 
|  | BYTE unusedBits; | 
|  |  | 
|  | /* yep, MS allows cUnusedBits to be >= 8 */ | 
|  | if (!blob->cUnusedBits) | 
|  | { | 
|  | dataBytes = blob->cbData; | 
|  | unusedBits = 0; | 
|  | } | 
|  | else if (blob->cbData * 8 > blob->cUnusedBits) | 
|  | { | 
|  | dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1; | 
|  | unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 : | 
|  | blob->cUnusedBits; | 
|  | } | 
|  | else | 
|  | { | 
|  | dataBytes = 0; | 
|  | unusedBits = 0; | 
|  | } | 
|  | CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + lenBytes + dataBytes + 1; | 
|  | if (!pbEncoded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | ret = TRUE; | 
|  | } | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | } | 
|  | else | 
|  | { | 
|  | ret = TRUE; | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_BITSTRING; | 
|  | CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | *pbEncoded++ = unusedBits; | 
|  | if (dataBytes) | 
|  | { | 
|  | BYTE mask = 0xff << unusedBits; | 
|  |  | 
|  | if (dataBytes > 1) | 
|  | { | 
|  | memcpy(pbEncoded, blob->pbData, dataBytes - 1); | 
|  | pbEncoded += dataBytes - 1; | 
|  | } | 
|  | *pbEncoded = *(blob->pbData + dataBytes - 1) & mask; | 
|  | } | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | struct AsnConstructedItem | 
|  | { | 
|  | BYTE                  tag; | 
|  | const void           *pvStructInfo; | 
|  | CryptEncodeObjectFunc encodeFunc; | 
|  | }; | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret; | 
|  | const struct AsnConstructedItem *item = pvStructInfo; | 
|  | DWORD len; | 
|  |  | 
|  | if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType, | 
|  | item->pvStructInfo, NULL, &len))) | 
|  | { | 
|  | DWORD dataLen, bytesNeeded; | 
|  |  | 
|  | CRYPT_EncodeLen(len, NULL, &dataLen); | 
|  | bytesNeeded = 1 + dataLen + len; | 
|  | if (!pbEncoded) | 
|  | *pcbEncoded = bytesNeeded; | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag; | 
|  | CRYPT_EncodeLen(len, pbEncoded, &dataLen); | 
|  | pbEncoded += dataLen; | 
|  | ret = item->encodeFunc(dwCertEncodingType, lpszStructType, | 
|  | item->pvStructInfo, pbEncoded, &len); | 
|  | if (!ret) | 
|  | { | 
|  | /* Some functions propagate their errors through the size */ | 
|  | *pcbEncoded = len; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Some functions propagate their errors through the size */ | 
|  | *pcbEncoded = len; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | const SPC_PE_IMAGE_DATA *imageData = pvStructInfo; | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, | 
|  | pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnEncodeSequenceItem items[2] = { | 
|  | { 0 } | 
|  | }; | 
|  | struct AsnConstructedItem constructed = { 0, imageData->pFile, | 
|  | WVTAsn1SpcLinkEncode }; | 
|  | DWORD cItem = 0; | 
|  |  | 
|  | if (imageData->Flags.cbData) | 
|  | { | 
|  | items[cItem].pvStructInfo = &imageData->Flags; | 
|  | items[cItem].encodeFunc = CRYPT_AsnEncodeBits; | 
|  | cItem++; | 
|  | } | 
|  | if (imageData->pFile) | 
|  | { | 
|  | items[cItem].pvStructInfo = &constructed; | 
|  | items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; | 
|  | cItem++; | 
|  | } | 
|  |  | 
|  | ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, | 
|  | pbEncoded, pcbEncoded); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | LPCSTR pszObjId = pvStructInfo; | 
|  | DWORD bytesNeeded = 0, lenBytes; | 
|  | BOOL ret = TRUE; | 
|  | int firstPos = 0; | 
|  | BYTE firstByte = 0; | 
|  |  | 
|  | TRACE("%s\n", debugstr_a(pszObjId)); | 
|  |  | 
|  | if (pszObjId) | 
|  | { | 
|  | const char *ptr; | 
|  | int val1, val2; | 
|  |  | 
|  | if (sscanf(pszObjId, "%d.%d%n", &val1, &val2, &firstPos) != 2) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_ERROR); | 
|  | return FALSE; | 
|  | } | 
|  | bytesNeeded++; | 
|  | firstByte = val1 * 40 + val2; | 
|  | ptr = pszObjId + firstPos; | 
|  | if (*ptr == '.') | 
|  | { | 
|  | ptr++; | 
|  | firstPos++; | 
|  | } | 
|  | while (ret && *ptr) | 
|  | { | 
|  | int pos; | 
|  |  | 
|  | /* note I assume each component is at most 32-bits long in base 2 */ | 
|  | if (sscanf(ptr, "%d%n", &val1, &pos) == 1) | 
|  | { | 
|  | if (val1 >= 0x10000000) | 
|  | bytesNeeded += 5; | 
|  | else if (val1 >= 0x200000) | 
|  | bytesNeeded += 4; | 
|  | else if (val1 >= 0x4000) | 
|  | bytesNeeded += 3; | 
|  | else if (val1 >= 0x80) | 
|  | bytesNeeded += 2; | 
|  | else | 
|  | bytesNeeded += 1; | 
|  | ptr += pos; | 
|  | if (*ptr == '.') | 
|  | ptr++; | 
|  | } | 
|  | else | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_ERROR); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  | CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes); | 
|  | } | 
|  | else | 
|  | lenBytes = 1; | 
|  | bytesNeeded += 1 + lenBytes; | 
|  | if (pbEncoded) | 
|  | { | 
|  | if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pbEncoded++ = ASN_OBJECTIDENTIFIER; | 
|  | CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | if (pszObjId) | 
|  | { | 
|  | const char *ptr; | 
|  | int val, pos; | 
|  |  | 
|  | *pbEncoded++ = firstByte; | 
|  | ptr = pszObjId + firstPos; | 
|  | while (ret && *ptr) | 
|  | { | 
|  | sscanf(ptr, "%d%n", &val, &pos); | 
|  | { | 
|  | unsigned char outBytes[5]; | 
|  | int numBytes, i; | 
|  |  | 
|  | if (val >= 0x10000000) | 
|  | numBytes = 5; | 
|  | else if (val >= 0x200000) | 
|  | numBytes = 4; | 
|  | else if (val >= 0x4000) | 
|  | numBytes = 3; | 
|  | else if (val >= 0x80) | 
|  | numBytes = 2; | 
|  | else | 
|  | numBytes = 1; | 
|  | for (i = numBytes; i > 0; i--) | 
|  | { | 
|  | outBytes[i - 1] = val & 0x7f; | 
|  | val >>= 7; | 
|  | } | 
|  | for (i = 0; i < numBytes - 1; i++) | 
|  | *pbEncoded++ = outBytes[i] | 0x80; | 
|  | *pbEncoded++ = outBytes[i]; | 
|  | ptr += pos; | 
|  | if (*ptr == '.') | 
|  | ptr++; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | *pcbEncoded = bytesNeeded; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | const CRYPT_DER_BLOB *blob = pvStructInfo; | 
|  | BOOL ret = TRUE; | 
|  |  | 
|  | if (!pbEncoded) | 
|  | *pcbEncoded = blob->cbData; | 
|  | else if (*pcbEncoded < blob->cbData) | 
|  | { | 
|  | *pcbEncoded = blob->cbData; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (blob->cbData) | 
|  | memcpy(pbEncoded, blob->pbData, blob->cbData); | 
|  | *pcbEncoded = blob->cbData; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams( | 
|  | DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, | 
|  | BYTE *pbEncoded, DWORD *pcbEncoded) | 
|  | { | 
|  | const CRYPT_ALGORITHM_IDENTIFIER *algo = pvStructInfo; | 
|  | static const BYTE asn1Null[] = { ASN_NULL, 0 }; | 
|  | static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null), | 
|  | (LPBYTE)asn1Null }; | 
|  | BOOL ret; | 
|  | struct AsnEncodeSequenceItem items[2] = { | 
|  | { algo->pszObjId, CRYPT_AsnEncodeOid, 0 }, | 
|  | { NULL,           CRYPT_CopyEncodedBlob, 0 }, | 
|  | }; | 
|  |  | 
|  | if (algo->Parameters.cbData) | 
|  | items[1].pvStructInfo = &algo->Parameters; | 
|  | else | 
|  | items[1].pvStructInfo = &nullBlob; | 
|  | ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeAttributeTypeValue(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | const CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue = pvStructInfo; | 
|  | struct AsnEncodeSequenceItem items[] = { | 
|  | { &typeValue->pszObjId, CRYPT_AsnEncodeOid, 0 }, | 
|  | { &typeValue->Value,    CRYPT_CopyEncodedBlob, 0 }, | 
|  | }; | 
|  |  | 
|  | return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | } | 
|  |  | 
|  | struct SPCDigest | 
|  | { | 
|  | CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm; | 
|  | CRYPT_HASH_BLOB            Digest; | 
|  | }; | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeSPCDigest(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | const struct SPCDigest *digest = pvStructInfo; | 
|  | struct AsnEncodeSequenceItem items[] = { | 
|  | { &digest->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams, 0 }, | 
|  | { &digest->Digest,          CRYPT_CopyEncodedBlob, 0 }, | 
|  | }; | 
|  |  | 
|  | return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcIndirectDataContentEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const SPC_INDIRECT_DATA_CONTENT *data = pvStructInfo; | 
|  | struct AsnEncodeSequenceItem items[] = { | 
|  | { &data->Data,            CRYPT_AsnEncodeAttributeTypeValue, 0 }, | 
|  | { &data->DigestAlgorithm, CRYPT_AsnEncodeSPCDigest, 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeBMPString(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = TRUE; | 
|  | LPCWSTR str = pvStructInfo; | 
|  | DWORD bytesNeeded, lenBytes, strLen; | 
|  |  | 
|  | if (str) | 
|  | strLen = lstrlenW(str); | 
|  | else | 
|  | strLen = 0; | 
|  | CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + lenBytes + strLen * 2; | 
|  | if (!pbEncoded) | 
|  | *pcbEncoded = bytesNeeded; | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | DWORD i; | 
|  |  | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_BMPSTRING; | 
|  | CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | for (i = 0; i < strLen; i++) | 
|  | { | 
|  | *pbEncoded++ = (str[i] & 0xff00) >> 8; | 
|  | *pbEncoded++ = str[i] & 0x00ff; | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | struct AsnEncodeTagSwappedItem | 
|  | { | 
|  | BYTE                  tag; | 
|  | const void           *pvStructInfo; | 
|  | CryptEncodeObjectFunc encodeFunc; | 
|  | }; | 
|  |  | 
|  | /* Sort of a wacky hack, it encodes something using the struct | 
|  | * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag | 
|  | * given in the struct AsnEncodeTagSwappedItem. | 
|  | */ | 
|  | static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret; | 
|  | const struct AsnEncodeTagSwappedItem *item = pvStructInfo; | 
|  |  | 
|  | ret = item->encodeFunc(dwCertEncodingType, lpszStructType, | 
|  | item->pvStructInfo, pbEncoded, pcbEncoded); | 
|  | if (ret && pbEncoded) | 
|  | *pbEncoded = item->tag; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcSpOpusInfoEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const SPC_SP_OPUS_INFO *info = pvStructInfo; | 
|  |  | 
|  | if (info->pMoreInfo && | 
|  | info->pMoreInfo->dwLinkChoice != SPC_URL_LINK_CHOICE && | 
|  | info->pMoreInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE && | 
|  | info->pMoreInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE) | 
|  | SetLastError(E_INVALIDARG); | 
|  | else if (info->pPublisherInfo && | 
|  | info->pPublisherInfo->dwLinkChoice != SPC_URL_LINK_CHOICE && | 
|  | info->pPublisherInfo->dwLinkChoice != SPC_MONIKER_LINK_CHOICE && | 
|  | info->pPublisherInfo->dwLinkChoice != SPC_FILE_LINK_CHOICE) | 
|  | SetLastError(E_INVALIDARG); | 
|  | else | 
|  | { | 
|  | struct AsnEncodeSequenceItem items[3] = { { 0 } }; | 
|  | struct AsnConstructedItem constructed[3] = { { 0 } }; | 
|  | struct AsnEncodeTagSwappedItem swapped; | 
|  | DWORD cItem = 0, cConstructed = 0; | 
|  |  | 
|  | if (info->pwszProgramName) | 
|  | { | 
|  | swapped.tag = ASN_CONTEXT; | 
|  | swapped.pvStructInfo = info->pwszProgramName; | 
|  | swapped.encodeFunc = CRYPT_AsnEncodeBMPString; | 
|  | constructed[cConstructed].tag = 0; | 
|  | constructed[cConstructed].pvStructInfo = &swapped; | 
|  | constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeSwapTag; | 
|  | items[cItem].pvStructInfo = &constructed[cConstructed]; | 
|  | items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; | 
|  | cConstructed++; | 
|  | cItem++; | 
|  | } | 
|  | if (info->pMoreInfo) | 
|  | { | 
|  | constructed[cConstructed].tag = 1; | 
|  | constructed[cConstructed].pvStructInfo = info->pMoreInfo; | 
|  | constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode; | 
|  | items[cItem].pvStructInfo = &constructed[cConstructed]; | 
|  | items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; | 
|  | cConstructed++; | 
|  | cItem++; | 
|  | } | 
|  | if (info->pPublisherInfo) | 
|  | { | 
|  | constructed[cConstructed].tag = 2; | 
|  | constructed[cConstructed].pvStructInfo = info->pPublisherInfo; | 
|  | constructed[cConstructed].encodeFunc = WVTAsn1SpcLinkEncode; | 
|  | items[cItem].pvStructInfo = &constructed[cConstructed]; | 
|  | items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed; | 
|  | cConstructed++; | 
|  | cItem++; | 
|  | } | 
|  | ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, cItem, pbEncoded, pcbEncoded); | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret; | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | DWORD significantBytes, lenBytes, bytesNeeded; | 
|  | BYTE padByte = 0; | 
|  | BOOL pad = FALSE; | 
|  | const CRYPT_INTEGER_BLOB *blob = pvStructInfo; | 
|  |  | 
|  | significantBytes = blob->cbData; | 
|  | if (significantBytes) | 
|  | { | 
|  | if (blob->pbData[significantBytes - 1] & 0x80) | 
|  | { | 
|  | /* negative, lop off leading (little-endian) 0xffs */ | 
|  | for (; significantBytes > 0 && | 
|  | blob->pbData[significantBytes - 1] == 0xff; significantBytes--) | 
|  | ; | 
|  | if (blob->pbData[significantBytes - 1] < 0x80) | 
|  | { | 
|  | padByte = 0xff; | 
|  | pad = TRUE; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* positive, lop off leading (little-endian) zeroes */ | 
|  | for (; significantBytes > 0 && | 
|  | !blob->pbData[significantBytes - 1]; significantBytes--) | 
|  | ; | 
|  | if (significantBytes == 0) | 
|  | significantBytes = 1; | 
|  | if (blob->pbData[significantBytes - 1] > 0x7f) | 
|  | { | 
|  | padByte = 0; | 
|  | pad = TRUE; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (pad) | 
|  | CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes); | 
|  | else | 
|  | CRYPT_EncodeLen(significantBytes, NULL, &lenBytes); | 
|  | bytesNeeded = 1 + lenBytes + significantBytes; | 
|  | if (pad) | 
|  | bytesNeeded++; | 
|  | if (!pbEncoded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | ret = TRUE; | 
|  | } | 
|  | else if (*pcbEncoded < bytesNeeded) | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbEncoded = bytesNeeded; | 
|  | *pbEncoded++ = ASN_INTEGER; | 
|  | if (pad) | 
|  | { | 
|  | CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | *pbEncoded++ = padByte; | 
|  | } | 
|  | else | 
|  | { | 
|  | CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes); | 
|  | pbEncoded += lenBytes; | 
|  | } | 
|  | for (; significantBytes > 0; significantBytes--) | 
|  | *(pbEncoded++) = blob->pbData[significantBytes - 1]; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | ret = FALSE; | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo }; | 
|  |  | 
|  | return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER, | 
|  | &blob, pbEncoded, pcbEncoded); | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1CatMemberInfoEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const CAT_MEMBERINFO *info = pvStructInfo; | 
|  | struct AsnEncodeSequenceItem items[] = { | 
|  | { info->pwszSubjGuid, CRYPT_AsnEncodeBMPString, 0 }, | 
|  | { &info->dwCertVersion, CRYPT_AsnEncodeInt, 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1CatNameValueEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const CAT_NAMEVALUE *value = pvStructInfo; | 
|  | struct AsnEncodeSequenceItem items[] = { | 
|  | { value->pwszTag,   CRYPT_AsnEncodeBMPString, 0 }, | 
|  | { &value->fdwFlags, CRYPT_AsnEncodeInt, 0 }, | 
|  | { &value->Value,    CRYPT_AsnEncodeOctets, 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL val = *(const BOOL *)pvStructInfo, ret; | 
|  |  | 
|  | TRACE("%d\n", val); | 
|  |  | 
|  | if (!pbEncoded) | 
|  | { | 
|  | *pcbEncoded = 3; | 
|  | ret = TRUE; | 
|  | } | 
|  | else if (*pcbEncoded < 3) | 
|  | { | 
|  | *pcbEncoded = 3; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbEncoded = 3; | 
|  | *pbEncoded++ = ASN_BOOL; | 
|  | *pbEncoded++ = 1; | 
|  | *pbEncoded++ = val ? 0xff : 0; | 
|  | ret = TRUE; | 
|  | } | 
|  | TRACE("returning %d (%08x)\n", ret, GetLastError()); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoEncode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded, | 
|  | DWORD *pcbEncoded) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType, | 
|  | debugstr_a(lpszStructType), pvStructInfo, pbEncoded, pcbEncoded); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | const SPC_FINANCIAL_CRITERIA *criteria = pvStructInfo; | 
|  | struct AsnEncodeSequenceItem items[] = { | 
|  | { &criteria->fFinancialInfoAvailable, CRYPT_AsnEncodeBool, 0 }, | 
|  | { &criteria->fMeetsCriteria,          CRYPT_AsnEncodeBool, 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, | 
|  | items, sizeof(items) / sizeof(items[0]), pbEncoded, pcbEncoded); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Gets the number of length bytes from the given (leading) length byte */ | 
|  | #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f)) | 
|  |  | 
|  | /* Helper function to get the encoded length of the data starting at pbEncoded, | 
|  | * where pbEncoded[0] is the tag.  If the data are too short to contain a | 
|  | * length or if the length is too large for cbEncoded, sets an appropriate | 
|  | * error code and returns FALSE. | 
|  | */ | 
|  | static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len) | 
|  | { | 
|  | BOOL ret; | 
|  |  | 
|  | if (cbEncoded <= 1) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | else if (pbEncoded[1] <= 0x7f) | 
|  | { | 
|  | if (pbEncoded[1] + 1 > cbEncoded) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_EOD); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *len = pbEncoded[1]; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | else if (pbEncoded[1] == 0x80) | 
|  | { | 
|  | FIXME("unimplemented for indefinite-length encoding\n"); | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]); | 
|  |  | 
|  | if (lenLen > sizeof(DWORD) + 1) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_LARGE); | 
|  | ret = FALSE; | 
|  | } | 
|  | else if (lenLen + 2 > cbEncoded) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | DWORD out = 0; | 
|  |  | 
|  | pbEncoded += 2; | 
|  | while (--lenLen) | 
|  | { | 
|  | out <<= 8; | 
|  | out |= *pbEncoded++; | 
|  | } | 
|  | if (out + lenLen + 1 > cbEncoded) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_EOD); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *len = out; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret; | 
|  | DWORD bytesNeeded, dataLen; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | if (!cbEncoded) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | else if (pbEncoded[0] != ASN_OCTETSTRING) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | ret = FALSE; | 
|  | } | 
|  | else if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) | 
|  | bytesNeeded = sizeof(CRYPT_DATA_BLOB); | 
|  | else | 
|  | bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB); | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | CRYPT_DATA_BLOB *blob; | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  |  | 
|  | blob = pvStructInfo; | 
|  | blob->cbData = dataLen; | 
|  | if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) | 
|  | blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes; | 
|  | else | 
|  | { | 
|  | assert(blob->pbData); | 
|  | if (blob->cbData) | 
|  | memcpy(blob->pbData, pbEncoded + 1 + lenBytes, | 
|  | blob->cbData); | 
|  | } | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL CRYPT_AsnDecodeSPCLinkInternal(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  | DWORD bytesNeeded = sizeof(SPC_LINK), dataLen; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  | DWORD realDataLen; | 
|  |  | 
|  | switch (pbEncoded[0]) | 
|  | { | 
|  | case ASN_CONTEXT: | 
|  | bytesNeeded += (dataLen + 1) * sizeof(WCHAR); | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | PSPC_LINK link = pvStructInfo; | 
|  | DWORD i; | 
|  |  | 
|  | link->dwLinkChoice = SPC_URL_LINK_CHOICE; | 
|  | for (i = 0; i < dataLen; i++) | 
|  | link->u.pwszUrl[i] = | 
|  | *(pbEncoded + 1 + lenBytes + i); | 
|  | link->u.pwszUrl[i] = '\0'; | 
|  | TRACE("returning url %s\n", debugstr_w(link->u.pwszUrl)); | 
|  | } | 
|  | break; | 
|  | case ASN_CONSTRUCTOR | ASN_CONTEXT | 1: | 
|  | { | 
|  | CRYPT_DATA_BLOB classId; | 
|  | DWORD size = sizeof(classId); | 
|  |  | 
|  | if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL, | 
|  | pbEncoded + 1 + lenBytes, cbEncoded - 1 - lenBytes, | 
|  | CRYPT_DECODE_NOCOPY_FLAG, &classId, &size))) | 
|  | { | 
|  | if (classId.cbData != sizeof(SPC_UUID)) | 
|  | { | 
|  | SetLastError(CRYPT_E_BAD_ENCODE); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | CRYPT_DATA_BLOB data; | 
|  |  | 
|  | /* The tag length for the classId must be 1 since the | 
|  | * length is correct. | 
|  | */ | 
|  | size = sizeof(data); | 
|  | if ((ret = CRYPT_AsnDecodeOctets(dwCertEncodingType, NULL, | 
|  | pbEncoded + 3 + lenBytes + classId.cbData, | 
|  | cbEncoded - 3 - lenBytes - classId.cbData, | 
|  | CRYPT_DECODE_NOCOPY_FLAG, &data, &size))) | 
|  | { | 
|  | bytesNeeded += data.cbData; | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | PSPC_LINK link = pvStructInfo; | 
|  |  | 
|  | link->dwLinkChoice = SPC_MONIKER_LINK_CHOICE; | 
|  | /* pwszFile pointer was set by caller, copy it | 
|  | * before overwriting it | 
|  | */ | 
|  | link->u.Moniker.SerializedData.pbData = | 
|  | (BYTE *)link->u.pwszFile; | 
|  | memcpy(link->u.Moniker.ClassId, classId.pbData, | 
|  | classId.cbData); | 
|  | memcpy(link->u.Moniker.SerializedData.pbData, | 
|  | data.pbData, data.cbData); | 
|  | link->u.Moniker.SerializedData.cbData = data.cbData; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ASN_CONSTRUCTOR | ASN_CONTEXT | 2: | 
|  | if (dataLen && pbEncoded[1 + lenBytes] != ASN_CONTEXT) | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | else if ((ret = CRYPT_GetLen(pbEncoded + 1 + lenBytes, dataLen, | 
|  | &realDataLen))) | 
|  | { | 
|  | BYTE realLenBytes = GET_LEN_BYTES(pbEncoded[2 + lenBytes]); | 
|  |  | 
|  | bytesNeeded += realDataLen + sizeof(WCHAR); | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | PSPC_LINK link = pvStructInfo; | 
|  | DWORD i; | 
|  | const BYTE *ptr = pbEncoded + 2 + lenBytes + realLenBytes; | 
|  |  | 
|  | link->dwLinkChoice = SPC_FILE_LINK_CHOICE; | 
|  | for (i = 0; i < dataLen / sizeof(WCHAR); i++) | 
|  | link->u.pwszFile[i] = | 
|  | hton16(*(const WORD *)(ptr + i * sizeof(WCHAR))); | 
|  | link->u.pwszFile[realDataLen / sizeof(WCHAR)] = '\0'; | 
|  | TRACE("returning file %s\n", debugstr_w(link->u.pwszFile)); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | bytesNeeded += sizeof(WCHAR); | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | PSPC_LINK link = pvStructInfo; | 
|  |  | 
|  | link->dwLinkChoice = SPC_FILE_LINK_CHOICE; | 
|  | link->u.pwszFile[0] = '\0'; | 
|  | ret = TRUE; | 
|  | } | 
|  | } | 
|  | break; | 
|  | default: | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | } | 
|  | } | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcLinkDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | DWORD bytesNeeded; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, | 
|  | lpszStructType, pbEncoded, cbEncoded, dwFlags, NULL, &bytesNeeded); | 
|  | if (ret) | 
|  | { | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | SPC_LINK *link = pvStructInfo; | 
|  |  | 
|  | link->u.pwszFile = | 
|  | (LPWSTR)((BYTE *)pvStructInfo + sizeof(SPC_LINK)); | 
|  | ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, | 
|  | lpszStructType, pbEncoded, cbEncoded, dwFlags, pvStructInfo, | 
|  | pcbStructInfo); | 
|  | } | 
|  | } | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, | 
|  | DWORD, DWORD, void *, DWORD *); | 
|  |  | 
|  | /* tag: | 
|  | *     The expected tag of the item.  If tag is 0, decodeFunc is called | 
|  | *     regardless of the tag value seen. | 
|  | * offset: | 
|  | *     A sequence is decoded into a struct.  The offset member is the | 
|  | *     offset of this item within that struct. | 
|  | * decodeFunc: | 
|  | *     The decoder function to use.  If this is NULL, then the member isn't | 
|  | *     decoded, but minSize space is reserved for it. | 
|  | * minSize: | 
|  | *     The minimum amount of space occupied after decoding.  You must set this. | 
|  | * optional: | 
|  | *     If true, and the tag doesn't match the expected tag for this item, | 
|  | *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is | 
|  | *     filled with 0 for this member. | 
|  | * hasPointer, pointerOffset: | 
|  | *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to | 
|  | *     the offset within the struct of the data pointer (or to the | 
|  | *     first data pointer, if more than one exist). | 
|  | * size: | 
|  | *     Used by CRYPT_AsnDecodeSequence, not for your use. | 
|  | */ | 
|  | struct AsnDecodeSequenceItem | 
|  | { | 
|  | BYTE                  tag; | 
|  | DWORD                 offset; | 
|  | CryptDecodeObjectFunc decodeFunc; | 
|  | DWORD                 minSize; | 
|  | BOOL                  optional; | 
|  | BOOL                  hasPointer; | 
|  | DWORD                 pointerOffset; | 
|  | DWORD                 size; | 
|  | }; | 
|  |  | 
|  | /* Align up to a DWORD_PTR boundary | 
|  | */ | 
|  | #define ALIGN_DWORD_PTR(x) (((x) + sizeof(DWORD_PTR) - 1) & ~(sizeof(DWORD_PTR) - 1)) | 
|  |  | 
|  | #define FINALMEMBERSIZE(s, member) (sizeof(s) - offsetof(s, member)) | 
|  | #define MEMBERSIZE(s, member, nextmember) \ | 
|  | (offsetof(s, nextmember) - offsetof(s, member)) | 
|  |  | 
|  |  | 
|  | /* Decodes the items in a sequence, where the items are described in items, | 
|  | * the encoded data are in pbEncoded with length cbEncoded.  Decodes into | 
|  | * pvStructInfo.  nextData is a pointer to the memory location at which the | 
|  | * first decoded item with a dynamic pointer should point. | 
|  | * Upon decoding, *cbDecoded is the total number of bytes decoded. | 
|  | */ | 
|  | static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType, | 
|  | struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, | 
|  | DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData, | 
|  | DWORD *cbDecoded) | 
|  | { | 
|  | BOOL ret; | 
|  | DWORD i, decoded = 0; | 
|  | const BYTE *ptr = pbEncoded; | 
|  |  | 
|  | TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded, | 
|  | cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded); | 
|  |  | 
|  | for (i = 0, ret = TRUE; ret && i < cItem; i++) | 
|  | { | 
|  | if (cbEncoded - (ptr - pbEncoded) != 0) | 
|  | { | 
|  | DWORD nextItemLen; | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded), | 
|  | &nextItemLen))) | 
|  | { | 
|  | BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]); | 
|  |  | 
|  | if (ptr[0] == items[i].tag || !items[i].tag) | 
|  | { | 
|  | if (nextData && pvStructInfo && items[i].hasPointer) | 
|  | { | 
|  | TRACE("Setting next pointer to %p\n", | 
|  | nextData); | 
|  | *(BYTE **)((BYTE *)pvStructInfo + | 
|  | items[i].pointerOffset) = nextData; | 
|  | } | 
|  | if (items[i].decodeFunc) | 
|  | { | 
|  | if (pvStructInfo) | 
|  | TRACE("decoding item %d\n", i); | 
|  | else | 
|  | TRACE("sizing item %d\n", i); | 
|  | ret = items[i].decodeFunc(dwCertEncodingType, | 
|  | NULL, ptr, 1 + nextItemLenBytes + nextItemLen, | 
|  | dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, | 
|  | pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset | 
|  | : NULL, &items[i].size); | 
|  | if (ret) | 
|  | { | 
|  | if (items[i].size < items[i].minSize) | 
|  | items[i].size = items[i].minSize; | 
|  | else if (items[i].size > items[i].minSize) | 
|  | { | 
|  | /* Account for alignment padding */ | 
|  | items[i].size = ALIGN_DWORD_PTR(items[i].size); | 
|  | } | 
|  | TRACE("item %d size: %d\n", i, items[i].size); | 
|  | if (nextData && items[i].hasPointer && | 
|  | items[i].size > items[i].minSize) | 
|  | nextData += items[i].size - items[i].minSize; | 
|  | ptr += 1 + nextItemLenBytes + nextItemLen; | 
|  | decoded += 1 + nextItemLenBytes + nextItemLen; | 
|  | TRACE("item %d: decoded %d bytes\n", i, | 
|  | 1 + nextItemLenBytes + nextItemLen); | 
|  | } | 
|  | else if (items[i].optional && | 
|  | GetLastError() == CRYPT_E_ASN1_BADTAG) | 
|  | { | 
|  | TRACE("skipping optional item %d\n", i); | 
|  | items[i].size = items[i].minSize; | 
|  | SetLastError(NOERROR); | 
|  | ret = TRUE; | 
|  | } | 
|  | else | 
|  | TRACE("item %d failed: %08x\n", i, | 
|  | GetLastError()); | 
|  | } | 
|  | else | 
|  | { | 
|  | TRACE("item %d: decoded %d bytes\n", i, | 
|  | 1 + nextItemLenBytes + nextItemLen); | 
|  | ptr += 1 + nextItemLenBytes + nextItemLen; | 
|  | decoded += 1 + nextItemLenBytes + nextItemLen; | 
|  | items[i].size = items[i].minSize; | 
|  | } | 
|  | } | 
|  | else if (items[i].optional) | 
|  | { | 
|  | TRACE("skipping optional item %d\n", i); | 
|  | items[i].size = items[i].minSize; | 
|  | } | 
|  | else | 
|  | { | 
|  | TRACE("item %d: tag %02x doesn't match expected %02x\n", | 
|  | i, ptr[0], items[i].tag); | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | ret = FALSE; | 
|  | } | 
|  | } | 
|  | } | 
|  | else if (items[i].optional) | 
|  | { | 
|  | TRACE("missing optional item %d, skipping\n", i); | 
|  | items[i].size = items[i].minSize; | 
|  | } | 
|  | else | 
|  | { | 
|  | TRACE("not enough bytes for item %d, failing\n", i); | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | } | 
|  | if (ret) | 
|  | *cbDecoded = decoded; | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* This decodes an arbitrary sequence into a contiguous block of memory | 
|  | * (basically, a struct.)  Each element being decoded is described by a struct | 
|  | * AsnDecodeSequenceItem, see above. | 
|  | * startingPointer is an optional pointer to the first place where dynamic | 
|  | * data will be stored.  If you know the starting offset, you may pass it | 
|  | * here.  Otherwise, pass NULL, and one will be inferred from the items. | 
|  | */ | 
|  | static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType, | 
|  | struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded, | 
|  | DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, | 
|  | void *startingPointer) | 
|  | { | 
|  | BOOL ret; | 
|  |  | 
|  | TRACE("%p, %d, %p, %d, %08x, %p, %d, %p\n", items, cItem, pbEncoded, | 
|  | cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo, startingPointer); | 
|  |  | 
|  | if (pbEncoded[0] == ASN_SEQUENCE) | 
|  | { | 
|  | DWORD dataLen; | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded; | 
|  | const BYTE *ptr = pbEncoded + 1 + lenBytes; | 
|  |  | 
|  | cbEncoded -= 1 + lenBytes; | 
|  | if (cbEncoded < dataLen) | 
|  | { | 
|  | TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen, | 
|  | cbEncoded); | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, ptr, | 
|  | cbEncoded, dwFlags, NULL, NULL, &cbDecoded); | 
|  | if (ret && cbDecoded != dataLen) | 
|  | { | 
|  | TRACE("expected %d decoded, got %d, failing\n", dataLen, | 
|  | cbDecoded); | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | if (ret) | 
|  | { | 
|  | DWORD i, bytesNeeded = 0, structSize = 0; | 
|  |  | 
|  | for (i = 0; i < cItem; i++) | 
|  | { | 
|  | bytesNeeded += items[i].size; | 
|  | structSize += items[i].minSize; | 
|  | } | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | BYTE *nextData; | 
|  |  | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | if (startingPointer) | 
|  | nextData = startingPointer; | 
|  | else | 
|  | nextData = (BYTE *)pvStructInfo + structSize; | 
|  | memset(pvStructInfo, 0, structSize); | 
|  | ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, | 
|  | ptr, cbEncoded, dwFlags, pvStructInfo, nextData, | 
|  | &cbDecoded); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | ret = FALSE; | 
|  | } | 
|  | TRACE("returning %d (%08x)\n", ret, GetLastError()); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret; | 
|  |  | 
|  | TRACE("(%p, %d, 0x%08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | if (pbEncoded[0] == ASN_BITSTRING) | 
|  | { | 
|  | DWORD bytesNeeded, dataLen; | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) | 
|  | bytesNeeded = sizeof(CRYPT_BIT_BLOB); | 
|  | else | 
|  | bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB); | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | CRYPT_BIT_BLOB *blob; | 
|  |  | 
|  | blob = pvStructInfo; | 
|  | blob->cbData = dataLen - 1; | 
|  | blob->cUnusedBits = *(pbEncoded + 1 + | 
|  | GET_LEN_BYTES(pbEncoded[1])); | 
|  | if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) | 
|  | { | 
|  | blob->pbData = (BYTE *)pbEncoded + 2 + | 
|  | GET_LEN_BYTES(pbEncoded[1]); | 
|  | } | 
|  | else | 
|  | { | 
|  | assert(blob->pbData); | 
|  | if (blob->cbData) | 
|  | { | 
|  | BYTE mask = 0xff << blob->cUnusedBits; | 
|  |  | 
|  | memcpy(blob->pbData, pbEncoded + 2 + | 
|  | GET_LEN_BYTES(pbEncoded[1]), blob->cbData); | 
|  | blob->pbData[blob->cbData - 1] &= mask; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | ret = FALSE; | 
|  | } | 
|  | TRACE("returning %d (%08x)\n", ret, GetLastError()); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeSPCLinkPointer(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  | DWORD dataLen; | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  | DWORD size; | 
|  | SPC_LINK **pLink = pvStructInfo; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, lpszStructType, | 
|  | pbEncoded + 1 + lenBytes, dataLen, dwFlags, NULL, &size); | 
|  | if (ret) | 
|  | { | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = size + sizeof(PSPC_LINK); | 
|  | else if (*pcbStructInfo < size + sizeof(PSPC_LINK)) | 
|  | { | 
|  | *pcbStructInfo = size + sizeof(PSPC_LINK); | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbStructInfo = size + sizeof(PSPC_LINK); | 
|  | /* Set imageData's pointer if necessary */ | 
|  | if (size > sizeof(SPC_LINK)) | 
|  | { | 
|  | (*pLink)->u.pwszUrl = | 
|  | (LPWSTR)((BYTE *)*pLink + sizeof(SPC_LINK)); | 
|  | } | 
|  | ret = CRYPT_AsnDecodeSPCLinkInternal(dwCertEncodingType, | 
|  | lpszStructType, pbEncoded + 1 + lenBytes, dataLen, dwFlags, | 
|  | *pLink, pcbStructInfo); | 
|  | } | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_BITSTRING, offsetof(SPC_PE_IMAGE_DATA, Flags), | 
|  | CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, | 
|  | offsetof(SPC_PE_IMAGE_DATA, Flags.pbData), 0 }, | 
|  | { ASN_CONSTRUCTOR | ASN_CONTEXT, offsetof(SPC_PE_IMAGE_DATA, pFile), | 
|  | CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE, | 
|  | offsetof(SPC_PE_IMAGE_DATA, pFile), 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, NULL); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeOidIgnoreTag(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = TRUE; | 
|  | DWORD dataLen; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  | DWORD bytesNeeded = sizeof(LPSTR); | 
|  |  | 
|  | if (dataLen) | 
|  | { | 
|  | /* The largest possible string for the first two components | 
|  | * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough. | 
|  | */ | 
|  | char firstTwo[6]; | 
|  | const BYTE *ptr; | 
|  |  | 
|  | snprintf(firstTwo, sizeof(firstTwo), "%d.%d", | 
|  | pbEncoded[1 + lenBytes] / 40, | 
|  | pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) | 
|  | * 40); | 
|  | bytesNeeded += strlen(firstTwo) + 1; | 
|  | for (ptr = pbEncoded + 2 + lenBytes; ret && | 
|  | ptr - pbEncoded - 1 - lenBytes < dataLen; ) | 
|  | { | 
|  | /* large enough for ".4000000" */ | 
|  | char str[9]; | 
|  | int val = 0; | 
|  |  | 
|  | while (ptr - pbEncoded - 1 - lenBytes < dataLen && | 
|  | (*ptr & 0x80)) | 
|  | { | 
|  | val <<= 7; | 
|  | val |= *ptr & 0x7f; | 
|  | ptr++; | 
|  | } | 
|  | if (ptr - pbEncoded - 1 - lenBytes >= dataLen || | 
|  | (*ptr & 0x80)) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | val <<= 7; | 
|  | val |= *ptr++; | 
|  | snprintf(str, sizeof(str), ".%d", val); | 
|  | bytesNeeded += strlen(str); | 
|  | } | 
|  | } | 
|  | } | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (dataLen) | 
|  | { | 
|  | const BYTE *ptr; | 
|  | LPSTR pszObjId = *(LPSTR *)pvStructInfo; | 
|  |  | 
|  | *pszObjId = 0; | 
|  | sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40, | 
|  | pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / | 
|  | 40) * 40); | 
|  | pszObjId += strlen(pszObjId); | 
|  | for (ptr = pbEncoded + 2 + lenBytes; ret && | 
|  | ptr - pbEncoded - 1 - lenBytes < dataLen; ) | 
|  | { | 
|  | int val = 0; | 
|  |  | 
|  | while (ptr - pbEncoded - 1 - lenBytes < dataLen && | 
|  | (*ptr & 0x80)) | 
|  | { | 
|  | val <<= 7; | 
|  | val |= *ptr & 0x7f; | 
|  | ptr++; | 
|  | } | 
|  | val <<= 7; | 
|  | val |= *ptr++; | 
|  | sprintf(pszObjId, ".%d", val); | 
|  | pszObjId += strlen(pszObjId); | 
|  | } | 
|  | } | 
|  | else | 
|  | *(LPSTR *)pvStructInfo = NULL; | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | if (!cbEncoded) | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | else if (pbEncoded[0] == ASN_OBJECTIDENTIFIER) | 
|  | ret = CRYPT_AsnDecodeOidIgnoreTag(dwCertEncodingType, lpszStructType, | 
|  | pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo); | 
|  | else | 
|  | SetLastError(CRYPT_E_ASN1_BADTAG); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = TRUE; | 
|  | DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB); | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG)) | 
|  | bytesNeeded += cbEncoded; | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | PCRYPT_OBJID_BLOB blob = pvStructInfo; | 
|  |  | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | blob->cbData = cbEncoded; | 
|  | if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG) | 
|  | blob->pbData = (LPBYTE)pbEncoded; | 
|  | else | 
|  | { | 
|  | assert(blob->pbData); | 
|  | memcpy(blob->pbData, pbEncoded, blob->cbData); | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeAttributeTypeValue(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | CRYPT_ATTRIBUTE_TYPE_VALUE *typeValue = pvStructInfo; | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), | 
|  | CRYPT_AsnDecodeOid, sizeof(LPSTR), FALSE, TRUE, | 
|  | offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, pszObjId), 0 }, | 
|  | { 0, offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value), | 
|  | CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_DATA_BLOB), TRUE, TRUE, | 
|  | offsetof(CRYPT_ATTRIBUTE_TYPE_VALUE, Value.pbData), 0 }, | 
|  | }; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | return CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, | 
|  | typeValue ? typeValue->pszObjId : NULL); | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | CRYPT_ALGORITHM_IDENTIFIER *algo = pvStructInfo; | 
|  | BOOL ret = TRUE; | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), | 
|  | CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE, | 
|  | offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 }, | 
|  | { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters), | 
|  | CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, | 
|  | offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 }, | 
|  | }; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL); | 
|  | if (ret && pvStructInfo) | 
|  | { | 
|  | TRACE("pszObjId is %p (%s)\n", algo->pszObjId, | 
|  | debugstr_a(algo->pszObjId)); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeSPCDigest(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | struct SPCDigest *digest = pvStructInfo; | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_SEQUENCEOF, offsetof(struct SPCDigest, DigestAlgorithm), | 
|  | CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER), | 
|  | FALSE, TRUE, | 
|  | offsetof(struct SPCDigest, DigestAlgorithm.pszObjId), 0 }, | 
|  | { ASN_OCTETSTRING, offsetof(struct SPCDigest, Digest), | 
|  | CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), | 
|  | FALSE, TRUE, offsetof(struct SPCDigest, Digest.pbData), 0 }, | 
|  | }; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | return CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, | 
|  | digest ? digest->DigestAlgorithm.pszObjId : NULL); | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcIndirectDataContentDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, Data), | 
|  | CRYPT_AsnDecodeAttributeTypeValue, | 
|  | sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE), FALSE, TRUE, | 
|  | offsetof(SPC_INDIRECT_DATA_CONTENT, Data.pszObjId), 0 }, | 
|  | { ASN_SEQUENCEOF, offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm), | 
|  | CRYPT_AsnDecodeSPCDigest, sizeof(struct SPCDigest), | 
|  | FALSE, TRUE, | 
|  | offsetof(SPC_INDIRECT_DATA_CONTENT, DigestAlgorithm.pszObjId), 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, NULL); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeBMPString(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret; | 
|  | DWORD bytesNeeded, dataLen; | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  |  | 
|  | bytesNeeded = dataLen + 2 + sizeof(LPWSTR); | 
|  | if (!pvStructInfo) | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | else if (*pcbStructInfo < bytesNeeded) | 
|  | { | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | LPWSTR str; | 
|  | DWORD i; | 
|  |  | 
|  | *pcbStructInfo = bytesNeeded; | 
|  | assert(pvStructInfo); | 
|  | str = *(LPWSTR *)pvStructInfo; | 
|  | for (i = 0; i < dataLen / 2; i++) | 
|  | str[i] = (pbEncoded[1 + lenBytes + 2 * i] << 8) | | 
|  | pbEncoded[1 + lenBytes + 2 * i + 1]; | 
|  | /* Decoded string is always NULL-terminated */ | 
|  | str[i] = '\0'; | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeProgramName(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  | DWORD dataLen; | 
|  |  | 
|  | TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pvStructInfo ? *pcbStructInfo : 0); | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  |  | 
|  | ret = CRYPT_AsnDecodeBMPString(dwCertEncodingType, lpszStructType, | 
|  | pbEncoded + 1 + lenBytes, dataLen, dwFlags, pvStructInfo, | 
|  | pcbStructInfo); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_CONSTRUCTOR | ASN_CONTEXT, | 
|  | offsetof(SPC_SP_OPUS_INFO, pwszProgramName), | 
|  | CRYPT_AsnDecodeProgramName, sizeof(LPCWSTR), TRUE, TRUE, | 
|  | offsetof(SPC_SP_OPUS_INFO, pwszProgramName), 0 }, | 
|  | { ASN_CONSTRUCTOR | ASN_CONTEXT | 1, | 
|  | offsetof(SPC_SP_OPUS_INFO, pMoreInfo), | 
|  | CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE, | 
|  | offsetof(SPC_SP_OPUS_INFO, pMoreInfo), 0 }, | 
|  | { ASN_CONSTRUCTOR | ASN_CONTEXT | 2, | 
|  | offsetof(SPC_SP_OPUS_INFO, pPublisherInfo), | 
|  | CRYPT_AsnDecodeSPCLinkPointer, sizeof(PSPC_LINK), TRUE, TRUE, | 
|  | offsetof(SPC_SP_OPUS_INFO, pPublisherInfo), 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, NULL); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Ignores tag.  Only allows integers 4 bytes or smaller in size. */ | 
|  | static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret; | 
|  | DWORD dataLen; | 
|  |  | 
|  | if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))) | 
|  | { | 
|  | BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]); | 
|  |  | 
|  | if (dataLen > sizeof(int)) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_LARGE); | 
|  | ret = FALSE; | 
|  | } | 
|  | else if (!pvStructInfo) | 
|  | *pcbStructInfo = sizeof(int); | 
|  | else if (*pcbStructInfo < sizeof(int)) | 
|  | { | 
|  | *pcbStructInfo = sizeof(int); | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | int val; | 
|  | DWORD i; | 
|  |  | 
|  | *pcbStructInfo = sizeof(int); | 
|  | if (dataLen && pbEncoded[1 + lenBytes] & 0x80) | 
|  | { | 
|  | /* initialize to a negative value to sign-extend */ | 
|  | val = -1; | 
|  | } | 
|  | else | 
|  | val = 0; | 
|  | for (i = 0; i < dataLen; i++) | 
|  | { | 
|  | val <<= 8; | 
|  | val |= pbEncoded[1 + lenBytes + i]; | 
|  | } | 
|  | memcpy(pvStructInfo, &val, sizeof(int)); | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1CatMemberInfoDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_BMPSTRING, offsetof(CAT_MEMBERINFO, pwszSubjGuid), | 
|  | CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE, | 
|  | offsetof(CAT_MEMBERINFO, pwszSubjGuid), 0 }, | 
|  | { ASN_INTEGER, offsetof(CAT_MEMBERINFO, dwCertVersion), | 
|  | CRYPT_AsnDecodeInt, FINALMEMBERSIZE(CAT_MEMBERINFO, dwCertVersion), | 
|  | FALSE, FALSE, 0, 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, NULL); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1CatNameValueDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_BMPSTRING, offsetof(CAT_NAMEVALUE, pwszTag), | 
|  | CRYPT_AsnDecodeBMPString, sizeof(LPWSTR), FALSE, TRUE, | 
|  | offsetof(CAT_NAMEVALUE, pwszTag), 0 }, | 
|  | { ASN_INTEGER, offsetof(CAT_NAMEVALUE, fdwFlags), | 
|  | CRYPT_AsnDecodeInt, MEMBERSIZE(CAT_NAMEVALUE, fdwFlags, Value), | 
|  | FALSE, FALSE, 0, 0 }, | 
|  | { ASN_OCTETSTRING, offsetof(CAT_NAMEVALUE, Value), | 
|  | CRYPT_AsnDecodeOctets, sizeof(CRYPT_DER_BLOB), FALSE, TRUE, | 
|  | offsetof(CAT_NAMEVALUE, Value.pbData), 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, NULL); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret; | 
|  |  | 
|  | if (cbEncoded < 3) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | return FALSE; | 
|  | } | 
|  | if (GET_LEN_BYTES(pbEncoded[1]) > 1) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | return FALSE; | 
|  | } | 
|  | if (pbEncoded[1] > 1) | 
|  | { | 
|  | SetLastError(CRYPT_E_ASN1_CORRUPT); | 
|  | return FALSE; | 
|  | } | 
|  | if (!pvStructInfo) | 
|  | { | 
|  | *pcbStructInfo = sizeof(BOOL); | 
|  | ret = TRUE; | 
|  | } | 
|  | else if (*pcbStructInfo < sizeof(BOOL)) | 
|  | { | 
|  | *pcbStructInfo = sizeof(BOOL); | 
|  | SetLastError(ERROR_MORE_DATA); | 
|  | ret = FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | *pcbStructInfo = sizeof(BOOL); | 
|  | *(BOOL *)pvStructInfo = pbEncoded[2] != 0; | 
|  | ret = TRUE; | 
|  | } | 
|  | TRACE("returning %d (%08x)\n", ret, GetLastError()); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | BOOL WINAPI WVTAsn1SpcFinancialCriteriaInfoDecode(DWORD dwCertEncodingType, | 
|  | LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, | 
|  | void *pvStructInfo, DWORD *pcbStructInfo) | 
|  | { | 
|  | BOOL ret = FALSE; | 
|  |  | 
|  | TRACE("(%p, %d, %08x, %p, %d)\n", pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, *pcbStructInfo); | 
|  |  | 
|  | __TRY | 
|  | { | 
|  | struct AsnDecodeSequenceItem items[] = { | 
|  | { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fFinancialInfoAvailable), | 
|  | CRYPT_AsnDecodeBool, MEMBERSIZE(SPC_FINANCIAL_CRITERIA, | 
|  | fFinancialInfoAvailable, fMeetsCriteria), FALSE, FALSE, 0, 0 }, | 
|  | { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria), | 
|  | CRYPT_AsnDecodeBool, FINALMEMBERSIZE(SPC_FINANCIAL_CRITERIA, | 
|  | fMeetsCriteria), FALSE, FALSE, 0, 0 }, | 
|  | }; | 
|  |  | 
|  | ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items, | 
|  | sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, | 
|  | pvStructInfo, pcbStructInfo, NULL); | 
|  | } | 
|  | __EXCEPT_PAGE_FAULT | 
|  | { | 
|  | SetLastError(STATUS_ACCESS_VIOLATION); | 
|  | } | 
|  | __ENDTRY | 
|  | TRACE("returning %d\n", ret); | 
|  | return ret; | 
|  | } |