diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c index 7b4da1cfec6..d04f747fa2f 100644 --- a/dlls/crypt32/encode.c +++ b/dlls/crypt32/encode.c @@ -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)); diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index 3c69eb2456e..759eceef2b3 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -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(); }