/* 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 #include #include #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 = (const CRYPT_DATA_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 = (const SPC_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 = (const CRYPT_BIT_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 = (const struct AsnConstructedItem *)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 = (const SPC_PE_IMAGE_DATA *)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 = (LPCSTR)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; 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 = (const CRYPT_DER_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 = (const CRYPT_ALGORITHM_IDENTIFIER *)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 = (const CRYPT_ATTRIBUTE_TYPE_VALUE *)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 = (const struct SPCDigest *)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 = (const SPC_INDIRECT_DATA_CONTENT *)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 = (LPCWSTR)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; } 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 = (const CRYPT_INTEGER_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; } 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 = (const CAT_MEMBERINFO *)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 = (const CAT_NAMEVALUE *)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 = (CRYPT_DATA_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 = (PSPC_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 = (PSPC_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 = (PSPC_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(*(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 = (PSPC_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 = (SPC_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; }; /* 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) { /* Account for alignment padding */ if (items[i].size % sizeof(DWORD)) items[i].size += sizeof(DWORD) - items[i].size % sizeof(DWORD); 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 = (BYTE *)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 = (CRYPT_BIT_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 = (SPC_LINK **)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 = (PCRYPT_OBJID_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 = (CRYPT_ATTRIBUTE_TYPE_VALUE *)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 = (CRYPT_ALGORITHM_IDENTIFIER *)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 = (struct SPCDigest *)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; } BOOL WINAPI WVTAsn1SpcSpOpusInfoDecode(DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo) { FIXME("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, pvStructInfo, *pcbStructInfo); return FALSE; } 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 CRYPT_AsnDecodeInteger(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 + sizeof(CRYPT_INTEGER_BLOB); if (!pvStructInfo) *pcbStructInfo = bytesNeeded; else if (*pcbStructInfo < bytesNeeded) { *pcbStructInfo = bytesNeeded; SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo; *pcbStructInfo = bytesNeeded; blob->cbData = dataLen; assert(blob->pbData); if (blob->cbData) { DWORD i; for (i = 0; i < blob->cbData; i++) { blob->pbData[i] = *(pbEncoded + 1 + lenBytes + dataLen - i - 1); } } } } 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; BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)]; CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; DWORD size = sizeof(buf); blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB); ret = CRYPT_AsnDecodeInteger(pbEncoded, cbEncoded, 0, buf, &size); if (ret) { if (!pvStructInfo) *pcbStructInfo = sizeof(int); else if (*pcbStructInfo < sizeof(int)) { *pcbStructInfo = sizeof(int); SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { int val, i; *pcbStructInfo = sizeof(int); if (blob->pbData[blob->cbData - 1] & 0x80) { /* initialize to a negative value to sign-extend */ val = -1; } else val = 0; for (i = 0; i < blob->cbData; i++) { val <<= 8; val |= blob->pbData[blob->cbData - i - 1]; } memcpy(pvStructInfo, &val, sizeof(int)); } } else if (GetLastError() == ERROR_MORE_DATA) SetLastError(CRYPT_E_ASN1_LARGE); 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, sizeof(DWORD), 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, sizeof(DWORD), 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] ? TRUE : FALSE; 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, sizeof(BOOL), FALSE, FALSE, 0, 0 }, { ASN_BOOL, offsetof(SPC_FINANCIAL_CRITERIA, fMeetsCriteria), CRYPT_AsnDecodeBool, sizeof(BOOL), 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; }