wintrust: Implement decoding SPC links.
This commit is contained in:
parent
44047e02c2
commit
29cae46fce
|
@ -4,7 +4,7 @@ SRCDIR = @srcdir@
|
|||
VPATH = @srcdir@
|
||||
MODULE = wintrust.dll
|
||||
IMPORTLIB = libwintrust.$(IMPLIBEXT)
|
||||
IMPORTS = crypt32 user32 advapi32 kernel32
|
||||
IMPORTS = crypt32 user32 advapi32 kernel32 ntdll
|
||||
DELAYIMPORTS = imagehlp
|
||||
|
||||
C_SRCS = \
|
||||
|
|
|
@ -18,16 +18,32 @@
|
|||
*
|
||||
*/
|
||||
#include <stdarg.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
|
||||
|
||||
BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
|
||||
DWORD *pcbEncoded)
|
||||
|
@ -48,14 +64,337 @@ BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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 WINAPI 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)
|
||||
{
|
||||
FIXME("(0x%08x, %s, %p, %d, 0x%08x, %p, %p)\n", dwCertEncodingType,
|
||||
debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
|
||||
pvStructInfo, pcbStructInfo);
|
||||
return FALSE;
|
||||
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;
|
||||
}
|
||||
|
||||
BOOL WINAPI WVTAsn1SpcPeImageDataDecode(DWORD dwCertEncodingType,
|
||||
|
|
|
@ -147,7 +147,6 @@ static void test_decodeSPCLink(void)
|
|||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
|
||||
emptyURLSPCLink, sizeof(emptyURLSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
|
||||
(BYTE *)&buf, &size);
|
||||
todo_wine
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
|
@ -160,7 +159,6 @@ static void test_decodeSPCLink(void)
|
|||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
|
||||
urlSPCLink, sizeof(urlSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
|
||||
(BYTE *)&buf, &size);
|
||||
todo_wine
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
|
@ -173,7 +171,6 @@ static void test_decodeSPCLink(void)
|
|||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
|
||||
fileSPCLink, sizeof(fileSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
|
||||
(BYTE *)&buf, &size);
|
||||
todo_wine
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
|
@ -186,7 +183,6 @@ static void test_decodeSPCLink(void)
|
|||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
|
||||
emptyMonikerSPCLink, sizeof(emptyMonikerSPCLink), CRYPT_DECODE_ALLOC_FLAG,
|
||||
NULL, (BYTE *)&buf, &size);
|
||||
todo_wine
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
|
@ -195,14 +191,15 @@ static void test_decodeSPCLink(void)
|
|||
link = (SPC_LINK *)buf;
|
||||
ok(link->dwLinkChoice == SPC_MONIKER_LINK_CHOICE,
|
||||
"Expected SPC_MONIKER_LINK_CHOICE, got %d\n", link->dwLinkChoice);
|
||||
ok(!memcmp(&link->Moniker, &emptyMoniker, sizeof(emptyMoniker)),
|
||||
"Unexpected value\n");
|
||||
ok(!memcmp(&link->Moniker.ClassId, &emptyMoniker.ClassId,
|
||||
sizeof(emptyMoniker.ClassId)), "Unexpected value\n");
|
||||
ok(link->Moniker.SerializedData.cbData == 0,
|
||||
"Expected no serialized data\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
|
||||
monikerSPCLink, sizeof(monikerSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL,
|
||||
(BYTE *)&buf, &size);
|
||||
todo_wine
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
|
@ -224,7 +221,6 @@ static void test_decodeSPCLink(void)
|
|||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT,
|
||||
badMonikerSPCLink, sizeof(badMonikerSPCLink), CRYPT_DECODE_ALLOC_FLAG,
|
||||
NULL, (BYTE *)&buf, &size);
|
||||
todo_wine
|
||||
ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
|
||||
"Expected CRYPT_E_BAD_ENCODE, got %08x\n", GetLastError());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue