| 1 | /*
 | 
|---|
| 2 |  * Copyright 2006 Juan Lang
 | 
|---|
| 3 |  *
 | 
|---|
| 4 |  * This library is free software; you can redistribute it and/or
 | 
|---|
| 5 |  * modify it under the terms of the GNU Lesser General Public
 | 
|---|
| 6 |  * License as published by the Free Software Foundation; either
 | 
|---|
| 7 |  * version 2.1 of the License, or (at your option) any later version.
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  * This library is distributed in the hope that it will be useful,
 | 
|---|
| 10 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 11 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
|---|
| 12 |  * Lesser General Public License for more details.
 | 
|---|
| 13 |  *
 | 
|---|
| 14 |  * You should have received a copy of the GNU Lesser General Public
 | 
|---|
| 15 |  * License along with this library; if not, write to the Free Software
 | 
|---|
| 16 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 | 
|---|
| 17 |  *
 | 
|---|
| 18 |  */
 | 
|---|
| 19 | #include <stdarg.h>
 | 
|---|
| 20 | #include <string.h>
 | 
|---|
| 21 | #define NONAMELESSUNION
 | 
|---|
| 22 | #include "windef.h"
 | 
|---|
| 23 | #include "winbase.h"
 | 
|---|
| 24 | #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
 | 
|---|
| 25 | #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
 | 
|---|
| 26 | #include "winerror.h"
 | 
|---|
| 27 | #include "wincrypt.h"
 | 
|---|
| 28 | #include "wine/debug.h"
 | 
|---|
| 29 | #include "wine/unicode.h"
 | 
|---|
| 30 | #include "crypt32_private.h"
 | 
|---|
| 31 | 
 | 
|---|
| 32 | WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 | 
|---|
| 33 | 
 | 
|---|
| 34 | #define DEFAULT_CYCLE_MODULUS 7
 | 
|---|
| 35 | 
 | 
|---|
| 36 | static HCERTCHAINENGINE CRYPT_defaultChainEngine;
 | 
|---|
| 37 | 
 | 
|---|
| 38 | /* This represents a subset of a certificate chain engine:  it doesn't include
 | 
|---|
| 39 |  * the "hOther" store described by MSDN, because I'm not sure how that's used.
 | 
|---|
| 40 |  * It also doesn't include the "hTrust" store, because I don't yet implement
 | 
|---|
| 41 |  * CTLs or complex certificate chains.
 | 
|---|
| 42 |  */
 | 
|---|
| 43 | typedef struct _CertificateChainEngine
 | 
|---|
| 44 | {
 | 
|---|
| 45 |     LONG       ref;
 | 
|---|
| 46 |     HCERTSTORE hRoot;
 | 
|---|
| 47 |     HCERTSTORE hWorld;
 | 
|---|
| 48 |     DWORD      dwFlags;
 | 
|---|
| 49 |     DWORD      dwUrlRetrievalTimeout;
 | 
|---|
| 50 |     DWORD      MaximumCachedCertificates;
 | 
|---|
| 51 |     DWORD      CycleDetectionModulus;
 | 
|---|
| 52 | } CertificateChainEngine, *PCertificateChainEngine;
 | 
|---|
| 53 | 
 | 
|---|
| 54 | static inline void CRYPT_AddStoresToCollection(HCERTSTORE collection,
 | 
|---|
| 55 |  DWORD cStores, HCERTSTORE *stores)
 | 
|---|
| 56 | {
 | 
|---|
| 57 |     DWORD i;
 | 
|---|
| 58 | 
 | 
|---|
| 59 |     for (i = 0; i < cStores; i++)
 | 
|---|
| 60 |         CertAddStoreToCollection(collection, stores[i], 0, 0);
 | 
|---|
| 61 | }
 | 
|---|
| 62 | 
 | 
|---|
| 63 | static inline void CRYPT_CloseStores(DWORD cStores, HCERTSTORE *stores)
 | 
|---|
| 64 | {
 | 
|---|
| 65 |     DWORD i;
 | 
|---|
| 66 | 
 | 
|---|
| 67 |     for (i = 0; i < cStores; i++)
 | 
|---|
| 68 |         CertCloseStore(stores[i], 0);
 | 
|---|
| 69 | }
 | 
|---|
| 70 | 
 | 
|---|
| 71 | static const WCHAR rootW[] = { 'R','o','o','t',0 };
 | 
|---|
| 72 | 
 | 
|---|
| 73 | static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store)
 | 
|---|
| 74 | {
 | 
|---|
| 75 |     BOOL ret = TRUE;
 | 
|---|
| 76 | 
 | 
|---|
| 77 |     if (store)
 | 
|---|
| 78 |     {
 | 
|---|
| 79 |         HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW);
 | 
|---|
| 80 |         PCCERT_CONTEXT cert = NULL, check;
 | 
|---|
| 81 |         BYTE hash[20];
 | 
|---|
| 82 |         DWORD size;
 | 
|---|
| 83 | 
 | 
|---|
| 84 |         do {
 | 
|---|
| 85 |             cert = CertEnumCertificatesInStore(store, cert);
 | 
|---|
| 86 |             if (cert)
 | 
|---|
| 87 |             {
 | 
|---|
| 88 |                 size = sizeof(hash);
 | 
|---|
| 89 | 
 | 
|---|
| 90 |                 ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
 | 
|---|
| 91 |                  hash, &size);
 | 
|---|
| 92 |                 if (ret)
 | 
|---|
| 93 |                 {
 | 
|---|
| 94 |                     CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
 | 
|---|
| 95 | 
 | 
|---|
| 96 |                     check = CertFindCertificateInStore(rootStore,
 | 
|---|
| 97 |                      cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
 | 
|---|
| 98 |                      NULL);
 | 
|---|
| 99 |                     if (!check)
 | 
|---|
| 100 |                         ret = FALSE;
 | 
|---|
| 101 |                     else
 | 
|---|
| 102 |                         CertFreeCertificateContext(check);
 | 
|---|
| 103 |                 }
 | 
|---|
| 104 |             }
 | 
|---|
| 105 |         } while (ret && cert);
 | 
|---|
| 106 |         if (cert)
 | 
|---|
| 107 |             CertFreeCertificateContext(cert);
 | 
|---|
| 108 |         CertCloseStore(rootStore, 0);
 | 
|---|
| 109 |     }
 | 
|---|
| 110 |     return ret;
 | 
|---|
| 111 | }
 | 
|---|
| 112 | 
 | 
|---|
| 113 | HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root,
 | 
|---|
| 114 |  PCERT_CHAIN_ENGINE_CONFIG pConfig)
 | 
|---|
| 115 | {
 | 
|---|
| 116 |     static const WCHAR caW[] = { 'C','A',0 };
 | 
|---|
| 117 |     static const WCHAR myW[] = { 'M','y',0 };
 | 
|---|
| 118 |     static const WCHAR trustW[] = { 'T','r','u','s','t',0 };
 | 
|---|
| 119 |     PCertificateChainEngine engine =
 | 
|---|
| 120 |      CryptMemAlloc(sizeof(CertificateChainEngine));
 | 
|---|
| 121 | 
 | 
|---|
| 122 |     if (engine)
 | 
|---|
| 123 |     {
 | 
|---|
| 124 |         HCERTSTORE worldStores[4];
 | 
|---|
| 125 | 
 | 
|---|
| 126 |         engine->ref = 1;
 | 
|---|
| 127 |         engine->hRoot = root;
 | 
|---|
| 128 |         engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
 | 
|---|
| 129 |          CERT_STORE_CREATE_NEW_FLAG, NULL);
 | 
|---|
| 130 |         worldStores[0] = CertDuplicateStore(engine->hRoot);
 | 
|---|
| 131 |         worldStores[1] = CertOpenSystemStoreW(0, caW);
 | 
|---|
| 132 |         worldStores[2] = CertOpenSystemStoreW(0, myW);
 | 
|---|
| 133 |         worldStores[3] = CertOpenSystemStoreW(0, trustW);
 | 
|---|
| 134 |         CRYPT_AddStoresToCollection(engine->hWorld,
 | 
|---|
| 135 |          sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
 | 
|---|
| 136 |         CRYPT_AddStoresToCollection(engine->hWorld,
 | 
|---|
| 137 |          pConfig->cAdditionalStore, pConfig->rghAdditionalStore);
 | 
|---|
| 138 |         CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]),
 | 
|---|
| 139 |          worldStores);
 | 
|---|
| 140 |         engine->dwFlags = pConfig->dwFlags;
 | 
|---|
| 141 |         engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout;
 | 
|---|
| 142 |         engine->MaximumCachedCertificates =
 | 
|---|
| 143 |          pConfig->MaximumCachedCertificates;
 | 
|---|
| 144 |         if (pConfig->CycleDetectionModulus)
 | 
|---|
| 145 |             engine->CycleDetectionModulus = pConfig->CycleDetectionModulus;
 | 
|---|
| 146 |         else
 | 
|---|
| 147 |             engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS;
 | 
|---|
| 148 |     }
 | 
|---|
| 149 |     return (HCERTCHAINENGINE)engine;
 | 
|---|
| 150 | }
 | 
|---|
| 151 | 
 | 
|---|
| 152 | BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
 | 
|---|
| 153 |  HCERTCHAINENGINE *phChainEngine)
 | 
|---|
| 154 | {
 | 
|---|
| 155 |     BOOL ret;
 | 
|---|
| 156 | 
 | 
|---|
| 157 |     TRACE("(%p, %p)\n", pConfig, phChainEngine);
 | 
|---|
| 158 | 
 | 
|---|
| 159 |     if (pConfig->cbSize != sizeof(*pConfig))
 | 
|---|
| 160 |     {
 | 
|---|
| 161 |         SetLastError(E_INVALIDARG);
 | 
|---|
| 162 |         return FALSE;
 | 
|---|
| 163 |     }
 | 
|---|
| 164 |     *phChainEngine = NULL;
 | 
|---|
| 165 |     ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot);
 | 
|---|
| 166 |     if (ret)
 | 
|---|
| 167 |     {
 | 
|---|
| 168 |         HCERTSTORE root;
 | 
|---|
| 169 |         HCERTCHAINENGINE engine;
 | 
|---|
| 170 | 
 | 
|---|
| 171 |         if (pConfig->hRestrictedRoot)
 | 
|---|
| 172 |             root = CertDuplicateStore(pConfig->hRestrictedRoot);
 | 
|---|
| 173 |         else
 | 
|---|
| 174 |             root = CertOpenSystemStoreW(0, rootW);
 | 
|---|
| 175 |         engine = CRYPT_CreateChainEngine(root, pConfig);
 | 
|---|
| 176 |         if (engine)
 | 
|---|
| 177 |         {
 | 
|---|
| 178 |             *phChainEngine = engine;
 | 
|---|
| 179 |             ret = TRUE;
 | 
|---|
| 180 |         }
 | 
|---|
| 181 |         else
 | 
|---|
| 182 |             ret = FALSE;
 | 
|---|
| 183 |     }
 | 
|---|
| 184 |     return ret;
 | 
|---|
| 185 | }
 | 
|---|
| 186 | 
 | 
|---|
| 187 | VOID WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
 | 
|---|
| 188 | {
 | 
|---|
| 189 |     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
 | 
|---|
| 190 | 
 | 
|---|
| 191 |     TRACE("(%p)\n", hChainEngine);
 | 
|---|
| 192 | 
 | 
|---|
| 193 |     if (engine && InterlockedDecrement(&engine->ref) == 0)
 | 
|---|
| 194 |     {
 | 
|---|
| 195 |         CertCloseStore(engine->hWorld, 0);
 | 
|---|
| 196 |         CertCloseStore(engine->hRoot, 0);
 | 
|---|
| 197 |         CryptMemFree(engine);
 | 
|---|
| 198 |     }
 | 
|---|
| 199 | }
 | 
|---|
| 200 | 
 | 
|---|
| 201 | static HCERTCHAINENGINE CRYPT_GetDefaultChainEngine(void)
 | 
|---|
| 202 | {
 | 
|---|
| 203 |     if (!CRYPT_defaultChainEngine)
 | 
|---|
| 204 |     {
 | 
|---|
| 205 |         CERT_CHAIN_ENGINE_CONFIG config = { 0 };
 | 
|---|
| 206 |         HCERTCHAINENGINE engine;
 | 
|---|
| 207 | 
 | 
|---|
| 208 |         config.cbSize = sizeof(config);
 | 
|---|
| 209 |         CertCreateCertificateChainEngine(&config, &engine);
 | 
|---|
| 210 |         InterlockedCompareExchangePointer(&CRYPT_defaultChainEngine, engine,
 | 
|---|
| 211 |          NULL);
 | 
|---|
| 212 |         if (CRYPT_defaultChainEngine != engine)
 | 
|---|
| 213 |             CertFreeCertificateChainEngine(engine);
 | 
|---|
| 214 |     }
 | 
|---|
| 215 |     return CRYPT_defaultChainEngine;
 | 
|---|
| 216 | }
 | 
|---|
| 217 | 
 | 
|---|
| 218 | void default_chain_engine_free(void)
 | 
|---|
| 219 | {
 | 
|---|
| 220 |     CertFreeCertificateChainEngine(CRYPT_defaultChainEngine);
 | 
|---|
| 221 | }
 | 
|---|
| 222 | 
 | 
|---|
| 223 | typedef struct _CertificateChain
 | 
|---|
| 224 | {
 | 
|---|
| 225 |     CERT_CHAIN_CONTEXT context;
 | 
|---|
| 226 |     HCERTSTORE world;
 | 
|---|
| 227 |     LONG ref;
 | 
|---|
| 228 | } CertificateChain, *PCertificateChain;
 | 
|---|
| 229 | 
 | 
|---|
| 230 | static inline BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
 | 
|---|
| 231 | {
 | 
|---|
| 232 |     return CertCompareCertificateName(cert->dwCertEncodingType,
 | 
|---|
| 233 |      &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
 | 
|---|
| 234 | }
 | 
|---|
| 235 | 
 | 
|---|
| 236 | static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
 | 
|---|
| 237 | {
 | 
|---|
| 238 |     CertFreeCertificateContext(element->pCertContext);
 | 
|---|
| 239 |     CryptMemFree(element);
 | 
|---|
| 240 | }
 | 
|---|
| 241 | 
 | 
|---|
| 242 | static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain)
 | 
|---|
| 243 | {
 | 
|---|
| 244 |     DWORD i, j, cyclicCertIndex = 0;
 | 
|---|
| 245 | 
 | 
|---|
| 246 |     /* O(n^2) - I don't think there's a faster way */
 | 
|---|
| 247 |     for (i = 0; !cyclicCertIndex && i < chain->cElement; i++)
 | 
|---|
| 248 |         for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++)
 | 
|---|
| 249 |             if (CertCompareCertificate(X509_ASN_ENCODING,
 | 
|---|
| 250 |              chain->rgpElement[i]->pCertContext->pCertInfo,
 | 
|---|
| 251 |              chain->rgpElement[j]->pCertContext->pCertInfo))
 | 
|---|
| 252 |                 cyclicCertIndex = j;
 | 
|---|
| 253 |     if (cyclicCertIndex)
 | 
|---|
| 254 |     {
 | 
|---|
| 255 |         chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus
 | 
|---|
| 256 |          |= CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
 | 
|---|
| 257 |         /* Release remaining certs */
 | 
|---|
| 258 |         for (i = cyclicCertIndex + 1; i < chain->cElement; i++)
 | 
|---|
| 259 |             CRYPT_FreeChainElement(chain->rgpElement[i]);
 | 
|---|
| 260 |         /* Truncate chain */
 | 
|---|
| 261 |         chain->cElement = cyclicCertIndex + 1;
 | 
|---|
| 262 |     }
 | 
|---|
| 263 | }
 | 
|---|
| 264 | 
 | 
|---|
| 265 | /* Checks whether the chain is cyclic by examining the last element's status */
 | 
|---|
| 266 | static inline BOOL CRYPT_IsSimpleChainCyclic(PCERT_SIMPLE_CHAIN chain)
 | 
|---|
| 267 | {
 | 
|---|
| 268 |     if (chain->cElement)
 | 
|---|
| 269 |         return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus
 | 
|---|
| 270 |          & CERT_TRUST_IS_CYCLIC;
 | 
|---|
| 271 |     else
 | 
|---|
| 272 |         return FALSE;
 | 
|---|
| 273 | }
 | 
|---|
| 274 | 
 | 
|---|
| 275 | static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus,
 | 
|---|
| 276 |  CERT_TRUST_STATUS *elementStatus)
 | 
|---|
| 277 | {
 | 
|---|
| 278 |     /* Any error that applies to an element also applies to a chain.. */
 | 
|---|
| 279 |     chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus;
 | 
|---|
| 280 |     /* but the bottom nibble of an element's info status doesn't apply to the
 | 
|---|
| 281 |      * chain.
 | 
|---|
| 282 |      */
 | 
|---|
| 283 |     chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0);
 | 
|---|
| 284 | }
 | 
|---|
| 285 | 
 | 
|---|
| 286 | static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine,
 | 
|---|
| 287 |  PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus)
 | 
|---|
| 288 | {
 | 
|---|
| 289 |     BOOL ret = FALSE;
 | 
|---|
| 290 |     PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
 | 
|---|
| 291 | 
 | 
|---|
| 292 |     if (element)
 | 
|---|
| 293 |     {
 | 
|---|
| 294 |         if (!chain->cElement)
 | 
|---|
| 295 |             chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT));
 | 
|---|
| 296 |         else
 | 
|---|
| 297 |             chain->rgpElement = CryptMemRealloc(chain->rgpElement,
 | 
|---|
| 298 |              (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
 | 
|---|
| 299 |         if (chain->rgpElement)
 | 
|---|
| 300 |         {
 | 
|---|
| 301 |             chain->rgpElement[chain->cElement++] = element;
 | 
|---|
| 302 |             memset(element, 0, sizeof(CERT_CHAIN_ELEMENT));
 | 
|---|
| 303 |             element->cbSize = sizeof(CERT_CHAIN_ELEMENT);
 | 
|---|
| 304 |             element->pCertContext = CertDuplicateCertificateContext(cert);
 | 
|---|
| 305 |             if (chain->cElement > 1)
 | 
|---|
| 306 |                 chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus
 | 
|---|
| 307 |                  = subjectInfoStatus;
 | 
|---|
| 308 |             /* FIXME: initialize the rest of element */
 | 
|---|
| 309 |             if (!(chain->cElement % engine->CycleDetectionModulus))
 | 
|---|
| 310 |                 CRYPT_CheckSimpleChainForCycles(chain);
 | 
|---|
| 311 |             CRYPT_CombineTrustStatus(&chain->TrustStatus,
 | 
|---|
| 312 |              &element->TrustStatus);
 | 
|---|
| 313 |             ret = TRUE;
 | 
|---|
| 314 |         }
 | 
|---|
| 315 |         else
 | 
|---|
| 316 |             CryptMemFree(element);
 | 
|---|
| 317 |     }
 | 
|---|
| 318 |     return ret;
 | 
|---|
| 319 | }
 | 
|---|
| 320 | 
 | 
|---|
| 321 | static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
 | 
|---|
| 322 | {
 | 
|---|
| 323 |     DWORD i;
 | 
|---|
| 324 | 
 | 
|---|
| 325 |     for (i = 0; i < chain->cElement; i++)
 | 
|---|
| 326 |         CRYPT_FreeChainElement(chain->rgpElement[i]);
 | 
|---|
| 327 |     CryptMemFree(chain->rgpElement);
 | 
|---|
| 328 |     CryptMemFree(chain);
 | 
|---|
| 329 | }
 | 
|---|
| 330 | 
 | 
|---|
| 331 | static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot,
 | 
|---|
| 332 |  PCERT_CHAIN_ELEMENT rootElement)
 | 
|---|
| 333 | {
 | 
|---|
| 334 |     BYTE hash[20];
 | 
|---|
| 335 |     DWORD size = sizeof(hash);
 | 
|---|
| 336 |     CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
 | 
|---|
| 337 |     PCCERT_CONTEXT trustedRoot;
 | 
|---|
| 338 | 
 | 
|---|
| 339 |     CertGetCertificateContextProperty(rootElement->pCertContext,
 | 
|---|
| 340 |      CERT_HASH_PROP_ID, hash, &size);
 | 
|---|
| 341 |     trustedRoot = CertFindCertificateInStore(hRoot,
 | 
|---|
| 342 |      rootElement->pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
 | 
|---|
| 343 |      &blob, NULL);
 | 
|---|
| 344 |     if (!trustedRoot)
 | 
|---|
| 345 |         rootElement->TrustStatus.dwErrorStatus |=
 | 
|---|
| 346 |          CERT_TRUST_IS_UNTRUSTED_ROOT;
 | 
|---|
| 347 |     else
 | 
|---|
| 348 |         CertFreeCertificateContext(trustedRoot);
 | 
|---|
| 349 | }
 | 
|---|
| 350 | 
 | 
|---|
| 351 | static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot,
 | 
|---|
| 352 |  PCERT_CHAIN_ELEMENT rootElement)
 | 
|---|
| 353 | {
 | 
|---|
| 354 |     PCCERT_CONTEXT root = rootElement->pCertContext;
 | 
|---|
| 355 | 
 | 
|---|
| 356 |     if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType,
 | 
|---|
| 357 |      CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
 | 
|---|
| 358 |      CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
 | 
|---|
| 359 |     {
 | 
|---|
| 360 |         TRACE("Last certificate's signature is invalid\n");
 | 
|---|
| 361 |         rootElement->TrustStatus.dwErrorStatus |=
 | 
|---|
| 362 |          CERT_TRUST_IS_NOT_SIGNATURE_VALID;
 | 
|---|
| 363 |     }
 | 
|---|
| 364 |     CRYPT_CheckTrustedStatus((HCERTSTORE)hRoot, rootElement);
 | 
|---|
| 365 | }
 | 
|---|
| 366 | 
 | 
|---|
| 367 | /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
 | 
|---|
| 368 |  * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a
 | 
|---|
| 369 |  * CERT_BASIC_CONSTRAINTS2_INFO.  If it neither extension is present, sets
 | 
|---|
| 370 |  * constraints->fCA to defaultIfNotSpecified.
 | 
|---|
| 371 |  * Returns FALSE if the extension is present but couldn't be decoded.
 | 
|---|
| 372 |  */
 | 
|---|
| 373 | static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
 | 
|---|
| 374 |  CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified)
 | 
|---|
| 375 | {
 | 
|---|
| 376 |     BOOL ret = TRUE;
 | 
|---|
| 377 |     PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
 | 
|---|
| 378 |      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
 | 
|---|
| 379 | 
 | 
|---|
| 380 |     constraints->fPathLenConstraint = FALSE;
 | 
|---|
| 381 |     if (ext)
 | 
|---|
| 382 |     {
 | 
|---|
| 383 |         CERT_BASIC_CONSTRAINTS_INFO *info;
 | 
|---|
| 384 |         DWORD size = 0;
 | 
|---|
| 385 | 
 | 
|---|
| 386 |         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
 | 
|---|
| 387 |          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
 | 
|---|
| 388 |          NULL, (LPBYTE)&info, &size);
 | 
|---|
| 389 |         if (ret)
 | 
|---|
| 390 |         {
 | 
|---|
| 391 |             if (info->SubjectType.cbData == 1)
 | 
|---|
| 392 |                 constraints->fCA =
 | 
|---|
| 393 |                  info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
 | 
|---|
| 394 |             LocalFree((HANDLE)info);
 | 
|---|
| 395 |         }
 | 
|---|
| 396 |     }
 | 
|---|
| 397 |     else
 | 
|---|
| 398 |     {
 | 
|---|
| 399 |         ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
 | 
|---|
| 400 |          cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
 | 
|---|
| 401 |         if (ext)
 | 
|---|
| 402 |         {
 | 
|---|
| 403 |             DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
 | 
|---|
| 404 | 
 | 
|---|
| 405 |             ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
 | 
|---|
| 406 |              szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
 | 
|---|
| 407 |              0, NULL, constraints, &size);
 | 
|---|
| 408 |         }
 | 
|---|
| 409 |         else
 | 
|---|
| 410 |             constraints->fCA = defaultIfNotSpecified;
 | 
|---|
| 411 |     }
 | 
|---|
| 412 |     return ret;
 | 
|---|
| 413 | }
 | 
|---|
| 414 | 
 | 
|---|
| 415 | /* Checks element's basic constraints to see if it can act as a CA, with
 | 
|---|
| 416 |  * remainingCAs CAs left in this chain.  Updates chainConstraints with the
 | 
|---|
| 417 |  * element's constraints, if:
 | 
|---|
| 418 |  * 1. chainConstraints doesn't have a path length constraint, or
 | 
|---|
| 419 |  * 2. element's path length constraint is smaller than chainConstraints's
 | 
|---|
| 420 |  * Sets *pathLengthConstraintViolated to TRUE if a path length violation
 | 
|---|
| 421 |  * occurs.
 | 
|---|
| 422 |  * Returns TRUE if the element can be a CA, and the length of the remaining
 | 
|---|
| 423 |  * chain is valid.
 | 
|---|
| 424 |  */
 | 
|---|
| 425 | static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
 | 
|---|
| 426 |  CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
 | 
|---|
| 427 |  BOOL *pathLengthConstraintViolated)
 | 
|---|
| 428 | {
 | 
|---|
| 429 |     BOOL validBasicConstraints;
 | 
|---|
| 430 |     CERT_BASIC_CONSTRAINTS2_INFO constraints;
 | 
|---|
| 431 | 
 | 
|---|
| 432 |     if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
 | 
|---|
| 433 |      &constraints, TRUE)) != NULL)
 | 
|---|
| 434 |     {
 | 
|---|
| 435 |         if (!constraints.fCA)
 | 
|---|
| 436 |         {
 | 
|---|
| 437 |             TRACE("chain element %d can't be a CA\n", remainingCAs + 1);
 | 
|---|
| 438 |             validBasicConstraints = FALSE;
 | 
|---|
| 439 |         }
 | 
|---|
| 440 |         else if (constraints.fPathLenConstraint)
 | 
|---|
| 441 |         {
 | 
|---|
| 442 |             /* If the element has path length constraints, they apply to the
 | 
|---|
| 443 |              * entire remaining chain.
 | 
|---|
| 444 |              */
 | 
|---|
| 445 |             if (!chainConstraints->fPathLenConstraint ||
 | 
|---|
| 446 |              constraints.dwPathLenConstraint <
 | 
|---|
| 447 |              chainConstraints->dwPathLenConstraint)
 | 
|---|
| 448 |             {
 | 
|---|
| 449 |                 TRACE("setting path length constraint to %d\n",
 | 
|---|
| 450 |                  chainConstraints->dwPathLenConstraint);
 | 
|---|
| 451 |                 chainConstraints->fPathLenConstraint = TRUE;
 | 
|---|
| 452 |                 chainConstraints->dwPathLenConstraint =
 | 
|---|
| 453 |                  constraints.dwPathLenConstraint;
 | 
|---|
| 454 |             }
 | 
|---|
| 455 |         }
 | 
|---|
| 456 |     }
 | 
