Juan Lang : crypt32: Halt chain creation when a cycle is detected.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Aug 31 14:01:20 CDT 2007


Module: wine
Branch: master
Commit: b8b787a81039c4a62c04540d2529593cf3f5fa87
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=b8b787a81039c4a62c04540d2529593cf3f5fa87

Author: Juan Lang <juan.lang at gmail.com>
Date:   Thu Aug 30 17:54:58 2007 -0700

crypt32: 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_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
      &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_GetIssuerFromStore(HCERTSTORE store,
     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(PCERT_SIMPLE_CHAIN chain,
                     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(PCERT_SIMPLE_CHAIN chain,
     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(HCERTCHAINENGINE hChainEngine,
     {
         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(HCERTCHAINENGINE hChainEngine,
 
             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 4cafd0e..2d42ccb 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -1529,14 +1529,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 },




More information about the wine-cvs mailing list