Juan Lang : crypt32: Check CA certificates for the enhanced key usage extension.

Alexandre Julliard julliard at winehq.org
Fri Oct 30 11:04:30 CDT 2009


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

Author: Juan Lang <juan.lang at gmail.com>
Date:   Wed Oct 28 17:33:24 2009 -0700

crypt32: Check CA certificates for the enhanced key usage extension.

---

 dlls/crypt32/chain.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index 0637646..90093ae 100644
--- a/dlls/crypt32/chain.c
+++ b/dlls/crypt32/chain.c
@@ -1173,6 +1173,58 @@ static BOOL CRYPT_KeyUsageValid(PCertificateChainEngine engine,
     return ret;
 }
 
+static BOOL CRYPT_ExtendedKeyUsageValidForCA(PCCERT_CONTEXT cert)
+{
+    PCERT_EXTENSION ext;
+    BOOL ret;
+
+    /* RFC 5280, section 4.2.1.12:  "In general, this extension will only
+     * appear in end entity certificates."  And, "If a certificate contains
+     * both a key usage extension and an extended key usage extension, then
+     * both extensions MUST be processed independently and the certificate MUST
+     * only be used for a purpose consistent with both extensions."  This seems
+     * to imply that it should be checked if present, and ignored if not.
+     * Unfortunately some CAs, e.g. the Thawte SGC CA, don't include the code
+     * signing extended key usage, whereas they do include the keyCertSign
+     * key usage.  Thus, when checking for a CA, we only require the
+     * code signing extended key usage if the extended key usage is critical.
+     */
+    ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
+     cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+    if (ext && ext->fCritical)
+    {
+        CERT_ENHKEY_USAGE *usage;
+        DWORD size;
+
+        ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
+         X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
+         CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size);
+        if (ret)
+        {
+            DWORD i;
+
+            /* Explicitly require the code signing extended key usage for a CA
+             * with an extended key usage extension.  That is, don't assume
+             * a cert is allowed to be a CA if it specifies the
+             * anyExtendedKeyUsage usage oid.  See again RFC 5280, section
+             * 4.2.1.12: "Applications that require the presence of a
+             * particular purpose MAY reject certificates that include the
+             * anyExtendedKeyUsage OID but not the particular OID expected for
+             * the application."
+             */
+            ret = FALSE;
+            for (i = 0; !ret && i < usage->cUsageIdentifier; i++)
+                if (!strcmp(usage->rgpszUsageIdentifier[i],
+                 szOID_PKIX_KP_CODE_SIGNING))
+                    ret = TRUE;
+            LocalFree(usage);
+        }
+    }
+    else
+        ret = TRUE;
+    return ret;
+}
+
 static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
 {
     BOOL ret = TRUE;
@@ -1196,6 +1248,8 @@ static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
                 ret = TRUE;
             else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME2))
                 ret = TRUE;
+            else if (!strcmp(oid, szOID_ENHANCED_KEY_USAGE))
+                ret = TRUE;
             else
             {
                 FIXME("unsupported critical extension %s\n",
@@ -1265,6 +1319,11 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
          constraints.fCA, i))
             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
+        if (i != 0)
+            if (!CRYPT_ExtendedKeyUsageValidForCA(
+             chain->rgpElement[i]->pCertContext))
+                chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+                 CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
         if (CRYPT_IsSimpleChainCyclic(chain))
         {
             /* If the chain is cyclic, then the path length constraints




More information about the wine-cvs mailing list