|---|
| 457 |     if (chainConstraints->fPathLenConstraint &&
 | 
|---|
| 458 |      remainingCAs > chainConstraints->dwPathLenConstraint)
 | 
|---|
| 459 |     {
 | 
|---|
| 460 |         TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs,
 | 
|---|
| 461 |          chainConstraints->dwPathLenConstraint);
 | 
|---|
| 462 |         validBasicConstraints = FALSE;
 | 
|---|
| 463 |         *pathLengthConstraintViolated = TRUE;
 | 
|---|
| 464 |     }
 | 
|---|
| 465 |     return validBasicConstraints;
 | 
|---|
| 466 | }
 | 
|---|
| 467 | 
 | 
|---|
| 468 | static BOOL url_matches(LPCWSTR constraint, LPCWSTR name,
 | 
|---|
| 469 |  DWORD *trustErrorStatus)
 | 
|---|
| 470 | {
 | 
|---|
| 471 |     BOOL match = FALSE;
 | 
|---|
| 472 | 
 | 
|---|
| 473 |     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
 | 
|---|
| 474 | 
 | 
|---|
| 475 |     if (!constraint)
 | 
|---|
| 476 |         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
 | 
|---|
| 477 |     else if (!name)
 | 
|---|
| 478 |         ; /* no match */
 | 
|---|
| 479 |     else if (constraint[0] == '.')
 | 
|---|
| 480 |     {
 | 
|---|
| 481 |         if (lstrlenW(name) > lstrlenW(constraint))
 | 
|---|
| 482 |             match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
 | 
|---|
| 483 |              constraint);
 | 
|---|
| 484 |     }
 | 
|---|
| 485 |     else
 | 
|---|
| 486 |         match = !lstrcmpiW(constraint, name);
 | 
|---|
| 487 |     return match;
 | 
|---|
| 488 | }
 | 
|---|
| 489 | 
 | 
|---|
| 490 | static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name,
 | 
|---|
| 491 |  DWORD *trustErrorStatus)
 | 
|---|
| 492 | {
 | 
|---|
| 493 |     BOOL match = FALSE;
 | 
|---|
| 494 |     LPCWSTR at;
 | 
|---|
| 495 | 
 | 
|---|
| 496 |     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
 | 
|---|
| 497 | 
 | 
|---|
| 498 |     if (!constraint)
 | 
|---|
| 499 |         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
 | 
|---|
| 500 |     else if (!name)
 | 
|---|
| 501 |         ; /* no match */
 | 
|---|
| 502 |     else if ((at = strchrW(constraint, '@')) != NULL)
 | 
|---|
| 503 |         match = !lstrcmpiW(constraint, name);
 | 
|---|
| 504 |     else
 | 
|---|
| 505 |     {
 | 
|---|
| 506 |         if ((at = strchrW(name, '@')) != NULL)
 | 
|---|
| 507 |             match = url_matches(constraint, at + 1, trustErrorStatus);
 | 
|---|
| 508 |         else
 | 
|---|
| 509 |             match = !lstrcmpiW(constraint, name);
 | 
|---|
| 510 |     }
 | 
|---|
| 511 |     return match;
 | 
|---|
| 512 | }
 | 
|---|
| 513 | 
 | 
|---|
| 514 | static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name,
 | 
|---|
| 515 |  DWORD *trustErrorStatus)
 | 
|---|
| 516 | {
 | 
|---|
| 517 |     BOOL match = FALSE;
 | 
|---|
| 518 | 
 | 
|---|
| 519 |     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
 | 
|---|
| 520 | 
 | 
|---|
| 521 |     if (!constraint)
 | 
|---|
| 522 |         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
 | 
|---|
| 523 |     else if (!name)
 | 
|---|
| 524 |         ; /* no match */
 | 
|---|
| 525 |     else if (lstrlenW(name) >= lstrlenW(constraint))
 | 
|---|
| 526 |         match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
 | 
|---|
| 527 |          constraint);
 | 
|---|
| 528 |     /* else:  name is too short, no match */
 | 
|---|
| 529 | 
 | 
|---|
| 530 |     return match;
 | 
|---|
| 531 | }
 | 
|---|
| 532 | 
 | 
|---|
| 533 | static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint,
 | 
|---|
| 534 |  const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus)
 | 
|---|
| 535 | {
 | 
|---|
| 536 |     BOOL match = FALSE;
 | 
|---|
| 537 | 
 | 
|---|
| 538 |     TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData,
 | 
|---|
| 539 |      name->cbData, name->pbData);
 | 
|---|
| 540 | 
 | 
|---|
| 541 |     if (constraint->cbData != sizeof(DWORD) * 2)
 | 
|---|
| 542 |         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
 | 
|---|
| 543 |     else if (name->cbData == sizeof(DWORD))
 | 
|---|
| 544 |     {
 | 
|---|
| 545 |         DWORD subnet, mask, addr;
 | 
|---|
| 546 | 
 | 
|---|
| 547 |         memcpy(&subnet, constraint->pbData, sizeof(subnet));
 | 
|---|
| 548 |         memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask));
 | 
|---|
| 549 |         memcpy(&addr, name->pbData, sizeof(addr));
 | 
|---|
| 550 |         /* These are really in big-endian order, but for equality matching we
 | 
|---|
| 551 |          * don't need to swap to host order
 | 
|---|
| 552 |          */
 | 
|---|
| 553 |         match = (subnet & mask) == (addr & mask);
 | 
|---|
| 554 |     }
 | 
|---|
| 555 |     /* else: name is wrong size, no match */
 | 
|---|
| 556 | 
 | 
|---|
| 557 |     return match;
 | 
|---|
| 558 | }
 | 
|---|
| 559 | 
 | 
|---|
| 560 | static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint,
 | 
|---|
| 561 |  const CERT_ALT_NAME_INFO *subjectName, DWORD *trustErrorStatus,
 | 
|---|
| 562 |  DWORD errorIfFound, DWORD errorIfNotFound)
 | 
|---|
| 563 | {
 | 
|---|
| 564 |     DWORD i;
 | 
|---|
| 565 |     BOOL match = FALSE;
 | 
|---|
| 566 | 
 | 
|---|
| 567 |     for (i = 0; i < subjectName->cAltEntry; i++)
 | 
|---|
| 568 |     {
 | 
|---|
| 569 |         if (subjectName->rgAltEntry[i].dwAltNameChoice ==
 | 
|---|
| 570 |          constraint->dwAltNameChoice)
 | 
|---|
| 571 |         {
 | 
|---|
| 572 |             switch (constraint->dwAltNameChoice)
 | 
|---|
| 573 |             {
 | 
|---|
| 574 |             case CERT_ALT_NAME_RFC822_NAME:
 | 
|---|
| 575 |                 match = rfc822_name_matches(constraint->u.pwszURL,
 | 
|---|
| 576 |                  subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
 | 
|---|
| 577 |                 break;
 | 
|---|
| 578 |             case CERT_ALT_NAME_DNS_NAME:
 | 
|---|
| 579 |                 match = dns_name_matches(constraint->u.pwszURL,
 | 
|---|
| 580 |                  subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
 | 
|---|
| 581 |                 break;
 | 
|---|
| 582 |             case CERT_ALT_NAME_URL:
 | 
|---|
| 583 |                 match = url_matches(constraint->u.pwszURL,
 | 
|---|
| 584 |                  subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
 | 
|---|
| 585 |                 break;
 | 
|---|
| 586 |             case CERT_ALT_NAME_IP_ADDRESS:
 | 
|---|
| 587 |                 match = ip_address_matches(&constraint->u.IPAddress,
 | 
|---|
| 588 |                  &subjectName->rgAltEntry[i].u.IPAddress, trustErrorStatus);
 | 
|---|
| 589 |                 break;
 | 
|---|
| 590 |             case CERT_ALT_NAME_DIRECTORY_NAME:
 | 
|---|
| 591 |             default:
 | 
|---|
| 592 |                 ERR("name choice %d unsupported in this context\n",
 | 
|---|
| 593 |                  constraint->dwAltNameChoice);
 | 
|---|
| 594 |                 *trustErrorStatus |=
 | 
|---|
| 595 |                  CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
 | 
|---|
| 596 |             }
 | 
|---|
| 597 |         }
 | 
|---|
| 598 |     }
 | 
|---|
| 599 |     *trustErrorStatus |= match ? errorIfFound : errorIfNotFound;
 | 
|---|
| 600 | }
 | 
|---|
| 601 | 
 | 
|---|
| 602 | static void CRYPT_CheckNameConstraints(
 | 
|---|
| 603 |  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
 | 
|---|
| 604 |  DWORD *trustErrorStatus)
 | 
|---|
| 605 | {
 | 
|---|
| 606 |     /* If there aren't any existing constraints, don't bother checking */
 | 
|---|
| 607 |     if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree)
 | 
|---|
| 608 |     {
 | 
|---|
| 609 |         CERT_EXTENSION *ext;
 | 
|---|
| 610 | 
 | 
|---|
| 611 |         if ((ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, cert->cExtension,
 | 
|---|
| 612 |          cert->rgExtension)) != NULL)
 | 
|---|
| 613 |         {
 | 
|---|
| 614 |             CERT_ALT_NAME_INFO *subjectName;
 | 
|---|
| 615 |             DWORD size;
 | 
|---|
| 616 | 
 | 
|---|
| 617 |             if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
 | 
|---|
| 618 |              ext->Value.pbData, ext->Value.cbData,
 | 
|---|
| 619 |              CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
 | 
|---|
| 620 |              &subjectName, &size))
 | 
|---|
| 621 |             {
 | 
|---|
| 622 |                 DWORD i;
 | 
|---|
| 623 | 
 | 
|---|
| 624 |                 for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
 | 
|---|
| 625 |                     CRYPT_FindMatchingNameEntry(
 | 
|---|
| 626 |                      &nameConstraints->rgExcludedSubtree[i].Base, subjectName,
 | 
|---|
| 627 |                      trustErrorStatus,
 | 
|---|
| 628 |                      CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, 0);
 | 
|---|
| 629 |                 for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
 | 
|---|
| 630 |                     CRYPT_FindMatchingNameEntry(
 | 
|---|
| 631 |                      &nameConstraints->rgPermittedSubtree[i].Base, subjectName,
 | 
|---|
| 632 |                      trustErrorStatus,
 | 
|---|
| 633 |                      0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT);
 | 
|---|
| 634 |                 LocalFree((HANDLE)subjectName);
 | 
|---|
| 635 |             }
 | 
|---|
| 636 |         }
 | 
|---|
| 637 |         else
 | 
|---|
| 638 |         {
 | 
|---|
| 639 |             if (nameConstraints->cPermittedSubtree)
 | 
|---|
| 640 |                 *trustErrorStatus |=
 | 
|---|
| 641 |                  CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
 | 
|---|
| 642 |             if (nameConstraints->cExcludedSubtree)
 | 
|---|
| 643 |                 *trustErrorStatus |=
 | 
|---|
| 644 |                  CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
 | 
|---|
| 645 |         }
 | 
|---|
| 646 |     }
 | 
|---|
| 647 | }
 | 
|---|
| 648 | 
 | 
|---|
| 649 | /* Gets cert's name constraints, if any.  Free with LocalFree. */
 | 
|---|
| 650 | static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert)
 | 
|---|
| 651 | {
 | 
|---|
| 652 |     CERT_NAME_CONSTRAINTS_INFO *info = NULL;
 | 
|---|
| 653 | 
 | 
|---|
| 654 |     CERT_EXTENSION *ext;
 | 
|---|
| 655 | 
 | 
|---|
| 656 |     if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension,
 | 
|---|
| 657 |      cert->rgExtension)) != NULL)
 | 
|---|
| 658 |     {
 | 
|---|
| 659 |         DWORD size;
 | 
|---|
| 660 | 
 | 
|---|
| 661 |         CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
 | 
|---|
| 662 |          ext->Value.pbData, ext->Value.cbData,
 | 
|---|
| 663 |          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info,
 | 
|---|
| 664 |          &size);
 | 
|---|
| 665 |     }
 | 
|---|
| 666 |     return info;
 | 
|---|
| 667 | }
 | 
|---|
| 668 | 
 | 
|---|
| 669 | static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
 | 
|---|
| 670 | {
 | 
|---|
| 671 |     int i, j;
 | 
|---|
| 672 | 
 | 
|---|
| 673 |     /* Microsoft's implementation appears to violate RFC 3280:  according to
 | 
|---|
| 674 |      * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's
 | 
|---|
| 675 |      * name constraint is violated in the end cert.  According to RFC 3280,
 | 
|---|
| 676 |      * the constraints should be checked against every subsequent certificate
 | 
|---|
| 677 |      * in the chain, not just the end cert.
 | 
|---|
| 678 |      * Microsoft's implementation also sets the name constraint errors on the
 | 
|---|
| 679 |      * certs whose constraints were violated, not on the certs that violated
 | 
|---|
| 680 |      * them.
 | 
|---|
| 681 |      * In order to be error-compatible with Microsoft's implementation, while
 | 
|---|
| 682 |      * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name
 | 
|---|
| 683 |      * constraints.
 | 
|---|
| 684 |      */
 | 
|---|
| 685 |     for (i = chain->cElement - 1; i > 0; i--)
 | 
|---|
| 686 |     {
 | 
|---|
| 687 |         CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
 | 
|---|
| 688 | 
 | 
|---|
| 689 |         if ((nameConstraints = CRYPT_GetNameConstraints(
 | 
|---|
| 690 |          chain->rgpElement[i]->pCertContext->pCertInfo)) != NULL)
 | 
|---|
| 691 |         {
 | 
|---|
| 692 |             for (j = i - 1; j >= 0; j--)
 | 
|---|
| 693 |             {
 | 
|---|
| 694 |                 DWORD errorStatus = 0;
 | 
|---|
| 695 | 
 | 
|---|
| 696 |                 /* According to RFC 3280, self-signed certs don't have name
 | 
|---|
| 697 |                  * constraints checked unless they're the end cert.
 | 
|---|
| 698 |                  */
 | 
|---|
| 699 |                 if (j == 0 || !CRYPT_IsCertificateSelfSigned(
 | 
|---|
| 700 |                  chain->rgpElement[j]->pCertContext))
 | 
|---|
| 701 |                 {
 | 
|---|
| 702 |                     CRYPT_CheckNameConstraints(nameConstraints,
 | 
|---|
| 703 |                      chain->rgpElement[i]->pCertContext->pCertInfo,
 | 
|---|
| 704 |                      &errorStatus);
 | 
|---|
| 705 |                     chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
 | 
|---|
| 706 |                      errorStatus;
 | 
|---|
| 707 |                 }
 | 
|---|
| 708 |             }
 | 
|---|
| 709 |             LocalFree((HANDLE)nameConstraints);
 | 
|---|
| 710 |         }
 | 
|---|
| 711 |     }
 | 
|---|
| 712 | }
 | 
|---|
| 713 | 
 | 
|---|
| 714 | static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
 | 
|---|
| 715 |  PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
 | 
|---|
| 716 | {
 | 
|---|
| 717 |     PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1];
 | 
|---|
| 718 |     int i;
 | 
|---|
| 719 |     BOOL pathLengthConstraintViolated = FALSE;
 | 
|---|
| 720 |     CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 };
 | 
|---|
| 721 | 
 | 
|---|
| 722 |     for (i = chain->cElement - 1; i >= 0; i--)
 | 
|---|
| 723 |     {
 | 
|---|
| 724 |         if (CertVerifyTimeValidity(time,
 | 
|---|
| 725 |          chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
 | 
|---|
| 726 |             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
 | 
|---|
| 727 |              CERT_TRUST_IS_NOT_TIME_VALID;
 | 
|---|
| 728 |         if (i != 0)
 | 
|---|
| 729 |         {
 | 
|---|
| 730 |             /* Check the signature of the cert this issued */
 | 
|---|
| 731 |             if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
 | 
|---|
| 732 |              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
 | 
|---|
| 733 |              (void *)chain->rgpElement[i - 1]->pCertContext,
 | 
|---|
| 734 |              CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
 | 
|---|
| 735 |              (void *)chain->rgpElement[i]->pCertContext, 0, NULL))
 | 
|---|
| 736 |                 chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |=
 | 
|---|
| 737 |                  CERT_TRUST_IS_NOT_SIGNATURE_VALID;
 | 
|---|
| 738 |             /* Once a path length constraint has been violated, every remaining
 | 
|---|
| 739 |              * CA cert's basic constraints is considered invalid.
 | 
|---|
| 740 |              */
 | 
|---|
| 741 |             if (pathLengthConstraintViolated)
 | 
|---|
| 742 |                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
 | 
|---|
| 743 |                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
 | 
|---|
| 744 |             else if (!CRYPT_CheckBasicConstraintsForCA(
 | 
|---|
| 745 |              chain->rgpElement[i]->pCertContext, &constraints, i - 1,
 | 
|---|
| 746 |              &pathLengthConstraintViolated))
 | 
|---|
| 747 |                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
 | 
|---|
| 748 |                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
 | 
|---|
| 749 |             else if (constraints.fPathLenConstraint &&
 | 
|---|
| 750 |              constraints.dwPathLenConstraint)
 | 
|---|
| 751 |             {
 | 
|---|
| 752 |                 /* This one's valid - decrement max length */
 | 
|---|
| 753 |                 constraints.dwPathLenConstraint--;
 | 
|---|
| 754 |             }
 | 
|---|
| 755 |         }
 | 
|---|
| 756 |         if (CRYPT_IsSimpleChainCyclic(chain))
 | 
|---|
| 757 |         {
 | 
|---|
| 758 |             /* If the chain is cyclic, then the path length constraints
 | 
|---|
| 759 |              * are violated, because the chain is infinitely long.
 | 
|---|
| 760 |              */
 | 
|---|
| 761 |             pathLengthConstraintViolated = TRUE;
 | 
|---|
| 762 |             chain->TrustStatus.dwErrorStatus |=
 | 
|---|
| 763 |              CERT_TRUST_IS_PARTIAL_CHAIN |
 | 
|---|
| 764 |              CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
 | 
|---|
| 765 |         }
 | 
|---|
| 766 |         /* FIXME: check valid usages */
 | 
|---|
| 767 |         CRYPT_CombineTrustStatus(&chain->TrustStatus,
 | 
|---|
| 768 |          &chain->rgpElement[i]->TrustStatus);
 | 
|---|
| 769 |     }
 | 
|---|
| 770 |     CRYPT_CheckChainNameConstraints(chain);
 | 
|---|
| 771 |     if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext))
 | 
|---|
| 772 |     {
 | 
|---|
| 773 |         rootElement->TrustStatus.dwInfoStatus |=
 | 
|---|
| 774 |          CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
 | 
|---|
| 775 |         CRYPT_CheckRootCert((HCERTCHAINENGINE)engine->hRoot, rootElement);
 | 
|---|
| 776 |     }
 | 
|---|
| 777 |     CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
 | 
|---|
| 778 | }
 | 
|---|
| 779 | 
 | 
|---|
| 780 | static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject,
 | 
|---|
| 781 |  PCCERT_CONTEXT prevIssuer, DWORD *infoStatus)
 | 
|---|
| 782 | {
 | 
|---|
| 783 |     PCCERT_CONTEXT issuer = NULL;
 | 
|---|
| 784 |     PCERT_EXTENSION ext;
 | 
|---|
| 785 |     DWORD size;
 | 
|---|
| 786 | 
 | 
|---|
| 787 |     *infoStatus = 0;
 | 
|---|
| 788 |     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
 | 
|---|
| 789 |      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)) != NULL)
 | 
|---|
| 790 |     {
 | 
|---|
| 791 |         CERT_AUTHORITY_KEY_ID_INFO *info;
 | 
|---|
| 792 |         BOOL ret;
 | 
|---|
| 793 | 
 | 
|---|
| 794 |         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
 | 
|---|
| 795 |          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
 | 
|---|
| 796 |          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
 | 
|---|
| 797 |          &info, &size);
 | 
|---|
| 798 |         if (ret)
 | 
|---|
| 799 |         {
 | 
|---|
| 800 |             CERT_ID id;
 | 
|---|
| 801 | 
 | 
|---|
| 802 |             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
 | 
|---|
| 803 |             {
 | 
|---|
| 804 |                 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
 | 
|---|
| 805 |                 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
 | 
|---|
| 806 |                  sizeof(CERT_NAME_BLOB));
 | 
|---|
| 807 |                 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
 | 
|---|
| 808 |                  &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
 | 
|---|
| 809 |                 issuer = CertFindCertificateInStore(store,
 | 
|---|
| 810 |                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
 | 
|---|
| 811 |                  prevIssuer);
 | 
|---|
| 812 |                 if (issuer)
 | 
|---|
| 813 |                     *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
 | 
|---|
| 814 |             }
 | 
|---|
| 815 |             else if (info->KeyId.cbData)
 | 
|---|
| 816 |             {
 | 
|---|
| 817 |                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
 | 
|---|
| 818 |                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
 | 
|---|
| 819 |                 issuer = CertFindCertificateInStore(store,
 | 
|---|
| 820 |                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
 | 
|---|
| 821 |                  prevIssuer);
 | 
|---|
| 822 |                 if (issuer)
 | 
|---|
| 823 |                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
 | 
|---|
| 824 |             }
 | 
|---|
| 825 |             LocalFree((HANDLE)info);
 | 
|---|
| 826 |         }
 | 
|---|
| 827 |     }
 | 
|---|
| 828 |     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
 | 
|---|
| 829 |      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)) != NULL)
 | 
|---|
| 830 |     {
 | 
|---|
| 831 |         CERT_AUTHORITY_KEY_ID2_INFO *info;
 | 
|---|
| 832 |         BOOL ret;
 | 
|---|
| 833 | 
 | 
|---|
| 834 |         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
 | 
|---|
| 835 |          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
 | 
|---|
| 836 |          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
 | 
|---|
| 837 |          &info, &size);
 | 
|---|
| 838 |         if (ret)
 | 
|---|
| 839 |         {
 | 
|---|
| 840 |             CERT_ID id;
 | 
|---|
| 841 | 
 | 
|---|
| 842 |             if (info->AuthorityCertIssuer.cAltEntry &&
 | 
|---|
| 843 |              info->AuthorityCertSerialNumber.cbData)
 | 
|---|
| 844 |             {
 | 
|---|
| 845 |                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
 | 
|---|
| 846 |                 DWORD i;
 | 
|---|
| 847 | 
 | 
|---|
| 848 |                 for (i = 0; !directoryName &&
 | 
|---|
| 849 |                  i < info->AuthorityCertIssuer.cAltEntry; i++)
 | 
|---|
| 850 |                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
 | 
|---|
| 851 |                      == CERT_ALT_NAME_DIRECTORY_NAME)
 | 
|---|
| 852 |                         directoryName =
 | 
|---|
| 853 |                          &info->AuthorityCertIssuer.rgAltEntry[i];
 | 
|---|
| 854 |                 if (directoryName)
 | 
|---|
| 855 |                 {
 | 
|---|
| 856 |                     id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
 | 
|---|
| 857 |                     memcpy(&id.u.IssuerSerialNumber.Issuer,
 | 
|---|
| 858 |                      &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
 | 
|---|
| 859 |                     memcpy(&id.u.IssuerSerialNumber.SerialNumber,
 | 
|---|
| 860 |                      &info->AuthorityCertSerialNumber,
 | 
|---|
| 861 |                      sizeof(CRYPT_INTEGER_BLOB));
 | 
|---|
| 862 |                     issuer = CertFindCertificateInStore(store,
 | 
|---|
| 863 |                      subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
 | 
|---|
| 864 |                      prevIssuer);
 | 
|---|
| 865 |                     if (issuer)
 | 
|---|
| 866 |                         *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
 | 
|---|
| 867 |                 }
 | 
|---|
| 868 |                 else
 | 
|---|
| 869 |                     FIXME("no supported name type in authority key id2\n");
 | 
|---|
| 870 |             }
 | 
|---|
| 871 |             else if (info->KeyId.cbData)
 | 
|---|
| 872 |             {
 | 
|---|
| 873 |                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
 | 
|---|
| 874 |                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
 | 
|---|
| 875 |                 issuer = CertFindCertificateInStore(store,
 | 
|---|
| 876 |                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
 | 
|---|
| 877 |                  prevIssuer);
 | 
|---|
| 878 |                 if (issuer)
 | 
|---|
| 879 |                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
 | 
|---|
| 880 |             }
 | 
|---|
| 881 |             LocalFree((HANDLE)info);
 | 
|---|
| 882 |         }
 | 
|---|
| 883 |     }
 | 
|---|
| 884 |     else
 | 
|---|
| 885 |     {
 | 
|---|
| 886 |         issuer = CertFindCertificateInStore(store,
 | 
|---|
| 887 |          subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
 | 
|---|
| 888 |          &subject->pCertInfo->Issuer, prevIssuer);
 | 
|---|
| 889 |         if (issuer)
 | 
|---|
| 890 |             *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
 | 
|---|
| 891 |     }
 | 
|---|
| 892 |     return issuer;
 | 
|---|
| 893 | }
 | 
|---|
| 894 | 
 | 
|---|
| 895 | /* Builds a simple chain by finding an issuer for the last cert in the chain,
 | 
|---|
| 896 |  * until reaching a self-signed cert, or until no issuer can be found.
 | 
|---|
| 897 |  */
 | 
|---|
| 898 | static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
 | 
|---|
| 899 |  HCERTSTORE world, PCERT_SIMPLE_CHAIN chain)
 | 
|---|
| 900 | {
 | 
|---|
| 901 |     BOOL ret = TRUE;
 | 
|---|
| 902 |     PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext;
 | 
|---|
| 903 | 
 | 
|---|
| 904 |     while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
 | 
|---|
| 905 |      !CRYPT_IsCertificateSelfSigned(cert))
 | 
|---|
| 906 |     {
 | 
|---|
| 907 |         DWORD infoStatus;
 | 
|---|
| 908 |         PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL, &infoStatus);
 | 
|---|
| 909 | 
 | 
|---|
| 910 |         if (issuer)
 | 
|---|
| 911 |         {
 | 
|---|
| 912 |             ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, infoStatus);
 | 
|---|
| 913 |             /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to
 | 
|---|
| 914 |              * close the enumeration that found it
 | 
|---|
| 915 |              */
 | 
|---|
| 916 |             CertFreeCertificateContext(issuer);
 | 
|---|
| 917 |             cert = issuer;
 | 
|---|
| 918 |         }
 | 
|---|
| 919 |         else
 | 
|---|
| 920 |         {
 | 
|---|
| 921 |             TRACE("Couldn't find issuer, halting chain creation\n");
 | 
|---|
| 922 |             chain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN;
 | 
|---|
| 923 |             break;
 | 
|---|
| 924 |         }
 | 
|---|
| 925 |     }
 | 
|---|
| 926 |     return ret;
 | 
|---|
| 927 | }
 | 
|---|
| 928 | 
 | 
|---|
| 929 | static BOOL CRYPT_GetSimpleChainForCert(PCertificateChainEngine engine,
 | 
|---|
| 930 |  HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime,
 | 
|---|
| 931 |  PCERT_SIMPLE_CHAIN *ppChain)
 | 
|---|
| 932 | {
 | 
|---|
| 933 |     BOOL ret = FALSE;
 | 
|---|
| 934 |     PCERT_SIMPLE_CHAIN chain;
 | 
|---|
| 935 | 
 | 
|---|
| 936 |     TRACE("(%p, %p, %p, %p)\n", engine, world, cert, pTime);
 | 
|---|
| 937 | 
 | 
|---|
| 938 |     chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
 | 
|---|
| 939 |     if (chain)
 | 
|---|
| 940 |     {
 | 
|---|
| 941 |         memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
 | 
|---|
| 942 |         chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
 | 
|---|
| 943 |         ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
 | 
|---|
| 944 |         if (ret)
 | 
|---|
| 945 |         {
 | 
|---|
| 946 |             ret = CRYPT_BuildSimpleChain(engine, world, chain);
 | 
|---|
| 947 |             if (ret)
 | 
|---|
| 948 |                 CRYPT_CheckSimpleChain(engine, chain, pTime);
 | 
|---|
| 949 |         }
 | 
|---|
| 950 |         if (!ret)
 | 
|---|
| 951 |         {
 | 
|---|
| 952 |             CRYPT_FreeSimpleChain(chain);
 | 
|---|
| 953 |             chain = NULL;
 | 
|---|
| 954 |         }
 | 
|---|
| 955 |         *ppChain = chain;
 | 
|---|
| 956 |     }
 | 
|---|
| 957 |     return ret;
 | 
|---|
| 958 | }
 | 
|---|
| 959 | 
 | 
|---|
| 960 | static BOOL CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine,
 | 
|---|
| 961 |  PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
 | 
|---|
| 962 |  PCertificateChain *ppChain)
 | 
|---|
| 963 | {
 | 
|---|
| 964 |     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
 | 
|---|
| 965 |     PCERT_SIMPLE_CHAIN simpleChain = NULL;
 | 
|---|
| 966 |     HCERTSTORE world;
 | 
|---|
| 967 |     BOOL ret;
 | 
|---|
| 968 | 
 | 
|---|
| 969 |     world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
 | 
|---|
| 970 |      CERT_STORE_CREATE_NEW_FLAG, NULL);
 | 
|---|
| 971 |     CertAddStoreToCollection(world, engine->hWorld, 0, 0);
 | 
|---|
| 972 |     if (hAdditionalStore)
 | 
|---|
| 973 |         CertAddStoreToCollection(world, hAdditionalStore, 0, 0);
 | 
|---|
| 974 |     /* FIXME: only simple chains are supported for now, as CTLs aren't
 | 
|---|
| 975 |      * supported yet.
 | 
|---|
| 976 |      */
 | 
|---|
| 977 |     if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime,
 | 
|---|
| 978 |      &simpleChain)) != NULL)
 | 
|---|
| 979 |     {
 | 
|---|
| 980 |         PCertificateChain chain = CryptMemAlloc(sizeof(CertificateChain));
 | 
|---|
| 981 | 
 | 
|---|
| 982 |         if (chain)
 | 
|---|
| 983 |         {
 | 
|---|
| 984 |             chain->ref = 1;
 | 
|---|
| 985 |             chain->world = world;
 | 
|---|
| 986 |             chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
 | 
|---|
| 987 |             chain->context.TrustStatus = simpleChain->TrustStatus;
 | 
|---|
| 988 |             chain->context.cChain = 1;
 | 
|---|
| 989 |             chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN));
 | 
|---|
| 990 |             chain->context.rgpChain[0] = simpleChain;
 | 
|---|
| 991 |             chain->context.cLowerQualityChainContext = 0;
 | 
|---|
| 992 |             chain->context.rgpLowerQualityChainContext = NULL;
 | 
|---|
| 993 |             chain->context.fHasRevocationFreshnessTime = FALSE;
 | 
|---|
| 994 |             chain->context.dwRevocationFreshnessTime = 0;
 | 
|---|
| 995 |         }
 | 
|---|
| 996 |         else
 | 
|---|
| 997 |             ret = FALSE;
 | 
|---|
| 998 |         *ppChain = chain;
 | 
|---|
| 999 |     }
 | 
|---|
| 1000 |     return ret;
 | 
|---|
| 1001 | }
 | 
|---|
| 1002 | 
 | 
|---|
| 1003 | /* Makes and returns a copy of chain, up to and including element iElement. */
 | 
|---|
| 1004 | static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement(
 | 
|---|
| 1005 |  PCERT_SIMPLE_CHAIN chain, DWORD iElement)
 | 
|---|
| 1006 | {
 | 
|---|
| 1007 |     PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
 | 
|---|
| 1008 | 
 | 
|---|
| 1009 |     if (copy)
 | 
|---|
| 1010 |     {
 | 
|---|
| 1011 |         memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN));
 | 
|---|
| 1012 |         copy->cbSize = sizeof(CERT_SIMPLE_CHAIN);
 | 
|---|
| 1013 |         copy->rgpElement =
 | 
|---|
| 1014 |          CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
 | 
|---|
| 1015 |         if (copy->rgpElement)
 | 
|---|
| 1016 |         {
 | 
|---|
| 1017 |             DWORD i;
 | 
|---|
| 1018 |             BOOL ret = TRUE;
 | 
|---|
| 1019 | 
 | 
|---|
| 1020 |             memset(copy->rgpElement, 0,
 | 
|---|
| 1021 |              (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
 | 
|---|
| 1022 |             for (i = 0; ret && i <= iElement; i++)
 | 
|---|
| 1023 |             {
 | 
|---|
| 1024 |                 PCERT_CHAIN_ELEMENT element =
 | 
|---|
| 1025 |                  CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
 | 
|---|
| 1026 | 
 | 
|---|
| 1027 |                 if (element)
 | 
|---|
| 1028 |                 {
 | 
|---|
| 1029 |                     *element = *chain->rgpElement[i];
 | 
|---|
| 1030 |                     element->pCertContext = CertDuplicateCertificateContext(
 | 
|---|
| 1031 |                      chain->rgpElement[i]->pCertContext);
 | 
|---|
| 1032 |                     /* Reset the trust status of the copied element, it'll get
 | 
|---|
| 1033 |                      * rechecked after the new chain is done.
 | 
|---|
| 1034 |                      */
 | 
|---|
| 1035 |                     memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
 | 
|---|
| 1036 |                     copy->rgpElement[copy->cElement++] = element;
 | 
|---|
| 1037 |                 }
 | 
|---|
| 1038 |                 else
 | 
|---|
| 1039 |                     ret = FALSE;
 | 
|---|
| 1040 |             }
 | 
|---|
| 1041 |             if (!ret)
 | 
|---|
| 1042 |             {
 | 
|---|
| 1043 |                 for (i = 0; i <= iElement; i++)
 | 
|---|
| 1044 |                     CryptMemFree(copy->rgpElement[i]);
 | 
|---|
| 1045 |                 CryptMemFree(copy->rgpElement);
 | 
|---|
| 1046 |                 CryptMemFree(copy);
 | 
|---|
| 1047 |                 copy = NULL;
 | 
|---|
| 1048 |             }
 | 
|---|
| 1049 |         }
 | 
|---|
| 1050 |         else
 | 
|---|
| 1051 |         {
 | 
|---|
| 1052 |             CryptMemFree(copy);
 | 
|---|
| 1053 |             copy = NULL;
 | 
|---|
| 1054 |         }
 | 
|---|
| 1055 |     }
 | 
|---|
| 1056 |     return copy;
 | 
|---|
| 1057 | }
 | 
|---|
| 1058 | 
 | 
|---|
| 1059 | static void CRYPT_FreeLowerQualityChains(PCertificateChain chain)
 | 
|---|
| 1060 | {
 | 
|---|
| 1061 |     DWORD i;
 | 
|---|
| 1062 | 
 | 
|---|
| 1063 |     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
 | 
|---|
| 1064 |         CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]);
 | 
|---|
| 1065 |     CryptMemFree(chain->context.rgpLowerQualityChainContext);
 | 
|---|
| 1066 |     chain->context.cLowerQualityChainContext = 0;
 | 
|---|
| 1067 |     chain->context.rgpLowerQualityChainContext = NULL;
 | 
|---|
| 1068 | }
 | 
|---|
| 1069 | 
 | 
|---|
| 1070 | static void CRYPT_FreeChainContext(PCertificateChain chain)
 | 
|---|
| 1071 | {
 | 
|---|
| 1072 |     DWORD i;
 | 
|---|
| 1073 | 
 | 
|---|
| 1074 |     CRYPT_FreeLowerQualityChains(chain);
 | 
|---|
| 1075 |     for (i = 0; i < chain->context.cChain; i++)
 | 
|---|
| 1076 |         CRYPT_FreeSimpleChain(chain->context.rgpChain[i]);
 | 
|---|
| 1077 |     CryptMemFree(chain->context.rgpChain);
 | 
|---|
| 1078 |     CertCloseStore(chain->world, 0);
 | 
|---|
| 1079 |     CryptMemFree(chain);
 | 
|---|
| 1080 | }
 | 
|---|
| 1081 | 
 | 
|---|
| 1082 | /* Makes and returns a copy of chain, up to and including element iElement of
 | 
|---|
| 1083 |  * simple chain iChain.
 | 
|---|
| 1084 |  */
 | 
|---|
| 1085 | static PCertificateChain CRYPT_CopyChainToElement(PCertificateChain chain,
 | 
|---|
| 1086 |  DWORD iChain, DWORD iElement)
 | 
|---|
| 1087 | {
 | 
|---|
| 1088 |     PCertificateChain copy = CryptMemAlloc(sizeof(CertificateChain));
 | 
|---|
| 1089 | 
 | 
|---|
| 1090 |     if (copy)
 | 
|---|
| 1091 |     {
 | 
|---|
| 1092 |         copy->ref = 1;
 | 
|---|
| 1093 |         copy->world = CertDuplicateStore(chain->world);
 | 
|---|
| 1094 |         copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
 | 
|---|
| 1095 |         /* Leave the trust status of the copied chain unset, it'll get
 | 
|---|
| 1096 |          * rechecked after the new chain is done.
 | 
|---|
| 1097 |          */
 | 
|---|
| 1098 |         memset(©->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
 | 
|---|
| 1099 |         copy->context.cLowerQualityChainContext = 0;
 | 
|---|
| 1100 |         copy->context.rgpLowerQualityChainContext = NULL;
 | 
|---|
| 1101 |         copy->context.fHasRevocationFreshnessTime = FALSE;
 | 
|---|
| 1102 |         copy->context.dwRevocationFreshnessTime = 0;
 | 
|---|
| 1103 |         copy->context.rgpChain = CryptMemAlloc(
 | 
|---|
| 1104 |          (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
 | 
|---|
| 1105 |         if (copy->context.rgpChain)
 | 
|---|
| 1106 |         {
 | 
|---|
| 1107 |             BOOL ret = TRUE;
 | 
|---|
| 1108 |             DWORD i;
 | 
|---|
| 1109 | 
 | 
|---|
| 1110 |             memset(copy->context.rgpChain, 0,
 | 
|---|
| 1111 |              (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
 | 
|---|
| 1112 |             if (iChain)
 | 
|---|
| 1113 |             {
 | 
|---|
| 1114 |                 for (i = 0; ret && iChain && i < iChain - 1; i++)
 | 
|---|
| 1115 |                 {
 | 
|---|
| 1116 |                     copy->context.rgpChain[i] =
 | 
|---|
| 1117 |                      CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
 | 
|---|
| 1118 |                      chain->context.rgpChain[i]->cElement - 1);
 | 
|---|
| 1119 |                     if (!copy->context.rgpChain[i])
 | 
|---|
| 1120 |                         ret = FALSE;
 | 
|---|
| 1121 |                 }
 | 
|---|
| 1122 |             }
 | 
|---|
| 1123 |             else
 | 
|---|
| 1124 |                 i = 0;
 | 
|---|
| 1125 |             if (ret)
 | 
|---|
| 1126 |             {
 | 
|---|
| 1127 |                 copy->context.rgpChain[i] =
 | 
|---|
| 1128 |                  CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
 | 
|---|
| 1129 |                  iElement);
 | 
|---|
| 1130 |                 if (!copy->context.rgpChain[i])
 | 
|---|
| 1131 |                     ret = FALSE;
 | 
|---|
| 1132 |             }
 | 
|---|
| 1133 |             if (!ret)
 | 
|---|
| 1134 |             {
 | 
|---|
| 1135 |                 CRYPT_FreeChainContext(copy);
 | 
|---|
| 1136 |                 copy = NULL;
 | 
|---|
| 1137 |             }
 | 
|---|
| 1138 |             else
 | 
|---|
| 1139 |                 copy->context.cChain = iChain + 1;
 | 
|---|
| 1140 |         }
 | 
|---|
| 1141 |         else
 | 
|---|
| 1142 |         {
 | 
|---|
| 1143 |             CryptMemFree(copy);
 | 
|---|
| 1144 |             copy = NULL;
 | 
|---|
| 1145 |         }
 | 
|---|
| 1146 |     }
 | 
|---|
| 1147 |     return copy;
 | 
|---|
| 1148 | }
 | 
|---|
| 1149 | 
 | 
|---|
| 1150 | static PCertificateChain CRYPT_BuildAlternateContextFromChain(
 | 
|---|
| 1151 |  HCERTCHAINENGINE hChainEngine, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
 | 
|---|
| 1152 |  PCertificateChain chain)
 | 
|---|
| 1153 | {
 | 
|---|
| 1154 |     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
 | 
|---|
| 1155 |     PCertificateChain alternate;
 | 
|---|
| 1156 | 
 | 
|---|
| 1157 |     TRACE("(%p, %p, %p, %p)\n", hChainEngine, pTime, hAdditionalStore, chain);
 | 
|---|
| 1158 | 
 | 
|---|
| 1159 |     /* Always start with the last "lower quality" chain to ensure a consistent
 | 
|---|
| 1160 |      * order of alternate creation:
 | 
|---|
| 1161 |      */
 | 
|---|
| 1162 |     if (chain->context.cLowerQualityChainContext)
 | 
|---|
| 1163 |         chain = (PCertificateChain)chain->context.rgpLowerQualityChainContext[
 | 
|---|
| 1164 |          chain->context.cLowerQualityChainContext - 1];
 | 
|---|
| 1165 |     /* A chain with only one element can't have any alternates */
 | 
|---|
| 1166 |     if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1)
 | 
|---|
| 1167 |         alternate = NULL;
 | 
|---|
| 1168 |     else
 | 
|---|
| 1169 |     {
 | 
|---|
| 1170 |         DWORD i, j, infoStatus;
 | 
|---|
| 1171 |         PCCERT_CONTEXT alternateIssuer = NULL;
 | 
|---|
| 1172 | 
 | 
|---|
| 1173 |         alternate = NULL;
 | 
|---|
| 1174 |         for (i = 0; !alternateIssuer && i < chain->context.cChain; i++)
 | 
|---|
| 1175 |             for (j = 0; !alternateIssuer &&
 | 
|---|
| 1176 |              j < chain->context.rgpChain[i]->cElement - 1; j++)
 | 
|---|
| 1177 |             {
 | 
|---|
| 1178 |                 PCCERT_CONTEXT subject =
 | 
|---|
| 1179 |                  chain->context.rgpChain[i]->rgpElement[j]->pCertContext;
 | 
|---|
| 1180 |                 PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext(
 | 
|---|
| 1181 |                  chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext);
 | 
|---|
| 1182 | 
 | 
|---|
| 1183 |                 alternateIssuer = CRYPT_GetIssuer(prevIssuer->hCertStore,
 | 
|---|
| 1184 |                  subject, prevIssuer, &infoStatus);
 | 
|---|
| 1185 |             }
 | 
|---|
| 1186 |         if (alternateIssuer)
 | 
|---|
| 1187 |         {
 | 
|---|
| 1188 |             i--;
 | 
|---|
| 1189 |             j--;
 | 
|---|
| 1190 |             alternate = CRYPT_CopyChainToElement(chain, i, j);
 | 
|---|
| 1191 |             if (alternate)
 | 
|---|
| 1192 |             {
 | 
|---|
| 1193 |                 BOOL ret = CRYPT_AddCertToSimpleChain(engine,
 | 
|---|
| 1194 |                  alternate->context.rgpChain[i], alternateIssuer, infoStatus);
 | 
|---|
| 1195 | 
 | 
|---|
| 1196 |                 /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it
 | 
|---|
| 1197 |                  * to close the enumeration that found it
 | 
|---|
| 1198 |                  */
 | 
|---|
| 1199 |                 CertFreeCertificateContext(alternateIssuer);
 | 
|---|
| 1200 |                 if (ret)
 | 
|---|
| 1201 |                 {
 | 
|---|
| 1202 |                     ret = CRYPT_BuildSimpleChain(engine, alternate->world,
 | 
|---|
| 1203 |                      alternate->context.rgpChain[i]);
 | 
|---|
| 1204 |                     if (ret)
 | 
|---|
| 1205 |                         CRYPT_CheckSimpleChain(engine,
 | 
|---|
| 1206 |                          alternate->context.rgpChain[i], pTime);
 | 
|---|
| 1207 |                     CRYPT_CombineTrustStatus(&alternate->context.TrustStatus,
 | 
|---|
| 1208 |                      &alternate->context.rgpChain[i]->TrustStatus);
 | 
|---|
| 1209 |                 }
 | 
|---|
| 1210 |                 if (!ret)
 | 
|---|
| 1211 |                 {
 | 
|---|
| 1212 |                     CRYPT_FreeChainContext(alternate);
 | 
|---|
| 1213 |                     alternate = NULL;
 | 
|---|
| 1214 |                 }
 | 
|---|
| 1215 |             }
 | 
|---|
| 1216 |         }
 | 
|---|
| 1217 |     }
 | 
|---|
| 1218 |     TRACE("%p\n", alternate);
 | 
|---|
| 1219 |     return alternate;
 | 
|---|
| 1220 | }
 | 
|---|
| 1221 | 
 | 
|---|
| 1222 | #define CHAIN_QUALITY_SIGNATURE_VALID 8
 | 
|---|
| 1223 | #define CHAIN_QUALITY_TIME_VALID      4
 | 
|---|
| 1224 | #define CHAIN_QUALITY_COMPLETE_CHAIN  2
 | 
|---|
| 1225 | #define CHAIN_QUALITY_TRUSTED_ROOT    1
 | 
|---|
| 1226 | 
 | 
|---|
| 1227 | #define CHAIN_QUALITY_HIGHEST \
 | 
|---|
| 1228 |  CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
 | 
|---|
| 1229 |  CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT
 | 
|---|
| 1230 | 
 | 
|---|
| 1231 | #define IS_TRUST_ERROR_SET(TrustStatus, bits) \
 | 
|---|
| 1232 |  (TrustStatus)->dwErrorStatus & (bits)
 | 
|---|
| 1233 | 
 | 
|---|
| 1234 | static DWORD CRYPT_ChainQuality(PCertificateChain chain)
 | 
|---|
| 1235 | {
 | 
|---|
| 1236 |     DWORD quality = CHAIN_QUALITY_HIGHEST;
 | 
|---|
| 1237 | 
 | 
|---|
| 1238 |     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
 | 
|---|
| 1239 |      CERT_TRUST_IS_UNTRUSTED_ROOT))
 | 
|---|
| 1240 |         quality &= ~CHAIN_QUALITY_TRUSTED_ROOT;
 | 
|---|
| 1241 |     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
 | 
|---|
| 1242 |      CERT_TRUST_IS_PARTIAL_CHAIN))
 | 
|---|
| 1243 |     if (chain->context.TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
 | 
|---|
| 1244 |         quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN;
 | 
|---|
| 1245 |     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
 | 
|---|
| 1246 |      CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED))
 | 
|---|
| 1247 |         quality &= ~CHAIN_QUALITY_TIME_VALID;
 | 
|---|
| 1248 |     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
 | 
|---|
| 1249 |      CERT_TRUST_IS_NOT_SIGNATURE_VALID))
 | 
|---|
| 1250 |         quality &= ~CHAIN_QUALITY_SIGNATURE_VALID;
 | 
|---|
| 1251 |     return quality;
 | 
|---|
| 1252 | }
 | 
|---|
| 1253 | 
 | 
|---|
| 1254 | /* Chooses the highest quality chain among chain and its "lower quality"
 | 
|---|
| 1255 |  * alternate chains.  Returns the highest quality chain, with all other
 | 
|---|
| 1256 |  * chains as lower quality chains of it.
 | 
|---|
| 1257 |  */
 | 
|---|
| 1258 | static PCertificateChain CRYPT_ChooseHighestQualityChain(
 | 
|---|
| 1259 |  PCertificateChain chain)
 | 
|---|
| 1260 | {
 | 
|---|
| 1261 |     DWORD i;
 | 
|---|
| 1262 | 
 | 
|---|
| 1263 |     /* There are always only two chains being considered:  chain, and an
 | 
|---|
| 1264 |      * alternate at chain->rgpLowerQualityChainContext[i].  If the alternate
 | 
|---|
| 1265 |      * has a higher quality than chain, the alternate gets assigned the lower
 | 
|---|
| 1266 |      * quality contexts, with chain taking the alternate's place among the
 | 
|---|
| 1267 |      * lower quality contexts.
 | 
|---|
| 1268 |      */
 | 
|---|
| 1269 |     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
 | 
|---|
| 1270 |     {
 | 
|---|
| 1271 |         PCertificateChain alternate =
 | 
|---|
| 1272 |          (PCertificateChain)chain->context.rgpLowerQualityChainContext[i];
 | 
|---|
| 1273 | 
 | 
|---|
| 1274 |         if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain))
 | 
|---|
| 1275 |         {
 | 
|---|
| 1276 |             alternate->context.cLowerQualityChainContext =
 | 
|---|
| 1277 |              chain->context.cLowerQualityChainContext;
 | 
|---|
| 1278 |             alternate->context.rgpLowerQualityChainContext =
 | 
|---|
| 1279 |              chain->context.rgpLowerQualityChainContext;
 | 
|---|
| 1280 |             alternate->context.rgpLowerQualityChainContext[i] =
 | 
|---|
| 1281 |              (PCCERT_CHAIN_CONTEXT)chain;
 | 
|---|
| 1282 |             chain->context.cLowerQualityChainContext = 0;
 | 
|---|
| 1283 |             chain->context.rgpLowerQualityChainContext = NULL;
 | 
|---|
| 1284 |             chain = alternate;
 | 
|---|
| 1285 |         }
 | 
|---|
| 1286 |     }
 | 
|---|
| 1287 |     return chain;
 | 
|---|
| 1288 | }
 | 
|---|
| 1289 | 
 | 
|---|
| 1290 | static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain,
 | 
|---|
| 1291 |  PCertificateChain alternate)
 | 
|---|
| 1292 | {
 | 
|---|
| 1293 |     BOOL ret;
 | 
|---|
| 1294 | 
 | 
|---|
| 1295 |     if (chain->context.cLowerQualityChainContext)
 | 
|---|
| 1296 |         chain->context.rgpLowerQualityChainContext =
 | 
|---|
| 1297 |          CryptMemRealloc(chain->context.rgpLowerQualityChainContext,
 | 
|---|
| 1298 |          (chain->context.cLowerQualityChainContext + 1) *
 | 
|---|
| 1299 |          sizeof(PCCERT_CHAIN_CONTEXT));
 | 
|---|
| 1300 |     else
 | 
|---|
| 1301 |         chain->context.rgpLowerQualityChainContext =
 | 
|---|
| 1302 |          CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT));
 | 
|---|
| 1303 |     if (chain->context.rgpLowerQualityChainContext)
 | 
|---|
| 1304 |     {
 | 
|---|
| 1305 |         chain->context.rgpLowerQualityChainContext[
 | 
|---|
| 1306 |          chain->context.cLowerQualityChainContext++] =
 | 
|---|
| 1307 |          (PCCERT_CHAIN_CONTEXT)alternate;
 | 
|---|
| 1308 |         ret = TRUE;
 | 
|---|
| 1309 |     }
 | 
|---|
| 1310 |     else
 | 
|---|
| 1311 |         ret = FALSE;
 | 
|---|
| 1312 |     return ret;
 | 
|---|
| 1313 | }
 | 
|---|
| 1314 | 
 | 
|---|
| 1315 | static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain(
 | 
|---|
| 1316 |  PCERT_CHAIN_CONTEXT chain, DWORD i)
 | 
|---|
| 1317 | {
 | 
|---|
| 1318 |     DWORD j, iElement;
 | 
|---|
| 1319 |     PCERT_CHAIN_ELEMENT element = NULL;
 | 
|---|
| 1320 | 
 | 
|---|
| 1321 |     for (j = 0, iElement = 0; !element && j < chain->cChain; j++)
 | 
|---|
| 1322 |     {
 | 
|---|
| 1323 |         if (iElement + chain->rgpChain[j]->cElement < i)
 | 
|---|
| 1324 |             iElement += chain->rgpChain[j]->cElement;
 | 
|---|
| 1325 |         else
 | 
|---|
| 1326 |             element = chain->rgpChain[j]->rgpElement[i - iElement];
 | 
|---|
| 1327 |     }
 | 
|---|
| 1328 |     return element;
 | 
|---|
| 1329 | }
 | 
|---|
| 1330 | 
 | 
|---|
| 1331 | typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS {
 | 
|---|
| 1332 |     DWORD            cbSize;
 | 
|---|
| 1333 |     CERT_USAGE_MATCH RequestedUsage;
 | 
|---|
| 1334 | } CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS;
 | 
|---|
| 1335 | 
 | 
|---|
| 1336 | static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
 | 
|---|
| 1337 |  LPFILETIME pTime, PCERT_CHAIN_PARA pChainPara, DWORD chainFlags)
 | 
|---|
| 1338 | {
 | 
|---|
| 1339 |     DWORD cContext;
 | 
|---|
| 1340 | 
 | 
|---|
| 1341 |     if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT)
 | 
|---|
| 1342 |         cContext = 1;
 | 
|---|
| 1343 |     else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) ||
 | 
|---|
| 1344 |      (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT))
 | 
