crypt32: Implement enhanced key usage.

Implement CertGetEnhancedKeyUsage, CertSetEnhancedKeyUsage,
CertAddEnhancedKeyUsageIdentifier, and
CertRemoveEnhancedKeyUsageIdentifier.
oldstable
Juan Lang 2006-02-18 15:49:54 +01:00 committed by Alexandre Julliard
parent 7eba266ea8
commit 079afa21de
4 changed files with 614 additions and 4 deletions

View File

@ -323,3 +323,262 @@ BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVe
pbDecoded, pcbDecoded, ppSignerCert);
return FALSE;
}
BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
{
PCERT_ENHKEY_USAGE usage = NULL;
DWORD bytesNeeded;
BOOL ret = TRUE;
TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
if (!pCertContext || !pcbUsage)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
{
DWORD propSize = 0;
if (CertGetCertificateContextProperty(pCertContext,
CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
{
LPBYTE buf = CryptMemAlloc(propSize);
if (buf)
{
if (CertGetCertificateContextProperty(pCertContext,
CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
{
ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
X509_ENHANCED_KEY_USAGE, buf, propSize,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
}
CryptMemFree(buf);
}
}
}
if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
{
PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
pCertContext->pCertInfo->cExtension,
pCertContext->pCertInfo->rgExtension);
if (ext)
{
ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
}
}
if (!usage)
{
/* If a particular location is specified, this should fail. Otherwise
* it should succeed with an empty usage. (This is true on Win2k and
* later, which we emulate.)
*/
if (dwFlags)
{
SetLastError(CRYPT_E_NOT_FOUND);
ret = FALSE;
}
else
bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
}
if (ret)
{
if (!pUsage)
*pcbUsage = bytesNeeded;
else if (*pcbUsage < bytesNeeded)
{
SetLastError(ERROR_MORE_DATA);
*pcbUsage = bytesNeeded;
ret = FALSE;
}
else
{
*pcbUsage = bytesNeeded;
if (usage)
{
DWORD i;
LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
sizeof(CERT_ENHKEY_USAGE) +
usage->cUsageIdentifier * sizeof(LPSTR));
pUsage->cUsageIdentifier = usage->cUsageIdentifier;
pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
sizeof(CERT_ENHKEY_USAGE));
for (i = 0; i < usage->cUsageIdentifier; i++)
{
pUsage->rgpszUsageIdentifier[i] = nextOID;
strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
nextOID += strlen(nextOID) + 1;
}
}
else
pUsage->cUsageIdentifier = 0;
}
}
if (usage)
LocalFree(usage);
TRACE("returning %d\n", ret);
return ret;
}
BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
PCERT_ENHKEY_USAGE pUsage)
{
BOOL ret;
TRACE("(%p, %p)\n", pCertContext, pUsage);
if (pUsage)
{
CRYPT_DATA_BLOB blob = { 0, NULL };
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
if (ret)
{
ret = CertSetCertificateContextProperty(pCertContext,
CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
LocalFree(blob.pbData);
}
}
else
ret = CertSetCertificateContextProperty(pCertContext,
CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
return ret;
}
BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
LPCSTR pszUsageIdentifier)
{
BOOL ret;
DWORD size;
TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
if (CertGetEnhancedKeyUsage(pCertContext,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
{
PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
if (usage)
{
ret = CertGetEnhancedKeyUsage(pCertContext,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
if (ret)
{
PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
if (newUsage)
{
LPSTR nextOID;
DWORD i;
newUsage->rgpszUsageIdentifier =
(LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
(usage->cUsageIdentifier + 1) * sizeof(LPSTR));
for (i = 0; i < usage->cUsageIdentifier; i++)
{
newUsage->rgpszUsageIdentifier[i] = nextOID;
strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
nextOID += strlen(nextOID) + 1;
}
newUsage->rgpszUsageIdentifier[i] = nextOID;
strcpy(nextOID, pszUsageIdentifier);
newUsage->cUsageIdentifier = i + 1;
ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
CryptMemFree(newUsage);
}
}
CryptMemFree(usage);
}
else
ret = FALSE;
}
else
{
PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
if (usage)
{
usage->rgpszUsageIdentifier =
(LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
usage->cUsageIdentifier = 1;
ret = CertSetEnhancedKeyUsage(pCertContext, usage);
CryptMemFree(usage);
}
else
ret = FALSE;
}
return ret;
}
BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
LPCSTR pszUsageIdentifier)
{
BOOL ret;
DWORD size;
CERT_ENHKEY_USAGE usage;
TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
size = sizeof(usage);
ret = CertGetEnhancedKeyUsage(pCertContext,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
if (!ret && GetLastError() == ERROR_MORE_DATA)
{
PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
if (pUsage)
{
ret = CertGetEnhancedKeyUsage(pCertContext,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
if (ret)
{
if (pUsage->cUsageIdentifier)
{
DWORD i;
BOOL found = FALSE;
for (i = 0; i < pUsage->cUsageIdentifier; i++)
{
if (!strcmp(pUsage->rgpszUsageIdentifier[i],
pszUsageIdentifier))
found = TRUE;
if (found && i < pUsage->cUsageIdentifier - 1)
pUsage->rgpszUsageIdentifier[i] =
pUsage->rgpszUsageIdentifier[i + 1];
}
pUsage->cUsageIdentifier--;
/* Remove the usage if it's empty */
if (pUsage->cUsageIdentifier)
ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
else
ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
}
}
CryptMemFree(pUsage);
}
else
ret = FALSE;
}
else
{
/* it fit in an empty usage, therefore there's nothing to remove */
ret = TRUE;
}
return ret;
}

View File

@ -6,7 +6,7 @@
@ stdcall CertAddEncodedCertificateToStore(long long ptr long long ptr)
@ stub CertAddEncodedCertificateToSystemStoreA
@ stub CertAddEncodedCertificateToSystemStoreW
@ stub CertAddEnhancedKeyUsageIdentifier
@ stdcall CertAddEnhancedKeyUsageIdentifier(ptr str)
@ stdcall CertAddSerializedElementToStore(ptr ptr long long long long ptr ptr)
@ stdcall CertAddStoreToCollection(ptr ptr long long)
@ stdcall CertAlgIdToOID(long)
@ -49,7 +49,7 @@
@ stdcall CertGetCTLContextProperty(ptr long ptr ptr)
@ stub CertGetCertificateChain
@ stdcall CertGetCertificateContextProperty(ptr long ptr ptr)
@ stub CertGetEnhancedKeyUsage
@ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr)
@ stub CertGetIntendedKeyUsage
@ stub CertGetIssuerCertificateFromStore
@ stdcall CertGetNameStringA(ptr long long ptr ptr long)
@ -65,7 +65,7 @@
@ stdcall CertOpenSystemStoreW(long wstr)
@ stdcall CertRDNValueToStrA(long ptr ptr long)
@ stdcall CertRDNValueToStrW(long ptr ptr long)
@ stub CertRemoveEnhancedKeyUsageIdentifier
@ stdcall CertRemoveEnhancedKeyUsageIdentifier(ptr str)
@ stdcall CertRemoveStoreFromCollection(long long)
@ stdcall CertSaveStore(long long long long ptr long)
@ stdcall CertSerializeCRLStoreElement(ptr long ptr ptr)
@ -74,7 +74,7 @@
@ stdcall CertSetCRLContextProperty(ptr long long ptr)
@ stdcall CertSetCTLContextProperty(ptr long long ptr)
@ stdcall CertSetCertificateContextProperty(ptr long long ptr)
@ stub CertSetEnhancedKeyUsage
@ stdcall CertSetEnhancedKeyUsage(ptr ptr)
@ stub CertStrToNameA
@ stub CertStrToNameW
@ stub CertVerifyCRLRevocation

View File

@ -299,9 +299,315 @@ static void testCertSigs(void)
CRYPT_DELETEKEYSET);
}
static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30,
0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00,
0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31,
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61,
0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00,
0x03, 0x01, 0x00, 0xa3, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d,
0x25, 0x01, 0x01, 0xff, 0x04, 0x21, 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 testKeyUsage(void)
{
BOOL ret;
PCCERT_CONTEXT context;
DWORD size;
/* Test base cases */
ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, NULL);
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
size = 1;
ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
size = 0;
ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
/* These crash
ret = CertSetEnhancedKeyUsage(NULL, NULL);
usage.cUsageIdentifier = 0;
ret = CertSetEnhancedKeyUsage(NULL, &usage);
*/
/* Test with a cert with no enhanced key usage extension */
context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
sizeof(bigCert));
ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
GetLastError());
if (context)
{
static const char oid[] = "1.2.3.4";
BYTE buf[sizeof(CERT_ENHKEY_USAGE) + 2 * (sizeof(LPSTR) + sizeof(oid))];
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
ret = CertGetEnhancedKeyUsage(context, 0, NULL, NULL);
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
"Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
size = 1;
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &size);
if (ret)
{
/* Windows 2000, ME, or later: even though it succeeded, we expect
* CRYPT_E_NOT_FOUND, which indicates there is no enhanced key
* usage set for this cert (which implies it's valid for all uses.)
*/
ok(GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
ok(size == sizeof(CERT_ENHKEY_USAGE), "Expected size %d, got %ld\n",
sizeof(CERT_ENHKEY_USAGE), size);
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
pUsage->cUsageIdentifier);
}
else
{
/* Windows NT, 95, or 98: it fails, and the last error is
* CRYPT_E_NOT_FOUND.
*/
ok(GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
}
/* I can add a usage identifier when no key usage has been set */
ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
GetLastError());
size = sizeof(buf);
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
ok(ret && GetLastError() == 0,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
pUsage->cUsageIdentifier);
if (pUsage->cUsageIdentifier)
ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
"Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
/* Now set an empty key usage */
pUsage->cUsageIdentifier = 0;
ret = CertSetEnhancedKeyUsage(context, pUsage);
ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
/* Shouldn't find it in the cert */
size = sizeof(buf);
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
/* Should find it as an extended property */
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
ok(ret && GetLastError() == 0,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
pUsage->cUsageIdentifier);
/* Should find it as either */
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(ret && GetLastError() == 0,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
pUsage->cUsageIdentifier);
/* Add a usage identifier */
ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
GetLastError());
size = sizeof(buf);
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(ret && GetLastError() == 0,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 1, "Expected 1 identifier, got %ld\n",
pUsage->cUsageIdentifier);
if (pUsage->cUsageIdentifier)
ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
"Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
/* Yep, I can re-add the same usage identifier */
ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
GetLastError());
size = sizeof(buf);
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(ret && GetLastError() == 0,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 2, "Expected 2 identifiers, got %ld\n",
pUsage->cUsageIdentifier);
if (pUsage->cUsageIdentifier)
ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
"Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
if (pUsage->cUsageIdentifier >= 2)
ok(!strcmp(pUsage->rgpszUsageIdentifier[1], oid),
"Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[1]);
/* Now set a NULL extended property--this deletes the property. */
ret = CertSetEnhancedKeyUsage(context, NULL);
ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
SetLastError(0xbaadcafe);
size = sizeof(buf);
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
CertFreeCertificateContext(context);
}
/* Now test with a cert with an enhanced key usage extension */
context = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage,
sizeof(certWithUsage));
ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
GetLastError());
if (context)
{
LPBYTE buf = NULL;
DWORD bufSize = 0, i;
/* The size may depend on what flags are used to query it, so I
* realloc the buffer for each test.
*/
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
/* Should find it in the cert */
size = bufSize;
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
ok(ret && GetLastError() == 0,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
pUsage->cUsageIdentifier);
for (i = 0; i < pUsage->cUsageIdentifier; i++)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
HeapFree(GetProcessHeap(), 0, buf);
}
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
/* Should find it as either */
size = bufSize;
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
/* In Windows, GetLastError returns CRYPT_E_NOT_FOUND not found
* here, even though the return is successful and the usage id
* count is positive. I don't enforce that here.
*/
ok(ret,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
pUsage->cUsageIdentifier);
for (i = 0; i < pUsage->cUsageIdentifier; i++)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
HeapFree(GetProcessHeap(), 0, buf);
}
/* Shouldn't find it as an extended property */
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size);
ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
"Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
/* Adding a usage identifier overrides the cert's usage!? */
ret = CertAddEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
GetLastError());
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
/* Should find it as either */
size = bufSize;
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(ret,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
pUsage->cUsageIdentifier);
ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA),
"Expected %s, got %s\n", szOID_RSA_RSA,
pUsage->rgpszUsageIdentifier[0]);
HeapFree(GetProcessHeap(), 0, buf);
}
/* But querying the cert directly returns its usage */
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
size = bufSize;
ret = CertGetEnhancedKeyUsage(context,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
ok(ret,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
pUsage->cUsageIdentifier);
for (i = 0; i < pUsage->cUsageIdentifier; i++)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
HeapFree(GetProcessHeap(), 0, buf);
}
/* And removing the only usage identifier in the extended property
* results in the cert's key usage being found.
*/
ret = CertRemoveEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
ok(ret, "CertRemoveEnhancedKeyUsage failed: %08lx\n", GetLastError());
ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
if (buf)
{
PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
/* Should find it as either */
size = bufSize;
ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
ok(ret,
"CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
pUsage->cUsageIdentifier);
for (i = 0; i < pUsage->cUsageIdentifier; i++)
ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
"Expected %s, got %s\n", keyUsages[i],
pUsage->rgpszUsageIdentifier[i]);
HeapFree(GetProcessHeap(), 0, buf);
}
CertFreeCertificateContext(context);
}
}
START_TEST(cert)
{
init_function_pointers();
testCryptHashCert();
testCertSigs();
testKeyUsage();
}

