Commit 12a9ec13 authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

Add encode/decode support for multi-byte integers.

parent f674f1f7
......@@ -771,6 +771,76 @@ static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
return TRUE;
}
static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
DWORD significantBytes;
BYTE padByte = 0, bytesNeeded;
BOOL pad = FALSE;
CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
if (!pvStructInfo)
{
SetLastError(STATUS_ACCESS_VIOLATION);
return FALSE;
}
/* FIXME: use exception handling to protect against bogus pointers */
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 (blob->pbData[significantBytes - 1] > 0x7f)
{
padByte = 0;
pad = TRUE;
}
}
}
bytesNeeded = 2 + significantBytes;
if (pad)
bytesNeeded++;
if (!pbEncoded)
{
*pcbEncoded = bytesNeeded;
return TRUE;
}
if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
bytesNeeded))
return FALSE;
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
pbEncoded = *(BYTE **)pbEncoded;
*pbEncoded++ = ASN_INTEGER;
if (pad)
{
*pbEncoded++ = significantBytes + 1;
*pbEncoded++ = padByte;
}
else
*pbEncoded++ = significantBytes;
for (; significantBytes > 0; significantBytes--)
*(pbEncoded++) = blob->pbData[significantBytes - 1];
return TRUE;
}
static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
......@@ -916,6 +986,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_INTEGER:
encodeFunc = CRYPT_AsnEncodeInt;
break;
case (WORD)X509_MULTI_BYTE_INTEGER:
encodeFunc = CRYPT_AsnEncodeInteger;
break;
case (WORD)X509_CHOICE_OF_TIME:
encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
break;
......@@ -1528,11 +1601,61 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
return FALSE;
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
*pcbStructInfo = sizeof(int);
memcpy(pvStructInfo, &val, sizeof(int));
return TRUE;
}
static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
DWORD bytesNeeded;
CRYPT_INTEGER_BLOB *blob;
if (!pbEncoded || !cbEncoded)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
if (pbEncoded[0] != ASN_INTEGER)
{
SetLastError(CRYPT_E_ASN1_BADTAG);
return FALSE;
}
if (cbEncoded <= 1)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
if (pbEncoded[1] > cbEncoded)
{
SetLastError(CRYPT_E_ASN1_EOD);
return FALSE;
}
bytesNeeded = pbEncoded[1] + sizeof(CRYPT_INTEGER_BLOB);
if (!pvStructInfo)
{
*pcbStructInfo = bytesNeeded;
return TRUE;
}
if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
pcbStructInfo, bytesNeeded))
return FALSE;
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
blob->cbData = pbEncoded[1];
blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
if (blob->cbData)
{
DWORD i;
for (i = 0; i < blob->cbData; i++)
blob->pbData[i] = *(pbEncoded + 2 + pbEncoded[1] - i - 1);
}
return TRUE;
}
#define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
do { \
BYTE i; \
......@@ -1667,7 +1790,6 @@ static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
{
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
*pcbStructInfo = sizeof(FILETIME);
ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
}
}
......@@ -1740,7 +1862,6 @@ static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
{
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
pvStructInfo = *(BYTE **)pvStructInfo;
*pcbStructInfo = sizeof(FILETIME);
ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
}
}
......@@ -1819,6 +1940,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_INTEGER:
decodeFunc = CRYPT_AsnDecodeInt;
break;
case (WORD)X509_MULTI_BYTE_INTEGER:
decodeFunc = CRYPT_AsnDecodeInteger;
break;
case (WORD)X509_CHOICE_OF_TIME:
decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
break;
......
......@@ -42,11 +42,29 @@ static const struct encodedInt ints[] = {
{ 0xbaddf00d, { 2, 4, 0xba, 0xdd, 0xf0, 0x0d } },
};
static void test_encodeint(DWORD dwEncoding)
struct encodedBigInt
{
BYTE *val;
BYTE *encoded;
BYTE *decoded;
};
static const struct encodedBigInt bigInts[] = {
{ "\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08",
"\x02\x0a\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff",
"\xff\xff\x01\x02\x03\x04\x05\x06\x07\x08" },
{ "\x08\x07\x06\x05\x04\x03\x02\x01\xff\xff\xff",
"\x02\x09\xff\x01\x02\x03\x04\x05\x06\x07\x08",
"\x08\x07\x06\x05\x04\x03\x02\x01\xff" },
};
static void test_encodeInt(DWORD dwEncoding)
{
DWORD bufSize = 0;
int i;
BOOL ret;
CRYPT_INTEGER_BLOB blob;
BYTE *buf = NULL;
/* CryptEncodeObjectEx with NULL bufSize crashes..
ret = CryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL,
......@@ -66,8 +84,7 @@ static void test_encodeint(DWORD dwEncoding)
"Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
{
BYTE *buf = NULL;
/* encode as normal integer */
ret = CryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0,
NULL, NULL, &bufSize);
ok(ret, "Expected success, got %ld\n", GetLastError());
......@@ -82,10 +99,54 @@ static void test_encodeint(DWORD dwEncoding)
"Encoded value of 0x%08x didn't match expected\n", ints[i].val);
LocalFree(buf);
}
/* encode as multibyte integer */
blob.cbData = sizeof(ints[i].val);
blob.pbData = (BYTE *)&ints[i].val;
ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
0, NULL, NULL, &bufSize);
ok(ret, "Expected success, got %ld\n", GetLastError());
ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
if (buf)
{
ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
buf[0]);
ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n",
buf[1], ints[i].encoded[1]);
ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1),
"Encoded value of 0x%08x didn't match expected\n", ints[i].val);
LocalFree(buf);
}
}
/* encode a couple bigger ints, just to show it's little-endian and leading
* sign bytes are dropped
*/
for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
{
blob.cbData = strlen(bigInts[i].val);
blob.pbData = (BYTE *)bigInts[i].val;
ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
0, NULL, NULL, &bufSize);
ok(ret, "Expected success, got %ld\n", GetLastError());
ret = CryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptEncodeObjectEx failed: %ld\n", GetLastError());
if (buf)
{
ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n",
buf[0]);
ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n",
buf[1], bigInts[i].encoded[1]);
ok(!memcmp(buf + 1, bigInts[i].encoded + 1,
bigInts[i].encoded[1] + 1),
"Encoded value didn't match expected\n");
LocalFree(buf);
}
}
}
static void test_decodeint(DWORD dwEncoding)
static void test_decodeInt(DWORD dwEncoding)
{
static const char bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff };
static const char testStr[] = { 0x16, 4, 't', 'e', 's', 't' };
......@@ -141,6 +202,33 @@ static void test_decodeint(DWORD dwEncoding)
LocalFree(buf);
}
}
for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++)
{
ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
(BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL,
&bufSize);
ok(ret && GetLastError() == NOERROR,
"Expected success and NOERROR, got %ld\n", GetLastError());
ret = CryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER,
(BYTE *)bigInts[i].encoded, bigInts[i].encoded[1] + 2,
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %ld\n", GetLastError());
ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB),
"Expected size at least %d, got %ld\n", sizeof(CRYPT_INTEGER_BLOB),
bufSize);
ok(buf != NULL, "Expected allocated buffer\n");
if (buf)
{
CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
ok(blob->cbData == strlen(bigInts[i].decoded),
"Expected len %d, got %ld\n", strlen(bigInts[i].decoded),
blob->cbData);
ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData),
"Unexpected value\n");
LocalFree(buf);
}
}
}
struct encodedFiletime
......@@ -646,8 +734,8 @@ START_TEST(encode)
for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++)
{
test_encodeint(encodings[i]);
test_decodeint(encodings[i]);
test_encodeInt(encodings[i]);
test_decodeInt(encodings[i]);
test_encodeFiletime(encodings[i]);
test_decodeFiletime(encodings[i]);
test_encodeName(encodings[i]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment