crypt32(9/17): Halt chain creation when a cycle is detected
Juan Lang
juan.lang at gmail.com
Thu Aug 30 20:16:42 CDT 2007
--Juan
-------------- next part --------------
From 1543f3660d48a670eaa2ff79d70887d9160442e5 Mon Sep 17 00:00:00 2001
From: Juan Lang <juan.lang at gmail.com>
Date: Thu, 30 Aug 2007 17:54:58 -0700
Subject: [PATCH] Halt chain creation when a cycle is detected
---
dlls/crypt32/chain.c | 62 +++++++++++++++++++++++++++++++++++---------
dlls/crypt32/tests/chain.c | 5 +---
2 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index b8ce476..1372ad8 100644
--- a/dlls/crypt32/chain.c
+++ b/dlls/crypt32/chain.c
@@ -212,6 +212,45 @@ static inline BOOL CRYPT_IsCertificateSe
&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
* with it. Returns NULL if no issuer whose public key matches cert's
* signature could be found.
@@ -233,8 +272,8 @@ static PCCERT_CONTEXT CRYPT_GetIssuerFro
return issuer;
}
-static BOOL CRYPT_AddCertToSimpleChain(PCERT_SIMPLE_CHAIN chain,
- PCCERT_CONTEXT cert, DWORD dwFlags)
+static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine,
+ PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD dwFlags)
{
BOOL ret = FALSE;
PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
@@ -273,13 +312,15 @@ static BOOL CRYPT_AddCertToSimpleChain(P
prevElement->TrustStatus.dwErrorStatus |=
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 */
+ chain->rgpElement[chain->cElement++] = element;
+ if (chain->cElement % engine->CycleDetectionModulus)
+ CRYPT_CheckSimpleChainForCycles(chain);
chain->TrustStatus.dwErrorStatus |=
element->TrustStatus.dwErrorStatus;
chain->TrustStatus.dwInfoStatus |=
element->TrustStatus.dwInfoStatus;
- chain->rgpElement[chain->cElement++] = element;
ret = TRUE;
}
else
@@ -288,12 +329,6 @@ static BOOL CRYPT_AddCertToSimpleChain(P
return ret;
}
-static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
-{
- CertFreeCertificateContext(element->pCertContext);
- CryptMemFree(element);
-}
-
static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
{
DWORD i;
@@ -327,8 +362,9 @@ static BOOL CRYPT_BuildSimpleChain(HCERT
{
memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
- ret = CRYPT_AddCertToSimpleChain(chain, cert, 0);
- while (ret && !CRYPT_IsCertificateSelfSigned(cert))
+ ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
+ while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
+ !CRYPT_IsCertificateSelfSigned(cert))
{
DWORD flags;
PCCERT_CONTEXT issuer = CRYPT_GetIssuerFromStore(world, cert,
@@ -336,7 +372,7 @@ static BOOL CRYPT_BuildSimpleChain(HCERT
if (issuer)
{
- ret = CRYPT_AddCertToSimpleChain(chain, issuer, flags);
+ ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, flags);
cert = issuer;
}
else
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index ecbca5c..ebab3ca 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -1528,14 +1528,13 @@ static ChainCheck chainCheck[] = {
CERT_TRUST_IS_NOT_TIME_VALID, 0 },
1, simpleStatus8 },
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 },
{ { 0, CERT_TRUST_HAS_PREFERRED_ISSUER },
{ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT |
CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_CYCLIC, 0 },
1, simpleStatus9 },
- TODO_ERROR | TODO_INFO },
- */
+ TODO_CHAIN | TODO_ERROR | TODO_INFO },
{ { sizeof(chain10) / sizeof(chain10[0]), chain10 },
{ { 0, CERT_TRUST_HAS_PREFERRED_ISSUER },
{ CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus10 },
--
1.4.1
More information about the wine-patches
mailing list