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); WINE_DEFAULT_DEBUG_CHANNEL(crypt);
struct GenericArray
{
DWORD cItems;
BYTE *rgItems;
};
typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *, typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
BYTE *, DWORD *); BYTE *, DWORD *);
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *, 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, static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); 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, static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded); PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
@ -1442,6 +1451,46 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
return ret; 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, static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded) PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
@ -2191,6 +2240,70 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
return ret; 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, BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
void *pvEncoded, DWORD *pcbEncoded) void *pvEncoded, DWORD *pcbEncoded)
@ -2244,6 +2357,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_ALTERNATE_NAME: case (WORD)X509_ALTERNATE_NAME:
encodeFunc = CRYPT_AsnEncodeAltName; encodeFunc = CRYPT_AsnEncodeAltName;
break; break;
case (WORD)X509_BASIC_CONSTRAINTS:
encodeFunc = CRYPT_AsnEncodeBasicConstraints;
break;
case (WORD)X509_BASIC_CONSTRAINTS2: case (WORD)X509_BASIC_CONSTRAINTS2:
encodeFunc = CRYPT_AsnEncodeBasicConstraints2; encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
break; break;
@ -2281,6 +2397,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_CRL_DIST_POINTS: case (WORD)X509_CRL_DIST_POINTS:
encodeFunc = CRYPT_AsnEncodeCRLDistPoints; encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
break; break;
case (WORD)X509_ENHANCED_KEY_USAGE:
encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
break;
default: default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
} }
@ -2295,6 +2414,8 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
encodeFunc = CRYPT_AsnEncodeBits; encodeFunc = CRYPT_AsnEncodeBits;
else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER)) else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
encodeFunc = CRYPT_AsnEncodeOctets; encodeFunc = CRYPT_AsnEncodeOctets;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
encodeFunc = CRYPT_AsnEncodeBasicConstraints;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
encodeFunc = CRYPT_AsnEncodeBasicConstraints2; encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
@ -2307,6 +2428,10 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
encodeFunc = CRYPT_AsnEncodeAltName; encodeFunc = CRYPT_AsnEncodeAltName;
else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
encodeFunc = CRYPT_AsnEncodeAltName; 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 else
TRACE("OID %s not found or unimplemented, looking for DLL\n", TRACE("OID %s not found or unimplemented, looking for DLL\n",
debugstr_a(lpszStructType)); debugstr_a(lpszStructType));
@ -2704,12 +2829,6 @@ struct AsnArrayItemSize
DWORD size; DWORD size;
}; };
struct GenericArray
{
DWORD cItems;
BYTE *rgItems;
};
/* Decodes an array of like types into a struct GenericArray. /* Decodes an array of like types into a struct GenericArray.
* The layout and decoding of the array are described by a struct * The layout and decoding of the array are described by a struct
* AsnArrayDescriptor. * AsnArrayDescriptor.
@ -3993,6 +4112,60 @@ static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
return ret; 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, static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
@ -5078,6 +5251,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType,
return ret; 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, BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo) PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
@ -5141,6 +5340,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_ALTERNATE_NAME: case (WORD)X509_ALTERNATE_NAME:
decodeFunc = CRYPT_AsnDecodeAltName; decodeFunc = CRYPT_AsnDecodeAltName;
break; break;
case (WORD)X509_BASIC_CONSTRAINTS:
decodeFunc = CRYPT_AsnDecodeBasicConstraints;
break;
case (WORD)X509_BASIC_CONSTRAINTS2: case (WORD)X509_BASIC_CONSTRAINTS2:
decodeFunc = CRYPT_AsnDecodeBasicConstraints2; decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
break; break;
@ -5178,6 +5380,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
case (WORD)X509_CRL_DIST_POINTS: case (WORD)X509_CRL_DIST_POINTS:
decodeFunc = CRYPT_AsnDecodeCRLDistPoints; decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
break; break;
case (WORD)X509_ENHANCED_KEY_USAGE:
decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
break;
default: default:
FIXME("%d: unimplemented\n", LOWORD(lpszStructType)); FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
} }
@ -5192,6 +5397,8 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
decodeFunc = CRYPT_AsnDecodeBits; decodeFunc = CRYPT_AsnDecodeBits;
else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER)) else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
decodeFunc = CRYPT_AsnDecodeOctets; decodeFunc = CRYPT_AsnDecodeOctets;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
decodeFunc = CRYPT_AsnDecodeBasicConstraints;
else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
decodeFunc = CRYPT_AsnDecodeBasicConstraints2; decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
@ -5204,6 +5411,10 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
decodeFunc = CRYPT_AsnDecodeAltName; decodeFunc = CRYPT_AsnDecodeAltName;
else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
decodeFunc = CRYPT_AsnDecodeAltName; 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 else
TRACE("OID %s not found or unimplemented, looking for DLL\n", TRACE("OID %s not found or unimplemented, looking for DLL\n",
debugstr_a(lpszStructType)); debugstr_a(lpszStructType));

View File

@ -654,7 +654,7 @@ static const struct EncodedName names[] = {
{ sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, bin45 }, { 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 emptyRDNs[] = { 0x30, 0x02, 0x31, 0 };
static const BYTE twoRDNs[] = { static const BYTE twoRDNs[] = {
0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04, 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()); ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
if (buf) if (buf)
{ {
ok(!memcmp(buf, emptyName, sizeof(emptyName)), ok(!memcmp(buf, emptySequence, sizeof(emptySequence)),
"Got unexpected encoding for empty name\n"); "Got unexpected encoding for empty name\n");
LocalFree(buf); LocalFree(buf);
} }
@ -921,8 +921,8 @@ static void test_decodeName(DWORD dwEncoding)
} }
/* test empty name */ /* test empty name */
bufSize = 0; bufSize = 0;
ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptyName, ret = CryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence,
emptyName[1] + 2, emptySequence[1] + 2,
CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL,
(BYTE *)&buf, &bufSize); (BYTE *)&buf, &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError()); 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 BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 };
static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e', static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e',
'h','q','.','o','r','g',0 }; 'h','q','.','o','r','g',0 };
@ -1019,9 +1018,9 @@ static void test_encodeAltName(DWORD dwEncoding)
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size); CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
if (buf) if (buf)
{ {
ok(size == sizeof(emptyAltName), "Expected size %d, got %ld\n", ok(size == sizeof(emptySequence), "Expected size %d, got %ld\n",
sizeof(emptyAltName), size); sizeof(emptySequence), size);
ok(!memcmp(buf, emptyAltName, size), "Unexpected value\n"); ok(!memcmp(buf, emptySequence, size), "Unexpected value\n");
LocalFree(buf); LocalFree(buf);
} }
/* Test with an empty entry */ /* Test with an empty entry */
@ -1124,8 +1123,8 @@ static void test_decodeAltName(DWORD dwEncoding)
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT, ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError()); "Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError());
/* Now expected cases */ /* Now expected cases */
ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyAltName, ret = CryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence,
emptyAltName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
&bufSize); &bufSize);
ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError()); ok(ret, "CryptDecodeObjectEx failed: %08lx\n", GetLastError());
if (buf) if (buf)
@ -1424,17 +1423,29 @@ static const struct Constraints2 constraints2[] = {
{ { TRUE, TRUE, 1}, bin62 }, { { 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) 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 */ /* First test with the simpler info2 */
for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++) for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++)
{ {
BOOL ret;
BYTE *buf = NULL;
DWORD bufSize = 0;
ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, ret = CryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2,
&constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf,
&bufSize); &bufSize);
@ -1449,6 +1460,39 @@ static void test_encodeBasicConstraints(DWORD dwEncoding)
LocalFree(buf); 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 }; 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); (BYTE *)&buf, &bufSize);
ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT, ok(!ret && GetLastError() == CRYPT_E_ASN1_CORRUPT,
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx\n", GetLastError()); "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 */ /* 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 */ /* Free *pInfo with HeapFree */
static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo) static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo)
{ {
@ -2909,6 +3074,8 @@ START_TEST(encode)
test_decodeCRLDistPoints(encodings[i]); test_decodeCRLDistPoints(encodings[i]);
test_encodeCRLToBeSigned(encodings[i]); test_encodeCRLToBeSigned(encodings[i]);
test_decodeCRLToBeSigned(encodings[i]); test_decodeCRLToBeSigned(encodings[i]);
test_encodeEnhancedKeyUsage(encodings[i]);
test_decodeEnhancedKeyUsage(encodings[i]);
} }
testPortPublicKeyInfo(); testPortPublicKeyInfo();
} }