crypt32: Halt chain creation when a cycle is detected.

This commit is contained in:
Juan Lang 2007-08-30 17:54:58 -07:00 committed by Alexandre Julliard
parent 51a9d208ee
commit b8b787a810
2 changed files with 51 additions and 16 deletions

View File

@ -212,6 +212,45 @@ static inline BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
&cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
} }
static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
{
CertFreeCertificateContext(element->pCertContext);
CryptMemFree(element);
}
static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain)
{
DWORD i, j, cyclicCertIndex = 0;
/* O(n^2) - I don't think there's a faster way */
for (i = 0; !cyclicCertIndex && i < chain->cElement; i++)
for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++)
if (CertCompareCertificate(X509_ASN_ENCODING,
chain->rgpElement[i]->pCertContext->pCertInfo,
chain->rgpElement[j]->pCertContext->pCertInfo))
cyclicCertIndex = j;
if (cyclicCertIndex)
{
chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus
|= CERT_TRUST_IS_CYCLIC;
/* Release remaining certs */
for (i = cyclicCertIndex + 1; i < chain->cElement; i++)
CRYPT_FreeChainElement(chain->rgpElement[i]);
/* Truncate chain */
chain->cElement = cyclicCertIndex + 1;
}
}
/* Checks whether the chain is cyclic by examining the last element's status */
static inline BOOL CRYPT_IsSimpleChainCyclic(PCERT_SIMPLE_CHAIN chain)
{
if (chain->cElement)
return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus
& CERT_TRUST_IS_CYCLIC;
else
return FALSE;
}
/* Gets cert's issuer from store, and returns the validity flags associated /* Gets cert's issuer from store, and returns the validity flags associated
* with it. Returns NULL if no issuer whose public key matches cert's * with it. Returns NULL if no issuer whose public key matches cert's
* signature could be found. * signature could be found.
@ -233,8 +272,8 @@ static PCCERT_CONTEXT CRYPT_GetIssuerFromStore(HCERTSTORE store,
return issuer; return issuer;
} }
static BOOL CRYPT_AddCertToSimpleChain(PCERT_SIMPLE_CHAIN chain, static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine,
PCCERT_CONTEXT cert, DWORD dwFlags) PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD dwFlags)
{ {
BOOL ret = FALSE; BOOL ret = FALSE;
PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT)); PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
@ -273,13 +312,15 @@ static BOOL CRYPT_AddCertToSimpleChain(PCERT_SIMPLE_CHAIN chain,
prevElement->TrustStatus.dwErrorStatus |= prevElement->TrustStatus.dwErrorStatus |=
CERT_TRUST_IS_NOT_TIME_NESTED; CERT_TRUST_IS_NOT_TIME_NESTED;
} }
/* FIXME: check valid usages, name constraints, and for cycles */ /* FIXME: check valid usages and name constraints */
/* FIXME: initialize the rest of element */ /* FIXME: initialize the rest of element */
chain->rgpElement[chain->cElement++] = element;
if (chain->cElement % engine->CycleDetectionModulus)
CRYPT_CheckSimpleChainForCycles(chain);
chain->TrustStatus.dwErrorStatus |= chain->TrustStatus.dwErrorStatus |=
element->TrustStatus.dwErrorStatus; element->TrustStatus.dwErrorStatus;
chain->TrustStatus.dwInfoStatus |= chain->TrustStatus.dwInfoStatus |=
element->TrustStatus.dwInfoStatus; element->TrustStatus.dwInfoStatus;
chain->rgpElement[chain->cElement++] = element;
ret = TRUE; ret = TRUE;
} }
else else
@ -288,12 +329,6 @@ static BOOL CRYPT_AddCertToSimpleChain(PCERT_SIMPLE_CHAIN chain,
return ret; return ret;
} }
static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
{
CertFreeCertificateContext(element->pCertContext);
CryptMemFree(element);
}
static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain) static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
{ {
DWORD i; DWORD i;
@ -327,8 +362,9 @@ static BOOL CRYPT_BuildSimpleChain(HCERTCHAINENGINE hChainEngine,
{ {
memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN)); memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
chain->cbSize = sizeof(CERT_SIMPLE_CHAIN); chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
ret = CRYPT_AddCertToSimpleChain(chain, cert, 0); ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
while (ret && !CRYPT_IsCertificateSelfSigned(cert)) while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
!CRYPT_IsCertificateSelfSigned(cert))
{ {
DWORD flags; DWORD flags;
PCCERT_CONTEXT issuer = CRYPT_GetIssuerFromStore(world, cert, PCCERT_CONTEXT issuer = CRYPT_GetIssuerFromStore(world, cert,
@ -336,7 +372,7 @@ static BOOL CRYPT_BuildSimpleChain(HCERTCHAINENGINE hChainEngine,
if (issuer) if (issuer)
{ {
ret = CRYPT_AddCertToSimpleChain(chain, issuer, flags); ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, flags);
cert = issuer; cert = issuer;
} }
else else

View File

@ -1529,14 +1529,13 @@ static ChainCheck chainCheck[] = {
CERT_TRUST_IS_NOT_TIME_VALID, 0 }, CERT_TRUST_IS_NOT_TIME_VALID, 0 },
1, simpleStatus8 }, 1, simpleStatus8 },
TODO_ERROR | TODO_INFO }, TODO_ERROR | TODO_INFO },
/* This (cyclic) chain never completes in Wine, so don't test it yet /* This (cyclic) chain fails in Wine */
{ { sizeof(chain9) / sizeof(chain9[0]), chain9 }, { { sizeof(chain9) / sizeof(chain9[0]), chain9 },
{ { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER },
{ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT | { CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT |
CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_CYCLIC, 0 }, CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_CYCLIC, 0 },
1, simpleStatus9 }, 1, simpleStatus9 },
TODO_ERROR | TODO_INFO }, TODO_CHAIN | TODO_ERROR | TODO_INFO },
*/
{ { sizeof(chain10) / sizeof(chain10[0]), chain10 }, { { sizeof(chain10) / sizeof(chain10[0]), chain10 },
{ { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER },
{ CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus10 }, { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus10 },