|---|
| 1345 |     {
 | 
|---|
| 1346 |         DWORD i;
 | 
|---|
| 1347 | 
 | 
|---|
| 1348 |         for (i = 0, cContext = 0; i < chain->cChain; i++)
 | 
|---|
| 1349 |         {
 | 
|---|
| 1350 |             if (i < chain->cChain - 1 ||
 | 
|---|
| 1351 |              chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN)
 | 
|---|
| 1352 |                 cContext += chain->rgpChain[i]->cElement;
 | 
|---|
| 1353 |             else
 | 
|---|
| 1354 |                 cContext += chain->rgpChain[i]->cElement - 1;
 | 
|---|
| 1355 |         }
 | 
|---|
| 1356 |     }
 | 
|---|
| 1357 |     else
 | 
|---|
| 1358 |         cContext = 0;
 | 
|---|
| 1359 |     if (cContext)
 | 
|---|
| 1360 |     {
 | 
|---|
| 1361 |         PCCERT_CONTEXT *contexts =
 | 
|---|
| 1362 |          CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT *));
 | 
|---|
| 1363 | 
 | 
|---|
| 1364 |         if (contexts)
 | 
|---|
| 1365 |         {
 | 
|---|
| 1366 |             DWORD i, j, iContext, revocationFlags;
 | 
|---|
| 1367 |             CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 };
 | 
|---|
| 1368 |             CERT_REVOCATION_STATUS revocationStatus =
 | 
|---|
| 1369 |              { sizeof(revocationStatus), 0 };
 | 
|---|
| 1370 |             BOOL ret;
 | 
|---|
| 1371 | 
 | 
|---|
| 1372 |             for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain;
 | 
|---|
| 1373 |              i++)
 | 
|---|
| 1374 |             {
 | 
|---|
| 1375 |                 for (j = 0; iContext < cContext &&
 | 
|---|
| 1376 |                  j < chain->rgpChain[i]->cElement; j++)
 | 
|---|
| 1377 |                     contexts[iContext++] =
 | 
|---|
| 1378 |                      chain->rgpChain[i]->rgpElement[j]->pCertContext;
 | 
|---|
| 1379 |             }
 | 
|---|
| 1380 |             revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG;
 | 
|---|
| 1381 |             if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY)
 | 
|---|
| 1382 |                 revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION;
 | 
|---|
| 1383 |             if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT)
 | 
|---|
| 1384 |                 revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG;
 | 
|---|
| 1385 |             revocationPara.pftTimeToUse = pTime;
 | 
|---|
| 1386 |             if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA))
 | 
|---|
| 1387 |             {
 | 
|---|
| 1388 |                 revocationPara.dwUrlRetrievalTimeout =
 | 
|---|
| 1389 |                  pChainPara->dwUrlRetrievalTimeout;
 | 
|---|
| 1390 |                 revocationPara.fCheckFreshnessTime =
 | 
|---|
| 1391 |                  pChainPara->fCheckRevocationFreshnessTime;
 | 
|---|
| 1392 |                 revocationPara.dwFreshnessTime =
 | 
|---|
| 1393 |                  pChainPara->dwRevocationFreshnessTime;
 | 
|---|
| 1394 |             }
 | 
|---|
| 1395 |             ret = CertVerifyRevocation(X509_ASN_ENCODING,
 | 
|---|
| 1396 |              CERT_CONTEXT_REVOCATION_TYPE, cContext, (void **)contexts,
 | 
|---|
| 1397 |              revocationFlags, &revocationPara, &revocationStatus);
 | 
|---|
| 1398 |             if (!ret)
 | 
|---|
| 1399 |             {
 | 
|---|
| 1400 |                 PCERT_CHAIN_ELEMENT element =
 | 
|---|
| 1401 |                  CRYPT_FindIthElementInChain(chain, revocationStatus.dwIndex);
 | 
|---|
| 1402 |                 DWORD error;
 | 
|---|
| 1403 | 
 | 
|---|
| 1404 |                 switch (revocationStatus.dwError)
 | 
|---|
| 1405 |                 {
 | 
|---|
| 1406 |                 case CRYPT_E_NO_REVOCATION_CHECK:
 | 
|---|
| 1407 |                 case CRYPT_E_NO_REVOCATION_DLL:
 | 
|---|
| 1408 |                 case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
 | 
|---|
| 1409 |                     error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
 | 
|---|
| 1410 |                     break;
 | 
|---|
| 1411 |                 case CRYPT_E_REVOCATION_OFFLINE:
 | 
|---|
| 1412 |                     error = CERT_TRUST_IS_OFFLINE_REVOCATION;
 | 
|---|
| 1413 |                     break;
 | 
|---|
| 1414 |                 case CRYPT_E_REVOKED:
 | 
|---|
| 1415 |                     error = CERT_TRUST_IS_REVOKED;
 | 
|---|
| 1416 |                     break;
 | 
|---|
| 1417 |                 default:
 | 
|---|
| 1418 |                     WARN("unmapped error %08x\n", revocationStatus.dwError);
 | 
|---|
| 1419 |                     error = 0;
 | 
|---|
| 1420 |                 }
 | 
|---|
| 1421 |                 if (element)
 | 
|---|
| 1422 |                 {
 | 
|---|
| 1423 |                     /* FIXME: set element's pRevocationInfo member */
 | 
|---|
| 1424 |                     element->TrustStatus.dwErrorStatus |= error;
 | 
|---|
| 1425 |                 }
 | 
|---|
| 1426 |                 chain->TrustStatus.dwErrorStatus |= error;
 | 
|---|
| 1427 |             }
 | 
|---|
| 1428 |             CryptMemFree(contexts);
 | 
|---|
| 1429 |         }
 | 
|---|
| 1430 |     }
 | 
|---|
| 1431 | }
 | 
|---|
| 1432 | 
 | 
|---|
| 1433 | BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
 | 
|---|
| 1434 |  PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
 | 
|---|
| 1435 |  PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
 | 
|---|
| 1436 |  PCCERT_CHAIN_CONTEXT* ppChainContext)
 | 
|---|
| 1437 | {
 | 
|---|
| 1438 |     BOOL ret;
 | 
|---|
| 1439 |     PCertificateChain chain = NULL;
 | 
|---|
| 1440 | 
 | 
|---|
| 1441 |     TRACE("(%p, %p, %p, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext,
 | 
|---|
| 1442 |      pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, ppChainContext);
 | 
|---|
| 1443 | 
 | 
|---|
| 1444 |     if (ppChainContext)
 | 
|---|
| 1445 |         *ppChainContext = NULL;
 | 
|---|
| 1446 |     if (!pChainPara)
 | 
|---|
| 1447 |     {
 | 
|---|
| 1448 |         SetLastError(E_INVALIDARG);
 | 
|---|
| 1449 |         return FALSE;
 | 
|---|
| 1450 |     }
 | 
|---|
| 1451 |     if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)
 | 
|---|
| 1452 |     {
 | 
|---|
| 1453 |         SetLastError(ERROR_INVALID_DATA);
 | 
|---|
| 1454 |         return FALSE;
 | 
|---|
| 1455 |     }
 | 
|---|
| 1456 |     if (pChainPara->cbSize != sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) &&
 | 
|---|
| 1457 |      pChainPara->cbSize != sizeof(CERT_CHAIN_PARA))
 | 
|---|
| 1458 |     {
 | 
|---|
| 1459 |         SetLastError(E_INVALIDARG);
 | 
|---|
| 1460 |         return FALSE;
 | 
|---|
| 1461 |     }
 | 
|---|
| 1462 |     if (!hChainEngine)
 | 
|---|
| 1463 |         hChainEngine = CRYPT_GetDefaultChainEngine();
 | 
|---|
| 1464 |     /* FIXME: what about HCCE_LOCAL_MACHINE? */
 | 
|---|
| 1465 |     ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime,
 | 
|---|
| 1466 |      hAdditionalStore, &chain);
 | 
|---|
| 1467 |     if (ret)
 | 
|---|
| 1468 |     {
 | 
|---|
| 1469 |         PCertificateChain alternate = NULL;
 | 
|---|
| 1470 |         PCERT_CHAIN_CONTEXT pChain;
 | 
|---|
| 1471 | 
 | 
|---|
| 1472 |         do {
 | 
|---|
| 1473 |             alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine,
 | 
|---|
| 1474 |              pTime, hAdditionalStore, chain);
 | 
|---|
| 1475 | 
 | 
|---|
| 1476 |             /* Alternate contexts are added as "lower quality" contexts of
 | 
|---|
| 1477 |              * chain, to avoid loops in alternate chain creation.
 | 
|---|
| 1478 |              * The highest-quality chain is chosen at the end.
 | 
|---|
| 1479 |              */
 | 
|---|
| 1480 |             if (alternate)
 | 
|---|
| 1481 |                 ret = CRYPT_AddAlternateChainToChain(chain, alternate);
 | 
|---|
| 1482 |         } while (ret && alternate);
 | 
|---|
| 1483 |         chain = CRYPT_ChooseHighestQualityChain(chain);
 | 
|---|
| 1484 |         if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
 | 
|---|
| 1485 |             CRYPT_FreeLowerQualityChains(chain);
 | 
|---|
| 1486 |         pChain = (PCERT_CHAIN_CONTEXT)chain;
 | 
|---|
| 1487 |         CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags);
 | 
|---|
| 1488 |         if (ppChainContext)
 | 
|---|
| 1489 |             *ppChainContext = pChain;
 | 
|---|
| 1490 |         else
 | 
|---|
| 1491 |             CertFreeCertificateChain(pChain);
 | 
|---|
| 1492 |     }
 | 
|---|
| 1493 |     TRACE("returning %d\n", ret);
 | 
|---|
| 1494 |     return ret;
 | 
|---|
| 1495 | }
 | 
|---|
| 1496 | 
 | 
|---|
| 1497 | PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain(
 | 
|---|
| 1498 |  PCCERT_CHAIN_CONTEXT pChainContext)
 | 
|---|
| 1499 | {
 | 
|---|
| 1500 |     PCertificateChain chain = (PCertificateChain)pChainContext;
 | 
|---|
| 1501 | 
 | 
|---|
| 1502 |     TRACE("(%p)\n", pChainContext);
 | 
|---|
| 1503 | 
 | 
|---|
| 1504 |     if (chain)
 | 
|---|
| 1505 |         InterlockedIncrement(&chain->ref);
 | 
|---|
| 1506 |     return pChainContext;
 | 
|---|
| 1507 | }
 | 
|---|
| 1508 | 
 | 
|---|
| 1509 | VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext)
 | 
|---|
| 1510 | {
 | 
|---|
| 1511 |     PCertificateChain chain = (PCertificateChain)pChainContext;
 | 
|---|
| 1512 | 
 | 
|---|
| 1513 |     TRACE("(%p)\n", pChainContext);
 | 
|---|
| 1514 | 
 | 
|---|
| 1515 |     if (chain)
 | 
|---|
| 1516 |     {
 | 
|---|
| 1517 |         if (InterlockedDecrement(&chain->ref) == 0)
 | 
|---|
| 1518 |             CRYPT_FreeChainContext(chain);
 | 
|---|
| 1519 |     }
 | 
|---|
| 1520 | }
 | 
|---|
| 1521 | 
 | 
|---|
| 1522 | static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error,
 | 
|---|
| 1523 |  LONG *iChain, LONG *iElement)
 | 
|---|
| 1524 | {
 | 
|---|
| 1525 |     DWORD i, j;
 | 
|---|
| 1526 | 
 | 
|---|
| 1527 |     for (i = 0; i < chain->cChain; i++)
 | 
|---|
| 1528 |         for (j = 0; j < chain->rgpChain[i]->cElement; j++)
 | 
|---|
| 1529 |             if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus &
 | 
|---|
| 1530 |              error)
 | 
|---|
| 1531 |             {
 | 
|---|
| 1532 |                 *iChain = i;
 | 
|---|
| 1533 |                 *iElement = j;
 | 
|---|
| 1534 |                 return;
 | 
|---|
| 1535 |             }
 | 
|---|
| 1536 | }
 | 
|---|
| 1537 | 
 | 
|---|
| 1538 | static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID,
 | 
|---|
| 1539 |  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
 | 
|---|
| 1540 |  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
 | 
|---|
| 1541 | {
 | 
|---|
| 1542 |     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
 | 
|---|
| 1543 |     if (pChainContext->TrustStatus.dwErrorStatus &
 | 
|---|
| 1544 |      CERT_TRUST_IS_NOT_SIGNATURE_VALID)
 | 
|---|
| 1545 |     {
 | 
|---|
| 1546 |         pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
 | 
|---|
| 1547 |         find_element_with_error(pChainContext,
 | 
|---|
| 1548 |          CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
 | 
|---|
| 1549 |          &pPolicyStatus->lElementIndex);
 | 
|---|
| 1550 |     }
 | 
|---|
| 1551 |     else if (pChainContext->TrustStatus.dwErrorStatus &
 | 
|---|
| 1552 |      CERT_TRUST_IS_UNTRUSTED_ROOT)
 | 
|---|
| 1553 |     {
 | 
|---|
| 1554 |         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
 | 
|---|
| 1555 |         find_element_with_error(pChainContext,
 | 
|---|
| 1556 |          CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
 | 
|---|
| 1557 |          &pPolicyStatus->lElementIndex);
 | 
|---|
| 1558 |     }
 | 
|---|
| 1559 |     else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
 | 
|---|
| 1560 |     {
 | 
|---|
| 1561 |         pPolicyStatus->dwError = CERT_E_CHAINING;
 | 
|---|
| 1562 |         find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC,
 | 
|---|
| 1563 |          &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex);
 | 
|---|
| 1564 |         /* For a cyclic chain, which element is a cycle isn't meaningful */
 | 
|---|
| 1565 |         pPolicyStatus->lElementIndex = -1;
 | 
|---|
| 1566 |     }
 | 
