| /* 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[8]; |
| const BYTE *ptr; |
| |
| sprintf(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; |
| pszObjId += sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40, |
| pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / |
| 40) * 40); |
| 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++; |
| pszObjId += sprintf(pszObjId, ".%d", val); |
| } |
| } |
| 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; |
| } |