Implement asn.1 encoding/decoding of times, with tests.
This commit is contained in:
parent
926e35532c
commit
cdc6772017
|
@ -25,6 +25,10 @@
|
|||
#include "snmp.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
/* a few asn.1 tags we need */
|
||||
#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
|
||||
#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||
|
||||
static const WCHAR szDllName[] = { 'D','l','l',0 };
|
||||
|
@ -313,6 +317,29 @@ BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
|
||||
DWORD bytesNeeded)
|
||||
{
|
||||
if (!pbEncoded || (!(dwFlags & CRYPT_ENCODE_ALLOC_FLAG) &&
|
||||
bytesNeeded > *pcbEncoded))
|
||||
{
|
||||
*pcbEncoded = bytesNeeded;
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
|
||||
{
|
||||
if (pEncodePara && pEncodePara->pfnAlloc)
|
||||
*(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
|
||||
else
|
||||
*(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
|
||||
if (!*(BYTE **)pbEncoded)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
|
@ -356,27 +383,11 @@ static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
|||
bytesNeeded = 2 + significantBytes;
|
||||
if (pad)
|
||||
bytesNeeded++;
|
||||
if (!pbEncoded || bytesNeeded > *pcbEncoded)
|
||||
{
|
||||
*pcbEncoded = bytesNeeded;
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
|
||||
bytesNeeded))
|
||||
return FALSE;
|
||||
}
|
||||
if (!pbEncoded)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
|
||||
{
|
||||
if (pEncodePara && pEncodePara->pfnAlloc)
|
||||
*(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
|
||||
else
|
||||
*(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
|
||||
if (!*(BYTE **)pbEncoded)
|
||||
return FALSE;
|
||||
pbEncoded = *(BYTE **)pbEncoded;
|
||||
}
|
||||
*pbEncoded++ = ASN_INTEGER;
|
||||
if (pad)
|
||||
{
|
||||
|
@ -390,6 +401,81 @@ static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
SYSTEMTIME sysTime;
|
||||
/* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
|
||||
* temporary buffer because the output buffer is not NULL-terminated.
|
||||
*/
|
||||
char buf[16];
|
||||
static const DWORD bytesNeeded = sizeof(buf) - 1;
|
||||
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
/* Sanity check the year, this is a two-digit year format */
|
||||
if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
|
||||
return FALSE;
|
||||
if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
|
||||
{
|
||||
SetLastError(CRYPT_E_BAD_ENCODE);
|
||||
return FALSE;
|
||||
}
|
||||
if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
|
||||
bytesNeeded))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
|
||||
pbEncoded = *(BYTE **)pbEncoded;
|
||||
buf[0] = ASN_UTCTIME;
|
||||
buf[1] = bytesNeeded - 2;
|
||||
snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
|
||||
sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
|
||||
sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
|
||||
sysTime.wSecond);
|
||||
memcpy(pbEncoded, buf, bytesNeeded);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
SYSTEMTIME sysTime;
|
||||
/* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
|
||||
* temporary buffer because the output buffer is not NULL-terminated.
|
||||
*/
|
||||
char buf[18];
|
||||
static const DWORD bytesNeeded = sizeof(buf) - 1;
|
||||
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
/* Check the year, if it's in the UTCTime range call that encode func */
|
||||
if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
|
||||
return FALSE;
|
||||
if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
|
||||
return CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
|
||||
pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
|
||||
if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
|
||||
bytesNeeded))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
|
||||
pbEncoded = *(BYTE **)pbEncoded;
|
||||
buf[0] = ASN_GENERALTIME;
|
||||
buf[1] = bytesNeeded - 2;
|
||||
snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
|
||||
sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
|
||||
sysTime.wMinute, sysTime.wSecond);
|
||||
memcpy(pbEncoded, buf, bytesNeeded);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
|
||||
DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
|
||||
|
||||
|
@ -411,23 +497,32 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
|||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
|
||||
&& (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
|
||||
{
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!HIWORD(lpszStructType))
|
||||
{
|
||||
if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == X509_ASN_ENCODING
|
||||
|| (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) ==
|
||||
PKCS_7_ASN_ENCODING)
|
||||
switch (LOWORD(lpszStructType))
|
||||
{
|
||||
switch (LOWORD(lpszStructType))
|
||||
{
|
||||
case (WORD)X509_INTEGER:
|
||||
encodeFunc = CRYPT_AsnEncodeInt;
|
||||
break;
|
||||
default:
|
||||
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
|
||||
}
|
||||
case (WORD)X509_INTEGER:
|
||||
encodeFunc = CRYPT_AsnEncodeInt;
|
||||
break;
|
||||
case (WORD)X509_CHOICE_OF_TIME:
|
||||
encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
|
||||
break;
|
||||
case (WORD)PKCS_UTC_TIME:
|
||||
encodeFunc = CRYPT_AsnEncodeUtcTime;
|
||||
break;
|
||||
default:
|
||||
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
|
||||
}
|
||||
}
|
||||
else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
|
||||
encodeFunc = CRYPT_AsnEncodeUtcTime;
|
||||
if (!encodeFunc)
|
||||
encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
|
||||
lpszStructType, "CryptEncodeObjectEx", &lib);
|
||||
|
@ -482,12 +577,33 @@ BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
|
||||
DWORD bytesNeeded)
|
||||
{
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
{
|
||||
if (pDecodePara && pDecodePara->pfnAlloc)
|
||||
*(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
|
||||
else
|
||||
*(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
|
||||
if (!*(BYTE **)pvStructInfo)
|
||||
return FALSE;
|
||||
}
|
||||
else if (*pcbStructInfo < bytesNeeded)
|
||||
{
|
||||
*pcbStructInfo = bytesNeeded;
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
int val, i;
|
||||
BOOL ret;
|
||||
|
||||
if (!pbEncoded || !cbEncoded)
|
||||
{
|
||||
|
@ -527,30 +643,192 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
|
|||
val <<= 8;
|
||||
val |= pbEncoded[2 + i];
|
||||
}
|
||||
if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
|
||||
pcbStructInfo, sizeof(int)))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
*pcbStructInfo = sizeof(int);
|
||||
memcpy(pvStructInfo, &val, sizeof(int));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
|
||||
do { \
|
||||
BYTE i; \
|
||||
\
|
||||
(word) = 0; \
|
||||
for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
|
||||
{ \
|
||||
if (!isdigit(*(pbEncoded))) \
|
||||
{ \
|
||||
SetLastError(CRYPT_E_ASN1_CORRUPT); \
|
||||
return FALSE; \
|
||||
} \
|
||||
(word) *= 10; \
|
||||
(word) += *(pbEncoded)++ - '0'; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
SYSTEMTIME sysTime = { 0 };
|
||||
BYTE len;
|
||||
|
||||
if (!pbEncoded || !cbEncoded)
|
||||
{
|
||||
if (pDecodePara && pDecodePara->pfnAlloc)
|
||||
*(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(sizeof(int));
|
||||
else
|
||||
*(BYTE **)pvStructInfo = LocalAlloc(0, sizeof(int));
|
||||
if (!*(BYTE **)pvStructInfo)
|
||||
return FALSE;
|
||||
memcpy(*(BYTE **)pvStructInfo, &val, sizeof(int));
|
||||
ret = TRUE;
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
else if (*pcbStructInfo < sizeof(int))
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
*pcbStructInfo = sizeof(int);
|
||||
*pcbStructInfo = sizeof(FILETIME);
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
ret = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
if (pbEncoded[0] != ASN_UTCTIME)
|
||||
{
|
||||
*pcbStructInfo = sizeof(int);
|
||||
memcpy(pvStructInfo, &val, sizeof(int));
|
||||
ret = TRUE;
|
||||
SetLastError(CRYPT_E_ASN1_BADTAG);
|
||||
return FALSE;
|
||||
}
|
||||
return ret;
|
||||
len = pbEncoded[1];
|
||||
/* FIXME: magic # */
|
||||
if (len < 10)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_CORRUPT);
|
||||
return FALSE;
|
||||
}
|
||||
pbEncoded += 2;
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
|
||||
if (sysTime.wYear >= 50)
|
||||
sysTime.wYear += 1900;
|
||||
else
|
||||
sysTime.wYear += 2000;
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
|
||||
if (len > 0)
|
||||
{
|
||||
if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
|
||||
else if (isdigit(*pbEncoded))
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
|
||||
if (len > 0)
|
||||
{
|
||||
/* FIXME: get timezone, for now assuming UTC (no adjustment) */
|
||||
}
|
||||
}
|
||||
|
||||
if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
|
||||
pcbStructInfo, sizeof(FILETIME)))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
*pcbStructInfo = sizeof(FILETIME);
|
||||
return SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
SYSTEMTIME sysTime = { 0 };
|
||||
BYTE len;
|
||||
|
||||
if (!pbEncoded || !cbEncoded)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
*pcbStructInfo = sizeof(FILETIME);
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
if (pbEncoded[0] == ASN_UTCTIME)
|
||||
return CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
|
||||
pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
|
||||
pcbStructInfo);
|
||||
if (pbEncoded[0] != ASN_GENERALTIME)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_BADTAG);
|
||||
return FALSE;
|
||||
}
|
||||
len = pbEncoded[1];
|
||||
/* FIXME: magic # */
|
||||
if (len < 10)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_CORRUPT);
|
||||
return FALSE;
|
||||
}
|
||||
pbEncoded += 2;
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
|
||||
if (len > 0)
|
||||
{
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
|
||||
if (len > 0)
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
|
||||
if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
|
||||
{
|
||||
BYTE digits;
|
||||
|
||||
pbEncoded++;
|
||||
len--;
|
||||
digits = min(len, 3); /* workaround macro weirdness */
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
|
||||
sysTime.wMilliseconds);
|
||||
}
|
||||
if (len >= 5 && (*pbEncoded == '+' || *pbEncoded == '-'))
|
||||
{
|
||||
WORD hours, minutes;
|
||||
BYTE sign = *pbEncoded++;
|
||||
|
||||
len--;
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
|
||||
if (hours >= 24)
|
||||
return CRYPT_E_ASN1_CORRUPT;
|
||||
CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
|
||||
if (minutes >= 60)
|
||||
return CRYPT_E_ASN1_CORRUPT;
|
||||
if (sign == '+')
|
||||
{
|
||||
sysTime.wHour += hours;
|
||||
sysTime.wMinute += minutes;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hours > sysTime.wHour)
|
||||
{
|
||||
sysTime.wDay--;
|
||||
sysTime.wHour = 24 - (hours - sysTime.wHour);
|
||||
}
|
||||
else
|
||||
sysTime.wHour -= hours;
|
||||
if (minutes > sysTime.wMinute)
|
||||
{
|
||||
sysTime.wHour--;
|
||||
sysTime.wMinute = 60 - (minutes - sysTime.wMinute);
|
||||
}
|
||||
else
|
||||
sysTime.wMinute -= minutes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
|
||||
pcbStructInfo, sizeof(FILETIME)))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
*pcbStructInfo = sizeof(FILETIME);
|
||||
return SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
|
||||
}
|
||||
|
||||
typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
|
||||
|
@ -574,23 +852,32 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
|||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
|
||||
&& (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
|
||||
{
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!HIWORD(lpszStructType))
|
||||
{
|
||||
if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == X509_ASN_ENCODING
|
||||
|| (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) ==
|
||||
PKCS_7_ASN_ENCODING)
|
||||
switch (LOWORD(lpszStructType))
|
||||
{
|
||||
switch (LOWORD(lpszStructType))
|
||||
{
|
||||
case (WORD)X509_INTEGER:
|
||||
decodeFunc = CRYPT_AsnDecodeInt;
|
||||
break;
|
||||
default:
|
||||
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
|
||||
}
|
||||
case (WORD)X509_INTEGER:
|
||||
decodeFunc = CRYPT_AsnDecodeInt;
|
||||
break;
|
||||
case (WORD)X509_CHOICE_OF_TIME:
|
||||
decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
|
||||
break;
|
||||
case (WORD)PKCS_UTC_TIME:
|
||||
decodeFunc = CRYPT_AsnDecodeUtcTime;
|
||||
break;
|
||||
default:
|
||||
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
|
||||
}
|
||||
}
|
||||
else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
|
||||
decodeFunc = CRYPT_AsnDecodeUtcTime;
|
||||
if (!decodeFunc)
|
||||
decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
|
||||
lpszStructType, "CryptDecodeObjectEx", &lib);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Unit test suite for crypt32.dll's CryptEncodeObjectEx
|
||||
* Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx
|
||||
*
|
||||
* Copyright 2005 Juan Lang
|
||||
*
|
||||
|
@ -144,6 +144,158 @@ static void test_decodeint(void)
|
|||
}
|
||||
}
|
||||
|
||||
struct encodedFiletime
|
||||
{
|
||||
SYSTEMTIME sysTime;
|
||||
BYTE *encodedTime;
|
||||
};
|
||||
|
||||
static void testTimeEncoding(LPCSTR encoding,
|
||||
const struct encodedFiletime *time)
|
||||
{
|
||||
FILETIME ft = { 0 };
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
BOOL ret;
|
||||
|
||||
ret = SystemTimeToFileTime(&time->sysTime, &ft);
|
||||
ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
|
||||
/* No test case, but both X509_ASN_ENCODING and PKCS_7_ASN_ENCODING have
|
||||
* the same effect for time encodings.
|
||||
*/
|
||||
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, encoding, &ft,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
/* years other than 1950-2050 are not allowed for encodings other than
|
||||
* X509_CHOICE_OF_TIME.
|
||||
*/
|
||||
if (encoding == X509_CHOICE_OF_TIME ||
|
||||
(time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
|
||||
{
|
||||
ok(ret, "CryptEncodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
|
||||
GetLastError());
|
||||
ok(buf != NULL, "Expected an allocated buffer\n");
|
||||
if (buf)
|
||||
{
|
||||
ok(buf[0] == time->encodedTime[0],
|
||||
"Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0],
|
||||
buf[0]);
|
||||
ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %ld\n",
|
||||
time->encodedTime[1], bufSize);
|
||||
ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]),
|
||||
"Got unexpected value for time encoding\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
ok(!ret && GetLastError() == CRYPT_E_BAD_ENCODE,
|
||||
"Expected CRYPT_E_BAD_ENCODE, got 0x%08lx\n", GetLastError());
|
||||
}
|
||||
|
||||
static void testTimeDecoding(LPCSTR encoding,
|
||||
const struct encodedFiletime *time)
|
||||
{
|
||||
FILETIME ft1 = { 0 }, ft2 = { 0 };
|
||||
DWORD size = sizeof(ft2);
|
||||
BOOL ret;
|
||||
|
||||
ret = SystemTimeToFileTime(&time->sysTime, &ft1);
|
||||
ok(ret, "SystemTimeToFileTime failed: %ld\n", GetLastError());
|
||||
/* No test case, but both X509_ASN_ENCODING and PKCS_7_ASN_ENCODING have
|
||||
* the same effect for time encodings.
|
||||
*/
|
||||
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, encoding, time->encodedTime,
|
||||
time->encodedTime[1] + 2, 0, NULL, &ft2, &size);
|
||||
/* years other than 1950-2050 are not allowed for encodings other than
|
||||
* X509_CHOICE_OF_TIME.
|
||||
*/
|
||||
if (encoding == X509_CHOICE_OF_TIME ||
|
||||
(time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050))
|
||||
{
|
||||
ok(ret, "CryptDecodeObjectEx failed: %ld (0x%08lx)\n", GetLastError(),
|
||||
GetLastError());
|
||||
ok(!memcmp(&ft1, &ft2, sizeof(ft1)),
|
||||
"Got unexpected value for time decoding\n");
|
||||
}
|
||||
else
|
||||
ok(!ret && GetLastError() == CRYPT_E_ASN1_BADTAG,
|
||||
"Expected CRYPT_E_ASN1_BADTAG, got 0x%08lx\n", GetLastError());
|
||||
}
|
||||
|
||||
static const struct encodedFiletime times[] = {
|
||||
{ { 2005, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0d" "050606161000Z" },
|
||||
{ { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "19450606161000Z" },
|
||||
{ { 2145, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x0f" "21450606161000Z" },
|
||||
};
|
||||
|
||||
static void test_encodeFiletime(void)
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
|
||||
{
|
||||
testTimeEncoding(X509_CHOICE_OF_TIME, ×[i]);
|
||||
testTimeEncoding(PKCS_UTC_TIME, ×[i]);
|
||||
testTimeEncoding(szOID_RSA_signingTime, ×[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_decodeFiletime(void)
|
||||
{
|
||||
static const struct encodedFiletime otherTimes[] = {
|
||||
{ { 1945, 6, 1, 6, 16, 10, 0, 0 }, "\x18" "\x13" "19450606161000.000Z" },
|
||||
{ { 1945, 6, 1, 6, 16, 10, 0, 999 }, "\x18" "\x13" "19450606161000.999Z" },
|
||||
{ { 1945, 6, 1, 6, 17, 10, 0, 0 }, "\x18" "\x13" "19450606161000+0100" },
|
||||
{ { 1945, 6, 1, 6, 15, 10, 0, 0 }, "\x18" "\x13" "19450606161000-0100" },
|
||||
{ { 1945, 6, 1, 6, 14, 55, 0, 0 }, "\x18" "\x13" "19450606161000-0115" },
|
||||
{ { 2145, 6, 1, 6, 16, 0, 0, 0 }, "\x18" "\x0a" "2145060616" },
|
||||
{ { 2045, 6, 1, 6, 16, 10, 0, 0 }, "\x17" "\x0a" "4506061610" },
|
||||
};
|
||||
/* An oddball case that succeeds in Windows, but doesn't seem correct
|
||||
{ { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
|
||||
*/
|
||||
static const char *bogusTimes[] = {
|
||||
/* oddly, this succeeds on Windows, with year 2765
|
||||
"\x18" "\x0f" "21r50606161000Z",
|
||||
*/
|
||||
"\x17" "\x08" "45060616",
|
||||
"\x18" "\x0f" "aaaaaaaaaaaaaaZ",
|
||||
"\x18" "\x04" "2145",
|
||||
"\x18" "\x08" "21450606",
|
||||
};
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < sizeof(times) / sizeof(times[0]); i++)
|
||||
{
|
||||
testTimeDecoding(X509_CHOICE_OF_TIME, ×[i]);
|
||||
testTimeDecoding(PKCS_UTC_TIME, ×[i]);
|
||||
testTimeDecoding(szOID_RSA_signingTime, ×[i]);
|
||||
}
|
||||
for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++)
|
||||
{
|
||||
testTimeDecoding(X509_CHOICE_OF_TIME, &otherTimes[i]);
|
||||
testTimeDecoding(PKCS_UTC_TIME, &otherTimes[i]);
|
||||
testTimeDecoding(szOID_RSA_signingTime, &otherTimes[i]);
|
||||
}
|
||||
for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++)
|
||||
{
|
||||
FILETIME ft;
|
||||
SYSTEMTIME sysTime;
|
||||
DWORD size = sizeof(ft);
|
||||
BOOL ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CHOICE_OF_TIME,
|
||||
bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft, &size);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
ret = FileTimeToSystemTime(&ft, &sysTime);
|
||||
printf("%02d %02d %04d %02d:%02d.%02d\n", sysTime.wMonth,
|
||||
sysTime.wDay, sysTime.wYear, sysTime.wHour, sysTime.wMinute,
|
||||
sysTime.wSecond);
|
||||
}
|
||||
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
|
||||
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
static void test_registerOIDFunction(void)
|
||||
{
|
||||
static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
|
||||
|
@ -202,5 +354,7 @@ START_TEST(encode)
|
|||
{
|
||||
test_encodeint();
|
||||
test_decodeint();
|
||||
test_encodeFiletime();
|
||||
test_decodeFiletime();
|
||||
test_registerOIDFunction();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue