From 07b735682bfcd5999b3306865e5158a56f7b21b5 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 28 Oct 2009 17:33:24 -0700 Subject: [PATCH] crypt32: Check CA certificates for the enhanced key usage extension. --- dlls/crypt32/chain.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c index 06376461d2b..90093ae04d1 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