View File

@ -681,6 +681,27 @@ typedef struct _CERT_CHAIN_POLICY_STATUS {
void *pvExtraPolicyStatus;
} CERT_CHAIN_POLICY_STATUS, *PCERT_CHAIN_POLICY_STATUS;
typedef struct _CERT_USAGE_MATCH {
DWORD dwType;
CERT_ENHKEY_USAGE Usage;
} CERT_USAGE_MATCH, *PCERT_USAGE_MATCH;
typedef struct _CTL_USAGE_MATCH {
DWORD dwType;
CTL_USAGE Usage;
} CTL_USAGE_MATCH, *PCTL_USAGE_MATCH;
typedef struct _CERT_CHAIN_PARA {
DWORD cbSize;
CERT_USAGE_MATCH RequestedUsage;
#ifdef CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
CERT_USAGE_MATCH RequestedIssuancePolicy;
DWORD dwUrlRetrievalTimeout;
BOOL fCheckRevocationFreshnessTime;
DWORD dwRevocationFreshnessTime;
#endif
} CERT_CHAIN_PARA, *PCERT_CHAIN_PARA;
typedef struct _CERT_SYSTEM_STORE_INFO {
DWORD cbSize;
} CERT_SYSTEM_STORE_INFO, *PCERT_SYSTEM_STORE_INFO;
@ -1881,6 +1902,19 @@ static const WCHAR CERT_PHYSICAL_STORE_AUTH_ROOT_NAME[] =
#define CERT_FIND_PUBKEY_MD5_HASH \
(CERT_COMPARE_PUBKEY_MD5_HASH << CERT_COMPARE_SHIFT)
#define CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG 0x1
#define CERT_FIND_OPTIONAL_CTL_USAGE_FLAG 0x1
#define CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG 0x2
#define CERT_FIND_EXT_ONLY_CTL_USAGE_FLAG 0x2
#define CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG 0x4
#define CERT_FIND_PROP_ONLY_CTL_USAGE_FLAG 0x4
#define CERT_FIND_NO_ENHKEY_USAGE_FLAG 0x8
#define CERT_FIND_NO_CTL_USAGE_FLAG 0x8
#define CERT_FIND_OR_ENHKEY_USAGE_FLAG 0x10
#define CERT_FIND_OR_CTL_USAGE_FLAG 0x10
#define CERT_FIND_VALID_ENHKEY_USAGE_FLAG 0x20
#define CERT_FIND_VALID_CTL_USAGE_FLAG 0x20
/* PFN_CERT_STORE_PROV_WRITE_CERT dwFlags values */
#define CERT_STORE_PROV_WRITE_ADD_FLAG 0x1
@ -2587,6 +2621,17 @@ BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement);
BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage);
BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
PCERT_ENHKEY_USAGE pUsage);
BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
LPCSTR pszUsageIdentifer);
BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
LPCSTR pszUsageIdentifer);
BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs);
BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded);
BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,