crypt32: More encoding/decoding.

Add support for encoding/decoding basic constraints and enhanced key
usage, with tests.
oldstable
Juan Lang 2006-02-16 19:39:27 +01:00 committed by Alexandre Julliard
parent 15e5dc29c1
commit 11fe62de8f
2 changed files with 399 additions and 21 deletions

View File

@ -70,6 +70,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
struct GenericArray
{
DWORD cItems;
BYTE *rgItems;
};
typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
BYTE *, DWORD *);
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
@ -91,6 +97,9 @@ static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
@ -1442,6 +1451,46 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret;
__TRY
{
const CERT_BASIC_CONSTRAINTS_INFO *info =
(const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
struct AsnEncodeSequenceItem items[3] = {
{ &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
{ 0 }
};
DWORD cItem = 1;
if (info->fPathLenConstraint)
{
items[cItem].pvStructInfo = &info->dwPathLenConstraint;
items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
cItem++;
}
if (info->cSubtreesConstraint)
{
items[cItem].pvStructInfo = &info->cSubtreesConstraint;
items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
cItem++;
}
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
dwFlags, pEncodePara, pbEncoded, pcbEncoded);
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
@ -2191,6 +2240,70 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
return ret;
}
static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret;
__TRY
{
const CERT_ENHKEY_USAGE *usage =
(const CERT_ENHKEY_USAGE *)pvStructInfo;
DWORD bytesNeeded = 0, lenBytes, size, i;
ret = TRUE;
for (i = 0; ret && i < usage->cUsageIdentifier; i++)
{
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
usage->rgpszUsageIdentifier[i],
dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
if (ret)
bytesNeeded += size;
}
CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
bytesNeeded += 1 + lenBytes;
if (ret)
{
if (!pbEncoded)
*pcbEncoded = bytesNeeded;
else
{
if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
pbEncoded, pcbEncoded, bytesNeeded)))
{
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
pbEncoded = *(BYTE **)pbEncoded;
*pbEncoded++ = ASN_SEQUENCEOF;
CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
&lenBytes);
pbEncoded += lenBytes;
for (i = 0; ret && i < usage->cUsageIdentifier; i++)
{
size = bytesNeeded;
ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
usage->rgpszUsageIdentifier[i],
dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
&size);
if (ret)
{
pbEncoded += size;
bytesNeeded -= size;
}
}
}
}
}
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
void *pvEncoded, DWORD *pcbEncoded)
@ -2244,6 +2357,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_ALTERNATE_NAME:
encodeFunc = CRYPT_AsnEncodeAltName;
break;
case (WORD)X509_BASIC_CONSTRAINTS:
encodeFunc = CRYPT_AsnEncodeBasicConstraints;
break;
case (WORD)X509_BASIC_CONSTRAINTS2:
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
break;
@ -2281,6 +2397,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_CRL_DIST_POINTS:
encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
break;
case (WORD)X509_ENHANCED_KEY_USAGE:
encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
break;
default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
}
@ -2295,6 +2414,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_CONSTRAINTS))
encodeFunc = CRYPT_AsnEncodeBasicConstraints;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
@ -2307,6 +2428,10 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
encodeFunc = CRYPT_AsnEncodeAltName;
else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
encodeFunc = CRYPT_AsnEncodeAltName;
else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
else
TRACE("OID %s not found or unimplemented, looking for DLL\n",
debugstr_a(lpszStructType));
@ -2704,12 +2829,6 @@ struct AsnArrayItemSize
DWORD size;
};
struct GenericArray
{
DWORD cItems;
BYTE *rgItems;
};
/* Decodes an array of like types into a struct GenericArray.
* The layout and decoding of the array are described by a struct
* AsnArrayDescriptor.
@ -3993,6 +4112,60 @@ static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
BOOL ret;
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE,
offsetof(CERT_NAME_BLOB, pbData) };
struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
pDecodePara, pvStructInfo, *pcbStructInfo);
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
pDecodePara, pvStructInfo, pcbStructInfo,
entries ? entries->rgItems : NULL);
TRACE("Returning %d (%08lx)\n", ret, GetLastError());
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
BOOL ret;
__TRY
{
struct AsnDecodeSequenceItem items[] = {
{ ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType),
CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 },
{ ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
{ ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints,
sizeof(struct GenericArray), TRUE, TRUE,
offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 },
};
ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
@ -5078,6 +5251,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType,
return ret;
}
static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
{
BOOL ret;
TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
pDecodePara, pvStructInfo, *pcbStructInfo);
__TRY
{
struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), TRUE, 0 };
ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
pDecodePara, pvStructInfo, pcbStructInfo, NULL);
}
__EXCEPT_PAGE_FAULT
{
SetLastError(STATUS_ACCESS_VIOLATION);
ret = FALSE;
}
__ENDTRY
return ret;
}
BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
@ -5141,6 +5340,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_ALTERNATE_NAME:
decodeFunc = CRYPT_AsnDecodeAltName;
break;
case (WORD)X509_BASIC_CONSTRAINTS:
decodeFunc = CRYPT_AsnDecodeBasicConstraints;
break;
case (WORD)X509_BASIC_CONSTRAINTS2:
decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
break;
@ -5178,6 +5380,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_CRL_DIST_POINTS:
decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
break;
case (WORD)X509_ENHANCED_KEY_USAGE:
decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
break;
default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
}
@ -5192,6 +5397,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_CONSTRAINTS))
decodeFunc = CRYPT_AsnDecodeBasicConstraints;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
@ -5204,6 +5411,10 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
decodeFunc = CRYPT_AsnDecodeAltName;
else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
decodeFunc = CRYPT_AsnDecodeAltName;
else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
else
TRACE("OID %s not found or unimplemented, looking for DLL\n",
debugstr_a(lpszStructType));

View File

@ -654,7 +654,7 @@ static const struct EncodedName names[] = {
{ sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, bin45 },
};
static const BYTE emptyName[] = { 0x30, 0 };
static const BYTE emptySequence[] = { 0x30, 0 };
static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
static const BYTE twoRDNs[] = {
0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04,
@ -731,7 +731,7 @@ static void test_encodeName(DWORD dwEncoding)
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(!memcmp(buf, emptyName, sizeof(emptyName)),
ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
"Got unexpected encoding for empty name\n");
LocalFree(buf);
}
@ -921,8 +921,8 @@ static void test_decodeName(DWORD dwEncoding)
}
/* test empty name */
bufSize = 0;
ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName,
emptyName[1] + 2,
ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
emptySequence[1] + 2,
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
(BYTE *)&buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
@ -990,7 +990,6 @@ static void test_decodeName(DWORD dwEncoding)
}
}
static const BYTE emptyAltName[] = { 0x30, 0x00 };
static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
'h','q','.','o','r','g',0 };
@ -1019,9 +1018,9 @@ static void test_encodeAltName(DWORD dwEncoding)
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
if (buf)
{
ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n",
sizeof(emptyAltName), size);
ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n");
ok(size == sizeof(emptySequence), "Expected size %d, got %ld\n",
sizeof(emptySequence), size);
ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
LocalFree(buf);
}
/* Test with an empty entry */
@ -1124,8 +1123,8 @@ static void test_decodeAltName(DWORD dwEncoding)
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
/* Now expected cases */
ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName,
emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
&bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
@ -1424,17 +1423,29 @@ static const struct Constraints2 constraints2[] = {
{ { TRUE, TRUE, 1}, bin62 },
};
static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 };
static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11,
0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16,
0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93,
0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00,
0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26,
0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30,
0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19,
0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 };
static void test_encodeBasicConstraints(DWORD dwEncoding)
{
DWORD i;
DWORD i, bufSize = 0;
CERT_BASIC_CONSTRAINTS_INFO info;
CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName),
(LPBYTE)encodedDomainName };
BOOL ret;
BYTE *buf = NULL;
/* 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);
@ -1449,6 +1460,39 @@ static void test_encodeBasicConstraints(DWORD dwEncoding)
LocalFree(buf);
}
}
/* Now test with more complex basic constraints */
info.SubjectType.cbData = 0;
info.fPathLenConstraint = FALSE;
info.cSubtreesConstraint = 0;
ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(bufSize == sizeof(emptyConstraint), "Expected %d bytes, got %ld\n",
sizeof(emptyConstraint), bufSize);
ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)),
"Unexpected value\n");
LocalFree(buf);
}
/* None of the certs I examined had any subtree constraint, but I test one
* anyway just in case.
*/
info.cSubtreesConstraint = 1;
info.rgSubtreesConstraint = &nameBlob;
ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(bufSize == sizeof(constraintWithDomainName),
"Expected %d bytes, got %ld\n", sizeof(constraintWithDomainName),
bufSize);
ok(!memcmp(buf, constraintWithDomainName,
sizeof(constraintWithDomainName)), "Unexpected value\n");
LocalFree(buf);
}
/* FIXME: test encoding with subject type. */
}
static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01,0 };
@ -1507,6 +1551,41 @@ static void test_decodeBasicConstraints(DWORD dwEncoding)
(BYTE *)&buf, &bufSize);
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
/* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */
ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL,
(BYTE *)&buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n");
LocalFree(buf);
}
ret = CryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS,
constraintWithDomainName, sizeof(constraintWithDomainName),
CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf;
ok(info->SubjectType.cbData == 0, "Expected no subject type\n");
ok(!info->fPathLenConstraint, "Expected no path length constraint\n");
ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n");
if (info->cSubtreesConstraint && info->rgSubtreesConstraint)
{
ok(info->rgSubtreesConstraint[0].cbData ==
sizeof(encodedDomainName), "Expected %d bytes, got %ld\n",
sizeof(encodedDomainName), info->rgSubtreesConstraint[0].cbData);
ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName,
sizeof(encodedDomainName)), "Unexpected value\n");
}
LocalFree(buf);
}
}
/* These are terrible public keys of course, I'm just testing encoding */
@ -2761,6 +2840,92 @@ static void test_decodeCRLToBeSigned(DWORD dwEncoding)
}
}
static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
static const BYTE encodedUsage[] = {
0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
static void test_encodeEnhancedKeyUsage(DWORD dwEncoding)
{
BOOL ret;
BYTE *buf = NULL;
DWORD size = 0;
CERT_ENHKEY_USAGE usage;
/* Test with empty usage */
usage.cUsageIdentifier = 0;
ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(size == sizeof(emptySequence), "Expected size %d, got %ld\n",
sizeof(emptySequence), size);
ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n");
LocalFree(buf);
}
/* Test with a few usages */
usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]);
usage.rgpszUsageIdentifier = (LPSTR *)keyUsages;
ret = CryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
ok(size == sizeof(encodedUsage), "Expected size %d, got %ld\n",
sizeof(encodedUsage), size);
ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n");
LocalFree(buf);
}
}
static void test_decodeEnhancedKeyUsage(DWORD dwEncoding)
{
BOOL ret;
LPBYTE buf = NULL;
DWORD size = 0;
ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL,
(BYTE *)&buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
ok(size >= sizeof(CERT_ENHKEY_USAGE),
"Expected size at least %d, got %ld\n", sizeof(CERT_ENHKEY_USAGE),
size);
ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %ld\n",
usage->cUsageIdentifier);
LocalFree(buf);
}
ret = CryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE,
encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL,
(BYTE *)&buf, &size);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf)
{
CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf;
DWORD i;
ok(size >= sizeof(CERT_ENHKEY_USAGE),
"Expected size at least %d, got %ld\n", sizeof(CERT_ENHKEY_USAGE),
size);
ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]),
"Expected %d CRL entries, got %ld\n",
sizeof(keyUsages) / sizeof(keyUsages[0]),
usage->cUsageIdentifier);
for (i = 0; i < usage->cUsageIdentifier; i++)
ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected OID %s, got %s\n", keyUsages[i],
usage->rgpszUsageIdentifier[i]);
LocalFree(buf);
}
}
/* Free *pInfo with HeapFree */
static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
{
@ -2909,6 +3074,8 @@ START_TEST(encode)
test_decodeCRLDistPoints(encodings[i]);
test_encodeCRLToBeSigned(encodings[i]);
test_decodeCRLToBeSigned(encodings[i]);
test_encodeEnhancedKeyUsage(encodings[i]);
test_decodeEnhancedKeyUsage(encodings[i]);
}
testPortPublicKeyInfo();
}