ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

chain.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2006 Juan Lang
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  *
00018  */
00019 #include <stdarg.h>
00020 #define NONAMELESSUNION
00021 #include "windef.h"
00022 #include "winbase.h"
00023 #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
00024 #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
00025 #include "wincrypt.h"
00026 #include "wininet.h"
00027 #include "wine/debug.h"
00028 #include "wine/unicode.h"
00029 #include "crypt32_private.h"
00030 
00031 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
00032 WINE_DECLARE_DEBUG_CHANNEL(chain);
00033 
00034 #define DEFAULT_CYCLE_MODULUS 7
00035 
00036 static HCERTCHAINENGINE CRYPT_defaultChainEngine;
00037 
00038 /* This represents a subset of a certificate chain engine:  it doesn't include
00039  * the "hOther" store described by MSDN, because I'm not sure how that's used.
00040  * It also doesn't include the "hTrust" store, because I don't yet implement
00041  * CTLs or complex certificate chains.
00042  */
00043 typedef struct _CertificateChainEngine
00044 {
00045     LONG       ref;
00046     HCERTSTORE hRoot;
00047     HCERTSTORE hWorld;
00048     DWORD      dwFlags;
00049     DWORD      dwUrlRetrievalTimeout;
00050     DWORD      MaximumCachedCertificates;
00051     DWORD      CycleDetectionModulus;
00052 } CertificateChainEngine, *PCertificateChainEngine;
00053 
00054 static inline void CRYPT_AddStoresToCollection(HCERTSTORE collection,
00055  DWORD cStores, HCERTSTORE *stores)
00056 {
00057     DWORD i;
00058 
00059     for (i = 0; i < cStores; i++)
00060         CertAddStoreToCollection(collection, stores[i], 0, 0);
00061 }
00062 
00063 static inline void CRYPT_CloseStores(DWORD cStores, HCERTSTORE *stores)
00064 {
00065     DWORD i;
00066 
00067     for (i = 0; i < cStores; i++)
00068         CertCloseStore(stores[i], 0);
00069 }
00070 
00071 static const WCHAR rootW[] = { 'R','o','o','t',0 };
00072 
00073 /* Finds cert in store by comparing the cert's hashes. */
00074 static PCCERT_CONTEXT CRYPT_FindCertInStore(HCERTSTORE store,
00075  PCCERT_CONTEXT cert)
00076 {
00077     PCCERT_CONTEXT matching = NULL;
00078     BYTE hash[20];
00079     DWORD size = sizeof(hash);
00080 
00081     if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash, &size))
00082     {
00083         CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
00084 
00085         matching = CertFindCertificateInStore(store, cert->dwCertEncodingType,
00086          0, CERT_FIND_SHA1_HASH, &blob, NULL);
00087     }
00088     return matching;
00089 }
00090 
00091 static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store)
00092 {
00093     BOOL ret = TRUE;
00094 
00095     if (store)
00096     {
00097         HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW);
00098         PCCERT_CONTEXT cert = NULL, check;
00099 
00100         do {
00101             cert = CertEnumCertificatesInStore(store, cert);
00102             if (cert)
00103             {
00104                 if (!(check = CRYPT_FindCertInStore(rootStore, cert)))
00105                     ret = FALSE;
00106                 else
00107                     CertFreeCertificateContext(check);
00108             }
00109         } while (ret && cert);
00110         if (cert)
00111             CertFreeCertificateContext(cert);
00112         CertCloseStore(rootStore, 0);
00113     }
00114     return ret;
00115 }
00116 
00117 HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root,
00118  PCERT_CHAIN_ENGINE_CONFIG pConfig)
00119 {
00120     static const WCHAR caW[] = { 'C','A',0 };
00121     static const WCHAR myW[] = { 'M','y',0 };
00122     static const WCHAR trustW[] = { 'T','r','u','s','t',0 };
00123     PCertificateChainEngine engine =
00124      CryptMemAlloc(sizeof(CertificateChainEngine));
00125 
00126     if (engine)
00127     {
00128         HCERTSTORE worldStores[4];
00129 
00130         engine->ref = 1;
00131         engine->hRoot = root;
00132         engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
00133          CERT_STORE_CREATE_NEW_FLAG, NULL);
00134         worldStores[0] = CertDuplicateStore(engine->hRoot);
00135         worldStores[1] = CertOpenSystemStoreW(0, caW);
00136         worldStores[2] = CertOpenSystemStoreW(0, myW);
00137         worldStores[3] = CertOpenSystemStoreW(0, trustW);
00138         CRYPT_AddStoresToCollection(engine->hWorld,
00139          sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
00140         CRYPT_AddStoresToCollection(engine->hWorld,
00141          pConfig->cAdditionalStore, pConfig->rghAdditionalStore);
00142         CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]),
00143          worldStores);
00144         engine->dwFlags = pConfig->dwFlags;
00145         engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout;
00146         engine->MaximumCachedCertificates =
00147          pConfig->MaximumCachedCertificates;
00148         if (pConfig->CycleDetectionModulus)
00149             engine->CycleDetectionModulus = pConfig->CycleDetectionModulus;
00150         else
00151             engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS;
00152     }
00153     return engine;
00154 }
00155 
00156 typedef struct _CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT
00157 {
00158     DWORD       cbSize;
00159     HCERTSTORE  hRestrictedRoot;
00160     HCERTSTORE  hRestrictedTrust;
00161     HCERTSTORE  hRestrictedOther;
00162     DWORD       cAdditionalStore;
00163     HCERTSTORE *rghAdditionalStore;
00164     DWORD       dwFlags;
00165     DWORD       dwUrlRetrievalTimeout;
00166     DWORD       MaximumCachedCertificates;
00167     DWORD       CycleDetectionModulus;
00168 } CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT;
00169 
00170 BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
00171  HCERTCHAINENGINE *phChainEngine)
00172 {
00173     BOOL ret;
00174 
00175     TRACE("(%p, %p)\n", pConfig, phChainEngine);
00176 
00177     if (pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT)
00178      && pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG))
00179     {
00180         SetLastError(E_INVALIDARG);
00181         return FALSE;
00182     }
00183     *phChainEngine = NULL;
00184     ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot);
00185     if (ret)
00186     {
00187         HCERTSTORE root;
00188         HCERTCHAINENGINE engine;
00189 
00190         if (pConfig->cbSize >= sizeof(CERT_CHAIN_ENGINE_CONFIG) &&
00191          pConfig->hExclusiveRoot)
00192             root = CertDuplicateStore(pConfig->hExclusiveRoot);
00193         else if (pConfig->hRestrictedRoot)
00194             root = CertDuplicateStore(pConfig->hRestrictedRoot);
00195         else
00196             root = CertOpenSystemStoreW(0, rootW);
00197         engine = CRYPT_CreateChainEngine(root, pConfig);
00198         if (engine)
00199         {
00200             *phChainEngine = engine;
00201             ret = TRUE;
00202         }
00203         else
00204             ret = FALSE;
00205     }
00206     return ret;
00207 }
00208 
00209 VOID WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
00210 {
00211     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
00212 
00213     TRACE("(%p)\n", hChainEngine);
00214 
00215     if (engine && InterlockedDecrement(&engine->ref) == 0)
00216     {
00217         CertCloseStore(engine->hWorld, 0);
00218         CertCloseStore(engine->hRoot, 0);
00219         CryptMemFree(engine);
00220     }
00221 }
00222 
00223 static HCERTCHAINENGINE CRYPT_GetDefaultChainEngine(void)
00224 {
00225     if (!CRYPT_defaultChainEngine)
00226     {
00227         CERT_CHAIN_ENGINE_CONFIG config = { 0 };
00228         HCERTCHAINENGINE engine;
00229 
00230         config.cbSize = sizeof(config);
00231         CertCreateCertificateChainEngine(&config, &engine);
00232         InterlockedCompareExchangePointer(&CRYPT_defaultChainEngine, engine,
00233          NULL);
00234         if (CRYPT_defaultChainEngine != engine)
00235             CertFreeCertificateChainEngine(engine);
00236     }
00237     return CRYPT_defaultChainEngine;
00238 }
00239 
00240 void default_chain_engine_free(void)
00241 {
00242     CertFreeCertificateChainEngine(CRYPT_defaultChainEngine);
00243 }
00244 
00245 typedef struct _CertificateChain
00246 {
00247     CERT_CHAIN_CONTEXT context;
00248     HCERTSTORE world;
00249     LONG ref;
00250 } CertificateChain, *PCertificateChain;
00251 
00252 static BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
00253 {
00254     PCERT_EXTENSION ext;
00255     DWORD size;
00256     BOOL ret;
00257 
00258     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
00259      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
00260     {
00261         CERT_AUTHORITY_KEY_ID2_INFO *info;
00262 
00263         ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
00264          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
00265          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
00266          &info, &size);
00267         if (ret)
00268         {
00269             if (info->AuthorityCertIssuer.cAltEntry &&
00270              info->AuthorityCertSerialNumber.cbData)
00271             {
00272                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
00273                 DWORD i;
00274 
00275                 for (i = 0; !directoryName &&
00276                  i < info->AuthorityCertIssuer.cAltEntry; i++)
00277                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
00278                      == CERT_ALT_NAME_DIRECTORY_NAME)
00279                         directoryName =
00280                          &info->AuthorityCertIssuer.rgAltEntry[i];
00281                 if (directoryName)
00282                 {
00283                     ret = CertCompareCertificateName(cert->dwCertEncodingType,
00284                      &directoryName->u.DirectoryName, &cert->pCertInfo->Issuer)
00285                      && CertCompareIntegerBlob(&info->AuthorityCertSerialNumber,
00286                      &cert->pCertInfo->SerialNumber);
00287                 }
00288                 else
00289                 {
00290                     FIXME("no supported name type in authority key id2\n");
00291                     ret = FALSE;
00292                 }
00293             }
00294             else if (info->KeyId.cbData)
00295             {
00296                 ret = CertGetCertificateContextProperty(cert,
00297                  CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
00298                 if (ret && size == info->KeyId.cbData)
00299                 {
00300                     LPBYTE buf = CryptMemAlloc(size);
00301 
00302                     if (buf)
00303                     {
00304                         CertGetCertificateContextProperty(cert,
00305                          CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
00306                         ret = !memcmp(buf, info->KeyId.pbData, size);
00307                         CryptMemFree(buf);
00308                     }
00309                 }
00310                 else
00311                     ret = FALSE;
00312             }
00313             LocalFree(info);
00314         }
00315     }
00316     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
00317      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
00318     {
00319         CERT_AUTHORITY_KEY_ID_INFO *info;
00320 
00321         ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
00322          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
00323          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
00324          &info, &size);
00325         if (ret)
00326         {
00327             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
00328             {
00329                 ret = CertCompareCertificateName(cert->dwCertEncodingType,
00330                  &info->CertIssuer, &cert->pCertInfo->Issuer) &&
00331                  CertCompareIntegerBlob(&info->CertSerialNumber,
00332                  &cert->pCertInfo->SerialNumber);
00333             }
00334             else if (info->KeyId.cbData)
00335             {
00336                 ret = CertGetCertificateContextProperty(cert,
00337                  CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
00338                 if (ret && size == info->KeyId.cbData)
00339                 {
00340                     LPBYTE buf = CryptMemAlloc(size);
00341 
00342                     if (buf)
00343                     {
00344                         CertGetCertificateContextProperty(cert,
00345                          CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
00346                         ret = !memcmp(buf, info->KeyId.pbData, size);
00347                         CryptMemFree(buf);
00348                     }
00349                     else
00350                         ret = FALSE;
00351                 }
00352                 else
00353                     ret = FALSE;
00354             }
00355             else
00356                 ret = FALSE;
00357             LocalFree(info);
00358         }
00359     }
00360     else
00361         ret = CertCompareCertificateName(cert->dwCertEncodingType,
00362          &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
00363     return ret;
00364 }
00365 
00366 static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
00367 {
00368     CertFreeCertificateContext(element->pCertContext);
00369     CryptMemFree(element);
00370 }
00371 
00372 static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain)
00373 {
00374     DWORD i, j, cyclicCertIndex = 0;
00375 
00376     /* O(n^2) - I don't think there's a faster way */
00377     for (i = 0; !cyclicCertIndex && i < chain->cElement; i++)
00378         for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++)
00379             if (CertCompareCertificate(X509_ASN_ENCODING,
00380              chain->rgpElement[i]->pCertContext->pCertInfo,
00381              chain->rgpElement[j]->pCertContext->pCertInfo))
00382                 cyclicCertIndex = j;
00383     if (cyclicCertIndex)
00384     {
00385         chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus
00386          |= CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
00387         /* Release remaining certs */
00388         for (i = cyclicCertIndex + 1; i < chain->cElement; i++)
00389             CRYPT_FreeChainElement(chain->rgpElement[i]);
00390         /* Truncate chain */
00391         chain->cElement = cyclicCertIndex + 1;
00392     }
00393 }
00394 
00395 /* Checks whether the chain is cyclic by examining the last element's status */
00396 static inline BOOL CRYPT_IsSimpleChainCyclic(const CERT_SIMPLE_CHAIN *chain)
00397 {
00398     if (chain->cElement)
00399         return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus
00400          & CERT_TRUST_IS_CYCLIC;
00401     else
00402         return FALSE;
00403 }
00404 
00405 static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus,
00406  const CERT_TRUST_STATUS *elementStatus)
00407 {
00408     /* Any error that applies to an element also applies to a chain.. */
00409     chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus;
00410     /* but the bottom nibble of an element's info status doesn't apply to the
00411      * chain.
00412      */
00413     chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0);
00414 }
00415 
00416 static BOOL CRYPT_AddCertToSimpleChain(const CertificateChainEngine *engine,
00417  PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus)
00418 {
00419     BOOL ret = FALSE;
00420     PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
00421 
00422     if (element)
00423     {
00424         if (!chain->cElement)
00425             chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT));
00426         else
00427             chain->rgpElement = CryptMemRealloc(chain->rgpElement,
00428              (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
00429         if (chain->rgpElement)
00430         {
00431             chain->rgpElement[chain->cElement++] = element;
00432             memset(element, 0, sizeof(CERT_CHAIN_ELEMENT));
00433             element->cbSize = sizeof(CERT_CHAIN_ELEMENT);
00434             element->pCertContext = CertDuplicateCertificateContext(cert);
00435             if (chain->cElement > 1)
00436                 chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus
00437                  = subjectInfoStatus;
00438             /* FIXME: initialize the rest of element */
00439             if (!(chain->cElement % engine->CycleDetectionModulus))
00440             {
00441                 CRYPT_CheckSimpleChainForCycles(chain);
00442                 /* Reinitialize the element pointer in case the chain is
00443                  * cyclic, in which case the chain is truncated.
00444                  */
00445                 element = chain->rgpElement[chain->cElement - 1];
00446             }
00447             CRYPT_CombineTrustStatus(&chain->TrustStatus,
00448              &element->TrustStatus);
00449             ret = TRUE;
00450         }
00451         else
00452             CryptMemFree(element);
00453     }
00454     return ret;
00455 }
00456 
00457 static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
00458 {
00459     DWORD i;
00460 
00461     for (i = 0; i < chain->cElement; i++)
00462         CRYPT_FreeChainElement(chain->rgpElement[i]);
00463     CryptMemFree(chain->rgpElement);
00464     CryptMemFree(chain);
00465 }
00466 
00467 static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot,
00468  PCERT_CHAIN_ELEMENT rootElement)
00469 {
00470     PCCERT_CONTEXT trustedRoot = CRYPT_FindCertInStore(hRoot,
00471      rootElement->pCertContext);
00472 
00473     if (!trustedRoot)
00474         rootElement->TrustStatus.dwErrorStatus |=
00475          CERT_TRUST_IS_UNTRUSTED_ROOT;
00476     else
00477         CertFreeCertificateContext(trustedRoot);
00478 }
00479 
00480 static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot,
00481  PCERT_CHAIN_ELEMENT rootElement)
00482 {
00483     PCCERT_CONTEXT root = rootElement->pCertContext;
00484 
00485     if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType,
00486      CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
00487      CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
00488     {
00489         TRACE_(chain)("Last certificate's signature is invalid\n");
00490         rootElement->TrustStatus.dwErrorStatus |=
00491          CERT_TRUST_IS_NOT_SIGNATURE_VALID;
00492     }
00493     CRYPT_CheckTrustedStatus(hRoot, rootElement);
00494 }
00495 
00496 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
00497  * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a
00498  * CERT_BASIC_CONSTRAINTS2_INFO.  If it neither extension is present, sets
00499  * constraints->fCA to defaultIfNotSpecified.
00500  * Returns FALSE if the extension is present but couldn't be decoded.
00501  */
00502 static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
00503  CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified)
00504 {
00505     BOOL ret = TRUE;
00506     PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
00507      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
00508 
00509     constraints->fPathLenConstraint = FALSE;
00510     if (ext)
00511     {
00512         CERT_BASIC_CONSTRAINTS_INFO *info;
00513         DWORD size = 0;
00514 
00515         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
00516          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
00517          NULL, &info, &size);
00518         if (ret)
00519         {
00520             if (info->SubjectType.cbData == 1)
00521                 constraints->fCA =
00522                  info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
00523             LocalFree(info);
00524         }
00525     }
00526     else
00527     {
00528         ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
00529          cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
00530         if (ext)
00531         {
00532             DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
00533 
00534             ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
00535              szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
00536              0, NULL, constraints, &size);
00537         }
00538         else
00539             constraints->fCA = defaultIfNotSpecified;
00540     }
00541     return ret;
00542 }
00543 
00544 /* Checks element's basic constraints to see if it can act as a CA, with
00545  * remainingCAs CAs left in this chain.  In general, a cert must include the
00546  * basic constraints extension, with the CA flag asserted, in order to be
00547  * allowed to be a CA.  A V1 or V2 cert, which has no extensions, is also
00548  * allowed to be a CA if it's installed locally (in the engine's world store.)
00549  * This matches the expected usage in RFC 5280, section 4.2.1.9:  a conforming
00550  * CA MUST include the basic constraints extension in all certificates that are
00551  * used to validate digital signatures on certificates.  It also matches
00552  * section 6.1.4(k): "If a certificate is a v1 or v2 certificate, then the
00553  * application MUST either verify that the certificate is a CA certificate
00554  * through out-of-band means or reject the certificate." Rejecting the
00555  * certificate prohibits a large number of commonly used certificates, so
00556  * accepting locally installed ones is a compromise.
00557  * Root certificates are also allowed to be CAs even without a basic
00558  * constraints extension.  This is implied by RFC 5280, section 6.1:  the
00559  * root of a certificate chain's only requirement is that it was used to issue
00560  * the next certificate in the chain.
00561  * Updates chainConstraints with the element's constraints, if:
00562  * 1. chainConstraints doesn't have a path length constraint, or
00563  * 2. element's path length constraint is smaller than chainConstraints's
00564  * Sets *pathLengthConstraintViolated to TRUE if a path length violation
00565  * occurs.
00566  * Returns TRUE if the element can be a CA, and the length of the remaining
00567  * chain is valid.
00568  */
00569 static BOOL CRYPT_CheckBasicConstraintsForCA(PCertificateChainEngine engine,
00570  PCCERT_CONTEXT cert, CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints,
00571  DWORD remainingCAs, BOOL isRoot, BOOL *pathLengthConstraintViolated)
00572 {
00573     BOOL validBasicConstraints, implicitCA = FALSE;
00574     CERT_BASIC_CONSTRAINTS2_INFO constraints;
00575 
00576     if (isRoot)
00577         implicitCA = TRUE;
00578     else if (cert->pCertInfo->dwVersion == CERT_V1 ||
00579      cert->pCertInfo->dwVersion == CERT_V2)
00580     {
00581         BYTE hash[20];
00582         DWORD size = sizeof(hash);
00583 
00584         if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
00585          hash, &size))
00586         {
00587             CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
00588             PCCERT_CONTEXT localCert = CertFindCertificateInStore(
00589              engine->hWorld, cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
00590              &blob, NULL);
00591 
00592             if (localCert)
00593             {
00594                 CertFreeCertificateContext(localCert);
00595                 implicitCA = TRUE;
00596             }
00597         }
00598     }
00599     if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
00600      &constraints, implicitCA)))
00601     {
00602         chainConstraints->fCA = constraints.fCA;
00603         if (!constraints.fCA)
00604         {
00605             TRACE_(chain)("chain element %d can't be a CA\n", remainingCAs + 1);
00606             validBasicConstraints = FALSE;
00607         }
00608         else if (constraints.fPathLenConstraint)
00609         {
00610             /* If the element has path length constraints, they apply to the
00611              * entire remaining chain.
00612              */
00613             if (!chainConstraints->fPathLenConstraint ||
00614              constraints.dwPathLenConstraint <
00615              chainConstraints->dwPathLenConstraint)
00616             {
00617                 TRACE_(chain)("setting path length constraint to %d\n",
00618                  chainConstraints->dwPathLenConstraint);
00619                 chainConstraints->fPathLenConstraint = TRUE;
00620                 chainConstraints->dwPathLenConstraint =
00621                  constraints.dwPathLenConstraint;
00622             }
00623         }
00624     }
00625     if (chainConstraints->fPathLenConstraint &&
00626      remainingCAs > chainConstraints->dwPathLenConstraint)
00627     {
00628         TRACE_(chain)("remaining CAs %d exceed max path length %d\n",
00629          remainingCAs, chainConstraints->dwPathLenConstraint);
00630         validBasicConstraints = FALSE;
00631         *pathLengthConstraintViolated = TRUE;
00632     }
00633     return validBasicConstraints;
00634 }
00635 
00636 static BOOL domain_name_matches(LPCWSTR constraint, LPCWSTR name)
00637 {
00638     BOOL match;
00639 
00640     /* RFC 5280, section 4.2.1.10:
00641      * "For URIs, the constraint applies to the host part of the name...
00642      *  When the constraint begins with a period, it MAY be expanded with one
00643      *  or more labels.  That is, the constraint ".example.com" is satisfied by
00644      *  both host.example.com and my.host.example.com.  However, the constraint
00645      *  ".example.com" is not satisfied by "example.com".  When the constraint
00646      *  does not begin with a period, it specifies a host."
00647      * and for email addresses,
00648      * "To indicate all Internet mail addresses on a particular host, the
00649      *  constraint is specified as the host name.  For example, the constraint
00650      *  "example.com" is satisfied by any mail address at the host
00651      *  "example.com".  To specify any address within a domain, the constraint
00652      *  is specified with a leading period (as with URIs)."
00653      */
00654     if (constraint[0] == '.')
00655     {
00656         /* Must be strictly greater than, a name can't begin with '.' */
00657         if (lstrlenW(name) > lstrlenW(constraint))
00658             match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
00659              constraint);
00660         else
00661         {
00662             /* name is too short, no match */
00663             match = FALSE;
00664         }
00665     }
00666     else
00667         match = !lstrcmpiW(name, constraint);
00668      return match;
00669 }
00670 
00671 static BOOL url_matches(LPCWSTR constraint, LPCWSTR name,
00672  DWORD *trustErrorStatus)
00673 {
00674     BOOL match = FALSE;
00675 
00676     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
00677 
00678     if (!constraint)
00679         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
00680     else if (!name)
00681         ; /* no match */
00682     else
00683     {
00684         LPCWSTR colon, authority_end, at, hostname = NULL;
00685         /* The maximum length for a hostname is 254 in the DNS, see RFC 1034 */
00686         WCHAR hostname_buf[255];
00687 
00688         /* RFC 5280: only the hostname portion of the URL is compared.  From
00689          * section 4.2.1.10:
00690          * "For URIs, the constraint applies to the host part of the name.
00691          *  The constraint MUST be specified as a fully qualified domain name
00692          *  and MAY specify a host or a domain."
00693          * The format for URIs is in RFC 2396.
00694          *
00695          * First, remove any scheme that's present. */
00696         colon = strchrW(name, ':');
00697         if (colon && *(colon + 1) == '/' && *(colon + 2) == '/')
00698             name = colon + 3;
00699         /* Next, find the end of the authority component.  (The authority is
00700          * generally just the hostname, but it may contain a username or a port.
00701          * Those are removed next.)
00702          */
00703         authority_end = strchrW(name, '/');
00704         if (!authority_end)
00705             authority_end = strchrW(name, '?');
00706         if (!authority_end)
00707             authority_end = name + strlenW(name);
00708         /* Remove any port number from the authority.  The userinfo portion
00709          * of an authority may contain a colon, so stop if a userinfo portion
00710          * is found (indicated by '@').
00711          */
00712         for (colon = authority_end; colon >= name && *colon != ':' &&
00713          *colon != '@'; colon--)
00714             ;
00715         if (*colon == ':')
00716             authority_end = colon;
00717         /* Remove any username from the authority */
00718         if ((at = strchrW(name, '@')))
00719             name = at;
00720         /* Ignore any path or query portion of the URL. */
00721         if (*authority_end)
00722         {
00723             if (authority_end - name < sizeof(hostname_buf) /
00724              sizeof(hostname_buf[0]))
00725             {
00726                 memcpy(hostname_buf, name,
00727                  (authority_end - name) * sizeof(WCHAR));
00728                 hostname_buf[authority_end - name] = 0;
00729                 hostname = hostname_buf;
00730             }
00731             /* else: Hostname is too long, not a match */
00732         }
00733         else
00734             hostname = name;
00735         if (hostname)
00736             match = domain_name_matches(constraint, hostname);
00737     }
00738     return match;
00739 }
00740 
00741 static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name,
00742  DWORD *trustErrorStatus)
00743 {
00744     BOOL match = FALSE;
00745     LPCWSTR at;
00746 
00747     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
00748 
00749     if (!constraint)
00750         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
00751     else if (!name)
00752         ; /* no match */
00753     else if (strchrW(constraint, '@'))
00754         match = !lstrcmpiW(constraint, name);
00755     else
00756     {
00757         if ((at = strchrW(name, '@')))
00758             match = domain_name_matches(constraint, at + 1);
00759         else
00760             match = !lstrcmpiW(constraint, name);
00761     }
00762     return match;
00763 }
00764 
00765 static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name,
00766  DWORD *trustErrorStatus)
00767 {
00768     BOOL match = FALSE;
00769 
00770     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
00771 
00772     if (!constraint)
00773         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
00774     else if (!name)
00775         ; /* no match */
00776     /* RFC 5280, section 4.2.1.10:
00777      * "DNS name restrictions are expressed as host.example.com.  Any DNS name
00778      *  that can be constructed by simply adding zero or more labels to the
00779      *  left-hand side of the name satisfies the name constraint.  For example,
00780      *  www.host.example.com would satisfy the constraint but host1.example.com
00781      *  would not."
00782      */
00783     else if (lstrlenW(name) == lstrlenW(constraint))
00784         match = !lstrcmpiW(name, constraint);
00785     else if (lstrlenW(name) > lstrlenW(constraint))
00786     {
00787         match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
00788          constraint);
00789         if (match)
00790         {
00791             BOOL dot = FALSE;
00792             LPCWSTR ptr;
00793 
00794             /* This only matches if name is a subdomain of constraint, i.e.
00795              * there's a '.' between the beginning of the name and the
00796              * matching portion of the name.
00797              */
00798             for (ptr = name + lstrlenW(name) - lstrlenW(constraint);
00799              !dot && ptr >= name; ptr--)
00800                 if (*ptr == '.')
00801                     dot = TRUE;
00802             match = dot;
00803         }
00804     }
00805     /* else:  name is too short, no match */
00806 
00807     return match;
00808 }
00809 
00810 static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint,
00811  const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus)
00812 {
00813     BOOL match = FALSE;
00814 
00815     TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData,
00816      name->cbData, name->pbData);
00817 
00818     /* RFC5280, section 4.2.1.10, iPAddress syntax: either 8 or 32 bytes, for
00819      * IPv4 or IPv6 addresses, respectively.
00820      */
00821     if (constraint->cbData != sizeof(DWORD) * 2 && constraint->cbData != 32)
00822         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
00823     else if (name->cbData == sizeof(DWORD) &&
00824      constraint->cbData == sizeof(DWORD) * 2)
00825     {
00826         DWORD subnet, mask, addr;
00827 
00828         memcpy(&subnet, constraint->pbData, sizeof(subnet));
00829         memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask));
00830         memcpy(&addr, name->pbData, sizeof(addr));
00831         /* These are really in big-endian order, but for equality matching we
00832          * don't need to swap to host order
00833          */
00834         match = (subnet & mask) == (addr & mask);
00835     }
00836     else if (name->cbData == 16 && constraint->cbData == 32)
00837     {
00838         const BYTE *subnet, *mask, *addr;
00839         DWORD i;
00840 
00841         subnet = constraint->pbData;
00842         mask = constraint->pbData + 16;
00843         addr = name->pbData;
00844         match = TRUE;
00845         for (i = 0; match && i < 16; i++)
00846             if ((subnet[i] & mask[i]) != (addr[i] & mask[i]))
00847                 match = FALSE;
00848     }
00849     /* else: name is wrong size, no match */
00850 
00851     return match;
00852 }
00853 
00854 static BOOL directory_name_matches(const CERT_NAME_BLOB *constraint,
00855  const CERT_NAME_BLOB *name)
00856 {
00857     CERT_NAME_INFO *constraintName;
00858     DWORD size;
00859     BOOL match = FALSE;
00860 
00861     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, constraint->pbData,
00862      constraint->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &constraintName, &size))
00863     {
00864         DWORD i;
00865 
00866         match = TRUE;
00867         for (i = 0; match && i < constraintName->cRDN; i++)
00868             match = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING,
00869              CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG,
00870              (CERT_NAME_BLOB *)name, &constraintName->rgRDN[i]);
00871         LocalFree(constraintName);
00872     }
00873     return match;
00874 }
00875 
00876 static BOOL alt_name_matches(const CERT_ALT_NAME_ENTRY *name,
00877  const CERT_ALT_NAME_ENTRY *constraint, DWORD *trustErrorStatus, BOOL *present)
00878 {
00879     BOOL match = FALSE;
00880 
00881     if (name->dwAltNameChoice == constraint->dwAltNameChoice)
00882     {
00883         if (present)
00884             *present = TRUE;
00885         switch (constraint->dwAltNameChoice)
00886         {
00887         case CERT_ALT_NAME_RFC822_NAME:
00888             match = rfc822_name_matches(constraint->u.pwszURL,
00889              name->u.pwszURL, trustErrorStatus);
00890             break;
00891         case CERT_ALT_NAME_DNS_NAME:
00892             match = dns_name_matches(constraint->u.pwszURL,
00893              name->u.pwszURL, trustErrorStatus);
00894             break;
00895         case CERT_ALT_NAME_URL:
00896             match = url_matches(constraint->u.pwszURL,
00897              name->u.pwszURL, trustErrorStatus);
00898             break;
00899         case CERT_ALT_NAME_IP_ADDRESS:
00900             match = ip_address_matches(&constraint->u.IPAddress,
00901              &name->u.IPAddress, trustErrorStatus);
00902             break;
00903         case CERT_ALT_NAME_DIRECTORY_NAME:
00904             match = directory_name_matches(&constraint->u.DirectoryName,
00905              &name->u.DirectoryName);
00906             break;
00907         default:
00908             ERR("name choice %d unsupported in this context\n",
00909              constraint->dwAltNameChoice);
00910             *trustErrorStatus |=
00911              CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
00912         }
00913     }
00914     else if (present)
00915         *present = FALSE;
00916     return match;
00917 }
00918 
00919 static BOOL alt_name_matches_excluded_name(const CERT_ALT_NAME_ENTRY *name,
00920  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
00921 {
00922     DWORD i;
00923     BOOL match = FALSE;
00924 
00925     for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++)
00926         match = alt_name_matches(name,
00927          &nameConstraints->rgExcludedSubtree[i].Base, trustErrorStatus, NULL);
00928     return match;
00929 }
00930 
00931 static BOOL alt_name_matches_permitted_name(const CERT_ALT_NAME_ENTRY *name,
00932  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus,
00933  BOOL *present)
00934 {
00935     DWORD i;
00936     BOOL match = FALSE;
00937 
00938     for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
00939         match = alt_name_matches(name,
00940          &nameConstraints->rgPermittedSubtree[i].Base, trustErrorStatus,
00941          present);
00942     return match;
00943 }
00944 
00945 static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert)
00946 {
00947     PCERT_EXTENSION ext;
00948 
00949     ext = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
00950      cert->cExtension, cert->rgExtension);
00951     if (!ext)
00952         ext = CertFindExtension(szOID_SUBJECT_ALT_NAME,
00953          cert->cExtension, cert->rgExtension);
00954     return ext;
00955 }
00956 
00957 static void compare_alt_name_with_constraints(const CERT_EXTENSION *altNameExt,
00958  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
00959 {
00960     CERT_ALT_NAME_INFO *subjectAltName;
00961     DWORD size;
00962 
00963     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
00964      altNameExt->Value.pbData, altNameExt->Value.cbData,
00965      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
00966      &subjectAltName, &size))
00967     {
00968         DWORD i;
00969 
00970         for (i = 0; i < subjectAltName->cAltEntry; i++)
00971         {
00972              BOOL nameFormPresent;
00973 
00974              /* A name constraint only applies if the name form is present.
00975               * From RFC 5280, section 4.2.1.10:
00976               * "Restrictions apply only when the specified name form is
00977               *  present.  If no name of the type is in the certificate,
00978               *  the certificate is acceptable."
00979               */
00980             if (alt_name_matches_excluded_name(
00981              &subjectAltName->rgAltEntry[i], nameConstraints,
00982              trustErrorStatus))
00983             {
00984                 TRACE_(chain)("subject alternate name form %d excluded\n",
00985                  subjectAltName->rgAltEntry[i].dwAltNameChoice);
00986                 *trustErrorStatus |=
00987                  CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
00988             }
00989             nameFormPresent = FALSE;
00990             if (!alt_name_matches_permitted_name(
00991              &subjectAltName->rgAltEntry[i], nameConstraints,
00992              trustErrorStatus, &nameFormPresent) && nameFormPresent)
00993             {
00994                 TRACE_(chain)("subject alternate name form %d not permitted\n",
00995                  subjectAltName->rgAltEntry[i].dwAltNameChoice);
00996                 *trustErrorStatus |=
00997                  CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
00998             }
00999         }
01000         LocalFree(subjectAltName);
01001     }
01002     else
01003         *trustErrorStatus |=
01004          CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS;
01005 }
01006 
01007 static BOOL rfc822_attr_matches_excluded_name(const CERT_RDN_ATTR *attr,
01008  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
01009 {
01010     DWORD i;
01011     BOOL match = FALSE;
01012 
01013     for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++)
01014     {
01015         const CERT_ALT_NAME_ENTRY *constraint =
01016          &nameConstraints->rgExcludedSubtree[i].Base;
01017 
01018         if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
01019             match = rfc822_name_matches(constraint->u.pwszRfc822Name,
01020              (LPCWSTR)attr->Value.pbData, trustErrorStatus);
01021     }
01022     return match;
01023 }
01024 
01025 static BOOL rfc822_attr_matches_permitted_name(const CERT_RDN_ATTR *attr,
01026  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus,
01027  BOOL *present)
01028 {
01029     DWORD i;
01030     BOOL match = FALSE;
01031 
01032     for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
01033     {
01034         const CERT_ALT_NAME_ENTRY *constraint =
01035          &nameConstraints->rgPermittedSubtree[i].Base;
01036 
01037         if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
01038         {
01039             *present = TRUE;
01040             match = rfc822_name_matches(constraint->u.pwszRfc822Name,
01041              (LPCWSTR)attr->Value.pbData, trustErrorStatus);
01042         }
01043     }
01044     return match;
01045 }
01046 
01047 static void compare_subject_with_email_constraints(
01048  const CERT_NAME_BLOB *subjectName,
01049  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
01050 {
01051     CERT_NAME_INFO *name;
01052     DWORD size;
01053 
01054     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME,
01055      subjectName->pbData, subjectName->cbData,
01056      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size))
01057     {
01058         DWORD i, j;
01059 
01060         for (i = 0; i < name->cRDN; i++)
01061             for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
01062                 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
01063                  szOID_RSA_emailAddr))
01064                 {
01065                     BOOL nameFormPresent;
01066 
01067                     /* A name constraint only applies if the name form is
01068                      * present.  From RFC 5280, section 4.2.1.10:
01069                      * "Restrictions apply only when the specified name form is
01070                      *  present.  If no name of the type is in the certificate,
01071                      *  the certificate is acceptable."
01072                      */
01073                     if (rfc822_attr_matches_excluded_name(
01074                      &name->rgRDN[i].rgRDNAttr[j], nameConstraints,
01075                      trustErrorStatus))
01076                     {
01077                         TRACE_(chain)(
01078                          "email address in subject name is excluded\n");
01079                         *trustErrorStatus |=
01080                          CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
01081                     }
01082                     nameFormPresent = FALSE;
01083                     if (!rfc822_attr_matches_permitted_name(
01084                      &name->rgRDN[i].rgRDNAttr[j], nameConstraints,
01085                      trustErrorStatus, &nameFormPresent) && nameFormPresent)
01086                     {
01087                         TRACE_(chain)(
01088                          "email address in subject name is not permitted\n");
01089                         *trustErrorStatus |=
01090                          CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
01091                     }
01092                 }
01093         LocalFree(name);
01094     }
01095     else
01096         *trustErrorStatus |=
01097          CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS;
01098 }
01099 
01100 static BOOL CRYPT_IsEmptyName(const CERT_NAME_BLOB *name)
01101 {
01102     BOOL empty;
01103 
01104     if (!name->cbData)
01105         empty = TRUE;
01106     else if (name->cbData == 2 && name->pbData[1] == 0)
01107     {
01108         /* An empty sequence is also empty */
01109         empty = TRUE;
01110     }
01111     else
01112         empty = FALSE;
01113     return empty;
01114 }
01115 
01116 static void compare_subject_with_constraints(const CERT_NAME_BLOB *subjectName,
01117  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
01118 {
01119     BOOL hasEmailConstraint = FALSE;
01120     DWORD i;
01121 
01122     /* In general, a subject distinguished name only matches a directory name
01123      * constraint.  However, an exception exists for email addresses.
01124      * From RFC 5280, section 4.2.1.6:
01125      * "Legacy implementations exist where an electronic mail address is
01126      *  embedded in the subject distinguished name as an emailAddress
01127      *  attribute [RFC2985]."
01128      * If an email address constraint exists, check that constraint separately.
01129      */
01130     for (i = 0; !hasEmailConstraint && i < nameConstraints->cExcludedSubtree;
01131      i++)
01132         if (nameConstraints->rgExcludedSubtree[i].Base.dwAltNameChoice ==
01133          CERT_ALT_NAME_RFC822_NAME)
01134             hasEmailConstraint = TRUE;
01135     for (i = 0; !hasEmailConstraint && i < nameConstraints->cPermittedSubtree;
01136      i++)
01137         if (nameConstraints->rgPermittedSubtree[i].Base.dwAltNameChoice ==
01138          CERT_ALT_NAME_RFC822_NAME)
01139             hasEmailConstraint = TRUE;
01140     if (hasEmailConstraint)
01141         compare_subject_with_email_constraints(subjectName, nameConstraints,
01142          trustErrorStatus);
01143     for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
01144     {
01145         CERT_ALT_NAME_ENTRY *constraint =
01146          &nameConstraints->rgExcludedSubtree[i].Base;
01147 
01148         if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME &&
01149          directory_name_matches(&constraint->u.DirectoryName, subjectName))
01150         {
01151             TRACE_(chain)("subject name is excluded\n");
01152             *trustErrorStatus |=
01153              CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
01154         }
01155     }
01156     /* RFC 5280, section 4.2.1.10:
01157      * "Restrictions apply only when the specified name form is present.
01158      *  If no name of the type is in the certificate, the certificate is
01159      *  acceptable."
01160      * An empty name can't have the name form present, so don't check it.
01161      */
01162     if (nameConstraints->cPermittedSubtree && !CRYPT_IsEmptyName(subjectName))
01163     {
01164         BOOL match = FALSE, hasDirectoryConstraint = FALSE;
01165 
01166         for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
01167         {
01168             CERT_ALT_NAME_ENTRY *constraint =
01169              &nameConstraints->rgPermittedSubtree[i].Base;
01170 
01171             if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME)
01172             {
01173                 hasDirectoryConstraint = TRUE;
01174                 match = directory_name_matches(&constraint->u.DirectoryName,
01175                  subjectName);
01176             }
01177         }
01178         if (hasDirectoryConstraint && !match)
01179         {
01180             TRACE_(chain)("subject name is not permitted\n");
01181             *trustErrorStatus |= CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
01182         }
01183     }
01184 }
01185 
01186 static void CRYPT_CheckNameConstraints(
01187  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
01188  DWORD *trustErrorStatus)
01189 {
01190     CERT_EXTENSION *ext = get_subject_alt_name_ext(cert);
01191 
01192     if (ext)
01193         compare_alt_name_with_constraints(ext, nameConstraints,
01194          trustErrorStatus);
01195     /* Name constraints apply to the subject alternative name as well as the
01196      * subject name.  From RFC 5280, section 4.2.1.10:
01197      * "Restrictions apply to the subject distinguished name and apply to
01198      *  subject alternative names."
01199      */
01200     compare_subject_with_constraints(&cert->Subject, nameConstraints,
01201      trustErrorStatus);
01202 }
01203 
01204 /* Gets cert's name constraints, if any.  Free with LocalFree. */
01205 static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert)
01206 {
01207     CERT_NAME_CONSTRAINTS_INFO *info = NULL;
01208 
01209     CERT_EXTENSION *ext;
01210 
01211     if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension,
01212      cert->rgExtension)))
01213     {
01214         DWORD size;
01215 
01216         CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
01217          ext->Value.pbData, ext->Value.cbData,
01218          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info,
01219          &size);
01220     }
01221     return info;
01222 }
01223 
01224 static BOOL CRYPT_IsValidNameConstraint(const CERT_NAME_CONSTRAINTS_INFO *info)
01225 {
01226     DWORD i;
01227     BOOL ret = TRUE;
01228 
01229     /* Make sure at least one permitted or excluded subtree is present.  From
01230      * RFC 5280, section 4.2.1.10:
01231      * "Conforming CAs MUST NOT issue certificates where name constraints is an
01232      *  empty sequence.  That is, either the permittedSubtrees field or the
01233      *  excludedSubtrees MUST be present."
01234      */
01235     if (!info->cPermittedSubtree && !info->cExcludedSubtree)
01236     {
01237         WARN_(chain)("constraints contain no permitted nor excluded subtree\n");
01238         ret = FALSE;
01239     }
01240     /* Check that none of the constraints specifies a minimum or a maximum.
01241      * See RFC 5280, section 4.2.1.10:
01242      * "Within this profile, the minimum and maximum fields are not used with
01243      *  any name forms, thus, the minimum MUST be zero, and maximum MUST be
01244      *  absent.  However, if an application encounters a critical name
01245      *  constraints extension that specifies other values for minimum or
01246      *  maximum for a name form that appears in a subsequent certificate, the
01247      *  application MUST either process these fields or reject the
01248      *  certificate."
01249      * Since it gives no guidance as to how to process these fields, we
01250      * reject any name constraint that contains them.
01251      */
01252     for (i = 0; ret && i < info->cPermittedSubtree; i++)
01253         if (info->rgPermittedSubtree[i].dwMinimum ||
01254          info->rgPermittedSubtree[i].fMaximum)
01255         {
01256             TRACE_(chain)("found a minimum or maximum in permitted subtrees\n");
01257             ret = FALSE;
01258         }
01259     for (i = 0; ret && i < info->cExcludedSubtree; i++)
01260         if (info->rgExcludedSubtree[i].dwMinimum ||
01261          info->rgExcludedSubtree[i].fMaximum)
01262         {
01263             TRACE_(chain)("found a minimum or maximum in excluded subtrees\n");
01264             ret = FALSE;
01265         }
01266     return ret;
01267 }
01268 
01269 static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
01270 {
01271     int i, j;
01272 
01273     /* Microsoft's implementation appears to violate RFC 3280:  according to
01274      * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's
01275      * name constraint is violated in the end cert.  According to RFC 3280,
01276      * the constraints should be checked against every subsequent certificate
01277      * in the chain, not just the end cert.
01278      * Microsoft's implementation also sets the name constraint errors on the
01279      * certs whose constraints were violated, not on the certs that violated
01280      * them.
01281      * In order to be error-compatible with Microsoft's implementation, while
01282      * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name
01283      * constraints.
01284      */
01285     for (i = chain->cElement - 1; i > 0; i--)
01286     {
01287         CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
01288 
01289         if ((nameConstraints = CRYPT_GetNameConstraints(
01290          chain->rgpElement[i]->pCertContext->pCertInfo)))
01291         {
01292             if (!CRYPT_IsValidNameConstraint(nameConstraints))
01293                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01294                  CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
01295             else
01296             {
01297                 for (j = i - 1; j >= 0; j--)
01298                 {
01299                     DWORD errorStatus = 0;
01300 
01301                     /* According to RFC 3280, self-signed certs don't have name
01302                      * constraints checked unless they're the end cert.
01303                      */
01304                     if (j == 0 || !CRYPT_IsCertificateSelfSigned(
01305                      chain->rgpElement[j]->pCertContext))
01306                     {
01307                         CRYPT_CheckNameConstraints(nameConstraints,
01308                          chain->rgpElement[j]->pCertContext->pCertInfo,
01309                          &errorStatus);
01310                         if (errorStatus)
01311                         {
01312                             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01313                              errorStatus;
01314                             CRYPT_CombineTrustStatus(&chain->TrustStatus,
01315                              &chain->rgpElement[i]->TrustStatus);
01316                         }
01317                         else
01318                             chain->rgpElement[i]->TrustStatus.dwInfoStatus |=
01319                              CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS;
01320                     }
01321                 }
01322             }
01323             LocalFree(nameConstraints);
01324         }
01325     }
01326 }
01327 
01328 /* Gets cert's policies info, if any.  Free with LocalFree. */
01329 static CERT_POLICIES_INFO *CRYPT_GetPolicies(PCCERT_CONTEXT cert)
01330 {
01331     PCERT_EXTENSION ext;
01332     CERT_POLICIES_INFO *policies = NULL;
01333 
01334     ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension,
01335      cert->pCertInfo->rgExtension);
01336     if (ext)
01337     {
01338         DWORD size;
01339 
01340         CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
01341          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
01342          &policies, &size);
01343     }
01344     return policies;
01345 }
01346 
01347 static void CRYPT_CheckPolicies(const CERT_POLICIES_INFO *policies, CERT_INFO *cert,
01348  DWORD *errorStatus)
01349 {
01350     DWORD i;
01351 
01352     for (i = 0; i < policies->cPolicyInfo; i++)
01353     {
01354         /* For now, the only accepted policy identifier is the anyPolicy
01355          * identifier.
01356          * FIXME: the policy identifiers should be compared against the
01357          * cert's certificate policies extension, subject to the policy
01358          * mappings extension, and the policy constraints extension.
01359          * See RFC 5280, sections 4.2.1.4, 4.2.1.5, and 4.2.1.11.
01360          */
01361         if (strcmp(policies->rgPolicyInfo[i].pszPolicyIdentifier,
01362          szOID_ANY_CERT_POLICY))
01363         {
01364             FIXME("unsupported policy %s\n",
01365              policies->rgPolicyInfo[i].pszPolicyIdentifier);
01366             *errorStatus |= CERT_TRUST_INVALID_POLICY_CONSTRAINTS;
01367         }
01368     }
01369 }
01370 
01371 static void CRYPT_CheckChainPolicies(PCERT_SIMPLE_CHAIN chain)
01372 {
01373     int i, j;
01374 
01375     for (i = chain->cElement - 1; i > 0; i--)
01376     {
01377         CERT_POLICIES_INFO *policies;
01378 
01379         if ((policies = CRYPT_GetPolicies(chain->rgpElement[i]->pCertContext)))
01380         {
01381             for (j = i - 1; j >= 0; j--)
01382             {
01383                 DWORD errorStatus = 0;
01384 
01385                 CRYPT_CheckPolicies(policies,
01386                  chain->rgpElement[j]->pCertContext->pCertInfo, &errorStatus);
01387                 if (errorStatus)
01388                 {
01389                     chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01390                      errorStatus;
01391                     CRYPT_CombineTrustStatus(&chain->TrustStatus,
01392                      &chain->rgpElement[i]->TrustStatus);
01393                 }
01394             }
01395             LocalFree(policies);
01396         }
01397     }
01398 }
01399 
01400 static LPWSTR name_value_to_str(const CERT_NAME_BLOB *name)
01401 {
01402     DWORD len = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name,
01403      CERT_SIMPLE_NAME_STR, NULL, 0);
01404     LPWSTR str = NULL;
01405 
01406     if (len)
01407     {
01408         str = CryptMemAlloc(len * sizeof(WCHAR));
01409         if (str)
01410             cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name,
01411              CERT_SIMPLE_NAME_STR, str, len);
01412     }
01413     return str;
01414 }
01415 
01416 static void dump_alt_name_entry(const CERT_ALT_NAME_ENTRY *entry)
01417 {
01418     LPWSTR str;
01419 
01420     switch (entry->dwAltNameChoice)
01421     {
01422     case CERT_ALT_NAME_OTHER_NAME:
01423         TRACE_(chain)("CERT_ALT_NAME_OTHER_NAME, oid = %s\n",
01424          debugstr_a(entry->u.pOtherName->pszObjId));
01425          break;
01426     case CERT_ALT_NAME_RFC822_NAME:
01427         TRACE_(chain)("CERT_ALT_NAME_RFC822_NAME: %s\n",
01428          debugstr_w(entry->u.pwszRfc822Name));
01429         break;
01430     case CERT_ALT_NAME_DNS_NAME:
01431         TRACE_(chain)("CERT_ALT_NAME_DNS_NAME: %s\n",
01432          debugstr_w(entry->u.pwszDNSName));
01433         break;
01434     case CERT_ALT_NAME_DIRECTORY_NAME:
01435         str = name_value_to_str(&entry->u.DirectoryName);
01436         TRACE_(chain)("CERT_ALT_NAME_DIRECTORY_NAME: %s\n", debugstr_w(str));
01437         CryptMemFree(str);
01438         break;
01439     case CERT_ALT_NAME_URL:
01440         TRACE_(chain)("CERT_ALT_NAME_URL: %s\n", debugstr_w(entry->u.pwszURL));
01441         break;
01442     case CERT_ALT_NAME_IP_ADDRESS:
01443         TRACE_(chain)("CERT_ALT_NAME_IP_ADDRESS: %d bytes\n",
01444          entry->u.IPAddress.cbData);
01445         break;
01446     case CERT_ALT_NAME_REGISTERED_ID:
01447         TRACE_(chain)("CERT_ALT_NAME_REGISTERED_ID: %s\n",
01448          debugstr_a(entry->u.pszRegisteredID));
01449         break;
01450     default:
01451         TRACE_(chain)("dwAltNameChoice = %d\n", entry->dwAltNameChoice);
01452     }
01453 }
01454 
01455 static void dump_alt_name(LPCSTR type, const CERT_EXTENSION *ext)
01456 {
01457     CERT_ALT_NAME_INFO *name;
01458     DWORD size;
01459 
01460     TRACE_(chain)("%s:\n", type);
01461     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
01462      ext->Value.pbData, ext->Value.cbData,
01463      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size))
01464     {
01465         DWORD i;
01466 
01467         TRACE_(chain)("%d alt name entries:\n", name->cAltEntry);
01468         for (i = 0; i < name->cAltEntry; i++)
01469             dump_alt_name_entry(&name->rgAltEntry[i]);
01470         LocalFree(name);
01471     }
01472 }
01473 
01474 static void dump_basic_constraints(const CERT_EXTENSION *ext)
01475 {
01476     CERT_BASIC_CONSTRAINTS_INFO *info;
01477     DWORD size = 0;
01478 
01479     if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
01480      ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
01481      NULL, &info, &size))
01482     {
01483         TRACE_(chain)("SubjectType: %02x\n", info->SubjectType.pbData[0]);
01484         TRACE_(chain)("%s path length constraint\n",
01485          info->fPathLenConstraint ? "has" : "doesn't have");
01486         TRACE_(chain)("path length=%d\n", info->dwPathLenConstraint);
01487         LocalFree(info);
01488     }
01489 }
01490 
01491 static void dump_basic_constraints2(const CERT_EXTENSION *ext)
01492 {
01493     CERT_BASIC_CONSTRAINTS2_INFO constraints;
01494     DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
01495 
01496     if (CryptDecodeObjectEx(X509_ASN_ENCODING,
01497      szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
01498      0, NULL, &constraints, &size))
01499     {
01500         TRACE_(chain)("basic constraints:\n");
01501         TRACE_(chain)("can%s be a CA\n", constraints.fCA ? "" : "not");
01502         TRACE_(chain)("%s path length constraint\n",
01503          constraints.fPathLenConstraint ? "has" : "doesn't have");
01504         TRACE_(chain)("path length=%d\n", constraints.dwPathLenConstraint);
01505     }
01506 }
01507 
01508 static void dump_key_usage(const CERT_EXTENSION *ext)
01509 {
01510     CRYPT_BIT_BLOB usage;
01511     DWORD size = sizeof(usage);
01512 
01513     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData,
01514      ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
01515     {
01516 #define trace_usage_bit(bits, bit) \
01517  if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
01518         if (usage.cbData)
01519         {
01520             trace_usage_bit(usage.pbData[0], CERT_DIGITAL_SIGNATURE_KEY_USAGE);
01521             trace_usage_bit(usage.pbData[0], CERT_NON_REPUDIATION_KEY_USAGE);
01522             trace_usage_bit(usage.pbData[0], CERT_KEY_ENCIPHERMENT_KEY_USAGE);
01523             trace_usage_bit(usage.pbData[0], CERT_DATA_ENCIPHERMENT_KEY_USAGE);
01524             trace_usage_bit(usage.pbData[0], CERT_KEY_AGREEMENT_KEY_USAGE);
01525             trace_usage_bit(usage.pbData[0], CERT_KEY_CERT_SIGN_KEY_USAGE);
01526             trace_usage_bit(usage.pbData[0], CERT_CRL_SIGN_KEY_USAGE);
01527             trace_usage_bit(usage.pbData[0], CERT_ENCIPHER_ONLY_KEY_USAGE);
01528         }
01529 #undef trace_usage_bit
01530         if (usage.cbData > 1 && usage.pbData[1] & CERT_DECIPHER_ONLY_KEY_USAGE)
01531             TRACE_(chain)("CERT_DECIPHER_ONLY_KEY_USAGE\n");
01532     }
01533 }
01534 
01535 static void dump_general_subtree(const CERT_GENERAL_SUBTREE *subtree)
01536 {
01537     dump_alt_name_entry(&subtree->Base);
01538     TRACE_(chain)("dwMinimum = %d, fMaximum = %d, dwMaximum = %d\n",
01539      subtree->dwMinimum, subtree->fMaximum, subtree->dwMaximum);
01540 }
01541 
01542 static void dump_name_constraints(const CERT_EXTENSION *ext)
01543 {
01544     CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
01545     DWORD size;
01546 
01547     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
01548      ext->Value.pbData, ext->Value.cbData,
01549      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &nameConstraints,
01550      &size))
01551     {
01552         DWORD i;
01553 
01554         TRACE_(chain)("%d permitted subtrees:\n",
01555          nameConstraints->cPermittedSubtree);
01556         for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
01557             dump_general_subtree(&nameConstraints->rgPermittedSubtree[i]);
01558         TRACE_(chain)("%d excluded subtrees:\n",
01559          nameConstraints->cExcludedSubtree);
01560         for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
01561             dump_general_subtree(&nameConstraints->rgExcludedSubtree[i]);
01562         LocalFree(nameConstraints);
01563     }
01564 }
01565 
01566 static void dump_cert_policies(const CERT_EXTENSION *ext)
01567 {
01568     CERT_POLICIES_INFO *policies;
01569     DWORD size;
01570 
01571     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
01572      ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
01573      &policies, &size))
01574     {
01575         DWORD i, j;
01576 
01577         TRACE_(chain)("%d policies:\n", policies->cPolicyInfo);
01578         for (i = 0; i < policies->cPolicyInfo; i++)
01579         {
01580             TRACE_(chain)("policy identifier: %s\n",
01581              debugstr_a(policies->rgPolicyInfo[i].pszPolicyIdentifier));
01582             TRACE_(chain)("%d policy qualifiers:\n",
01583              policies->rgPolicyInfo[i].cPolicyQualifier);
01584             for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
01585                 TRACE_(chain)("%s\n", debugstr_a(
01586                  policies->rgPolicyInfo[i].rgPolicyQualifier[j].
01587                  pszPolicyQualifierId));
01588         }
01589         LocalFree(policies);
01590     }
01591 }
01592 
01593 static void dump_enhanced_key_usage(const CERT_EXTENSION *ext)
01594 {
01595     CERT_ENHKEY_USAGE *usage;
01596     DWORD size;
01597 
01598     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
01599      ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
01600      &usage, &size))
01601     {
01602         DWORD i;
01603 
01604         TRACE_(chain)("%d usages:\n", usage->cUsageIdentifier);
01605         for (i = 0; i < usage->cUsageIdentifier; i++)
01606             TRACE_(chain)("%s\n", usage->rgpszUsageIdentifier[i]);
01607         LocalFree(usage);
01608     }
01609 }
01610 
01611 static void dump_netscape_cert_type(const CERT_EXTENSION *ext)
01612 {
01613     CRYPT_BIT_BLOB usage;
01614     DWORD size = sizeof(usage);
01615 
01616     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData,
01617      ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
01618     {
01619 #define trace_cert_type_bit(bits, bit) \
01620  if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
01621         if (usage.cbData)
01622         {
01623             trace_cert_type_bit(usage.pbData[0],
01624              NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE);
01625             trace_cert_type_bit(usage.pbData[0],
01626              NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE);
01627             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CERT_TYPE);
01628             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CERT_TYPE);
01629             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SSL_CA_CERT_TYPE);
01630             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CA_CERT_TYPE);
01631             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CA_CERT_TYPE);
01632         }
01633 #undef trace_cert_type_bit
01634     }
01635 }
01636 
01637 static void dump_extension(const CERT_EXTENSION *ext)
01638 {
01639     TRACE_(chain)("%s (%scritical)\n", debugstr_a(ext->pszObjId),
01640      ext->fCritical ? "" : "not ");
01641     if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME))
01642         dump_alt_name("subject alt name", ext);
01643     else  if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME))
01644         dump_alt_name("issuer alt name", ext);
01645     else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS))
01646         dump_basic_constraints(ext);
01647     else if (!strcmp(ext->pszObjId, szOID_KEY_USAGE))
01648         dump_key_usage(ext);
01649     else if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME2))
01650         dump_alt_name("subject alt name 2", ext);
01651     else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME2))
01652         dump_alt_name("issuer alt name 2", ext);
01653     else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS2))
01654         dump_basic_constraints2(ext);
01655     else if (!strcmp(ext->pszObjId, szOID_NAME_CONSTRAINTS))
01656         dump_name_constraints(ext);
01657     else if (!strcmp(ext->pszObjId, szOID_CERT_POLICIES))
01658         dump_cert_policies(ext);
01659     else if (!strcmp(ext->pszObjId, szOID_ENHANCED_KEY_USAGE))
01660         dump_enhanced_key_usage(ext);
01661     else if (!strcmp(ext->pszObjId, szOID_NETSCAPE_CERT_TYPE))
01662         dump_netscape_cert_type(ext);
01663 }
01664 
01665 static LPCSTR filetime_to_str(const FILETIME *time)
01666 {
01667     char date[80];
01668     char dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
01669     SYSTEMTIME sysTime;
01670 
01671     if (!time) return "(null)";
01672 
01673     GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
01674      sizeof(dateFmt) / sizeof(dateFmt[0]));
01675     FileTimeToSystemTime(time, &sysTime);
01676     GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
01677      sizeof(date) / sizeof(date[0]));
01678     return wine_dbg_sprintf("%s", date);
01679 }
01680 
01681 static void dump_element(PCCERT_CONTEXT cert)
01682 {
01683     LPWSTR name = NULL;
01684     DWORD len, i;
01685 
01686     TRACE_(chain)("%p: version %d\n", cert, cert->pCertInfo->dwVersion);
01687     len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
01688      CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
01689     name = CryptMemAlloc(len * sizeof(WCHAR));
01690     if (name)
01691     {
01692         CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
01693          CERT_NAME_ISSUER_FLAG, NULL, name, len);
01694         TRACE_(chain)("issued by %s\n", debugstr_w(name));
01695         CryptMemFree(name);
01696     }
01697     len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
01698      NULL, 0);
01699     name = CryptMemAlloc(len * sizeof(WCHAR));
01700     if (name)
01701     {
01702         CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
01703          name, len);
01704         TRACE_(chain)("issued to %s\n", debugstr_w(name));
01705         CryptMemFree(name);
01706     }
01707     TRACE_(chain)("valid from %s to %s\n",
01708      filetime_to_str(&cert->pCertInfo->NotBefore),
01709      filetime_to_str(&cert->pCertInfo->NotAfter));
01710     TRACE_(chain)("%d extensions\n", cert->pCertInfo->cExtension);
01711     for (i = 0; i < cert->pCertInfo->cExtension; i++)
01712         dump_extension(&cert->pCertInfo->rgExtension[i]);
01713 }
01714 
01715 static BOOL CRYPT_KeyUsageValid(PCertificateChainEngine engine,
01716  PCCERT_CONTEXT cert, BOOL isRoot, BOOL isCA, DWORD index)
01717 {
01718     PCERT_EXTENSION ext;
01719     BOOL ret;
01720     BYTE usageBits = 0;
01721 
01722     ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension,
01723      cert->pCertInfo->rgExtension);
01724     if (ext)
01725     {
01726         CRYPT_BIT_BLOB usage;
01727         DWORD size = sizeof(usage);
01728 
01729         ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS,
01730          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
01731          &usage, &size);
01732         if (!ret)
01733             return FALSE;
01734         else if (usage.cbData > 2)
01735         {
01736             /* The key usage extension only defines 9 bits => no more than 2
01737              * bytes are needed to encode all known usages.
01738              */
01739             return FALSE;
01740         }
01741         else
01742         {
01743             /* The only bit relevant to chain validation is the keyCertSign
01744              * bit, which is always in the least significant byte of the
01745              * key usage bits.
01746              */
01747             usageBits = usage.pbData[usage.cbData - 1];
01748         }
01749     }
01750     if (isCA)
01751     {
01752         if (!ext)
01753         {
01754             /* MS appears to violate RFC 5280, section 4.2.1.3 (Key Usage)
01755              * here.  Quoting the RFC:
01756              * "This [key usage] extension MUST appear in certificates that
01757              * contain public keys that are used to validate digital signatures
01758              * on other public key certificates or CRLs."
01759              * MS appears to accept certs that do not contain key usage
01760              * extensions as CA certs.  V1 and V2 certificates did not have
01761              * extensions, and many root certificates are V1 certificates, so
01762              * perhaps this is prudent.  On the other hand, MS also accepts V3
01763              * certs without key usage extensions.  Because some CAs, e.g.
01764              * Certum, also do not include key usage extensions in their
01765              * intermediate certificates, we are forced to accept V3
01766              * certificates without key usage extensions as well.
01767              */
01768             ret = TRUE;
01769         }
01770         else
01771         {
01772             if (!(usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE))
01773             {
01774                 WARN_(chain)("keyCertSign not asserted on a CA cert\n");
01775                 ret = FALSE;
01776             }
01777             else
01778                 ret = TRUE;
01779         }
01780     }
01781     else
01782     {
01783         if (ext && (usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE))
01784         {
01785             WARN_(chain)("keyCertSign asserted on a non-CA cert\n");
01786             ret = FALSE;
01787         }
01788         else
01789             ret = TRUE;
01790     }
01791     return ret;
01792 }
01793 
01794 static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
01795 {
01796     BOOL ret = TRUE;
01797     DWORD i;
01798 
01799     for (i = 0; ret && i < cert->pCertInfo->cExtension; i++)
01800     {
01801         if (cert->pCertInfo->rgExtension[i].fCritical)
01802         {
01803             LPCSTR oid = cert->pCertInfo->rgExtension[i].pszObjId;
01804 
01805             if (!strcmp(oid, szOID_BASIC_CONSTRAINTS))
01806                 ret = TRUE;
01807             else if (!strcmp(oid, szOID_BASIC_CONSTRAINTS2))
01808                 ret = TRUE;
01809             else if (!strcmp(oid, szOID_NAME_CONSTRAINTS))
01810                 ret = TRUE;
01811             else if (!strcmp(oid, szOID_KEY_USAGE))
01812                 ret = TRUE;
01813             else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME))
01814                 ret = TRUE;
01815             else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME2))
01816                 ret = TRUE;
01817             else if (!strcmp(oid, szOID_CERT_POLICIES))
01818                 ret = TRUE;
01819             else if (!strcmp(oid, szOID_ENHANCED_KEY_USAGE))
01820                 ret = TRUE;
01821             else
01822             {
01823                 FIXME("unsupported critical extension %s\n",
01824                  debugstr_a(oid));
01825                 ret = FALSE;
01826             }
01827         }
01828     }
01829     return ret;
01830 }
01831 
01832 static BOOL CRYPT_IsCertVersionValid(PCCERT_CONTEXT cert)
01833 {
01834     BOOL ret = TRUE;
01835 
01836     /* Checks whether the contents of the cert match the cert's version. */
01837     switch (cert->pCertInfo->dwVersion)
01838     {
01839     case CERT_V1:
01840         /* A V1 cert may not contain unique identifiers.  See RFC 5280,
01841          * section 4.1.2.8:
01842          * "These fields MUST only appear if the version is 2 or 3 (Section
01843          *  4.1.2.1).  These fields MUST NOT appear if the version is 1."
01844          */
01845         if (cert->pCertInfo->IssuerUniqueId.cbData ||
01846          cert->pCertInfo->SubjectUniqueId.cbData)
01847             ret = FALSE;
01848         /* A V1 cert may not contain extensions.  See RFC 5280, section 4.1.2.9:
01849          * "This field MUST only appear if the version is 3 (Section 4.1.2.1)."
01850          */
01851         if (cert->pCertInfo->cExtension)
01852             ret = FALSE;
01853         break;
01854     case CERT_V2:
01855         /* A V2 cert may not contain extensions.  See RFC 5280, section 4.1.2.9:
01856          * "This field MUST only appear if the version is 3 (Section 4.1.2.1)."
01857          */
01858         if (cert->pCertInfo->cExtension)
01859             ret = FALSE;
01860         break;
01861     case CERT_V3:
01862         /* Do nothing, all fields are allowed for V3 certs */
01863         break;
01864     default:
01865         WARN_(chain)("invalid cert version %d\n", cert->pCertInfo->dwVersion);
01866         ret = FALSE;
01867     }
01868     return ret;
01869 }
01870 
01871 static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
01872  PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
01873 {
01874     PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1];
01875     int i;
01876     BOOL pathLengthConstraintViolated = FALSE;
01877     CERT_BASIC_CONSTRAINTS2_INFO constraints = { FALSE, FALSE, 0 };
01878 
01879     TRACE_(chain)("checking chain with %d elements for time %s\n",
01880      chain->cElement, filetime_to_str(time));
01881     for (i = chain->cElement - 1; i >= 0; i--)
01882     {
01883         BOOL isRoot;
01884 
01885         if (TRACE_ON(chain))
01886             dump_element(chain->rgpElement[i]->pCertContext);
01887         if (i == chain->cElement - 1)
01888             isRoot = CRYPT_IsCertificateSelfSigned(
01889              chain->rgpElement[i]->pCertContext);
01890         else
01891             isRoot = FALSE;
01892         if (!CRYPT_IsCertVersionValid(chain->rgpElement[i]->pCertContext))
01893         {
01894             /* MS appears to accept certs whose versions don't match their
01895              * contents, so there isn't an appropriate error code.
01896              */
01897             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01898              CERT_TRUST_INVALID_EXTENSION;
01899         }
01900         if (CertVerifyTimeValidity(time,
01901          chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
01902             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01903              CERT_TRUST_IS_NOT_TIME_VALID;
01904         if (i != 0)
01905         {
01906             /* Check the signature of the cert this issued */
01907             if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
01908              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
01909              (void *)chain->rgpElement[i - 1]->pCertContext,
01910              CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
01911              (void *)chain->rgpElement[i]->pCertContext, 0, NULL))
01912                 chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |=
01913                  CERT_TRUST_IS_NOT_SIGNATURE_VALID;
01914             /* Once a path length constraint has been violated, every remaining
01915              * CA cert's basic constraints is considered invalid.
01916              */
01917             if (pathLengthConstraintViolated)
01918                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01919                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
01920             else if (!CRYPT_CheckBasicConstraintsForCA(engine,
01921              chain->rgpElement[i]->pCertContext, &constraints, i - 1, isRoot,
01922              &pathLengthConstraintViolated))
01923                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01924                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
01925             else if (constraints.fPathLenConstraint &&
01926              constraints.dwPathLenConstraint)
01927             {
01928                 /* This one's valid - decrement max length */
01929                 constraints.dwPathLenConstraint--;
01930             }
01931         }
01932         else
01933         {
01934             /* Check whether end cert has a basic constraints extension */
01935             if (!CRYPT_DecodeBasicConstraints(
01936              chain->rgpElement[i]->pCertContext, &constraints, FALSE))
01937                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01938                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
01939         }
01940         if (!CRYPT_KeyUsageValid(engine, chain->rgpElement[i]->pCertContext,
01941          isRoot, constraints.fCA, i))
01942             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01943              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
01944         if (CRYPT_IsSimpleChainCyclic(chain))
01945         {
01946             /* If the chain is cyclic, then the path length constraints
01947              * are violated, because the chain is infinitely long.
01948              */
01949             pathLengthConstraintViolated = TRUE;
01950             chain->TrustStatus.dwErrorStatus |=
01951              CERT_TRUST_IS_PARTIAL_CHAIN |
01952              CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
01953         }
01954         /* Check whether every critical extension is supported */
01955         if (!CRYPT_CriticalExtensionsSupported(
01956          chain->rgpElement[i]->pCertContext))
01957             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
01958              CERT_TRUST_INVALID_EXTENSION |
01959              CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT;
01960         CRYPT_CombineTrustStatus(&chain->TrustStatus,
01961          &chain->rgpElement[i]->TrustStatus);
01962     }
01963     CRYPT_CheckChainNameConstraints(chain);
01964     CRYPT_CheckChainPolicies(chain);
01965     if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext))
01966     {
01967         rootElement->TrustStatus.dwInfoStatus |=
01968          CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
01969         CRYPT_CheckRootCert(engine->hRoot, rootElement);
01970     }
01971     CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
01972 }
01973 
01974 static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject,
01975  PCCERT_CONTEXT prevIssuer, DWORD *infoStatus)
01976 {
01977     PCCERT_CONTEXT issuer = NULL;
01978     PCERT_EXTENSION ext;
01979     DWORD size;
01980 
01981     *infoStatus = 0;
01982     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
01983      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
01984     {
01985         CERT_AUTHORITY_KEY_ID_INFO *info;
01986         BOOL ret;
01987 
01988         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
01989          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
01990          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
01991          &info, &size);
01992         if (ret)
01993         {
01994             CERT_ID id;
01995 
01996             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
01997             {
01998                 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
01999                 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
02000                  sizeof(CERT_NAME_BLOB));
02001                 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
02002                  &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
02003                 issuer = CertFindCertificateInStore(store,
02004                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
02005                  prevIssuer);
02006                 if (issuer)
02007                 {
02008                     TRACE_(chain)("issuer found by issuer/serial number\n");
02009                     *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
02010                 }
02011             }
02012             else if (info->KeyId.cbData)
02013             {
02014                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
02015                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
02016                 issuer = CertFindCertificateInStore(store,
02017                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
02018                  prevIssuer);
02019                 if (issuer)
02020                 {
02021                     TRACE_(chain)("issuer found by key id\n");
02022                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
02023                 }
02024             }
02025             LocalFree(info);
02026         }
02027     }
02028     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
02029      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
02030     {
02031         CERT_AUTHORITY_KEY_ID2_INFO *info;
02032         BOOL ret;
02033 
02034         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
02035          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
02036          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
02037          &info, &size);
02038         if (ret)
02039         {
02040             CERT_ID id;
02041 
02042             if (info->AuthorityCertIssuer.cAltEntry &&
02043              info->AuthorityCertSerialNumber.cbData)
02044             {
02045                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
02046                 DWORD i;
02047 
02048                 for (i = 0; !directoryName &&
02049                  i < info->AuthorityCertIssuer.cAltEntry; i++)
02050                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
02051                      == CERT_ALT_NAME_DIRECTORY_NAME)
02052                         directoryName =
02053                          &info->AuthorityCertIssuer.rgAltEntry[i];
02054                 if (directoryName)
02055                 {
02056                     id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
02057                     memcpy(&id.u.IssuerSerialNumber.Issuer,
02058                      &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
02059                     memcpy(&id.u.IssuerSerialNumber.SerialNumber,
02060                      &info->AuthorityCertSerialNumber,
02061                      sizeof(CRYPT_INTEGER_BLOB));
02062                     issuer = CertFindCertificateInStore(store,
02063                      subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
02064                      prevIssuer);
02065                     if (issuer)
02066                     {
02067                         TRACE_(chain)("issuer found by directory name\n");
02068                         *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
02069                     }
02070                 }
02071                 else
02072                     FIXME("no supported name type in authority key id2\n");
02073             }
02074             else if (info->KeyId.cbData)
02075             {
02076                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
02077                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
02078                 issuer = CertFindCertificateInStore(store,
02079                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
02080                  prevIssuer);
02081                 if (issuer)
02082                 {
02083                     TRACE_(chain)("issuer found by key id\n");
02084                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
02085                 }
02086             }
02087             LocalFree(info);
02088         }
02089     }
02090     else
02091     {
02092         issuer = CertFindCertificateInStore(store,
02093          subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
02094          &subject->pCertInfo->Issuer, prevIssuer);
02095         TRACE_(chain)("issuer found by name\n");
02096         *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
02097     }
02098     return issuer;
02099 }
02100 
02101 /* Builds a simple chain by finding an issuer for the last cert in the chain,
02102  * until reaching a self-signed cert, or until no issuer can be found.
02103  */
02104 static BOOL CRYPT_BuildSimpleChain(const CertificateChainEngine *engine,
02105  HCERTSTORE world, PCERT_SIMPLE_CHAIN chain)
02106 {
02107     BOOL ret = TRUE;
02108     PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext;
02109 
02110     while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
02111      !CRYPT_IsCertificateSelfSigned(cert))
02112     {
02113         PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL,
02114          &chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
02115 
02116         if (issuer)
02117         {
02118             ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer,
02119              chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
02120             /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to
02121              * close the enumeration that found it
02122              */
02123             CertFreeCertificateContext(issuer);
02124             cert = issuer;
02125         }
02126         else
02127         {
02128             TRACE_(chain)("Couldn't find issuer, halting chain creation\n");
02129             chain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN;
02130             break;
02131         }
02132     }
02133     return ret;
02134 }
02135 
02136 static LPCSTR debugstr_filetime(LPFILETIME pTime)
02137 {
02138     if (!pTime)
02139         return "(nil)";
02140     return wine_dbg_sprintf("%p (%s)", pTime, filetime_to_str(pTime));
02141 }
02142 
02143 static BOOL CRYPT_GetSimpleChainForCert(PCertificateChainEngine engine,
02144  HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime,
02145  PCERT_SIMPLE_CHAIN *ppChain)
02146 {
02147     BOOL ret = FALSE;
02148     PCERT_SIMPLE_CHAIN chain;
02149 
02150     TRACE("(%p, %p, %p, %s)\n", engine, world, cert, debugstr_filetime(pTime));
02151 
02152     chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
02153     if (chain)
02154     {
02155         memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
02156         chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
02157         ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
02158         if (ret)
02159         {
02160             ret = CRYPT_BuildSimpleChain(engine, world, chain);
02161             if (ret)
02162                 CRYPT_CheckSimpleChain(engine, chain, pTime);
02163         }
02164         if (!ret)
02165         {
02166             CRYPT_FreeSimpleChain(chain);
02167             chain = NULL;
02168         }
02169         *ppChain = chain;
02170     }
02171     return ret;
02172 }
02173 
02174 static BOOL CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine,
02175  PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
02176  PCertificateChain *ppChain)
02177 {
02178     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
02179     PCERT_SIMPLE_CHAIN simpleChain = NULL;
02180     HCERTSTORE world;
02181     BOOL ret;
02182 
02183     world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
02184      CERT_STORE_CREATE_NEW_FLAG, NULL);
02185     CertAddStoreToCollection(world, engine->hWorld, 0, 0);
02186     if (hAdditionalStore)
02187         CertAddStoreToCollection(world, hAdditionalStore, 0, 0);
02188     /* FIXME: only simple chains are supported for now, as CTLs aren't
02189      * supported yet.
02190      */
02191     if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime,
02192      &simpleChain)))
02193     {
02194         PCertificateChain chain = CryptMemAlloc(sizeof(CertificateChain));
02195 
02196         if (chain)
02197         {
02198             chain->ref = 1;
02199             chain->world = world;
02200             chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
02201             chain->context.TrustStatus = simpleChain->TrustStatus;
02202             chain->context.cChain = 1;
02203             chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN));
02204             chain->context.rgpChain[0] = simpleChain;
02205             chain->context.cLowerQualityChainContext = 0;
02206             chain->context.rgpLowerQualityChainContext = NULL;
02207             chain->context.fHasRevocationFreshnessTime = FALSE;
02208             chain->context.dwRevocationFreshnessTime = 0;
02209         }
02210         else
02211             ret = FALSE;
02212         *ppChain = chain;
02213     }
02214     return ret;
02215 }
02216 
02217 /* Makes and returns a copy of chain, up to and including element iElement. */
02218 static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement(
02219  const CERT_SIMPLE_CHAIN *chain, DWORD iElement)
02220 {
02221     PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
02222 
02223     if (copy)
02224     {
02225         memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN));
02226         copy->cbSize = sizeof(CERT_SIMPLE_CHAIN);
02227         copy->rgpElement =
02228          CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
02229         if (copy->rgpElement)
02230         {
02231             DWORD i;
02232             BOOL ret = TRUE;
02233 
02234             memset(copy->rgpElement, 0,
02235              (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
02236             for (i = 0; ret && i <= iElement; i++)
02237             {
02238                 PCERT_CHAIN_ELEMENT element =
02239                  CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
02240 
02241                 if (element)
02242                 {
02243                     *element = *chain->rgpElement[i];
02244                     element->pCertContext = CertDuplicateCertificateContext(
02245                      chain->rgpElement[i]->pCertContext);
02246                     /* Reset the trust status of the copied element, it'll get
02247                      * rechecked after the new chain is done.
02248                      */
02249                     memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
02250                     copy->rgpElement[copy->cElement++] = element;
02251                 }
02252                 else
02253                     ret = FALSE;
02254             }
02255             if (!ret)
02256             {
02257                 for (i = 0; i <= iElement; i++)
02258                     CryptMemFree(copy->rgpElement[i]);
02259                 CryptMemFree(copy->rgpElement);
02260                 CryptMemFree(copy);
02261                 copy = NULL;
02262             }
02263         }
02264         else
02265         {
02266             CryptMemFree(copy);
02267             copy = NULL;
02268         }
02269     }
02270     return copy;
02271 }
02272 
02273 static void CRYPT_FreeLowerQualityChains(PCertificateChain chain)
02274 {
02275     DWORD i;
02276 
02277     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
02278         CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]);
02279     CryptMemFree(chain->context.rgpLowerQualityChainContext);
02280     chain->context.cLowerQualityChainContext = 0;
02281     chain->context.rgpLowerQualityChainContext = NULL;
02282 }
02283 
02284 static void CRYPT_FreeChainContext(PCertificateChain chain)
02285 {
02286     DWORD i;
02287 
02288     CRYPT_FreeLowerQualityChains(chain);
02289     for (i = 0; i < chain->context.cChain; i++)
02290         CRYPT_FreeSimpleChain(chain->context.rgpChain[i]);
02291     CryptMemFree(chain->context.rgpChain);
02292     CertCloseStore(chain->world, 0);
02293     CryptMemFree(chain);
02294 }
02295 
02296 /* Makes and returns a copy of chain, up to and including element iElement of
02297  * simple chain iChain.
02298  */
02299 static PCertificateChain CRYPT_CopyChainToElement(PCertificateChain chain,
02300  DWORD iChain, DWORD iElement)
02301 {
02302     PCertificateChain copy = CryptMemAlloc(sizeof(CertificateChain));
02303 
02304     if (copy)
02305     {
02306         copy->ref = 1;
02307         copy->world = CertDuplicateStore(chain->world);
02308         copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
02309         /* Leave the trust status of the copied chain unset, it'll get
02310          * rechecked after the new chain is done.
02311          */
02312         memset(&copy->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
02313         copy->context.cLowerQualityChainContext = 0;
02314         copy->context.rgpLowerQualityChainContext = NULL;
02315         copy->context.fHasRevocationFreshnessTime = FALSE;
02316         copy->context.dwRevocationFreshnessTime = 0;
02317         copy->context.rgpChain = CryptMemAlloc(
02318          (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
02319         if (copy->context.rgpChain)
02320         {
02321             BOOL ret = TRUE;
02322             DWORD i;
02323 
02324             memset(copy->context.rgpChain, 0,
02325              (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
02326             if (iChain)
02327             {
02328                 for (i = 0; ret && iChain && i < iChain - 1; i++)
02329                 {
02330                     copy->context.rgpChain[i] =
02331                      CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
02332                      chain->context.rgpChain[i]->cElement - 1);
02333                     if (!copy->context.rgpChain[i])
02334                         ret = FALSE;
02335                 }
02336             }
02337             else
02338                 i = 0;
02339             if (ret)
02340             {
02341                 copy->context.rgpChain[i] =
02342                  CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
02343                  iElement);
02344                 if (!copy->context.rgpChain[i])
02345                     ret = FALSE;
02346             }
02347             if (!ret)
02348             {
02349                 CRYPT_FreeChainContext(copy);
02350                 copy = NULL;
02351             }
02352             else
02353                 copy->context.cChain = iChain + 1;
02354         }
02355         else
02356         {
02357             CryptMemFree(copy);
02358             copy = NULL;
02359         }
02360     }
02361     return copy;
02362 }
02363 
02364 static PCertificateChain CRYPT_BuildAlternateContextFromChain(
02365  HCERTCHAINENGINE hChainEngine, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
02366  PCertificateChain chain)
02367 {
02368     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
02369     PCertificateChain alternate;
02370 
02371     TRACE("(%p, %s, %p, %p)\n", hChainEngine, debugstr_filetime(pTime),
02372      hAdditionalStore, chain);
02373 
02374     /* Always start with the last "lower quality" chain to ensure a consistent
02375      * order of alternate creation:
02376      */
02377     if (chain->context.cLowerQualityChainContext)
02378         chain = (PCertificateChain)chain->context.rgpLowerQualityChainContext[
02379          chain->context.cLowerQualityChainContext - 1];
02380     /* A chain with only one element can't have any alternates */
02381     if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1)
02382         alternate = NULL;
02383     else
02384     {
02385         DWORD i, j, infoStatus;
02386         PCCERT_CONTEXT alternateIssuer = NULL;
02387 
02388         alternate = NULL;
02389         for (i = 0; !alternateIssuer && i < chain->context.cChain; i++)
02390             for (j = 0; !alternateIssuer &&
02391              j < chain->context.rgpChain[i]->cElement - 1; j++)
02392             {
02393                 PCCERT_CONTEXT subject =
02394                  chain->context.rgpChain[i]->rgpElement[j]->pCertContext;
02395                 PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext(
02396                  chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext);
02397 
02398                 alternateIssuer = CRYPT_GetIssuer(prevIssuer->hCertStore,
02399                  subject, prevIssuer, &infoStatus);
02400             }
02401         if (alternateIssuer)
02402         {
02403             i--;
02404             j--;
02405             alternate = CRYPT_CopyChainToElement(chain, i, j);
02406             if (alternate)
02407             {
02408                 BOOL ret = CRYPT_AddCertToSimpleChain(engine,
02409                  alternate->context.rgpChain[i], alternateIssuer, infoStatus);
02410 
02411                 /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it
02412                  * to close the enumeration that found it
02413                  */
02414                 CertFreeCertificateContext(alternateIssuer);
02415                 if (ret)
02416                 {
02417                     ret = CRYPT_BuildSimpleChain(engine, alternate->world,
02418                      alternate->context.rgpChain[i]);
02419                     if (ret)
02420                         CRYPT_CheckSimpleChain(engine,
02421                          alternate->context.rgpChain[i], pTime);
02422                     CRYPT_CombineTrustStatus(&alternate->context.TrustStatus,
02423                      &alternate->context.rgpChain[i]->TrustStatus);
02424                 }
02425                 if (!ret)
02426                 {
02427                     CRYPT_FreeChainContext(alternate);
02428                     alternate = NULL;
02429                 }
02430             }
02431         }
02432     }
02433     TRACE("%p\n", alternate);
02434     return alternate;
02435 }
02436 
02437 #define CHAIN_QUALITY_SIGNATURE_VALID   0x16
02438 #define CHAIN_QUALITY_TIME_VALID        8
02439 #define CHAIN_QUALITY_COMPLETE_CHAIN    4
02440 #define CHAIN_QUALITY_BASIC_CONSTRAINTS 2
02441 #define CHAIN_QUALITY_TRUSTED_ROOT      1
02442 
02443 #define CHAIN_QUALITY_HIGHEST \
02444  CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
02445  CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_BASIC_CONSTRAINTS | \
02446  CHAIN_QUALITY_TRUSTED_ROOT
02447 
02448 #define IS_TRUST_ERROR_SET(TrustStatus, bits) \
02449  (TrustStatus)->dwErrorStatus & (bits)
02450 
02451 static DWORD CRYPT_ChainQuality(const CertificateChain *chain)
02452 {
02453     DWORD quality = CHAIN_QUALITY_HIGHEST;
02454 
02455     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
02456      CERT_TRUST_IS_UNTRUSTED_ROOT))
02457         quality &= ~CHAIN_QUALITY_TRUSTED_ROOT;
02458     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
02459      CERT_TRUST_INVALID_BASIC_CONSTRAINTS))
02460         quality &= ~CHAIN_QUALITY_BASIC_CONSTRAINTS;
02461     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
02462      CERT_TRUST_IS_PARTIAL_CHAIN))
02463         quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN;
02464     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
02465      CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED))
02466         quality &= ~CHAIN_QUALITY_TIME_VALID;
02467     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
02468      CERT_TRUST_IS_NOT_SIGNATURE_VALID))
02469         quality &= ~CHAIN_QUALITY_SIGNATURE_VALID;
02470     return quality;
02471 }
02472 
02473 /* Chooses the highest quality chain among chain and its "lower quality"
02474  * alternate chains.  Returns the highest quality chain, with all other
02475  * chains as lower quality chains of it.
02476  */
02477 static PCertificateChain CRYPT_ChooseHighestQualityChain(
02478  PCertificateChain chain)
02479 {
02480     DWORD i;
02481 
02482     /* There are always only two chains being considered:  chain, and an
02483      * alternate at chain->rgpLowerQualityChainContext[i].  If the alternate
02484      * has a higher quality than chain, the alternate gets assigned the lower
02485      * quality contexts, with chain taking the alternate's place among the
02486      * lower quality contexts.
02487      */
02488     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
02489     {
02490         PCertificateChain alternate =
02491          (PCertificateChain)chain->context.rgpLowerQualityChainContext[i];
02492 
02493         if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain))
02494         {
02495             alternate->context.cLowerQualityChainContext =
02496              chain->context.cLowerQualityChainContext;
02497             alternate->context.rgpLowerQualityChainContext =
02498              chain->context.rgpLowerQualityChainContext;
02499             alternate->context.rgpLowerQualityChainContext[i] =
02500              (PCCERT_CHAIN_CONTEXT)chain;
02501             chain->context.cLowerQualityChainContext = 0;
02502             chain->context.rgpLowerQualityChainContext = NULL;
02503             chain = alternate;
02504         }
02505     }
02506     return chain;
02507 }
02508 
02509 static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain,
02510  const CertificateChain *alternate)
02511 {
02512     BOOL ret;
02513 
02514     if (chain->context.cLowerQualityChainContext)
02515         chain->context.rgpLowerQualityChainContext =
02516          CryptMemRealloc(chain->context.rgpLowerQualityChainContext,
02517          (chain->context.cLowerQualityChainContext + 1) *
02518          sizeof(PCCERT_CHAIN_CONTEXT));
02519     else
02520         chain->context.rgpLowerQualityChainContext =
02521          CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT));
02522     if (chain->context.rgpLowerQualityChainContext)
02523     {
02524         chain->context.rgpLowerQualityChainContext[
02525          chain->context.cLowerQualityChainContext++] =
02526          (PCCERT_CHAIN_CONTEXT)alternate;
02527         ret = TRUE;
02528     }
02529     else
02530         ret = FALSE;
02531     return ret;
02532 }
02533 
02534 static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain(
02535  const CERT_CHAIN_CONTEXT *chain, DWORD i)
02536 {
02537     DWORD j, iElement;
02538     PCERT_CHAIN_ELEMENT element = NULL;
02539 
02540     for (j = 0, iElement = 0; !element && j < chain->cChain; j++)
02541     {
02542         if (iElement + chain->rgpChain[j]->cElement < i)
02543             iElement += chain->rgpChain[j]->cElement;
02544         else
02545             element = chain->rgpChain[j]->rgpElement[i - iElement];
02546     }
02547     return element;
02548 }
02549 
02550 typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS {
02551     DWORD            cbSize;
02552     CERT_USAGE_MATCH RequestedUsage;
02553 } CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS;
02554 
02555 static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
02556  LPFILETIME pTime, HCERTSTORE hAdditionalStore,
02557  const CERT_CHAIN_PARA *pChainPara, DWORD chainFlags)
02558 {
02559     DWORD cContext;
02560 
02561     if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT)
02562         cContext = 1;
02563     else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) ||
02564      (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT))
02565     {
02566         DWORD i;
02567 
02568         for (i = 0, cContext = 0; i < chain->cChain; i++)
02569         {
02570             if (i < chain->cChain - 1 ||
02571              chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN)
02572                 cContext += chain->rgpChain[i]->cElement;
02573             else
02574                 cContext += chain->rgpChain[i]->cElement - 1;
02575         }
02576     }
02577     else
02578         cContext = 0;
02579     if (cContext)
02580     {
02581         DWORD i, j, iContext, revocationFlags;
02582         CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 };
02583         CERT_REVOCATION_STATUS revocationStatus =
02584          { sizeof(revocationStatus), 0 };
02585         BOOL ret;
02586 
02587         revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG;
02588         if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY)
02589             revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION;
02590         if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT)
02591             revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG;
02592         revocationPara.pftTimeToUse = pTime;
02593         if (hAdditionalStore)
02594         {
02595             revocationPara.cCertStore = 1;
02596             revocationPara.rgCertStore = &hAdditionalStore;
02597             revocationPara.hCrlStore = hAdditionalStore;
02598         }
02599         if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA))
02600         {
02601             revocationPara.dwUrlRetrievalTimeout =
02602              pChainPara->dwUrlRetrievalTimeout;
02603             revocationPara.fCheckFreshnessTime =
02604              pChainPara->fCheckRevocationFreshnessTime;
02605             revocationPara.dwFreshnessTime =
02606              pChainPara->dwRevocationFreshnessTime;
02607         }
02608         for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain; i++)
02609         {
02610             for (j = 0; iContext < cContext &&
02611              j < chain->rgpChain[i]->cElement; j++, iContext++)
02612             {
02613                 PCCERT_CONTEXT certToCheck =
02614                  chain->rgpChain[i]->rgpElement[j]->pCertContext;
02615 
02616                 if (j < chain->rgpChain[i]->cElement - 1)
02617                     revocationPara.pIssuerCert =
02618                      chain->rgpChain[i]->rgpElement[j + 1]->pCertContext;
02619                 else
02620                     revocationPara.pIssuerCert = NULL;
02621                 ret = CertVerifyRevocation(X509_ASN_ENCODING,
02622                  CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certToCheck,
02623                  revocationFlags, &revocationPara, &revocationStatus);
02624                 if (!ret)
02625                 {
02626                     PCERT_CHAIN_ELEMENT element = CRYPT_FindIthElementInChain(
02627                      chain, iContext);
02628                     DWORD error;
02629 
02630                     switch (revocationStatus.dwError)
02631                     {
02632                     case CRYPT_E_NO_REVOCATION_CHECK:
02633                     case CRYPT_E_NO_REVOCATION_DLL:
02634                     case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
02635                         /* If the revocation status is unknown, it's assumed
02636                          * to be offline too.
02637                          */
02638                         error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
02639                          CERT_TRUST_IS_OFFLINE_REVOCATION;
02640                         break;
02641                     case CRYPT_E_REVOCATION_OFFLINE:
02642                         error = CERT_TRUST_IS_OFFLINE_REVOCATION;
02643                         break;
02644                     case CRYPT_E_REVOKED:
02645                         error = CERT_TRUST_IS_REVOKED;
02646                         break;
02647                     default:
02648                         WARN("unmapped error %08x\n", revocationStatus.dwError);
02649                         error = 0;
02650                     }
02651                     if (element)
02652                     {
02653                         /* FIXME: set element's pRevocationInfo member */
02654                         element->TrustStatus.dwErrorStatus |= error;
02655                     }
02656                     chain->TrustStatus.dwErrorStatus |= error;
02657                 }
02658             }
02659         }
02660     }
02661 }
02662 
02663 static void CRYPT_CheckUsages(PCERT_CHAIN_CONTEXT chain,
02664  const CERT_CHAIN_PARA *pChainPara)
02665 {
02666     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) &&
02667      pChainPara->RequestedUsage.Usage.cUsageIdentifier)
02668     {
02669         PCCERT_CONTEXT endCert;
02670         PCERT_EXTENSION ext;
02671         BOOL validForUsage;
02672 
02673         /* A chain, if created, always includes the end certificate */
02674         endCert = chain->rgpChain[0]->rgpElement[0]->pCertContext;
02675         /* The extended key usage extension specifies how a certificate's
02676          * public key may be used.  From RFC 5280, section 4.2.1.12:
02677          * "This extension indicates one or more purposes for which the
02678          *  certified public key may be used, in addition to or in place of the
02679          *  basic purposes indicated in the key usage extension."
02680          * If the extension is present, it only satisfies the requested usage
02681          * if that usage is included in the extension:
02682          * "If the extension is present, then the certificate MUST only be used
02683          *  for one of the purposes indicated."
02684          * There is also the special anyExtendedKeyUsage OID, but it doesn't
02685          * have to be respected:
02686          * "Applications that require the presence of a particular purpose
02687          *  MAY reject certificates that include the anyExtendedKeyUsage OID
02688          *  but not the particular OID expected for the application."
02689          * For now, I'm being more conservative and ignoring the presence of
02690          * the anyExtendedKeyUsage OID.
02691          */
02692         if ((ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
02693          endCert->pCertInfo->cExtension, endCert->pCertInfo->rgExtension)))
02694         {
02695             const CERT_ENHKEY_USAGE *requestedUsage =
02696              &pChainPara->RequestedUsage.Usage;
02697             CERT_ENHKEY_USAGE *usage;
02698             DWORD size;
02699 
02700             if (CryptDecodeObjectEx(X509_ASN_ENCODING,
02701              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
02702              CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size))
02703             {
02704                 if (pChainPara->RequestedUsage.dwType == USAGE_MATCH_TYPE_AND)
02705                 {
02706                     DWORD i, j;
02707 
02708                     /* For AND matches, all usages must be present */
02709                     validForUsage = TRUE;
02710                     for (i = 0; validForUsage &&
02711                      i < requestedUsage->cUsageIdentifier; i++)
02712                     {
02713                         BOOL match = FALSE;
02714 
02715                         for (j = 0; !match && j < usage->cUsageIdentifier; j++)
02716                             match = !strcmp(usage->rgpszUsageIdentifier[j],
02717                              requestedUsage->rgpszUsageIdentifier[i]);
02718                         if (!match)
02719                             validForUsage = FALSE;
02720                     }
02721                 }
02722                 else
02723                 {
02724                     DWORD i, j;
02725 
02726                     /* For OR matches, any matching usage suffices */
02727                     validForUsage = FALSE;
02728                     for (i = 0; !validForUsage &&
02729                      i < requestedUsage->cUsageIdentifier; i++)
02730                     {
02731                         for (j = 0; !validForUsage &&
02732                          j < usage->cUsageIdentifier; j++)
02733                             validForUsage =
02734                              !strcmp(usage->rgpszUsageIdentifier[j],
02735                              requestedUsage->rgpszUsageIdentifier[i]);
02736                     }
02737                 }
02738                 LocalFree(usage);
02739             }
02740             else
02741                 validForUsage = FALSE;
02742         }
02743         else
02744         {
02745             /* If the extension isn't present, any interpretation is valid:
02746              * "Certificate using applications MAY require that the extended
02747              *  key usage extension be present and that a particular purpose
02748              *  be indicated in order for the certificate to be acceptable to
02749              *  that application."
02750              * Not all web sites include the extended key usage extension, so
02751              * accept chains without it.
02752              */
02753             TRACE_(chain)("requested usage from certificate with no usages\n");
02754             validForUsage = TRUE;
02755         }
02756         if (!validForUsage)
02757         {
02758             chain->TrustStatus.dwErrorStatus |=
02759              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
02760             chain->rgpChain[0]->rgpElement[0]->TrustStatus.dwErrorStatus |=
02761              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
02762         }
02763     }
02764     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA) &&
02765      pChainPara->RequestedIssuancePolicy.Usage.cUsageIdentifier)
02766         FIXME("unimplemented for RequestedIssuancePolicy\n");
02767 }
02768 
02769 static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch)
02770 {
02771     if (usageMatch->Usage.cUsageIdentifier)
02772     {
02773         DWORD i;
02774 
02775         TRACE_(chain)("%s: %s\n", name,
02776          usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR");
02777         for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++)
02778             TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]);
02779     }
02780 }
02781 
02782 static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara)
02783 {
02784     TRACE_(chain)("%d\n", pChainPara->cbSize);
02785     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS))
02786         dump_usage_match("RequestedUsage", &pChainPara->RequestedUsage);
02787     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA))
02788     {
02789         dump_usage_match("RequestedIssuancePolicy",
02790          &pChainPara->RequestedIssuancePolicy);
02791         TRACE_(chain)("%d\n", pChainPara->dwUrlRetrievalTimeout);
02792         TRACE_(chain)("%d\n", pChainPara->fCheckRevocationFreshnessTime);
02793         TRACE_(chain)("%d\n", pChainPara->dwRevocationFreshnessTime);
02794     }
02795 }
02796 
02797 BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
02798  PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
02799  PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
02800  PCCERT_CHAIN_CONTEXT* ppChainContext)
02801 {
02802     BOOL ret;
02803     PCertificateChain chain = NULL;
02804 
02805     TRACE("(%p, %p, %s, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext,
02806      debugstr_filetime(pTime), hAdditionalStore, pChainPara, dwFlags,
02807      pvReserved, ppChainContext);
02808 
02809     if (ppChainContext)
02810         *ppChainContext = NULL;
02811     if (!pChainPara)
02812     {
02813         SetLastError(E_INVALIDARG);
02814         return FALSE;
02815     }
02816     if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)
02817     {
02818         SetLastError(ERROR_INVALID_DATA);
02819         return FALSE;
02820     }
02821 
02822     if (!hChainEngine)
02823         hChainEngine = CRYPT_GetDefaultChainEngine();
02824     if (TRACE_ON(chain))
02825         dump_chain_para(pChainPara);
02826     /* FIXME: what about HCCE_LOCAL_MACHINE? */
02827     ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime,
02828      hAdditionalStore, &chain);
02829     if (ret)
02830     {
02831         PCertificateChain alternate = NULL;
02832         PCERT_CHAIN_CONTEXT pChain;
02833 
02834         do {
02835             alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine,
02836              pTime, hAdditionalStore, chain);
02837 
02838             /* Alternate contexts are added as "lower quality" contexts of
02839              * chain, to avoid loops in alternate chain creation.
02840              * The highest-quality chain is chosen at the end.
02841              */
02842             if (alternate)
02843                 ret = CRYPT_AddAlternateChainToChain(chain, alternate);
02844         } while (ret && alternate);
02845         chain = CRYPT_ChooseHighestQualityChain(chain);
02846         if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
02847             CRYPT_FreeLowerQualityChains(chain);
02848         pChain = (PCERT_CHAIN_CONTEXT)chain;
02849         CRYPT_VerifyChainRevocation(pChain, pTime, hAdditionalStore,
02850          pChainPara, dwFlags);
02851         CRYPT_CheckUsages(pChain, pChainPara);
02852         TRACE_(chain)("error status: %08x\n",
02853          pChain->TrustStatus.dwErrorStatus);
02854         if (ppChainContext)
02855             *ppChainContext = pChain;
02856         else
02857             CertFreeCertificateChain(pChain);
02858     }
02859     TRACE("returning %d\n", ret);
02860     return ret;
02861 }
02862 
02863 PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain(
02864  PCCERT_CHAIN_CONTEXT pChainContext)
02865 {
02866     PCertificateChain chain = (PCertificateChain)pChainContext;
02867 
02868     TRACE("(%p)\n", pChainContext);
02869 
02870     if (chain)
02871         InterlockedIncrement(&chain->ref);
02872     return pChainContext;
02873 }
02874 
02875 VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext)
02876 {
02877     PCertificateChain chain = (PCertificateChain)pChainContext;
02878 
02879     TRACE("(%p)\n", pChainContext);
02880 
02881     if (chain)
02882     {
02883         if (InterlockedDecrement(&chain->ref) == 0)
02884             CRYPT_FreeChainContext(chain);
02885     }
02886 }
02887 
02888 PCCERT_CHAIN_CONTEXT WINAPI CertFindChainInStore(HCERTSTORE store,
02889  DWORD certEncodingType, DWORD findFlags, DWORD findType,
02890  const void *findPara, PCCERT_CHAIN_CONTEXT prevChainContext)
02891 {
02892     FIXME("(%p, %08x, %08x, %d, %p, %p): stub\n", store, certEncodingType,
02893      findFlags, findType, findPara, prevChainContext);
02894     return NULL;
02895 }
02896 
02897 static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error,
02898  LONG *iChain, LONG *iElement)
02899 {
02900     DWORD i, j;
02901 
02902     for (i = 0; i < chain->cChain; i++)
02903         for (j = 0; j < chain->rgpChain[i]->cElement; j++)
02904             if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus &
02905              error)
02906             {
02907                 *iChain = i;
02908                 *iElement = j;
02909                 return;
02910             }
02911 }
02912 
02913 static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID,
02914  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
02915  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
02916 {
02917     DWORD checks = 0;
02918 
02919     if (pPolicyPara)
02920         checks = pPolicyPara->dwFlags;
02921     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
02922     pPolicyStatus->dwError = NO_ERROR;
02923     if (pChainContext->TrustStatus.dwErrorStatus &
02924      CERT_TRUST_IS_NOT_SIGNATURE_VALID)
02925     {
02926         pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
02927         find_element_with_error(pChainContext,
02928          CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
02929          &pPolicyStatus->lElementIndex);
02930     }
02931     else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
02932     {
02933         pPolicyStatus->dwError = CERT_E_CHAINING;
02934         find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC,
02935          &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex);
02936         /* For a cyclic chain, which element is a cycle isn't meaningful */
02937         pPolicyStatus->lElementIndex = -1;
02938     }
02939     if (!pPolicyStatus->dwError &&
02940      pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT &&
02941      !(checks & CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG))
02942     {
02943         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
02944         find_element_with_error(pChainContext,
02945          CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
02946          &pPolicyStatus->lElementIndex);
02947     }
02948     if (!pPolicyStatus->dwError &&
02949      pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
02950     {
02951         pPolicyStatus->dwError = CERT_E_EXPIRED;
02952         find_element_with_error(pChainContext,
02953          CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex,
02954          &pPolicyStatus->lElementIndex);
02955     }
02956     if (!pPolicyStatus->dwError &&
02957      pChainContext->TrustStatus.dwErrorStatus &
02958      CERT_TRUST_IS_NOT_VALID_FOR_USAGE &&
02959      !(checks & CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG))
02960     {
02961         pPolicyStatus->dwError = CERT_E_WRONG_USAGE;
02962         find_element_with_error(pChainContext,
02963          CERT_TRUST_IS_NOT_VALID_FOR_USAGE, &pPolicyStatus->lChainIndex,
02964          &pPolicyStatus->lElementIndex);
02965     }
02966     if (!pPolicyStatus->dwError &&
02967      pChainContext->TrustStatus.dwErrorStatus &
02968      CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT &&
02969      !(checks & CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG))
02970     {
02971         pPolicyStatus->dwError = CERT_E_CRITICAL;
02972         find_element_with_error(pChainContext,
02973          CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, &pPolicyStatus->lChainIndex,
02974          &pPolicyStatus->lElementIndex);
02975     }
02976     return TRUE;
02977 }
02978 
02979 static BYTE msTestPubKey1[] = {
02980 0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9,
02981 0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7,
02982 0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f,
02983 0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10,
02984 0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
02985 static BYTE msTestPubKey2[] = {
02986 0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5,
02987 0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8,
02988 0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6,
02989 0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18,
02990 0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 };
02991 
02992 static void dump_authenticode_extra_chain_policy_para(
02993  AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA *extraPara)
02994 {
02995     if (extraPara)
02996     {
02997         TRACE_(chain)("cbSize = %d\n", extraPara->cbSize);
02998         TRACE_(chain)("dwRegPolicySettings = %08x\n",
02999          extraPara->dwRegPolicySettings);
03000         TRACE_(chain)("pSignerInfo = %p\n", extraPara->pSignerInfo);
03001     }
03002 }
03003 
03004 static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID,
03005  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
03006  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
03007 {
03008     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
03009      pPolicyStatus);
03010     AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA *extraPara = NULL;
03011 
03012     if (pPolicyPara)
03013         extraPara = pPolicyPara->pvExtraPolicyPara;
03014     if (TRACE_ON(chain))
03015         dump_authenticode_extra_chain_policy_para(extraPara);
03016     if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT)
03017     {
03018         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
03019         BOOL isMSTestRoot = FALSE;
03020         PCCERT_CONTEXT failingCert =
03021          pChainContext->rgpChain[pPolicyStatus->lChainIndex]->
03022          rgpElement[pPolicyStatus->lElementIndex]->pCertContext;
03023         DWORD i;
03024         CRYPT_DATA_BLOB keyBlobs[] = {
03025          { sizeof(msTestPubKey1), msTestPubKey1 },
03026          { sizeof(msTestPubKey2), msTestPubKey2 },
03027         };
03028 
03029         /* Check whether the root is an MS test root */
03030         for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
03031          i++)
03032         {
03033             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
03034             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
03035             if (CertComparePublicKeyInfo(
03036              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
03037              &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
03038                 isMSTestRoot = TRUE;
03039         }
03040         if (isMSTestRoot)
03041             pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT;
03042     }
03043     return ret;
03044 }
03045 
03046 static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID,
03047  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
03048  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
03049 {
03050     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
03051     if (pChainContext->TrustStatus.dwErrorStatus &
03052      CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
03053     {
03054         pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS;
03055         find_element_with_error(pChainContext,
03056          CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex,
03057          &pPolicyStatus->lElementIndex);
03058     }
03059     else
03060         pPolicyStatus->dwError = NO_ERROR;
03061     return TRUE;
03062 }
03063 
03064 static BOOL match_dns_to_subject_alt_name(const CERT_EXTENSION *ext,
03065  LPCWSTR server_name)
03066 {
03067     BOOL matches = FALSE;
03068     CERT_ALT_NAME_INFO *subjectName;
03069     DWORD size;
03070 
03071     TRACE_(chain)("%s\n", debugstr_w(server_name));
03072     /* This could be spoofed by the embedded NULL vulnerability, since the
03073      * returned CERT_ALT_NAME_INFO doesn't have a way to indicate the
03074      * encoded length of a name.  Fortunately CryptDecodeObjectEx fails if
03075      * the encoded form of the name contains a NULL.
03076      */
03077     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
03078      ext->Value.pbData, ext->Value.cbData,
03079      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
03080      &subjectName, &size))
03081     {
03082         DWORD i;
03083 
03084         /* RFC 5280 states that multiple instances of each name type may exist,
03085          * in section 4.2.1.6:
03086          * "Multiple name forms, and multiple instances of each name form,
03087          *  MAY be included."
03088          * It doesn't specify the behavior in such cases, but both RFC 2818
03089          * and RFC 2595 explicitly accept a certificate if any name matches.
03090          */
03091         for (i = 0; !matches && i < subjectName->cAltEntry; i++)
03092         {
03093             if (subjectName->rgAltEntry[i].dwAltNameChoice ==
03094              CERT_ALT_NAME_DNS_NAME)
03095             {
03096                 TRACE_(chain)("dNSName: %s\n", debugstr_w(
03097                  subjectName->rgAltEntry[i].u.pwszDNSName));
03098                 if (subjectName->rgAltEntry[i].u.pwszDNSName[0] == '*')
03099                 {
03100                     LPCWSTR server_name_dot;
03101 
03102                     /* Matching a wildcard: a wildcard matches a single name
03103                      * component, which is terminated by a dot.  RFC 1034
03104                      * doesn't define whether multiple wildcards are allowed,
03105                      * but I will assume that they are not until proven
03106                      * otherwise.  RFC 1034 also states that 'the "*" label
03107                      * always matches at least one whole label and sometimes
03108                      * more, but always whole labels.'  Native crypt32 does not
03109                      * match more than one label with a wildcard, so I do the
03110                      * same here.  Thus, a wildcard only accepts the first
03111                      * label, then requires an exact match of the remaining
03112                      * string.
03113                      */
03114                     server_name_dot = strchrW(server_name, '.');
03115                     if (server_name_dot)
03116                     {
03117                         if (!strcmpiW(server_name_dot,
03118                          subjectName->rgAltEntry[i].u.pwszDNSName + 1))
03119                             matches = TRUE;
03120                     }
03121                 }
03122                 else if (!strcmpiW(server_name,
03123                  subjectName->rgAltEntry[i].u.pwszDNSName))
03124                     matches = TRUE;
03125             }
03126         }
03127         LocalFree(subjectName);
03128     }
03129     return matches;
03130 }
03131 
03132 static BOOL find_matching_domain_component(const CERT_NAME_INFO *name,
03133  LPCWSTR component)
03134 {
03135     BOOL matches = FALSE;
03136     DWORD i, j;
03137 
03138     for (i = 0; !matches && i < name->cRDN; i++)
03139         for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
03140             if (!strcmp(szOID_DOMAIN_COMPONENT,
03141              name->rgRDN[i].rgRDNAttr[j].pszObjId))
03142             {
03143                 const CERT_RDN_ATTR *attr;
03144 
03145                 attr = &name->rgRDN[i].rgRDNAttr[j];
03146                 /* Compare with memicmpW rather than strcmpiW in order to avoid
03147                  * a match with a string with an embedded NULL.  The component
03148                  * must match one domain component attribute's entire string
03149                  * value with a case-insensitive match.
03150                  */
03151                 matches = !memicmpW(component, (LPCWSTR)attr->Value.pbData,
03152                  attr->Value.cbData / sizeof(WCHAR));
03153             }
03154     return matches;
03155 }
03156 
03157 static BOOL match_domain_component(LPCWSTR allowed_component, DWORD allowed_len,
03158  LPCWSTR server_component, DWORD server_len, BOOL allow_wildcards,
03159  BOOL *see_wildcard)
03160 {
03161     LPCWSTR allowed_ptr, server_ptr;
03162     BOOL matches = TRUE;
03163 
03164     *see_wildcard = FALSE;
03165     if (server_len < allowed_len)
03166     {
03167         WARN_(chain)("domain component %s too short for %s\n",
03168          debugstr_wn(server_component, server_len),
03169          debugstr_wn(allowed_component, allowed_len));
03170         /* A domain component can't contain a wildcard character, so a domain
03171          * component shorter than the allowed string can't produce a match.
03172          */
03173         return FALSE;
03174     }
03175     for (allowed_ptr = allowed_component, server_ptr = server_component;
03176          matches && allowed_ptr - allowed_component < allowed_len;
03177          allowed_ptr++, server_ptr++)
03178     {
03179         if (*allowed_ptr == '*')
03180         {
03181             if (allowed_ptr - allowed_component < allowed_len - 1)
03182             {
03183                 WARN_(chain)("non-wildcard characters after wildcard not supported\n");
03184                 matches = FALSE;
03185             }
03186             else if (!allow_wildcards)
03187             {
03188                 WARN_(chain)("wildcard after non-wildcard component\n");
03189                 matches = FALSE;
03190             }
03191             else
03192             {
03193                 /* the preceding characters must have matched, so the rest of
03194                  * the component also matches.
03195                  */
03196                 *see_wildcard = TRUE;
03197                 break;
03198             }
03199         }
03200         if (matches)
03201             matches = tolowerW(*allowed_ptr) == tolowerW(*server_ptr);
03202     }
03203     if (matches && server_ptr - server_component < server_len)
03204     {
03205         /* If there are unmatched characters in the server domain component,
03206          * the server domain only matches if the allowed string ended in a '*'.
03207          */
03208         matches = *allowed_ptr == '*';
03209     }
03210     return matches;
03211 }
03212 
03213 static BOOL match_common_name(LPCWSTR server_name, const CERT_RDN_ATTR *nameAttr)
03214 {
03215     LPCWSTR allowed = (LPCWSTR)nameAttr->Value.pbData;
03216     LPCWSTR allowed_component = allowed;
03217     DWORD allowed_len = nameAttr->Value.cbData / sizeof(WCHAR);
03218     LPCWSTR server_component = server_name;
03219     DWORD server_len = strlenW(server_name);
03220     BOOL matches = TRUE, allow_wildcards = TRUE;
03221 
03222     TRACE_(chain)("CN = %s\n", debugstr_wn(allowed_component, allowed_len));
03223 
03224     /* From RFC 2818 (HTTP over TLS), section 3.1:
03225      * "Names may contain the wildcard character * which is considered to match
03226      *  any single domain name component or component fragment. E.g.,
03227      *  *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com
03228      *  but not bar.com."
03229      *
03230      * And from RFC 2595 (Using TLS with IMAP, POP3 and ACAP), section 2.4:
03231      * "A "*" wildcard character MAY be used as the left-most name component in
03232      *  the certificate.  For example, *.example.com would match a.example.com,
03233      *  foo.example.com, etc. but would not match example.com."
03234      *
03235      * There are other protocols which use TLS, and none of them is
03236      * authoritative.  This accepts certificates in common usage, e.g.
03237      * *.domain.com matches www.domain.com but not domain.com, and
03238      * www*.domain.com matches www1.domain.com but not mail.domain.com.
03239      */
03240     do {
03241         LPCWSTR allowed_dot, server_dot;
03242 
03243         allowed_dot = memchrW(allowed_component, '.',
03244          allowed_len - (allowed_component - allowed));
03245         server_dot = memchrW(server_component, '.',
03246          server_len - (server_component - server_name));
03247         /* The number of components must match */
03248         if ((!allowed_dot && server_dot) || (allowed_dot && !server_dot))
03249         {
03250             if (!allowed_dot)
03251                 WARN_(chain)("%s: too many components for CN=%s\n",
03252                  debugstr_w(server_name), debugstr_wn(allowed, allowed_len));
03253             else
03254                 WARN_(chain)("%s: not enough components for CN=%s\n",
03255                  debugstr_w(server_name), debugstr_wn(allowed, allowed_len));
03256             matches = FALSE;
03257         }
03258         else
03259         {
03260             LPCWSTR allowed_end, server_end;
03261             BOOL has_wildcard;
03262 
03263             allowed_end = allowed_dot ? allowed_dot : allowed + allowed_len;
03264             server_end = server_dot ? server_dot : server_name + server_len;
03265             matches = match_domain_component(allowed_component,
03266              allowed_end - allowed_component, server_component,
03267              server_end - server_component, allow_wildcards, &has_wildcard);
03268             /* Once a non-wildcard component is seen, no wildcard components
03269              * may follow
03270              */
03271             if (!has_wildcard)
03272                 allow_wildcards = FALSE;
03273             if (matches)
03274             {
03275                 allowed_component = allowed_dot ? allowed_dot + 1 : allowed_end;
03276                 server_component = server_dot ? server_dot + 1 : server_end;
03277             }
03278         }
03279     } while (matches && allowed_component &&
03280      allowed_component - allowed < allowed_len &&
03281      server_component && server_component - server_name < server_len);
03282     TRACE_(chain)("returning %d\n", matches);
03283     return matches;
03284 }
03285 
03286 static BOOL match_dns_to_subject_dn(PCCERT_CONTEXT cert, LPCWSTR server_name)
03287 {
03288     BOOL matches = FALSE;
03289     CERT_NAME_INFO *name;
03290     DWORD size;
03291 
03292     TRACE_(chain)("%s\n", debugstr_w(server_name));
03293     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME,
03294      cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData,
03295      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
03296      &name, &size))
03297     {
03298         /* If the subject distinguished name contains any name components,
03299          * make sure all of them are present.
03300          */
03301         if (CertFindRDNAttr(szOID_DOMAIN_COMPONENT, name))
03302         {
03303             LPCWSTR ptr = server_name;
03304 
03305             do {
03306                 LPCWSTR dot = strchrW(ptr, '.'), end;
03307                 /* 254 is the maximum DNS label length, see RFC 1035 */
03308                 WCHAR component[255];
03309                 DWORD len;
03310 
03311                 end = dot ? dot : ptr + strlenW(ptr);
03312                 len = end - ptr;
03313                 if (len >= sizeof(component) / sizeof(component[0]))
03314                 {
03315                     WARN_(chain)("domain component %s too long\n",
03316                      debugstr_wn(ptr, len));
03317                     matches = FALSE;
03318                 }
03319                 else
03320                 {
03321                     memcpy(component, ptr, len * sizeof(WCHAR));
03322                     component[len] = 0;
03323                     matches = find_matching_domain_component(name, component);
03324                 }
03325                 ptr = dot ? dot + 1 : end;
03326             } while (matches && ptr && *ptr);
03327         }
03328         else
03329         {
03330             DWORD i, j;
03331 
03332             /* If the certificate isn't using a DN attribute in the name, make
03333              * make sure at least one common name matches.  From RFC 2818,
03334              * section 3.1:
03335              * "If more than one identity of a given type is present in the
03336              * certificate (e.g., more than one dNSName name, a match in any
03337              * one of the set is considered acceptable.)"
03338              */
03339             for (i = 0; !matches && i < name->cRDN; i++)
03340                 for (j = 0; !matches && j < name->rgRDN[i].cRDNAttr; j++)
03341                 {
03342                     PCERT_RDN_ATTR attr = &name->rgRDN[i].rgRDNAttr[j];
03343 
03344                     if (attr->pszObjId && !strcmp(szOID_COMMON_NAME,
03345                      attr->pszObjId))
03346                         matches = match_common_name(server_name, attr);
03347                 }
03348         }
03349         LocalFree(name);
03350     }
03351     return matches;
03352 }
03353 
03354 static void dump_ssl_extra_chain_policy_para(HTTPSPolicyCallbackData *sslPara)
03355 {
03356     if (sslPara)
03357     {
03358         TRACE_(chain)("cbSize = %d\n", sslPara->u.cbSize);
03359         TRACE_(chain)("dwAuthType = %d\n", sslPara->dwAuthType);
03360         TRACE_(chain)("fdwChecks = %08x\n", sslPara->fdwChecks);
03361         TRACE_(chain)("pwszServerName = %s\n",
03362          debugstr_w(sslPara->pwszServerName));
03363     }
03364 }
03365 
03366 static BOOL WINAPI verify_ssl_policy(LPCSTR szPolicyOID,
03367  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
03368  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
03369 {
03370     HTTPSPolicyCallbackData *sslPara = NULL;
03371     DWORD checks = 0;
03372 
03373     if (pPolicyPara)
03374         sslPara = pPolicyPara->pvExtraPolicyPara;
03375     if (TRACE_ON(chain))
03376         dump_ssl_extra_chain_policy_para(sslPara);
03377     if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData))
03378         checks = sslPara->fdwChecks;
03379     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
03380     if (pChainContext->TrustStatus.dwErrorStatus &
03381      CERT_TRUST_IS_NOT_SIGNATURE_VALID)
03382     {
03383         pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
03384         find_element_with_error(pChainContext,
03385          CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
03386          &pPolicyStatus->lElementIndex);
03387     }
03388     else if (pChainContext->TrustStatus.dwErrorStatus &
03389      CERT_TRUST_IS_UNTRUSTED_ROOT &&
03390      !(checks & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
03391     {
03392         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
03393         find_element_with_error(pChainContext,
03394          CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
03395          &pPolicyStatus->lElementIndex);
03396     }
03397     else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
03398     {
03399         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
03400         find_element_with_error(pChainContext,
03401          CERT_TRUST_IS_CYCLIC, &pPolicyStatus->lChainIndex,
03402          &pPolicyStatus->lElementIndex);
03403         /* For a cyclic chain, which element is a cycle isn't meaningful */
03404         pPolicyStatus->lElementIndex = -1;
03405     }
03406     else if (pChainContext->TrustStatus.dwErrorStatus &
03407      CERT_TRUST_IS_NOT_TIME_VALID &&
03408      !(checks & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
03409     {
03410         pPolicyStatus->dwError = CERT_E_EXPIRED;
03411         find_element_with_error(pChainContext,
03412          CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex,
03413          &pPolicyStatus->lElementIndex);
03414     }
03415     else if (pChainContext->TrustStatus.dwErrorStatus &
03416      CERT_TRUST_IS_NOT_VALID_FOR_USAGE &&
03417      !(checks & SECURITY_FLAG_IGNORE_WRONG_USAGE))
03418     {
03419         pPolicyStatus->dwError = CERT_E_WRONG_USAGE;
03420         find_element_with_error(pChainContext,
03421          CERT_TRUST_IS_NOT_VALID_FOR_USAGE, &pPolicyStatus->lChainIndex,
03422          &pPolicyStatus->lElementIndex);
03423     }
03424     else if (pChainContext->TrustStatus.dwErrorStatus &
03425      CERT_TRUST_IS_REVOKED && !(checks & SECURITY_FLAG_IGNORE_REVOCATION))
03426     {
03427         pPolicyStatus->dwError = CERT_E_REVOKED;
03428         find_element_with_error(pChainContext,
03429          CERT_TRUST_IS_REVOKED, &pPolicyStatus->lChainIndex,
03430          &pPolicyStatus->lElementIndex);
03431     }
03432     else if (pChainContext->TrustStatus.dwErrorStatus &
03433      CERT_TRUST_IS_OFFLINE_REVOCATION &&
03434      !(checks & SECURITY_FLAG_IGNORE_REVOCATION))
03435     {
03436         pPolicyStatus->dwError = CERT_E_REVOCATION_FAILURE;
03437         find_element_with_error(pChainContext,
03438          CERT_TRUST_IS_OFFLINE_REVOCATION, &pPolicyStatus->lChainIndex,
03439          &pPolicyStatus->lElementIndex);
03440     }
03441     else if (pChainContext->TrustStatus.dwErrorStatus &
03442      CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT)
03443     {
03444         pPolicyStatus->dwError = CERT_E_CRITICAL;
03445         find_element_with_error(pChainContext,
03446          CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, &pPolicyStatus->lChainIndex,
03447          &pPolicyStatus->lElementIndex);
03448     }
03449     else
03450         pPolicyStatus->dwError = NO_ERROR;
03451     /* We only need bother checking whether the name in the end certificate
03452      * matches if the chain is otherwise okay.
03453      */
03454     if (!pPolicyStatus->dwError && pPolicyPara &&
03455      pPolicyPara->cbSize >= sizeof(CERT_CHAIN_POLICY_PARA))
03456     {
03457         if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData))
03458         {
03459             if (sslPara->dwAuthType == AUTHTYPE_SERVER &&
03460              sslPara->pwszServerName &&
03461              !(checks & SECURITY_FLAG_IGNORE_CERT_CN_INVALID))
03462             {
03463                 PCCERT_CONTEXT cert;
03464                 PCERT_EXTENSION altNameExt;
03465                 BOOL matches;
03466 
03467                 cert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
03468                 altNameExt = get_subject_alt_name_ext(cert->pCertInfo);
03469                 /* If the alternate name extension exists, the name it contains
03470                  * is bound to the certificate, so make sure the name matches
03471                  * it.  Otherwise, look for the server name in the subject
03472                  * distinguished name.  RFC5280, section 4.2.1.6:
03473                  * "Whenever such identities are to be bound into a
03474                  *  certificate, the subject alternative name (or issuer
03475                  *  alternative name) extension MUST be used; however, a DNS
03476                  *  name MAY also be represented in the subject field using the
03477                  *  domainComponent attribute."
03478                  */
03479                 if (altNameExt)
03480                     matches = match_dns_to_subject_alt_name(altNameExt,
03481                      sslPara->pwszServerName);
03482                 else
03483                     matches = match_dns_to_subject_dn(cert,
03484                      sslPara->pwszServerName);
03485                 if (!matches)
03486                 {
03487                     pPolicyStatus->dwError = CERT_E_CN_NO_MATCH;
03488                     pPolicyStatus->lChainIndex = 0;
03489                     pPolicyStatus->lElementIndex = 0;
03490                 }
03491             }
03492         }
03493     }
03494     return TRUE;
03495 }
03496 
03497 static BYTE msPubKey1[] = {
03498 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
03499 0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
03500 0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29,
03501 0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16,
03502 0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60,
03503 0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5,
03504 0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d,
03505 0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61,
03506 0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e,
03507 0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94,
03508 0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb,
03509 0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a,
03510 0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d,
03511 0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb,
03512 0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08,
03513 0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43,
03514 0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf,
03515 0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 };
03516 static BYTE msPubKey2[] = {
03517 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6,
03518 0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25,
03519 0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2,
03520 0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54,
03521 0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62,
03522 0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a,
03523 0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7,
03524 0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84,
03525 0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9,
03526 0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91,
03527 0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52,
03528 0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80,
03529 0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18,
03530 0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07,
03531 0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef,
03532 0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0,
03533 0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30,
03534 0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 };
03535 static BYTE msPubKey3[] = {
03536 0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4,
03537 0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7,
03538 0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94,
03539 0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04,
03540 0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d,
03541 0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09,
03542 0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae,
03543 0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7,
03544 0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f,
03545 0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94,
03546 0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d,
03547 0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05,
03548 0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e,
03549 0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d,
03550 0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b,
03551 0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67,
03552 0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08,
03553 0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5,
03554 0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64,
03555 0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38,
03556 0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0,
03557 0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9,
03558 0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28,
03559 0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc,
03560 0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45,
03561 0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde,
03562 0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04,
03563 0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89,
03564 0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11,
03565 0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32,
03566 0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40,
03567 0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41,
03568 0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1,
03569 0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5,
03570 0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00,
03571 0x01 };
03572 
03573 static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
03574  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
03575  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
03576 {
03577     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
03578      pPolicyStatus);
03579 
03580     if (ret && !pPolicyStatus->dwError)
03581     {
03582         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
03583         BOOL isMSRoot = FALSE;
03584         DWORD i;
03585         CRYPT_DATA_BLOB keyBlobs[] = {
03586          { sizeof(msPubKey1), msPubKey1 },
03587          { sizeof(msPubKey2), msPubKey2 },
03588          { sizeof(msPubKey3), msPubKey3 },
03589         };
03590         PCERT_SIMPLE_CHAIN rootChain =
03591          pChainContext->rgpChain[pChainContext->cChain -1 ];
03592         PCCERT_CONTEXT root =
03593          rootChain->rgpElement[rootChain->cElement - 1]->pCertContext;
03594 
03595         for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
03596          i++)
03597         {
03598             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
03599             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
03600             if (CertComparePublicKeyInfo(
03601              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
03602              &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
03603                 isMSRoot = TRUE;
03604         }
03605         if (isMSRoot)
03606             pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0;
03607     }
03608     return ret;
03609 }
03610 
03611 typedef BOOL (WINAPI *CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID,
03612  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
03613  PCERT_CHAIN_POLICY_STATUS pPolicyStatus);
03614 
03615 static void dump_policy_para(PCERT_CHAIN_POLICY_PARA para)
03616 {
03617     if (para)
03618     {
03619         TRACE_(chain)("cbSize = %d\n", para->cbSize);
03620         TRACE_(chain)("dwFlags = %08x\n", para->dwFlags);
03621         TRACE_(chain)("pvExtraPolicyPara = %p\n", para->pvExtraPolicyPara);
03622     }
03623 }
03624 
03625 BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID,
03626  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
03627  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
03628 {
03629     static HCRYPTOIDFUNCSET set = NULL;
03630     BOOL ret = FALSE;
03631     CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL;
03632     HCRYPTOIDFUNCADDR hFunc = NULL;
03633 
03634     TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext,
03635      pPolicyPara, pPolicyStatus);
03636     if (TRACE_ON(chain))
03637         dump_policy_para(pPolicyPara);
03638 
03639     if (IS_INTOID(szPolicyOID))
03640     {
03641         switch (LOWORD(szPolicyOID))
03642         {
03643         case LOWORD(CERT_CHAIN_POLICY_BASE):
03644             verifyPolicy = verify_base_policy;
03645             break;
03646         case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE):
03647             verifyPolicy = verify_authenticode_policy;
03648             break;
03649         case LOWORD(CERT_CHAIN_POLICY_SSL):
03650             verifyPolicy = verify_ssl_policy;
03651             break;
03652         case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS):
03653             verifyPolicy = verify_basic_constraints_policy;
03654             break;
03655         case LOWORD(CERT_CHAIN_POLICY_MICROSOFT_ROOT):
03656             verifyPolicy = verify_ms_root_policy;
03657             break;
03658         default:
03659             FIXME("unimplemented for %d\n", LOWORD(szPolicyOID));
03660         }
03661     }
03662     if (!verifyPolicy)
03663     {
03664         if (!set)
03665             set = CryptInitOIDFunctionSet(
03666              CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0);
03667         CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0,
03668          (void **)&verifyPolicy, &hFunc);
03669     }
03670     if (verifyPolicy)
03671         ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara,
03672          pPolicyStatus);
03673     if (hFunc)
03674         CryptFreeOIDFunctionAddress(hFunc, 0);
03675     TRACE("returning %d (%08x)\n", ret, pPolicyStatus->dwError);
03676     return ret;
03677 }

Generated on Sat May 26 2012 04:21:46 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.