mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 12:49:45 +00:00
- implement encode and decode of BasicConstraints2, sequence of any
- fix encoding of integer value 0 - more tests
This commit is contained in:
parent
c48c3abd92
commit
94bd145865
@ -42,6 +42,7 @@
|
||||
#include "wine/debug.h"
|
||||
|
||||
/* a few asn.1 tags we need */
|
||||
#define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
|
||||
#define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
|
||||
#define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
|
||||
#define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
|
||||
@ -56,6 +57,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt);
|
||||
|
||||
static const WCHAR szDllName[] = { 'D','l','l',0 };
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
|
||||
|
||||
static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
|
||||
LPCSTR pszOID)
|
||||
{
|
||||
@ -767,8 +775,7 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
|
||||
pbEncoded = *(BYTE **)pbEncoded;
|
||||
/* FIXME: could this be encoded using X509_SEQUENCE_OF_ANY? */
|
||||
*pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCEOF;
|
||||
*pbEncoded++ = ASN_SEQUENCEOF;
|
||||
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &size);
|
||||
pbEncoded += size;
|
||||
for (i = 0; ret && i < info->cRDN; i++)
|
||||
@ -786,6 +793,84 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
if (!pbEncoded)
|
||||
{
|
||||
*pcbEncoded = 3;
|
||||
return TRUE;
|
||||
}
|
||||
if (*pcbEncoded < 3)
|
||||
{
|
||||
*pcbEncoded = 3;
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
*pcbEncoded = 3;
|
||||
*pbEncoded++ = ASN_BOOL;
|
||||
*pbEncoded++ = 1;
|
||||
*pbEncoded++ = val ? 0xff : 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
CERT_BASIC_CONSTRAINTS2_INFO *info =
|
||||
(CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
|
||||
DWORD bytesNeeded = 0, lenBytes, caLen = 0, pathConstraintLen = 0;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
return FALSE;
|
||||
}
|
||||
if (info->fCA)
|
||||
{
|
||||
ret = CRYPT_EncodeBool(TRUE, NULL, &caLen);
|
||||
if (ret)
|
||||
bytesNeeded += caLen;
|
||||
}
|
||||
if (info->fPathLenConstraint)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER,
|
||||
&info->dwPathLenConstraint, 0, NULL, NULL, &pathConstraintLen);
|
||||
if (ret)
|
||||
bytesNeeded += pathConstraintLen;
|
||||
}
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
|
||||
bytesNeeded += 1 + lenBytes;
|
||||
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_SEQUENCE;
|
||||
CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
if (info->fCA)
|
||||
{
|
||||
ret = CRYPT_EncodeBool(TRUE, pbEncoded, &caLen);
|
||||
if (ret)
|
||||
pbEncoded += caLen;
|
||||
}
|
||||
if (info->fPathLenConstraint)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER,
|
||||
&info->dwPathLenConstraint, 0, NULL, pbEncoded, &pathConstraintLen);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
@ -898,9 +983,11 @@ static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
neg = TRUE;
|
||||
val = -val;
|
||||
}
|
||||
for (significantBytes = sizeof(val); !(val & 0xff000000);
|
||||
val <<= 8, significantBytes--)
|
||||
for (significantBytes = sizeof(val); significantBytes > 0 &&
|
||||
!(val & 0xff000000); val <<= 8, significantBytes--)
|
||||
;
|
||||
if (significantBytes == 0)
|
||||
significantBytes = 1;
|
||||
if (neg)
|
||||
{
|
||||
val = -val;
|
||||
@ -966,6 +1053,8 @@ static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
|
||||
for (; significantBytes > 0 &&
|
||||
blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
|
||||
;
|
||||
if (significantBytes == 0)
|
||||
significantBytes = 1;
|
||||
if (blob->pbData[significantBytes - 1] < 0x80)
|
||||
{
|
||||
padByte = 0xff;
|
||||
@ -978,6 +1067,8 @@ static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
|
||||
for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
|
||||
significantBytes--)
|
||||
;
|
||||
if (significantBytes == 0)
|
||||
significantBytes = 1;
|
||||
if (blob->pbData[significantBytes - 1] > 0x7f)
|
||||
{
|
||||
padByte = 0;
|
||||
@ -1042,6 +1133,8 @@ static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
|
||||
for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
|
||||
significantBytes--)
|
||||
;
|
||||
if (significantBytes == 0)
|
||||
significantBytes = 1;
|
||||
if (blob->pbData[significantBytes - 1] > 0x7f)
|
||||
pad = TRUE;
|
||||
}
|
||||
@ -1206,6 +1299,44 @@ static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
DWORD bytesNeeded, dataLen, lenBytes, i;
|
||||
CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
|
||||
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
return FALSE;
|
||||
}
|
||||
/* FIXME: use exception handling to catch bogus pointers */
|
||||
for (i = 0, dataLen = 0; i < seq->cValue; i++)
|
||||
dataLen += seq->rgValue[i].cbData;
|
||||
CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
|
||||
bytesNeeded = 1 + lenBytes + dataLen;
|
||||
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_SEQUENCEOF;
|
||||
CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
|
||||
pbEncoded += lenBytes;
|
||||
for (i = 0; i < seq->cValue; i++)
|
||||
{
|
||||
memcpy(pbEncoded, seq->rgValue[i].pbData, seq->rgValue[i].cbData);
|
||||
pbEncoded += seq->rgValue[i].cbData;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
|
||||
DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
|
||||
|
||||
@ -1235,6 +1366,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
}
|
||||
|
||||
SetLastError(NOERROR);
|
||||
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
|
||||
*(BYTE **)pvEncoded = NULL;
|
||||
if (!HIWORD(lpszStructType))
|
||||
{
|
||||
switch (LOWORD(lpszStructType))
|
||||
@ -1242,6 +1375,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
case (WORD)X509_NAME:
|
||||
encodeFunc = CRYPT_AsnEncodeName;
|
||||
break;
|
||||
case (WORD)X509_BASIC_CONSTRAINTS2:
|
||||
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
|
||||
break;
|
||||
case (WORD)X509_OCTET_STRING:
|
||||
encodeFunc = CRYPT_AsnEncodeOctets;
|
||||
break;
|
||||
@ -1264,6 +1400,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
case (WORD)X509_CHOICE_OF_TIME:
|
||||
encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
|
||||
break;
|
||||
case (WORD)X509_SEQUENCE_OF_ANY:
|
||||
encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
|
||||
break;
|
||||
case (WORD)PKCS_UTC_TIME:
|
||||
encodeFunc = CRYPT_AsnEncodeUtcTime;
|
||||
break;
|
||||
@ -1279,6 +1418,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
encodeFunc = CRYPT_AsnEncodeBits;
|
||||
else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
|
||||
encodeFunc = CRYPT_AsnEncodeOctets;
|
||||
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
|
||||
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
|
||||
else
|
||||
TRACE("OID %s not found or unimplemented, looking for DLL\n",
|
||||
debugstr_a(lpszStructType));
|
||||
@ -1915,6 +2056,119 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
|
||||
BOOL *val)
|
||||
{
|
||||
if (cbEncoded < 3)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_CORRUPT);
|
||||
return FALSE;
|
||||
}
|
||||
if (pbEncoded[0] != ASN_BOOL)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_BADTAG);
|
||||
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;
|
||||
}
|
||||
*val = pbEncoded[2] ? TRUE : FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
DWORD bytesNeeded, dataLen;
|
||||
BYTE lenBytes;
|
||||
CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
|
||||
BOOL ret = TRUE;
|
||||
|
||||
if (!pbEncoded)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_EOD);
|
||||
return FALSE;
|
||||
}
|
||||
if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
|
||||
return FALSE;
|
||||
/* sanity-check length, space enough for 7 bytes of integer and 3 bytes of
|
||||
* bool
|
||||
*/
|
||||
if (dataLen > 10)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_CORRUPT);
|
||||
return FALSE;
|
||||
}
|
||||
if (pbEncoded[0] != ASN_SEQUENCE)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_BADTAG);
|
||||
return FALSE;
|
||||
}
|
||||
lenBytes = GET_LEN_BYTES(pbEncoded[1]);
|
||||
bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
|
||||
if (!pvStructInfo)
|
||||
{
|
||||
*pcbStructInfo = bytesNeeded;
|
||||
return TRUE;
|
||||
}
|
||||
pbEncoded += 1 + lenBytes;
|
||||
cbEncoded -= 1 + lenBytes;
|
||||
if (cbEncoded)
|
||||
{
|
||||
DWORD size;
|
||||
|
||||
if (pbEncoded[0] == ASN_BOOL)
|
||||
{
|
||||
ret = CRYPT_DecodeBool(pbEncoded, cbEncoded, &info.fCA);
|
||||
if (ret)
|
||||
{
|
||||
cbEncoded -= 2 + pbEncoded[1];
|
||||
pbEncoded += 2 + pbEncoded[1];
|
||||
}
|
||||
}
|
||||
if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
|
||||
{
|
||||
size = sizeof(info.dwPathLenConstraint);
|
||||
ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
|
||||
pbEncoded, cbEncoded, 0, NULL, &info.dwPathLenConstraint,
|
||||
&size);
|
||||
if (ret)
|
||||
{
|
||||
cbEncoded -= 2 + pbEncoded[1];
|
||||
pbEncoded += 2 + pbEncoded[1];
|
||||
if (cbEncoded)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_CORRUPT);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
info.fPathLenConstraint = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
CERT_BASIC_CONSTRAINTS2_INFO *out;
|
||||
|
||||
if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
|
||||
pcbStructInfo, bytesNeeded))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
out = (CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
|
||||
memcpy(out, &info, sizeof(*out));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
@ -2481,6 +2735,94 @@ static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
{
|
||||
DWORD bytesNeeded, dataLen, remainingLen, cValue;
|
||||
BYTE lenBytes;
|
||||
BOOL ret = TRUE;
|
||||
const BYTE *ptr;
|
||||
|
||||
if (!pbEncoded || !cbEncoded)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_EOD);
|
||||
return FALSE;
|
||||
}
|
||||
if (pbEncoded[0] != ASN_SEQUENCEOF)
|
||||
{
|
||||
SetLastError(CRYPT_E_ASN1_BADTAG);
|
||||
return FALSE;
|
||||
}
|
||||
if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
|
||||
return FALSE;
|
||||
lenBytes = GET_LEN_BYTES(pbEncoded[1]);
|
||||
bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
|
||||
cValue = 0;
|
||||
ptr = pbEncoded + 1 + lenBytes;
|
||||
remainingLen = dataLen;
|
||||
while (ret && remainingLen)
|
||||
{
|
||||
DWORD nextLen;
|
||||
|
||||
ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
|
||||
if (ret)
|
||||
{
|
||||
DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
|
||||
|
||||
remainingLen -= 1 + nextLenBytes + nextLen;
|
||||
ptr += 1 + nextLenBytes + nextLen;
|
||||
bytesNeeded += sizeof(CRYPT_DER_BLOB);
|
||||
if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
|
||||
bytesNeeded += 1 + nextLenBytes + nextLen;
|
||||
cValue++;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_SEQUENCE_OF_ANY *seq;
|
||||
BYTE *nextPtr;
|
||||
DWORD i;
|
||||
|
||||
if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
|
||||
pcbStructInfo, bytesNeeded))
|
||||
return FALSE;
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
|
||||
seq->cValue = cValue;
|
||||
seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq + sizeof(*seq));
|
||||
nextPtr = (BYTE *)seq->rgValue + cValue * sizeof(CRYPT_DER_BLOB);
|
||||
ptr = pbEncoded + 1 + lenBytes;
|
||||
remainingLen = dataLen;
|
||||
i = 0;
|
||||
while (ret && remainingLen)
|
||||
{
|
||||
DWORD nextLen;
|
||||
|
||||
ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
|
||||
if (ret)
|
||||
{
|
||||
DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
|
||||
|
||||
seq->rgValue[i].cbData = 1 + nextLenBytes + nextLen;
|
||||
if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
|
||||
seq->rgValue[i].pbData = (BYTE *)ptr;
|
||||
else
|
||||
{
|
||||
seq->rgValue[i].pbData = nextPtr;
|
||||
memcpy(nextPtr, ptr, 1 + nextLenBytes + nextLen);
|
||||
nextPtr += 1 + nextLenBytes + nextLen;
|
||||
}
|
||||
remainingLen -= 1 + nextLenBytes + nextLen;
|
||||
ptr += 1 + nextLenBytes + nextLen;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
|
||||
DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
|
||||
|
||||
@ -2510,6 +2852,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
}
|
||||
|
||||
SetLastError(NOERROR);
|
||||
if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
|
||||
*(BYTE **)pvStructInfo = NULL;
|
||||
if (!HIWORD(lpszStructType))
|
||||
{
|
||||
switch (LOWORD(lpszStructType))
|
||||
@ -2517,6 +2861,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
case (WORD)X509_NAME:
|
||||
decodeFunc = CRYPT_AsnDecodeName;
|
||||
break;
|
||||
case (WORD)X509_BASIC_CONSTRAINTS2:
|
||||
decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
|
||||
break;
|
||||
case (WORD)X509_OCTET_STRING:
|
||||
decodeFunc = CRYPT_AsnDecodeOctets;
|
||||
break;
|
||||
@ -2539,6 +2886,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
case (WORD)X509_CHOICE_OF_TIME:
|
||||
decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
|
||||
break;
|
||||
case (WORD)X509_SEQUENCE_OF_ANY:
|
||||
decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
|
||||
break;
|
||||
case (WORD)PKCS_UTC_TIME:
|
||||
decodeFunc = CRYPT_AsnDecodeUtcTime;
|
||||
break;
|
||||
@ -2554,6 +2904,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
|
||||
decodeFunc = CRYPT_AsnDecodeBits;
|
||||
else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
|
||||
decodeFunc = CRYPT_AsnDecodeOctets;
|
||||
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
|
||||
decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
|
||||
else
|
||||
TRACE("OID %s not found or unimplemented, looking for DLL\n",
|
||||
debugstr_a(lpszStructType));
|
||||
|
@ -977,6 +977,211 @@ static void test_decodeBits(DWORD dwEncoding)
|
||||
}
|
||||
}
|
||||
|
||||
struct Constraints2
|
||||
{
|
||||
CERT_BASIC_CONSTRAINTS2_INFO info;
|
||||
const BYTE *encoded;
|
||||
};
|
||||
|
||||
static const struct Constraints2 constraints2[] = {
|
||||
/* empty constraints */
|
||||
{ { FALSE, FALSE, 0}, "\x30\x00" },
|
||||
/* can be a CA */
|
||||
{ { TRUE, FALSE, 0}, "\x30\x03\x01\x01\xff" },
|
||||
/* has path length constraints set (MSDN implies fCA needs to be TRUE as well,
|
||||
* but that's not the case
|
||||
*/
|
||||
{ { FALSE, TRUE, 0}, "\x30\x03\x02\x01\x00" },
|
||||
/* can be a CA and has path length constraints set */
|
||||
{ { TRUE, TRUE, 1}, "\x30\x06\x01\x01\xff\x02\x01\x01" },
|
||||
};
|
||||
|
||||
static void test_encodeBasicConstraints(DWORD dwEncoding)
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
/* First test with the simpler info2 */
|
||||
for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
|
||||
{
|
||||
BOOL ret;
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
|
||||
&constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == constraints2[i].encoded[1] + 2,
|
||||
"Expected %d bytes, got %ld\n", constraints2[i].encoded[1] + 2,
|
||||
bufSize);
|
||||
ok(!memcmp(buf, constraints2[i].encoded,
|
||||
constraints2[i].encoded[1] + 2), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_decodeBasicConstraints(DWORD dwEncoding)
|
||||
{
|
||||
static const BYTE inverted[] = "\x30\x06\x02\x01\x01\x01\x01\xff";
|
||||
static const struct Constraints2 badBool = { { TRUE, TRUE, 1 },
|
||||
"\x30\x06\x01\x01\x01\x02\x01\x01" };
|
||||
DWORD i;
|
||||
BOOL ret;
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
|
||||
/* First test with simpler info2 */
|
||||
for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
|
||||
{
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
|
||||
constraints2[i].encoded, constraints2[i].encoded[1] + 2,
|
||||
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
CERT_BASIC_CONSTRAINTS2_INFO *info =
|
||||
(CERT_BASIC_CONSTRAINTS2_INFO *)buf;
|
||||
|
||||
ok(!memcmp(info, &constraints2[i].info, sizeof(*info)),
|
||||
"Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
/* Check with the order of encoded elements inverted */
|
||||
buf = (PBYTE)1;
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
|
||||
inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
|
||||
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
|
||||
ok(!buf, "Expected buf to be set to NULL\n");
|
||||
/* Check with a non-DER bool */
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
|
||||
badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
|
||||
(BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
CERT_BASIC_CONSTRAINTS2_INFO *info =
|
||||
(CERT_BASIC_CONSTRAINTS2_INFO *)buf;
|
||||
|
||||
ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* Check with a non-basic constraints value */
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
|
||||
names[0].encoded, names[0].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL,
|
||||
(BYTE *)&buf, &bufSize);
|
||||
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
|
||||
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
|
||||
}
|
||||
|
||||
static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01,
|
||||
0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02,
|
||||
0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
|
||||
|
||||
static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30,
|
||||
0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f,
|
||||
0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02,
|
||||
0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d };
|
||||
|
||||
static void test_encodeSequenceOfAny(DWORD dwEncoding)
|
||||
{
|
||||
CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])];
|
||||
CRYPT_SEQUENCE_OF_ANY seq;
|
||||
DWORD i;
|
||||
BOOL ret;
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
|
||||
/* Encode a homogenous sequence */
|
||||
for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++)
|
||||
{
|
||||
blobs[i].cbData = ints[i].encoded[1] + 2;
|
||||
blobs[i].pbData = ints[i].encoded;
|
||||
}
|
||||
seq.cValue = sizeof(ints) / sizeof(ints[0]);
|
||||
seq.rgValue = blobs;
|
||||
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == sizeof(intSequence), "Expected %d bytes, got %ld\n",
|
||||
sizeof(intSequence), bufSize);
|
||||
ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
/* Change the type of the first element in the sequence, and give it
|
||||
* another go
|
||||
*/
|
||||
blobs[0].cbData = times[0].encodedTime[1] + 2;
|
||||
blobs[0].pbData = (BYTE *)times[0].encodedTime;
|
||||
ret = CryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
ok(bufSize == sizeof(mixedSequence), "Expected %d bytes, got %ld\n",
|
||||
sizeof(mixedSequence), bufSize);
|
||||
ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2),
|
||||
"Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_decodeSequenceOfAny(DWORD dwEncoding)
|
||||
{
|
||||
BOOL ret;
|
||||
BYTE *buf = NULL;
|
||||
DWORD bufSize = 0;
|
||||
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence,
|
||||
intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
|
||||
DWORD i;
|
||||
|
||||
ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
|
||||
"Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
|
||||
seq->cValue);
|
||||
for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++)
|
||||
{
|
||||
ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2,
|
||||
"Expected %d bytes, got %ld\n", ints[i].encoded[1] + 2,
|
||||
seq->rgValue[i].cbData);
|
||||
ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded,
|
||||
ints[i].encoded[1] + 2), "Unexpected value\n");
|
||||
}
|
||||
LocalFree(buf);
|
||||
}
|
||||
ret = CryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence,
|
||||
mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
|
||||
&bufSize);
|
||||
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
|
||||
if (buf)
|
||||
{
|
||||
CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf;
|
||||
|
||||
ok(seq->cValue == sizeof(ints) / sizeof(ints[0]),
|
||||
"Expected %d elements, got %ld\n", sizeof(ints) / sizeof(ints[0]),
|
||||
seq->cValue);
|
||||
/* Just check the first element since it's all that changed */
|
||||
ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2,
|
||||
"Expected %d bytes, got %ld\n", times[0].encodedTime[1] + 2,
|
||||
seq->rgValue[0].cbData);
|
||||
ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime,
|
||||
times[0].encodedTime[1] + 2), "Unexpected value\n");
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_registerOIDFunction(void)
|
||||
{
|
||||
static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
|
||||
@ -1051,6 +1256,10 @@ START_TEST(encode)
|
||||
test_decodeOctets(encodings[i]);
|
||||
test_encodeBits(encodings[i]);
|
||||
test_decodeBits(encodings[i]);
|
||||
test_encodeBasicConstraints(encodings[i]);
|
||||
test_decodeBasicConstraints(encodings[i]);
|
||||
test_encodeSequenceOfAny(encodings[i]);
|
||||
test_decodeSequenceOfAny(encodings[i]);
|
||||
}
|
||||
test_registerOIDFunction();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user