Commit 912c3e60 authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

crypt32: Implement cert chain revocation checking.

parent 5928c698
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#define NONAMELESSUNION #define NONAMELESSUNION
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
#define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
#include "wincrypt.h" #include "wincrypt.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/unicode.h" #include "wine/unicode.h"
...@@ -775,7 +777,6 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine, ...@@ -775,7 +777,6 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER; CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
CRYPT_CheckRootCert(engine->hRoot, rootElement); CRYPT_CheckRootCert(engine->hRoot, rootElement);
} }
/* FIXME: check revocation of every cert with CertVerifyRevocation */
CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus); CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
} }
...@@ -1307,19 +1308,123 @@ static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain, ...@@ -1307,19 +1308,123 @@ static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain,
return ret; return ret;
} }
static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain(
PCERT_CHAIN_CONTEXT chain, DWORD i)
{
DWORD j, iElement;
PCERT_CHAIN_ELEMENT element = NULL;
for (j = 0, iElement = 0; !element && j < chain->cChain; j++)
{
if (iElement + chain->rgpChain[j]->cElement < i)
iElement += chain->rgpChain[j]->cElement;
else
element = chain->rgpChain[j]->rgpElement[i - iElement];
}
return element;
}
typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS { typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS {
DWORD cbSize; DWORD cbSize;
CERT_USAGE_MATCH RequestedUsage; CERT_USAGE_MATCH RequestedUsage;
} CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS; } CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS;
typedef struct _CERT_CHAIN_PARA_EXTRA_FIELDS { static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
DWORD cbSize; LPFILETIME pTime, PCERT_CHAIN_PARA pChainPara, DWORD chainFlags)
CERT_USAGE_MATCH RequestedUsage; {
CERT_USAGE_MATCH RequestedIssuancePolicy; DWORD cContext;
DWORD dwUrlRetrievalTimeout;
BOOL fCheckRevocationFreshnessTime; if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT)
DWORD dwRevocationFreshnessTime; cContext = 1;
} CERT_CHAIN_PARA_EXTRA_FIELDS, *PCERT_CHAIN_PARA_EXTRA_FIELDS; else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) ||
(chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT))
{
DWORD i;
for (i = 0, cContext = 0; i < chain->cChain; i++)
{
if (i < chain->cChain - 1 ||
chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN)
cContext += chain->rgpChain[i]->cElement;
else
cContext += chain->rgpChain[i]->cElement - 1;
}
}
else
cContext = 0;
if (cContext)
{
PCCERT_CONTEXT *contexts =
CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT *));
if (contexts)
{
DWORD i, j, iContext, revocationFlags;
CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 };
CERT_REVOCATION_STATUS revocationStatus =
{ sizeof(revocationStatus), 0 };
BOOL ret;
for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain;
i++)
{
for (j = 0; iContext < cContext &&
j < chain->rgpChain[i]->cElement; j++)
contexts[iContext++] =
chain->rgpChain[i]->rgpElement[j]->pCertContext;
}
revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG;
if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY)
revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION;
if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT)
revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG;
revocationPara.pftTimeToUse = pTime;
if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA))
{
revocationPara.dwUrlRetrievalTimeout =
pChainPara->dwUrlRetrievalTimeout;
revocationPara.fCheckFreshnessTime =
pChainPara->fCheckRevocationFreshnessTime;
revocationPara.dwFreshnessTime =
pChainPara->dwRevocationFreshnessTime;
}
ret = CertVerifyRevocation(X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE, cContext, (void **)contexts,
revocationFlags, &revocationPara, &revocationStatus);
if (!ret)
{
PCERT_CHAIN_ELEMENT element =
CRYPT_FindIthElementInChain(chain, revocationStatus.dwIndex);
DWORD error;
switch (revocationStatus.dwError)
{
case CRYPT_E_NO_REVOCATION_CHECK:
case CRYPT_E_NO_REVOCATION_DLL:
case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
break;
case CRYPT_E_REVOCATION_OFFLINE:
error = CERT_TRUST_IS_OFFLINE_REVOCATION;
break;
case CRYPT_E_REVOKED:
error = CERT_TRUST_IS_REVOKED;
break;
default:
WARN("unmapped error %08x\n", revocationStatus.dwError);
error = 0;
}
if (element)
{
/* FIXME: set element's pRevocationInfo member */
element->TrustStatus.dwErrorStatus |= error;
}
chain->TrustStatus.dwErrorStatus |= error;
}
CryptMemFree(contexts);
}
}
}
BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
...@@ -1344,15 +1449,21 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, ...@@ -1344,15 +1449,21 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
SetLastError(ERROR_INVALID_DATA); SetLastError(ERROR_INVALID_DATA);
return FALSE; return FALSE;
} }
if (pChainPara->cbSize != sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) &&
pChainPara->cbSize != sizeof(CERT_CHAIN_PARA))
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if (!hChainEngine) if (!hChainEngine)
hChainEngine = CRYPT_GetDefaultChainEngine(); hChainEngine = CRYPT_GetDefaultChainEngine();
/* FIXME: what about HCCE_LOCAL_MACHINE? */ /* FIXME: what about HCCE_LOCAL_MACHINE? */
/* FIXME: pChainPara is for now ignored */
ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime, ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime,
hAdditionalStore, &chain); hAdditionalStore, &chain);
if (ret) if (ret)
{ {
PCertificateChain alternate = NULL; PCertificateChain alternate = NULL;
PCERT_CHAIN_CONTEXT pChain;
do { do {
alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine, alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine,
...@@ -1368,10 +1479,12 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, ...@@ -1368,10 +1479,12 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
chain = CRYPT_ChooseHighestQualityChain(chain); chain = CRYPT_ChooseHighestQualityChain(chain);
if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS)) if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
CRYPT_FreeLowerQualityChains(chain); CRYPT_FreeLowerQualityChains(chain);
pChain = (PCERT_CHAIN_CONTEXT)chain;
CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags);
if (ppChainContext) if (ppChainContext)
*ppChainContext = (PCCERT_CHAIN_CONTEXT)chain; *ppChainContext = pChain;
else else
CertFreeCertificateChain((PCCERT_CHAIN_CONTEXT)chain); CertFreeCertificateChain(pChain);
} }
TRACE("returning %d\n", ret); TRACE("returning %d\n", ret);
return ret; return ret;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment