Implement asn.1 encoding/decoding of times, with tests.

This commit is contained in:
Juan Lang 2005-06-08 18:31:21 +00:00 committed by Alexandre Julliard
parent 926e35532c
commit cdc6772017
2 changed files with 499 additions and 58 deletions

View File

@ -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);

View File

@ -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, &times[i]);
testTimeEncoding(PKCS_UTC_TIME, &times[i]);
testTimeEncoding(szOID_RSA_signingTime, &times[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, &times[i]);
testTimeDecoding(PKCS_UTC_TIME, &times[i]);
testTimeDecoding(szOID_RSA_signingTime, &times[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();
}