|---|
| 1567 |     else
 | 
|---|
| 1568 |         pPolicyStatus->dwError = NO_ERROR;
 | 
|---|
| 1569 |     return TRUE;
 | 
|---|
| 1570 | }
 | 
|---|
| 1571 | 
 | 
|---|
| 1572 | static BYTE msTestPubKey1[] = {
 | 
|---|
| 1573 | 0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9,
 | 
|---|
| 1574 | 0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7,
 | 
|---|
| 1575 | 0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f,
 | 
|---|
| 1576 | 0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10,
 | 
|---|
| 1577 | 0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
 | 
|---|
| 1578 | static BYTE msTestPubKey2[] = {
 | 
|---|
| 1579 | 0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5,
 | 
|---|
| 1580 | 0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8,
 | 
|---|
| 1581 | 0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6,
 | 
|---|
| 1582 | 0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18,
 | 
|---|
| 1583 | 0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 };
 | 
|---|
| 1584 | 
 | 
|---|
| 1585 | static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID,
 | 
|---|
| 1586 |  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
 | 
|---|
| 1587 |  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
 | 
|---|
| 1588 | {
 | 
|---|
| 1589 |     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
 | 
|---|
| 1590 |      pPolicyStatus);
 | 
|---|
| 1591 | 
 | 
|---|
| 1592 |     if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT)
 | 
|---|
| 1593 |     {
 | 
|---|
| 1594 |         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
 | 
|---|
| 1595 |         BOOL isMSTestRoot = FALSE;
 | 
|---|
| 1596 |         PCCERT_CONTEXT failingCert =
 | 
|---|
| 1597 |          pChainContext->rgpChain[pPolicyStatus->lChainIndex]->
 | 
|---|
| 1598 |          rgpElement[pPolicyStatus->lElementIndex]->pCertContext;
 | 
|---|
| 1599 |         DWORD i;
 | 
|---|
| 1600 |         CRYPT_DATA_BLOB keyBlobs[] = {
 | 
|---|
| 1601 |          { sizeof(msTestPubKey1), msTestPubKey1 },
 | 
|---|
| 1602 |          { sizeof(msTestPubKey2), msTestPubKey2 },
 | 
|---|
| 1603 |         };
 | 
|---|
| 1604 | 
 | 
|---|
| 1605 |         /* Check whether the root is an MS test root */
 | 
|---|
| 1606 |         for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
 | 
|---|
| 1607 |          i++)
 | 
|---|
| 1608 |         {
 | 
|---|
| 1609 |             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
 | 
|---|
| 1610 |             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
 | 
|---|
| 1611 |             if (CertComparePublicKeyInfo(
 | 
|---|
| 1612 |              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
 | 
|---|
| 1613 |              &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
 | 
|---|
| 1614 |                 isMSTestRoot = TRUE;
 | 
|---|
| 1615 |         }
 | 
|---|
| 1616 |         if (isMSTestRoot)
 | 
|---|
| 1617 |             pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT;
 | 
|---|
| 1618 |     }
 | 
|---|
| 1619 |     return ret;
 | 
|---|
| 1620 | }
 | 
|---|
| 1621 | 
 | 
|---|
| 1622 | static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID,
 | 
|---|
| 1623 |  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
 | 
|---|
| 1624 |  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
 | 
|---|
| 1625 | {
 | 
|---|
| 1626 |     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
 | 
|---|
| 1627 |     if (pChainContext->TrustStatus.dwErrorStatus &
 | 
|---|
| 1628 |      CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
 | 
|---|
| 1629 |     {
 | 
|---|
| 1630 |         pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS;
 | 
|---|
| 1631 |         find_element_with_error(pChainContext,
 | 
|---|
| 1632 |          CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex,
 | 
|---|
| 1633 |          &pPolicyStatus->lElementIndex);
 | 
|---|
| 1634 |     }
 | 
|---|
| 1635 |     else
 | 
|---|
| 1636 |         pPolicyStatus->dwError = NO_ERROR;
 | 
|---|
| 1637 |     return TRUE;
 | 
|---|
| 1638 | }
 | 
|---|
| 1639 | 
 | 
|---|
| 1640 | static BYTE msPubKey1[] = {
 | 
|---|
| 1641 | 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
 | 
|---|
| 1642 | 0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
 | 
|---|
| 1643 | 0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29,
 | 
|---|
| 1644 | 0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16,
 | 
|---|
| 1645 | 0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60,
 | 
|---|
| 1646 | 0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5,
 | 
|---|
| 1647 | 0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d,
 | 
|---|
| 1648 | 0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61,
 | 
|---|
| 1649 | 0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e,
 | 
|---|
| 1650 | 0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94,
 | 
|---|
| 1651 | 0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb,
 | 
|---|
| 1652 | 0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a,
 | 
|---|
| 1653 | 0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d,
 | 
|---|
| 1654 | 0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb,
 | 
|---|
| 1655 | 0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08,
 | 
|---|
| 1656 | 0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43,
 | 
|---|
| 1657 | 0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf,
 | 
|---|
| 1658 | 0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 };
 | 
|---|
| 1659 | static BYTE msPubKey2[] = {
 | 
|---|
| 1660 | 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6,
 | 
|---|
| 1661 | 0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25,
 | 
|---|
| 1662 | 0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2,
 | 
|---|
| 1663 | 0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54,
 | 
|---|
| 1664 | 0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62,
 | 
|---|
| 1665 | 0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a,
 | 
|---|
| 1666 | 0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7,
 | 
|---|
| 1667 | 0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84,
 | 
|---|
| 1668 | 0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9,
 | 
|---|
| 1669 | 0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91,
 | 
|---|
| 1670 | 0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52,
 | 
|---|
| 1671 | 0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80,
 | 
|---|
| 1672 | 0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18,
 | 
|---|
| 1673 | 0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07,
 | 
|---|
| 1674 | 0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef,
 | 
|---|
| 1675 | 0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0,
 | 
|---|
| 1676 | 0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30,
 | 
|---|
| 1677 | 0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 };
 | 
|---|
| 1678 | static BYTE msPubKey3[] = {
 | 
|---|
| 1679 | 0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4,
 | 
|---|
| 1680 | 0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7,
 | 
|---|
| 1681 | 0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94,
 | 
|---|
| 1682 | 0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04,
 | 
|---|
| 1683 | 0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d,
 | 
|---|
| 1684 | 0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09,
 | 
|---|
| 1685 | 0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae,
 | 
|---|
| 1686 | 0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7,
 | 
|---|
| 1687 | 0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f,
 | 
|---|
| 1688 | 0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94,
 | 
|---|
| 1689 | 0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d,
 | 
|---|
| 1690 | 0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05,
 | 
|---|
| 1691 | 0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e,
 | 
|---|
| 1692 | 0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d,
 | 
|---|
| 1693 | 0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b,
 | 
|---|
| 1694 | 0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67,
 | 
|---|
| 1695 | 0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08,
 | 
|---|
| 1696 | 0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5,
 | 
|---|
| 1697 | 0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64,
 | 
|---|
| 1698 | 0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38,
 | 
|---|
| 1699 | 0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0,
 | 
|---|
| 1700 | 0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9,
 | 
|---|
| 1701 | 0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28,
 | 
|---|
| 1702 | 0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc,
 | 
|---|
| 1703 | 0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45,
 | 
|---|
| 1704 | 0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde,
 | 
|---|
| 1705 | 0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04,
 | 
|---|
| 1706 | 0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89,
 | 
|---|
| 1707 | 0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11,
 | 
|---|
| 1708 | 0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32,
 | 
|---|
| 1709 | 0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40,
 | 
|---|
| 1710 | 0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41,
 | 
|---|
| 1711 | 0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1,
 | 
|---|
| 1712 | 0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5,
 | 
|---|
| 1713 | 0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00,
 | 
|---|
| 1714 | 0x01 };
 | 
|---|
| 1715 | 
 | 
|---|
| 1716 | static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
 | 
|---|
| 1717 |  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
 | 
|---|
| 1718 |  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
 | 
|---|
| 1719 | {
 | 
|---|
| 1720 |     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
 | 
|---|
| 1721 |      pPolicyStatus);
 | 
|---|
| 1722 | 
 | 
|---|
| 1723 |     if (ret && !pPolicyStatus->dwError)
 | 
|---|
| 1724 |     {
 | 
|---|
| 1725 |         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
 | 
|---|
| 1726 |         BOOL isMSRoot = FALSE;
 | 
|---|
| 1727 |         DWORD i;
 | 
|---|
| 1728 |         CRYPT_DATA_BLOB keyBlobs[] = {
 | 
|---|
| 1729 |          { sizeof(msPubKey1), msPubKey1 },
 | 
|---|
| 1730 |          { sizeof(msPubKey2), msPubKey2 },
 | 
|---|
| 1731 |          { sizeof(msPubKey3), msPubKey3 },
 | 
|---|
| 1732 |         };
 | 
|---|
| 1733 |         PCERT_SIMPLE_CHAIN rootChain =
 | 
|---|
| 1734 |          pChainContext->rgpChain[pChainContext->cChain -1 ];
 | 
|---|
| 1735 |         PCCERT_CONTEXT root =
 | 
|---|
| 1736 |          rootChain->rgpElement[rootChain->cElement - 1]->pCertContext;
 | 
|---|
| 1737 | 
 | 
|---|
| 1738 |         for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
 | 
|---|
| 1739 |          i++)
 | 
|---|
| 1740 |         {
 | 
|---|
| 1741 |             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
 | 
|---|
| 1742 |             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
 | 
|---|
| 1743 |             if (CertComparePublicKeyInfo(
 | 
|---|
| 1744 |              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
 | 
|---|
| 1745 |              &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
 | 
|---|
| 1746 |                 isMSRoot = TRUE;
 | 
|---|
| 1747 |         }
 | 
|---|
| 1748 |         if (isMSRoot)
 | 
|---|
| 1749 |             pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0;
 | 
|---|
| 1750 |     }
 | 
|---|
| 1751 |     return ret;
 | 
|---|
| 1752 | }
 | 
|---|
| 1753 | 
 | 
|---|
| 1754 | typedef BOOL (*WINAPI CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID,
 | 
|---|
| 1755 |  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
 | 
|---|
| 1756 |  PCERT_CHAIN_POLICY_STATUS pPolicyStatus);
 | 
|---|
| 1757 | 
 | 
|---|
| 1758 | BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID,
 | 
|---|
| 1759 |  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
 | 
|---|
| 1760 |  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
 | 
|---|
| 1761 | {
 | 
|---|
| 1762 |     static HCRYPTOIDFUNCSET set = NULL;
 | 
|---|
| 1763 |     BOOL ret = FALSE;
 | 
|---|
| 1764 |     CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL;
 | 
|---|
| 1765 |     HCRYPTOIDFUNCADDR hFunc = NULL;
 | 
|---|
| 1766 | 
 | 
|---|
| 1767 |     TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext,
 | 
|---|
| 1768 |      pPolicyPara, pPolicyStatus);
 | 
|---|
| 1769 | 
 | 
|---|
| 1770 |     if (!HIWORD(szPolicyOID))
 | 
|---|
| 1771 |     {
 | 
|---|
| 1772 |         switch (LOWORD(szPolicyOID))
 | 
|---|
| 1773 |         {
 | 
|---|
| 1774 |         case LOWORD(CERT_CHAIN_POLICY_BASE):
 | 
|---|
| 1775 |             verifyPolicy = verify_base_policy;
 | 
|---|
| 1776 |             break;
 | 
|---|
| 1777 |         case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE):
 | 
|---|
| 1778 |             verifyPolicy = verify_authenticode_policy;
 | 
|---|
| 1779 |             break;
 | 
|---|
| 1780 |         case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS):
 | 
|---|
| 1781 |             verifyPolicy = verify_basic_constraints_policy;
 | 
|---|
| 1782 |             break;
 | 
|---|
| 1783 |         case LOWORD(CERT_CHAIN_POLICY_MICROSOFT_ROOT):
 | 
|---|
| 1784 |             verifyPolicy = verify_ms_root_policy;
 | 
|---|
| 1785 |             break;
 | 
|---|
| 1786 |         default:
 | 
|---|
| 1787 |             FIXME("unimplemented for %d\n", LOWORD(szPolicyOID));
 | 
|---|
| 1788 |         }
 | 
|---|
| 1789 |     }
 | 
|---|
| 1790 |     if (!verifyPolicy)
 | 
|---|
| 1791 |     {
 | 
|---|
| 1792 |         if (!set)
 | 
|---|
| 1793 |             set = CryptInitOIDFunctionSet(
 | 
|---|
| 1794 |              CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0);
 | 
|---|
| 1795 |         CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0,
 | 
|---|
| 1796 |          (void **)&verifyPolicy, &hFunc);
 | 
|---|
| 1797 |     }
 | 
|---|
| 1798 |     if (verifyPolicy)
 | 
|---|
| 1799 |         ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara,
 | 
|---|
| 1800 |          pPolicyStatus);
 | 
|---|
| 1801 |     if (hFunc)
 | 
|---|
| 1802 |         CryptFreeOIDFunctionAddress(hFunc, 0);
 | 
|---|
| 1803 |     return ret;
 | 
|---|
| 1804 | }
 | 
|---|