crypt32: Implement enhanced key usage.
Implement CertGetEnhancedKeyUsage, CertSetEnhancedKeyUsage, CertAddEnhancedKeyUsageIdentifier, and CertRemoveEnhancedKeyUsageIdentifier.
This commit is contained in:
parent
7eba266ea8
commit
079afa21de
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue