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 #define NONAMELESSUNION 21 #include "windef.h" 22 #include "winbase.h" 23 #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS 24 #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS 25 #include "wincrypt.h" 26 #include "wininet.h" 27 #include "wine/debug.h" 28 #include "wine/unicode.h" 29 #include "crypt32_private.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(crypt); 32 WINE_DECLARE_DEBUG_CHANNEL(chain); 33 34 #define DEFAULT_CYCLE_MODULUS 7 35 36 /* This represents a subset of a certificate chain engine: it doesn't include 37 * the "hOther" store described by MSDN, because I'm not sure how that's used. 38 * It also doesn't include the "hTrust" store, because I don't yet implement 39 * CTLs or complex certificate chains. 40 */ 41 typedef struct _CertificateChainEngine 42 { 43 LONG ref; 44 HCERTSTORE hRoot; 45 HCERTSTORE hWorld; 46 DWORD dwFlags; 47 DWORD dwUrlRetrievalTimeout; 48 DWORD MaximumCachedCertificates; 49 DWORD CycleDetectionModulus; 50 } CertificateChainEngine; 51 52 static inline void CRYPT_AddStoresToCollection(HCERTSTORE collection, 53 DWORD cStores, HCERTSTORE *stores) 54 { 55 DWORD i; 56 57 for (i = 0; i < cStores; i++) 58 CertAddStoreToCollection(collection, stores[i], 0, 0); 59 } 60 61 static inline void CRYPT_CloseStores(DWORD cStores, HCERTSTORE *stores) 62 { 63 DWORD i; 64 65 for (i = 0; i < cStores; i++) 66 CertCloseStore(stores[i], 0); 67 } 68 69 static const WCHAR rootW[] = { 'R','o','o','t',0 }; 70 71 /* Finds cert in store by comparing the cert's hashes. */ 72 static PCCERT_CONTEXT CRYPT_FindCertInStore(HCERTSTORE store, 73 PCCERT_CONTEXT cert) 74 { 75 PCCERT_CONTEXT matching = NULL; 76 BYTE hash[20]; 77 DWORD size = sizeof(hash); 78 79 if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash, &size)) 80 { 81 CRYPT_HASH_BLOB blob = { sizeof(hash), hash }; 82 83 matching = CertFindCertificateInStore(store, cert->dwCertEncodingType, 84 0, CERT_FIND_SHA1_HASH, &blob, NULL); 85 } 86 return matching; 87 } 88 89 static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store) 90 { 91 BOOL ret = TRUE; 92 93 if (store) 94 { 95 HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW); 96 PCCERT_CONTEXT cert = NULL, check; 97 98 do { 99 cert = CertEnumCertificatesInStore(store, cert); 100 if (cert) 101 { 102 if (!(check = CRYPT_FindCertInStore(rootStore, cert))) 103 ret = FALSE; 104 else 105 CertFreeCertificateContext(check); 106 } 107 } while (ret && cert); 108 if (cert) 109 CertFreeCertificateContext(cert); 110 CertCloseStore(rootStore, 0); 111 } 112 return ret; 113 } 114 115 HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root, DWORD system_store, const CERT_CHAIN_ENGINE_CONFIG *config) 116 { 117 CertificateChainEngine *engine; 118 HCERTSTORE worldStores[4]; 119 120 static const WCHAR caW[] = { 'C','A',0 }; 121 static const WCHAR myW[] = { 'M','y',0 }; 122 static const WCHAR trustW[] = { 'T','r','u','s','t',0 }; 123 124 if(!root) { 125 if(config->cbSize >= sizeof(CERT_CHAIN_ENGINE_CONFIG) && config->hExclusiveRoot) 126 root = CertDuplicateStore(config->hExclusiveRoot); 127 else if (config->hRestrictedRoot) 128 root = CertDuplicateStore(config->hRestrictedRoot); 129 else 130 root = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, rootW); 131 if(!root) 132 return NULL; 133 } 134 135 engine = CryptMemAlloc(sizeof(CertificateChainEngine)); 136 if(!engine) { 137 CertCloseStore(root, 0); 138 return NULL; 139 } 140 141 engine->ref = 1; 142 engine->hRoot = root; 143 engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); 144 worldStores[0] = CertDuplicateStore(engine->hRoot); 145 worldStores[1] = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, caW); 146 worldStores[2] = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, myW); 147 worldStores[3] = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, trustW); 148 149 CRYPT_AddStoresToCollection(engine->hWorld, sizeof(worldStores) / sizeof(worldStores[0]), worldStores); 150 CRYPT_AddStoresToCollection(engine->hWorld, config->cAdditionalStore, config->rghAdditionalStore); 151 CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]), worldStores); 152 153 engine->dwFlags = config->dwFlags; 154 engine->dwUrlRetrievalTimeout = config->dwUrlRetrievalTimeout; 155 engine->MaximumCachedCertificates = config->MaximumCachedCertificates; 156 if(config->CycleDetectionModulus) 157 engine->CycleDetectionModulus = config->CycleDetectionModulus; 158 else 159 engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS; 160 161 return engine; 162 } 163 164 static CertificateChainEngine *default_cu_engine, *default_lm_engine; 165 166 static CertificateChainEngine *get_chain_engine(HCERTCHAINENGINE handle, BOOL allow_default) 167 { 168 const CERT_CHAIN_ENGINE_CONFIG config = { sizeof(config) }; 169 170 if(handle == HCCE_CURRENT_USER) { 171 if(!allow_default) 172 return NULL; 173 174 if(!default_cu_engine) { 175 handle = CRYPT_CreateChainEngine(NULL, CERT_SYSTEM_STORE_CURRENT_USER, &config); 176 InterlockedCompareExchangePointer((void**)&default_cu_engine, handle, NULL); 177 if(default_cu_engine != handle) 178 CertFreeCertificateChainEngine(handle); 179 } 180 181 return default_cu_engine; 182 } 183 184 if(handle == HCCE_LOCAL_MACHINE) { 185 if(!allow_default) 186 return NULL; 187 188 if(!default_lm_engine) { 189 handle = CRYPT_CreateChainEngine(NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, &config); 190 InterlockedCompareExchangePointer((void**)&default_lm_engine, handle, NULL); 191 if(default_lm_engine != handle) 192 CertFreeCertificateChainEngine(handle); 193 } 194 195 return default_lm_engine; 196 } 197 198 return (CertificateChainEngine*)handle; 199 } 200 201 static void free_chain_engine(CertificateChainEngine *engine) 202 { 203 if(!engine || InterlockedDecrement(&engine->ref)) 204 return; 205 206 CertCloseStore(engine->hWorld, 0); 207 CertCloseStore(engine->hRoot, 0); 208 CryptMemFree(engine); 209 } 210 211 typedef struct _CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT 212 { 213 DWORD cbSize; 214 HCERTSTORE hRestrictedRoot; 215 HCERTSTORE hRestrictedTrust; 216 HCERTSTORE hRestrictedOther; 217 DWORD cAdditionalStore; 218 HCERTSTORE *rghAdditionalStore; 219 DWORD dwFlags; 220 DWORD dwUrlRetrievalTimeout; 221 DWORD MaximumCachedCertificates; 222 DWORD CycleDetectionModulus; 223 } CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT; 224 225 BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig, 226 HCERTCHAINENGINE *phChainEngine) 227 { 228 BOOL ret; 229 230 TRACE("(%p, %p)\n", pConfig, phChainEngine); 231 232 if (pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT) 233 && pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG)) 234 { 235 SetLastError(E_INVALIDARG); 236 return FALSE; 237 } 238 ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot); 239 if (!ret) 240 { 241 *phChainEngine = NULL; 242 return FALSE; 243 } 244 245 *phChainEngine = CRYPT_CreateChainEngine(NULL, CERT_SYSTEM_STORE_CURRENT_USER, pConfig); 246 return *phChainEngine != NULL; 247 } 248 249 void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine) 250 { 251 TRACE("(%p)\n", hChainEngine); 252 free_chain_engine(get_chain_engine(hChainEngine, FALSE)); 253 } 254 255 void default_chain_engine_free(void) 256 { 257 free_chain_engine(default_cu_engine); 258 free_chain_engine(default_lm_engine); 259 } 260 261 typedef struct _CertificateChain 262 { 263 CERT_CHAIN_CONTEXT context; 264 HCERTSTORE world; 265 LONG ref; 266 } CertificateChain; 267 268 BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert, DWORD *type) 269 { 270 PCERT_EXTENSION ext; 271 DWORD size; 272 BOOL ret; 273 274 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, 275 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 276 { 277 CERT_AUTHORITY_KEY_ID2_INFO *info; 278 279 ret = CryptDecodeObjectEx(cert->dwCertEncodingType, 280 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, 281 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 282 &info, &size); 283 if (ret) 284 { 285 if (info->AuthorityCertIssuer.cAltEntry && 286 info->AuthorityCertSerialNumber.cbData) 287 { 288 PCERT_ALT_NAME_ENTRY directoryName = NULL; 289 DWORD i; 290 291 for (i = 0; !directoryName && 292 i < info->AuthorityCertIssuer.cAltEntry; i++) 293 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice 294 == CERT_ALT_NAME_DIRECTORY_NAME) 295 directoryName = 296 &info->AuthorityCertIssuer.rgAltEntry[i]; 297 if (directoryName) 298 { 299 ret = CertCompareCertificateName(cert->dwCertEncodingType, 300 &directoryName->u.DirectoryName, &cert->pCertInfo->Issuer) 301 && CertCompareIntegerBlob(&info->AuthorityCertSerialNumber, 302 &cert->pCertInfo->SerialNumber); 303 if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER; 304 } 305 else 306 { 307 FIXME("no supported name type in authority key id2\n"); 308 ret = FALSE; 309 } 310 } 311 else if (info->KeyId.cbData) 312 { 313 ret = CertGetCertificateContextProperty(cert, 314 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); 315 if (ret && size == info->KeyId.cbData) 316 { 317 LPBYTE buf = CryptMemAlloc(size); 318 319 if (buf) 320 { 321 CertGetCertificateContextProperty(cert, 322 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); 323 ret = !memcmp(buf, info->KeyId.pbData, size); 324 CryptMemFree(buf); 325 if (type) *type = CERT_TRUST_HAS_KEY_MATCH_ISSUER; 326 } 327 else 328 ret = FALSE; 329 } 330 else 331 ret = FALSE; 332 } 333 LocalFree(info); 334 } 335 } 336 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, 337 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) 338 { 339 CERT_AUTHORITY_KEY_ID_INFO *info; 340 341 ret = CryptDecodeObjectEx(cert->dwCertEncodingType, 342 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, 343 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 344 &info, &size); 345 if (ret) 346 { 347 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) 348 { 349 ret = CertCompareCertificateName(cert->dwCertEncodingType, 350 &info->CertIssuer, &cert->pCertInfo->Issuer) && 351 CertCompareIntegerBlob(&info->CertSerialNumber, 352 &cert->pCertInfo->SerialNumber); 353 if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER; 354 } 355 else if (info->KeyId.cbData) 356 { 357 ret = CertGetCertificateContextProperty(cert, 358 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); 359 if (ret && size == info->KeyId.cbData) 360 { 361 LPBYTE buf = CryptMemAlloc(size); 362 363 if (buf) 364 { 365 CertGetCertificateContextProperty(cert, 366 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); 367 ret = !memcmp(buf, info->KeyId.pbData, size); 368 CryptMemFree(buf); 369 if (type) *type = CERT_TRUST_HAS_KEY_MATCH_ISSUER; 370 } 371 else 372 ret = FALSE; 373 } 374 else 375 ret = FALSE; 376 } 377 else 378 ret = FALSE; 379 LocalFree(info); 380 } 381 } 382 else 383 { 384 ret = CertCompareCertificateName(cert->dwCertEncodingType, 385 &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer); 386 if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER; 387 } 388 return ret; 389 } 390 391 static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element) 392 { 393 CertFreeCertificateContext(element->pCertContext); 394 CryptMemFree(element); 395 } 396 397 static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain) 398 { 399 DWORD i, j, cyclicCertIndex = 0; 400 401 /* O(n^2) - I don't think there's a faster way */ 402 for (i = 0; !cyclicCertIndex && i < chain->cElement; i++) 403 for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++) 404 if (CertCompareCertificate(X509_ASN_ENCODING, 405 chain->rgpElement[i]->pCertContext->pCertInfo, 406 chain->rgpElement[j]->pCertContext->pCertInfo)) 407 cyclicCertIndex = j; 408 if (cyclicCertIndex) 409 { 410 chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus 411 |= CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_BASIC_CONSTRAINTS; 412 /* Release remaining certs */ 413 for (i = cyclicCertIndex + 1; i < chain->cElement; i++) 414 CRYPT_FreeChainElement(chain->rgpElement[i]); 415 /* Truncate chain */ 416 chain->cElement = cyclicCertIndex + 1; 417 } 418 } 419 420 /* Checks whether the chain is cyclic by examining the last element's status */ 421 static inline BOOL CRYPT_IsSimpleChainCyclic(const CERT_SIMPLE_CHAIN *chain) 422 { 423 if (chain->cElement) 424 return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus 425 & CERT_TRUST_IS_CYCLIC; 426 else 427 return FALSE; 428 } 429 430 static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus, 431 const CERT_TRUST_STATUS *elementStatus) 432 { 433 /* Any error that applies to an element also applies to a chain.. */ 434 chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus; 435 /* but the bottom nibble of an element's info status doesn't apply to the 436 * chain. 437 */ 438 chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0); 439 } 440 441 static BOOL CRYPT_AddCertToSimpleChain(const CertificateChainEngine *engine, 442 PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus) 443 { 444 BOOL ret = FALSE; 445 PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT)); 446 447 if (element) 448 { 449 if (!chain->cElement) 450 chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT)); 451 else 452 chain->rgpElement = CryptMemRealloc(chain->rgpElement, 453 (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT)); 454 if (chain->rgpElement) 455 { 456 chain->rgpElement[chain->cElement++] = element; 457 memset(element, 0, sizeof(CERT_CHAIN_ELEMENT)); 458 element->cbSize = sizeof(CERT_CHAIN_ELEMENT); 459 element->pCertContext = CertDuplicateCertificateContext(cert); 460 if (chain->cElement > 1) 461 chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus 462 = subjectInfoStatus; 463 /* FIXME: initialize the rest of element */ 464 if (!(chain->cElement % engine->CycleDetectionModulus)) 465 { 466 CRYPT_CheckSimpleChainForCycles(chain); 467 /* Reinitialize the element pointer in case the chain is 468 * cyclic, in which case the chain is truncated. 469 */ 470 element = chain->rgpElement[chain->cElement - 1]; 471 } 472 CRYPT_CombineTrustStatus(&chain->TrustStatus, 473 &element->TrustStatus); 474 ret = TRUE; 475 } 476 else 477 CryptMemFree(element); 478 } 479 return ret; 480 } 481 482 static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain) 483 { 484 DWORD i; 485 486 for (i = 0; i < chain->cElement; i++) 487 CRYPT_FreeChainElement(chain->rgpElement[i]); 488 CryptMemFree(chain->rgpElement); 489 CryptMemFree(chain); 490 } 491 492 static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot, 493 PCERT_CHAIN_ELEMENT rootElement) 494 { 495 PCCERT_CONTEXT trustedRoot = CRYPT_FindCertInStore(hRoot, 496 rootElement->pCertContext); 497 498 if (!trustedRoot) 499 rootElement->TrustStatus.dwErrorStatus |= 500 CERT_TRUST_IS_UNTRUSTED_ROOT; 501 else 502 CertFreeCertificateContext(trustedRoot); 503 } 504 505 static void CRYPT_CheckRootCert(HCERTSTORE hRoot, 506 PCERT_CHAIN_ELEMENT rootElement) 507 { 508 PCCERT_CONTEXT root = rootElement->pCertContext; 509 510 if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType, 511 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root, 512 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL)) 513 { 514 TRACE_(chain)("Last certificate's signature is invalid\n"); 515 rootElement->TrustStatus.dwErrorStatus |= 516 CERT_TRUST_IS_NOT_SIGNATURE_VALID; 517 } 518 CRYPT_CheckTrustedStatus(hRoot, rootElement); 519 } 520 521 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS 522 * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a 523 * CERT_BASIC_CONSTRAINTS2_INFO. If it neither extension is present, sets 524 * constraints->fCA to defaultIfNotSpecified. 525 * Returns FALSE if the extension is present but couldn't be decoded. 526 */ 527 static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert, 528 CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified) 529 { 530 BOOL ret = TRUE; 531 PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS, 532 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); 533 534 constraints->fPathLenConstraint = FALSE; 535 if (ext) 536 { 537 CERT_BASIC_CONSTRAINTS_INFO *info; 538 DWORD size = 0; 539 540 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS, 541 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, 542 NULL, &info, &size); 543 if (ret) 544 { 545 if (info->SubjectType.cbData == 1) 546 constraints->fCA = 547 info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG; 548 LocalFree(info); 549 } 550 } 551 else 552 { 553 ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2, 554 cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); 555 if (ext) 556 { 557 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO); 558 559 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, 560 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData, 561 0, NULL, constraints, &size); 562 } 563 else 564 constraints->fCA = defaultIfNotSpecified; 565 } 566 return ret; 567 } 568 569 /* Checks element's basic constraints to see if it can act as a CA, with 570 * remainingCAs CAs left in this chain. In general, a cert must include the 571 * basic constraints extension, with the CA flag asserted, in order to be 572 * allowed to be a CA. A V1 or V2 cert, which has no extensions, is also 573 * allowed to be a CA if it's installed locally (in the engine's world store.) 574 * This matches the expected usage in RFC 5280, section 4.2.1.9: a conforming 575 * CA MUST include the basic constraints extension in all certificates that are 576 * used to validate digital signatures on certificates. It also matches 577 * section 6.1.4(k): "If a certificate is a v1 or v2 certificate, then the 578 * application MUST either verify that the certificate is a CA certificate 579 * through out-of-band means or reject the certificate." Rejecting the 580 * certificate prohibits a large number of commonly used certificates, so 581 * accepting locally installed ones is a compromise. 582 * Root certificates are also allowed to be CAs even without a basic 583 * constraints extension. This is implied by RFC 5280, section 6.1: the 584 * root of a certificate chain's only requirement is that it was used to issue 585 * the next certificate in the chain. 586 * Updates chainConstraints with the element's constraints, if: 587 * 1. chainConstraints doesn't have a path length constraint, or 588 * 2. element's path length constraint is smaller than chainConstraints's 589 * Sets *pathLengthConstraintViolated to TRUE if a path length violation 590 * occurs. 591 * Returns TRUE if the element can be a CA, and the length of the remaining 592 * chain is valid. 593 */ 594 static BOOL CRYPT_CheckBasicConstraintsForCA(CertificateChainEngine *engine, 595 PCCERT_CONTEXT cert, CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, 596 DWORD remainingCAs, BOOL isRoot, BOOL *pathLengthConstraintViolated) 597 { 598 BOOL validBasicConstraints, implicitCA = FALSE; 599 CERT_BASIC_CONSTRAINTS2_INFO constraints; 600 601 if (isRoot) 602 implicitCA = TRUE; 603 else if (cert->pCertInfo->dwVersion == CERT_V1 || 604 cert->pCertInfo->dwVersion == CERT_V2) 605 { 606 BYTE hash[20]; 607 DWORD size = sizeof(hash); 608 609 if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, 610 hash, &size)) 611 { 612 CRYPT_HASH_BLOB blob = { sizeof(hash), hash }; 613 PCCERT_CONTEXT localCert = CertFindCertificateInStore( 614 engine->hWorld, cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, 615 &blob, NULL); 616 617 if (localCert) 618 { 619 CertFreeCertificateContext(localCert); 620 implicitCA = TRUE; 621 } 622 } 623 } 624 if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert, 625 &constraints, implicitCA))) 626 { 627 chainConstraints->fCA = constraints.fCA; 628 if (!constraints.fCA) 629 { 630 TRACE_(chain)("chain element %d can't be a CA\n", remainingCAs + 1); 631 validBasicConstraints = FALSE; 632 } 633 else if (constraints.fPathLenConstraint) 634 { 635 /* If the element has path length constraints, they apply to the 636 * entire remaining chain. 637 */ 638 if (!chainConstraints->fPathLenConstraint || 639 constraints.dwPathLenConstraint < 640 chainConstraints->dwPathLenConstraint) 641 { 642 TRACE_(chain)("setting path length constraint to %d\n", 643 chainConstraints->dwPathLenConstraint); 644 chainConstraints->fPathLenConstraint = TRUE; 645 chainConstraints->dwPathLenConstraint = 646 constraints.dwPathLenConstraint; 647 } 648 } 649 } 650 if (chainConstraints->fPathLenConstraint && 651 remainingCAs > chainConstraints->dwPathLenConstraint) 652 { 653 TRACE_(chain)("remaining CAs %d exceed max path length %d\n", 654 remainingCAs, chainConstraints->dwPathLenConstraint); 655 validBasicConstraints = FALSE; 656 *pathLengthConstraintViolated = TRUE; 657 } 658 return validBasicConstraints; 659 } 660 661 static BOOL domain_name_matches(LPCWSTR constraint, LPCWSTR name) 662 { 663 BOOL match; 664 665 /* RFC 5280, section 4.2.1.10: 666 * "For URIs, the constraint applies to the host part of the name... 667 * When the constraint begins with a period, it MAY be expanded with one 668 * or more labels. That is, the constraint ".example.com" is satisfied by 669 * both host.example.com and my.host.example.com. However, the constraint 670 * ".example.com" is not satisfied by "example.com". When the constraint 671 * does not begin with a period, it specifies a host." 672 * and for email addresses, 673 * "To indicate all Internet mail addresses on a particular host, the 674 * constraint is specified as the host name. For example, the constraint 675 * "example.com" is satisfied by any mail address at the host 676 * "example.com". To specify any address within a domain, the constraint 677 * is specified with a leading period (as with URIs)." 678 */ 679 if (constraint[0] == '.') 680 { 681 /* Must be strictly greater than, a name can't begin with '.' */ 682 if (lstrlenW(name) > lstrlenW(constraint)) 683 match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), 684 constraint); 685 else 686 { 687 /* name is too short, no match */ 688 match = FALSE; 689 } 690 } 691 else 692 match = !lstrcmpiW(name, constraint); 693 return match; 694 } 695 696 static BOOL url_matches(LPCWSTR constraint, LPCWSTR name, 697 DWORD *trustErrorStatus) 698 { 699 BOOL match = FALSE; 700 701 TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name)); 702 703 if (!constraint) 704 *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; 705 else if (!name) 706 ; /* no match */ 707 else 708 { 709 LPCWSTR colon, authority_end, at, hostname = NULL; 710 /* The maximum length for a hostname is 254 in the DNS, see RFC 1034 */ 711 WCHAR hostname_buf[255]; 712 713 /* RFC 5280: only the hostname portion of the URL is compared. From 714 * section 4.2.1.10: 715 * "For URIs, the constraint applies to the host part of the name. 716 * The constraint MUST be specified as a fully qualified domain name 717 * and MAY specify a host or a domain." 718 * The format for URIs is in RFC 2396. 719 * 720 * First, remove any scheme that's present. */ 721 colon = strchrW(name, ':'); 722 if (colon && *(colon + 1) == '/' && *(colon + 2) == '/') 723 name = colon + 3; 724 /* Next, find the end of the authority component. (The authority is 725 * generally just the hostname, but it may contain a username or a port. 726 * Those are removed next.) 727 */ 728 authority_end = strchrW(name, '/'); 729 if (!authority_end) 730 authority_end = strchrW(name, '?'); 731 if (!authority_end) 732 authority_end = name + strlenW(name); 733 /* Remove any port number from the authority. The userinfo portion 734 * of an authority may contain a colon, so stop if a userinfo portion 735 * is found (indicated by '@'). 736 */ 737 for (colon = authority_end; colon >= name && *colon != ':' && 738 *colon != '@'; colon--) 739 ; 740 if (*colon == ':') 741 authority_end = colon; 742 /* Remove any username from the authority */ 743 if ((at = strchrW(name, '@'))) 744 name = at; 745 /* Ignore any path or query portion of the URL. */ 746 if (*authority_end) 747 { 748 if (authority_end - name < sizeof(hostname_buf) / 749 sizeof(hostname_buf[0])) 750 { 751 memcpy(hostname_buf, name, 752 (authority_end - name) * sizeof(WCHAR)); 753 hostname_buf[authority_end - name] = 0; 754 hostname = hostname_buf; 755 } 756 /* else: Hostname is too long, not a match */ 757 } 758 else 759 hostname = name; 760 if (hostname) 761 match = domain_name_matches(constraint, hostname); 762 } 763 return match; 764 } 765 766 static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name, 767 DWORD *trustErrorStatus) 768 { 769 BOOL match = FALSE; 770 LPCWSTR at; 771 772 TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name)); 773 774 if (!constraint) 775 *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; 776 else if (!name) 777 ; /* no match */ 778 else if (strchrW(constraint, '@')) 779 match = !lstrcmpiW(constraint, name); 780 else 781 { 782 if ((at = strchrW(name, '@'))) 783 match = domain_name_matches(constraint, at + 1); 784 else 785 match = !lstrcmpiW(constraint, name); 786 } 787 return match; 788 } 789 790 static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name, 791 DWORD *trustErrorStatus) 792 { 793 BOOL match = FALSE; 794 795 TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name)); 796 797 if (!constraint) 798 *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; 799 else if (!name) 800 ; /* no match */ 801 /* RFC 5280, section 4.2.1.10: 802 * "DNS name restrictions are expressed as host.example.com. Any DNS name 803 * that can be constructed by simply adding zero or more labels to the 804 * left-hand side of the name satisfies the name constraint. For example, 805 * www.host.example.com would satisfy the constraint but host1.example.com 806 * would not." 807 */ 808 else if (lstrlenW(name) == lstrlenW(constraint)) 809 match = !lstrcmpiW(name, constraint); 810 else if (lstrlenW(name) > lstrlenW(constraint)) 811 { 812 match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint), 813 constraint); 814 if (match) 815 { 816 BOOL dot = FALSE; 817 LPCWSTR ptr; 818 819 /* This only matches if name is a subdomain of constraint, i.e. 820 * there's a '.' between the beginning of the name and the 821 * matching portion of the name. 822 */ 823 for (ptr = name + lstrlenW(name) - lstrlenW(constraint); 824 !dot && ptr >= name; ptr--) 825 if (*ptr == '.') 826 dot = TRUE; 827 match = dot; 828 } 829 } 830 /* else: name is too short, no match */ 831 832 return match; 833 } 834 835 static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint, 836 const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus) 837 { 838 BOOL match = FALSE; 839 840 TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData, 841 name->cbData, name->pbData); 842 843 /* RFC5280, section 4.2.1.10, iPAddress syntax: either 8 or 32 bytes, for 844 * IPv4 or IPv6 addresses, respectively. 845 */ 846 if (constraint->cbData != sizeof(DWORD) * 2 && constraint->cbData != 32) 847 *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS; 848 else if (name->cbData == sizeof(DWORD) && 849 constraint->cbData == sizeof(DWORD) * 2) 850 { 851 DWORD subnet, mask, addr; 852 853 memcpy(&subnet, constraint->pbData, sizeof(subnet)); 854 memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask)); 855 memcpy(&addr, name->pbData, sizeof(addr)); 856 /* These are really in big-endian order, but for equality matching we 857 * don't need to swap to host order 858 */ 859 match = (subnet & mask) == (addr & mask); 860 } 861 else if (name->cbData == 16 && constraint->cbData == 32) 862 { 863 const BYTE *subnet, *mask, *addr; 864 DWORD i; 865 866 subnet = constraint->pbData; 867 mask = constraint->pbData + 16; 868 addr = name->pbData; 869 match = TRUE; 870 for (i = 0; match && i < 16; i++) 871 if ((subnet[i] & mask[i]) != (addr[i] & mask[i])) 872 match = FALSE; 873 } 874 /* else: name is wrong size, no match */ 875 876 return match; 877 } 878 879 static BOOL directory_name_matches(const CERT_NAME_BLOB *constraint, 880 const CERT_NAME_BLOB *name) 881 { 882 CERT_NAME_INFO *constraintName; 883 DWORD size; 884 BOOL match = FALSE; 885 886 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, constraint->pbData, 887 constraint->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &constraintName, &size)) 888 { 889 DWORD i; 890 891 match = TRUE; 892 for (i = 0; match && i < constraintName->cRDN; i++) 893 match = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 894 CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG, 895 (CERT_NAME_BLOB *)name, &constraintName->rgRDN[i]); 896 LocalFree(constraintName); 897 } 898 return match; 899 } 900 901 static BOOL alt_name_matches(const CERT_ALT_NAME_ENTRY *name, 902 const CERT_ALT_NAME_ENTRY *constraint, DWORD *trustErrorStatus, BOOL *present) 903 { 904 BOOL match = FALSE; 905 906 if (name->dwAltNameChoice == constraint->dwAltNameChoice) 907 { 908 if (present) 909 *present = TRUE; 910 switch (constraint->dwAltNameChoice) 911 { 912 case CERT_ALT_NAME_RFC822_NAME: 913 match = rfc822_name_matches(constraint->u.pwszURL, 914 name->u.pwszURL, trustErrorStatus); 915 break; 916 case CERT_ALT_NAME_DNS_NAME: 917 match = dns_name_matches(constraint->u.pwszURL, 918 name->u.pwszURL, trustErrorStatus); 919 break; 920 case CERT_ALT_NAME_URL: 921 match = url_matches(constraint->u.pwszURL, 922 name->u.pwszURL, trustErrorStatus); 923 break; 924 case CERT_ALT_NAME_IP_ADDRESS: 925 match = ip_address_matches(&constraint->u.IPAddress, 926 &name->u.IPAddress, trustErrorStatus); 927 break; 928 case CERT_ALT_NAME_DIRECTORY_NAME: 929 match = directory_name_matches(&constraint->u.DirectoryName, 930 &name->u.DirectoryName); 931 break; 932 default: 933 ERR("name choice %d unsupported in this context\n", 934 constraint->dwAltNameChoice); 935 *trustErrorStatus |= 936 CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT; 937 } 938 } 939 else if (present) 940 *present = FALSE; 941 return match; 942 } 943 944 static BOOL alt_name_matches_excluded_name(const CERT_ALT_NAME_ENTRY *name, 945 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) 946 { 947 DWORD i; 948 BOOL match = FALSE; 949 950 for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++) 951 match = alt_name_matches(name, 952 &nameConstraints->rgExcludedSubtree[i].Base, trustErrorStatus, NULL); 953 return match; 954 } 955 956 static BOOL alt_name_matches_permitted_name(const CERT_ALT_NAME_ENTRY *name, 957 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus, 958 BOOL *present) 959 { 960 DWORD i; 961 BOOL match = FALSE; 962 963 for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++) 964 match = alt_name_matches(name, 965 &nameConstraints->rgPermittedSubtree[i].Base, trustErrorStatus, 966 present); 967 return match; 968 } 969 970 static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert) 971 { 972 PCERT_EXTENSION ext; 973 974 ext = CertFindExtension(szOID_SUBJECT_ALT_NAME2, 975 cert->cExtension, cert->rgExtension); 976 if (!ext) 977 ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, 978 cert->cExtension, cert->rgExtension); 979 return ext; 980 } 981 982 static void compare_alt_name_with_constraints(const CERT_EXTENSION *altNameExt, 983 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) 984 { 985 CERT_ALT_NAME_INFO *subjectAltName; 986 DWORD size; 987 988 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, 989 altNameExt->Value.pbData, altNameExt->Value.cbData, 990 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 991 &subjectAltName, &size)) 992 { 993 DWORD i; 994 995 for (i = 0; i < subjectAltName->cAltEntry; i++) 996 { 997 BOOL nameFormPresent; 998 999 /* A name constraint only applies if the name form is present. 1000 * From RFC 5280, section 4.2.1.10: 1001 * "Restrictions apply only when the specified name form is 1002 * present. If no name of the type is in the certificate, 1003 * the certificate is acceptable." 1004 */ 1005 if (alt_name_matches_excluded_name( 1006 &subjectAltName->rgAltEntry[i], nameConstraints, 1007 trustErrorStatus)) 1008 { 1009 TRACE_(chain)("subject alternate name form %d excluded\n", 1010 subjectAltName->rgAltEntry[i].dwAltNameChoice); 1011 *trustErrorStatus |= 1012 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; 1013 } 1014 nameFormPresent = FALSE; 1015 if (!alt_name_matches_permitted_name( 1016 &subjectAltName->rgAltEntry[i], nameConstraints, 1017 trustErrorStatus, &nameFormPresent) && nameFormPresent) 1018 { 1019 TRACE_(chain)("subject alternate name form %d not permitted\n", 1020 subjectAltName->rgAltEntry[i].dwAltNameChoice); 1021 *trustErrorStatus |= 1022 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; 1023 } 1024 } 1025 LocalFree(subjectAltName); 1026 } 1027 else 1028 *trustErrorStatus |= 1029 CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS; 1030 } 1031 1032 static BOOL rfc822_attr_matches_excluded_name(const CERT_RDN_ATTR *attr, 1033 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) 1034 { 1035 DWORD i; 1036 BOOL match = FALSE; 1037 1038 for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++) 1039 { 1040 const CERT_ALT_NAME_ENTRY *constraint = 1041 &nameConstraints->rgExcludedSubtree[i].Base; 1042 1043 if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME) 1044 match = rfc822_name_matches(constraint->u.pwszRfc822Name, 1045 (LPCWSTR)attr->Value.pbData, trustErrorStatus); 1046 } 1047 return match; 1048 } 1049 1050 static BOOL rfc822_attr_matches_permitted_name(const CERT_RDN_ATTR *attr, 1051 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus, 1052 BOOL *present) 1053 { 1054 DWORD i; 1055 BOOL match = FALSE; 1056 1057 for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++) 1058 { 1059 const CERT_ALT_NAME_ENTRY *constraint = 1060 &nameConstraints->rgPermittedSubtree[i].Base; 1061 1062 if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME) 1063 { 1064 *present = TRUE; 1065 match = rfc822_name_matches(constraint->u.pwszRfc822Name, 1066 (LPCWSTR)attr->Value.pbData, trustErrorStatus); 1067 } 1068 } 1069 return match; 1070 } 1071 1072 static void compare_subject_with_email_constraints( 1073 const CERT_NAME_BLOB *subjectName, 1074 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) 1075 { 1076 CERT_NAME_INFO *name; 1077 DWORD size; 1078 1079 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME, 1080 subjectName->pbData, subjectName->cbData, 1081 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size)) 1082 { 1083 DWORD i, j; 1084 1085 for (i = 0; i < name->cRDN; i++) 1086 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++) 1087 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId, 1088 szOID_RSA_emailAddr)) 1089 { 1090 BOOL nameFormPresent; 1091 1092 /* A name constraint only applies if the name form is 1093 * present. From RFC 5280, section 4.2.1.10: 1094 * "Restrictions apply only when the specified name form is 1095 * present. If no name of the type is in the certificate, 1096 * the certificate is acceptable." 1097 */ 1098 if (rfc822_attr_matches_excluded_name( 1099 &name->rgRDN[i].rgRDNAttr[j], nameConstraints, 1100 trustErrorStatus)) 1101 { 1102 TRACE_(chain)( 1103 "email address in subject name is excluded\n"); 1104 *trustErrorStatus |= 1105 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; 1106 } 1107 nameFormPresent = FALSE; 1108 if (!rfc822_attr_matches_permitted_name( 1109 &name->rgRDN[i].rgRDNAttr[j], nameConstraints, 1110 trustErrorStatus, &nameFormPresent) && nameFormPresent) 1111 { 1112 TRACE_(chain)( 1113 "email address in subject name is not permitted\n"); 1114 *trustErrorStatus |= 1115 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; 1116 } 1117 } 1118 LocalFree(name); 1119 } 1120 else 1121 *trustErrorStatus |= 1122 CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS; 1123 } 1124 1125 static BOOL CRYPT_IsEmptyName(const CERT_NAME_BLOB *name) 1126 { 1127 BOOL empty; 1128 1129 if (!name->cbData) 1130 empty = TRUE; 1131 else if (name->cbData == 2 && name->pbData[1] == 0) 1132 { 1133 /* An empty sequence is also empty */ 1134 empty = TRUE; 1135 } 1136 else 1137 empty = FALSE; 1138 return empty; 1139 } 1140 1141 static void compare_subject_with_constraints(const CERT_NAME_BLOB *subjectName, 1142 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus) 1143 { 1144 BOOL hasEmailConstraint = FALSE; 1145 DWORD i; 1146 1147 /* In general, a subject distinguished name only matches a directory name 1148 * constraint. However, an exception exists for email addresses. 1149 * From RFC 5280, section 4.2.1.6: 1150 * "Legacy implementations exist where an electronic mail address is 1151 * embedded in the subject distinguished name as an emailAddress 1152 * attribute [RFC2985]." 1153 * If an email address constraint exists, check that constraint separately. 1154 */ 1155 for (i = 0; !hasEmailConstraint && i < nameConstraints->cExcludedSubtree; 1156 i++) 1157 if (nameConstraints->rgExcludedSubtree[i].Base.dwAltNameChoice == 1158 CERT_ALT_NAME_RFC822_NAME) 1159 hasEmailConstraint = TRUE; 1160 for (i = 0; !hasEmailConstraint && i < nameConstraints->cPermittedSubtree; 1161 i++) 1162 if (nameConstraints->rgPermittedSubtree[i].Base.dwAltNameChoice == 1163 CERT_ALT_NAME_RFC822_NAME) 1164 hasEmailConstraint = TRUE; 1165 if (hasEmailConstraint) 1166 compare_subject_with_email_constraints(subjectName, nameConstraints, 1167 trustErrorStatus); 1168 for (i = 0; i < nameConstraints->cExcludedSubtree; i++) 1169 { 1170 CERT_ALT_NAME_ENTRY *constraint = 1171 &nameConstraints->rgExcludedSubtree[i].Base; 1172 1173 if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME && 1174 directory_name_matches(&constraint->u.DirectoryName, subjectName)) 1175 { 1176 TRACE_(chain)("subject name is excluded\n"); 1177 *trustErrorStatus |= 1178 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT; 1179 } 1180 } 1181 /* RFC 5280, section 4.2.1.10: 1182 * "Restrictions apply only when the specified name form is present. 1183 * If no name of the type is in the certificate, the certificate is 1184 * acceptable." 1185 * An empty name can't have the name form present, so don't check it. 1186 */ 1187 if (nameConstraints->cPermittedSubtree && !CRYPT_IsEmptyName(subjectName)) 1188 { 1189 BOOL match = FALSE, hasDirectoryConstraint = FALSE; 1190 1191 for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++) 1192 { 1193 CERT_ALT_NAME_ENTRY *constraint = 1194 &nameConstraints->rgPermittedSubtree[i].Base; 1195 1196 if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME) 1197 { 1198 hasDirectoryConstraint = TRUE; 1199 match = directory_name_matches(&constraint->u.DirectoryName, 1200 subjectName); 1201 } 1202 } 1203 if (hasDirectoryConstraint && !match) 1204 { 1205 TRACE_(chain)("subject name is not permitted\n"); 1206 *trustErrorStatus |= CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT; 1207 } 1208 } 1209 } 1210 1211 static void CRYPT_CheckNameConstraints( 1212 const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert, 1213 DWORD *trustErrorStatus) 1214 { 1215 CERT_EXTENSION *ext = get_subject_alt_name_ext(cert); 1216 1217 if (ext) 1218 compare_alt_name_with_constraints(ext, nameConstraints, 1219 trustErrorStatus); 1220 /* Name constraints apply to the subject alternative name as well as the 1221 * subject name. From RFC 5280, section 4.2.1.10: 1222 * "Restrictions apply to the subject distinguished name and apply to 1223 * subject alternative names." 1224 */ 1225 compare_subject_with_constraints(&cert->Subject, nameConstraints, 1226 trustErrorStatus); 1227 } 1228 1229 /* Gets cert's name constraints, if any. Free with LocalFree. */ 1230 static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert) 1231 { 1232 CERT_NAME_CONSTRAINTS_INFO *info = NULL; 1233 1234 CERT_EXTENSION *ext; 1235 1236 if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension, 1237 cert->rgExtension))) 1238 { 1239 DWORD size; 1240 1241 CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS, 1242 ext->Value.pbData, ext->Value.cbData, 1243 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info, 1244 &size); 1245 } 1246 return info; 1247 } 1248 1249 static BOOL CRYPT_IsValidNameConstraint(const CERT_NAME_CONSTRAINTS_INFO *info) 1250 { 1251 DWORD i; 1252 BOOL ret = TRUE; 1253 1254 /* Make sure at least one permitted or excluded subtree is present. From 1255 * RFC 5280, section 4.2.1.10: 1256 * "Conforming CAs MUST NOT issue certificates where name constraints is an 1257 * empty sequence. That is, either the permittedSubtrees field or the 1258 * excludedSubtrees MUST be present." 1259 */ 1260 if (!info->cPermittedSubtree && !info->cExcludedSubtree) 1261 { 1262 WARN_(chain)("constraints contain no permitted nor excluded subtree\n"); 1263 ret = FALSE; 1264 } 1265 /* Check that none of the constraints specifies a minimum or a maximum. 1266 * See RFC 5280, section 4.2.1.10: 1267 * "Within this profile, the minimum and maximum fields are not used with 1268 * any name forms, thus, the minimum MUST be zero, and maximum MUST be 1269 * absent. However, if an application encounters a critical name 1270 * constraints extension that specifies other values for minimum or 1271 * maximum for a name form that appears in a subsequent certificate, the 1272 * application MUST either process these fields or reject the 1273 * certificate." 1274 * Since it gives no guidance as to how to process these fields, we 1275 * reject any name constraint that contains them. 1276 */ 1277 for (i = 0; ret && i < info->cPermittedSubtree; i++) 1278 if (info->rgPermittedSubtree[i].dwMinimum || 1279 info->rgPermittedSubtree[i].fMaximum) 1280 { 1281 TRACE_(chain)("found a minimum or maximum in permitted subtrees\n"); 1282 ret = FALSE; 1283 } 1284 for (i = 0; ret && i < info->cExcludedSubtree; i++) 1285 if (info->rgExcludedSubtree[i].dwMinimum || 1286 info->rgExcludedSubtree[i].fMaximum) 1287 { 1288 TRACE_(chain)("found a minimum or maximum in excluded subtrees\n"); 1289 ret = FALSE; 1290 } 1291 return ret; 1292 } 1293 1294 static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain) 1295 { 1296 int i, j; 1297 1298 /* Microsoft's implementation appears to violate RFC 3280: according to 1299 * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's 1300 * name constraint is violated in the end cert. According to RFC 3280, 1301 * the constraints should be checked against every subsequent certificate 1302 * in the chain, not just the end cert. 1303 * Microsoft's implementation also sets the name constraint errors on the 1304 * certs whose constraints were violated, not on the certs that violated 1305 * them. 1306 * In order to be error-compatible with Microsoft's implementation, while 1307 * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name 1308 * constraints. 1309 */ 1310 for (i = chain->cElement - 1; i > 0; i--) 1311 { 1312 CERT_NAME_CONSTRAINTS_INFO *nameConstraints; 1313 1314 if ((nameConstraints = CRYPT_GetNameConstraints( 1315 chain->rgpElement[i]->pCertContext->pCertInfo))) 1316 { 1317 if (!CRYPT_IsValidNameConstraint(nameConstraints)) 1318 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1319 CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT; 1320 else 1321 { 1322 for (j = i - 1; j >= 0; j--) 1323 { 1324 DWORD errorStatus = 0; 1325 1326 /* According to RFC 3280, self-signed certs don't have name 1327 * constraints checked unless they're the end cert. 1328 */ 1329 if (j == 0 || !CRYPT_IsCertificateSelfSigned( 1330 chain->rgpElement[j]->pCertContext, NULL)) 1331 { 1332 CRYPT_CheckNameConstraints(nameConstraints, 1333 chain->rgpElement[j]->pCertContext->pCertInfo, 1334 &errorStatus); 1335 if (errorStatus) 1336 { 1337 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1338 errorStatus; 1339 CRYPT_CombineTrustStatus(&chain->TrustStatus, 1340 &chain->rgpElement[i]->TrustStatus); 1341 } 1342 else 1343 chain->rgpElement[i]->TrustStatus.dwInfoStatus |= 1344 CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS; 1345 } 1346 } 1347 } 1348 LocalFree(nameConstraints); 1349 } 1350 } 1351 } 1352 1353 /* Gets cert's policies info, if any. Free with LocalFree. */ 1354 static CERT_POLICIES_INFO *CRYPT_GetPolicies(PCCERT_CONTEXT cert) 1355 { 1356 PCERT_EXTENSION ext; 1357 CERT_POLICIES_INFO *policies = NULL; 1358 1359 ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension, 1360 cert->pCertInfo->rgExtension); 1361 if (ext) 1362 { 1363 DWORD size; 1364 1365 CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES, 1366 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, 1367 &policies, &size); 1368 } 1369 return policies; 1370 } 1371 1372 static void CRYPT_CheckPolicies(const CERT_POLICIES_INFO *policies, CERT_INFO *cert, 1373 DWORD *errorStatus) 1374 { 1375 DWORD i; 1376 1377 for (i = 0; i < policies->cPolicyInfo; i++) 1378 { 1379 /* For now, the only accepted policy identifier is the anyPolicy 1380 * identifier. 1381 * FIXME: the policy identifiers should be compared against the 1382 * cert's certificate policies extension, subject to the policy 1383 * mappings extension, and the policy constraints extension. 1384 * See RFC 5280, sections 4.2.1.4, 4.2.1.5, and 4.2.1.11. 1385 */ 1386 if (strcmp(policies->rgPolicyInfo[i].pszPolicyIdentifier, 1387 szOID_ANY_CERT_POLICY)) 1388 { 1389 FIXME("unsupported policy %s\n", 1390 policies->rgPolicyInfo[i].pszPolicyIdentifier); 1391 *errorStatus |= CERT_TRUST_INVALID_POLICY_CONSTRAINTS; 1392 } 1393 } 1394 } 1395 1396 static void CRYPT_CheckChainPolicies(PCERT_SIMPLE_CHAIN chain) 1397 { 1398 int i, j; 1399 1400 for (i = chain->cElement - 1; i > 0; i--) 1401 { 1402 CERT_POLICIES_INFO *policies; 1403 1404 if ((policies = CRYPT_GetPolicies(chain->rgpElement[i]->pCertContext))) 1405 { 1406 for (j = i - 1; j >= 0; j--) 1407 { 1408 DWORD errorStatus = 0; 1409 1410 CRYPT_CheckPolicies(policies, 1411 chain->rgpElement[j]->pCertContext->pCertInfo, &errorStatus); 1412 if (errorStatus) 1413 { 1414 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1415 errorStatus; 1416 CRYPT_CombineTrustStatus(&chain->TrustStatus, 1417 &chain->rgpElement[i]->TrustStatus); 1418 } 1419 } 1420 LocalFree(policies); 1421 } 1422 } 1423 } 1424 1425 static LPWSTR name_value_to_str(const CERT_NAME_BLOB *name) 1426 { 1427 DWORD len = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name, 1428 CERT_SIMPLE_NAME_STR, NULL, 0); 1429 LPWSTR str = NULL; 1430 1431 if (len) 1432 { 1433 str = CryptMemAlloc(len * sizeof(WCHAR)); 1434 if (str) 1435 cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name, 1436 CERT_SIMPLE_NAME_STR, str, len); 1437 } 1438 return str; 1439 } 1440 1441 static void dump_alt_name_entry(const CERT_ALT_NAME_ENTRY *entry) 1442 { 1443 LPWSTR str; 1444 1445 switch (entry->dwAltNameChoice) 1446 { 1447 case CERT_ALT_NAME_OTHER_NAME: 1448 TRACE_(chain)("CERT_ALT_NAME_OTHER_NAME, oid = %s\n", 1449 debugstr_a(entry->u.pOtherName->pszObjId)); 1450 break; 1451 case CERT_ALT_NAME_RFC822_NAME: 1452 TRACE_(chain)("CERT_ALT_NAME_RFC822_NAME: %s\n", 1453 debugstr_w(entry->u.pwszRfc822Name)); 1454 break; 1455 case CERT_ALT_NAME_DNS_NAME: 1456 TRACE_(chain)("CERT_ALT_NAME_DNS_NAME: %s\n", 1457 debugstr_w(entry->u.pwszDNSName)); 1458 break; 1459 case CERT_ALT_NAME_DIRECTORY_NAME: 1460 str = name_value_to_str(&entry->u.DirectoryName); 1461 TRACE_(chain)("CERT_ALT_NAME_DIRECTORY_NAME: %s\n", debugstr_w(str)); 1462 CryptMemFree(str); 1463 break; 1464 case CERT_ALT_NAME_URL: 1465 TRACE_(chain)("CERT_ALT_NAME_URL: %s\n", debugstr_w(entry->u.pwszURL)); 1466 break; 1467 case CERT_ALT_NAME_IP_ADDRESS: 1468 TRACE_(chain)("CERT_ALT_NAME_IP_ADDRESS: %d bytes\n", 1469 entry->u.IPAddress.cbData); 1470 break; 1471 case CERT_ALT_NAME_REGISTERED_ID: 1472 TRACE_(chain)("CERT_ALT_NAME_REGISTERED_ID: %s\n", 1473 debugstr_a(entry->u.pszRegisteredID)); 1474 break; 1475 default: 1476 TRACE_(chain)("dwAltNameChoice = %d\n", entry->dwAltNameChoice); 1477 } 1478 } 1479 1480 static void dump_alt_name(LPCSTR type, const CERT_EXTENSION *ext) 1481 { 1482 CERT_ALT_NAME_INFO *name; 1483 DWORD size; 1484 1485 TRACE_(chain)("%s:\n", type); 1486 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, 1487 ext->Value.pbData, ext->Value.cbData, 1488 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size)) 1489 { 1490 DWORD i; 1491 1492 TRACE_(chain)("%d alt name entries:\n", name->cAltEntry); 1493 for (i = 0; i < name->cAltEntry; i++) 1494 dump_alt_name_entry(&name->rgAltEntry[i]); 1495 LocalFree(name); 1496 } 1497 } 1498 1499 static void dump_basic_constraints(const CERT_EXTENSION *ext) 1500 { 1501 CERT_BASIC_CONSTRAINTS_INFO *info; 1502 DWORD size = 0; 1503 1504 if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS, 1505 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, 1506 NULL, &info, &size)) 1507 { 1508 TRACE_(chain)("SubjectType: %02x\n", info->SubjectType.pbData[0]); 1509 TRACE_(chain)("%s path length constraint\n", 1510 info->fPathLenConstraint ? "has" : "doesn't have"); 1511 TRACE_(chain)("path length=%d\n", info->dwPathLenConstraint); 1512 LocalFree(info); 1513 } 1514 } 1515 1516 static void dump_basic_constraints2(const CERT_EXTENSION *ext) 1517 { 1518 CERT_BASIC_CONSTRAINTS2_INFO constraints; 1519 DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO); 1520 1521 if (CryptDecodeObjectEx(X509_ASN_ENCODING, 1522 szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData, 1523 0, NULL, &constraints, &size)) 1524 { 1525 TRACE_(chain)("basic constraints:\n"); 1526 TRACE_(chain)("can%s be a CA\n", constraints.fCA ? "" : "not"); 1527 TRACE_(chain)("%s path length constraint\n", 1528 constraints.fPathLenConstraint ? "has" : "doesn't have"); 1529 TRACE_(chain)("path length=%d\n", constraints.dwPathLenConstraint); 1530 } 1531 } 1532 1533 static void dump_key_usage(const CERT_EXTENSION *ext) 1534 { 1535 CRYPT_BIT_BLOB usage; 1536 DWORD size = sizeof(usage); 1537 1538 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData, 1539 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size)) 1540 { 1541 #define trace_usage_bit(bits, bit) \ 1542 if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit) 1543 if (usage.cbData) 1544 { 1545 trace_usage_bit(usage.pbData[0], CERT_DIGITAL_SIGNATURE_KEY_USAGE); 1546 trace_usage_bit(usage.pbData[0], CERT_NON_REPUDIATION_KEY_USAGE); 1547 trace_usage_bit(usage.pbData[0], CERT_KEY_ENCIPHERMENT_KEY_USAGE); 1548 trace_usage_bit(usage.pbData[0], CERT_DATA_ENCIPHERMENT_KEY_USAGE); 1549 trace_usage_bit(usage.pbData[0], CERT_KEY_AGREEMENT_KEY_USAGE); 1550 trace_usage_bit(usage.pbData[0], CERT_KEY_CERT_SIGN_KEY_USAGE); 1551 trace_usage_bit(usage.pbData[0], CERT_CRL_SIGN_KEY_USAGE); 1552 trace_usage_bit(usage.pbData[0], CERT_ENCIPHER_ONLY_KEY_USAGE); 1553 } 1554 #undef trace_usage_bit 1555 if (usage.cbData > 1 && usage.pbData[1] & CERT_DECIPHER_ONLY_KEY_USAGE) 1556 TRACE_(chain)("CERT_DECIPHER_ONLY_KEY_USAGE\n"); 1557 } 1558 } 1559 1560 static void dump_general_subtree(const CERT_GENERAL_SUBTREE *subtree) 1561 { 1562 dump_alt_name_entry(&subtree->Base); 1563 TRACE_(chain)("dwMinimum = %d, fMaximum = %d, dwMaximum = %d\n", 1564 subtree->dwMinimum, subtree->fMaximum, subtree->dwMaximum); 1565 } 1566 1567 static void dump_name_constraints(const CERT_EXTENSION *ext) 1568 { 1569 CERT_NAME_CONSTRAINTS_INFO *nameConstraints; 1570 DWORD size; 1571 1572 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS, 1573 ext->Value.pbData, ext->Value.cbData, 1574 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &nameConstraints, 1575 &size)) 1576 { 1577 DWORD i; 1578 1579 TRACE_(chain)("%d permitted subtrees:\n", 1580 nameConstraints->cPermittedSubtree); 1581 for (i = 0; i < nameConstraints->cPermittedSubtree; i++) 1582 dump_general_subtree(&nameConstraints->rgPermittedSubtree[i]); 1583 TRACE_(chain)("%d excluded subtrees:\n", 1584 nameConstraints->cExcludedSubtree); 1585 for (i = 0; i < nameConstraints->cExcludedSubtree; i++) 1586 dump_general_subtree(&nameConstraints->rgExcludedSubtree[i]); 1587 LocalFree(nameConstraints); 1588 } 1589 } 1590 1591 static void dump_cert_policies(const CERT_EXTENSION *ext) 1592 { 1593 CERT_POLICIES_INFO *policies; 1594 DWORD size; 1595 1596 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES, 1597 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, 1598 &policies, &size)) 1599 { 1600 DWORD i, j; 1601 1602 TRACE_(chain)("%d policies:\n", policies->cPolicyInfo); 1603 for (i = 0; i < policies->cPolicyInfo; i++) 1604 { 1605 TRACE_(chain)("policy identifier: %s\n", 1606 debugstr_a(policies->rgPolicyInfo[i].pszPolicyIdentifier)); 1607 TRACE_(chain)("%d policy qualifiers:\n", 1608 policies->rgPolicyInfo[i].cPolicyQualifier); 1609 for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++) 1610 TRACE_(chain)("%s\n", debugstr_a( 1611 policies->rgPolicyInfo[i].rgPolicyQualifier[j]. 1612 pszPolicyQualifierId)); 1613 } 1614 LocalFree(policies); 1615 } 1616 } 1617 1618 static void dump_enhanced_key_usage(const CERT_EXTENSION *ext) 1619 { 1620 CERT_ENHKEY_USAGE *usage; 1621 DWORD size; 1622 1623 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, 1624 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, 1625 &usage, &size)) 1626 { 1627 DWORD i; 1628 1629 TRACE_(chain)("%d usages:\n", usage->cUsageIdentifier); 1630 for (i = 0; i < usage->cUsageIdentifier; i++) 1631 TRACE_(chain)("%s\n", usage->rgpszUsageIdentifier[i]); 1632 LocalFree(usage); 1633 } 1634 } 1635 1636 static void dump_netscape_cert_type(const CERT_EXTENSION *ext) 1637 { 1638 CRYPT_BIT_BLOB usage; 1639 DWORD size = sizeof(usage); 1640 1641 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData, 1642 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size)) 1643 { 1644 #define trace_cert_type_bit(bits, bit) \ 1645 if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit) 1646 if (usage.cbData) 1647 { 1648 trace_cert_type_bit(usage.pbData[0], 1649 NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE); 1650 trace_cert_type_bit(usage.pbData[0], 1651 NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE); 1652 trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CERT_TYPE); 1653 trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CERT_TYPE); 1654 trace_cert_type_bit(usage.pbData[0], NETSCAPE_SSL_CA_CERT_TYPE); 1655 trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CA_CERT_TYPE); 1656 trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CA_CERT_TYPE); 1657 } 1658 #undef trace_cert_type_bit 1659 } 1660 } 1661 1662 static void dump_extension(const CERT_EXTENSION *ext) 1663 { 1664 TRACE_(chain)("%s (%scritical)\n", debugstr_a(ext->pszObjId), 1665 ext->fCritical ? "" : "not "); 1666 if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME)) 1667 dump_alt_name("subject alt name", ext); 1668 else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME)) 1669 dump_alt_name("issuer alt name", ext); 1670 else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS)) 1671 dump_basic_constraints(ext); 1672 else if (!strcmp(ext->pszObjId, szOID_KEY_USAGE)) 1673 dump_key_usage(ext); 1674 else if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME2)) 1675 dump_alt_name("subject alt name 2", ext); 1676 else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME2)) 1677 dump_alt_name("issuer alt name 2", ext); 1678 else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS2)) 1679 dump_basic_constraints2(ext); 1680 else if (!strcmp(ext->pszObjId, szOID_NAME_CONSTRAINTS)) 1681 dump_name_constraints(ext); 1682 else if (!strcmp(ext->pszObjId, szOID_CERT_POLICIES)) 1683 dump_cert_policies(ext); 1684 else if (!strcmp(ext->pszObjId, szOID_ENHANCED_KEY_USAGE)) 1685 dump_enhanced_key_usage(ext); 1686 else if (!strcmp(ext->pszObjId, szOID_NETSCAPE_CERT_TYPE)) 1687 dump_netscape_cert_type(ext); 1688 } 1689 1690 static LPCSTR filetime_to_str(const FILETIME *time) 1691 { 1692 char date[80]; 1693 char dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */ 1694 SYSTEMTIME sysTime; 1695 1696 if (!time) return "(null)"; 1697 1698 GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt, 1699 sizeof(dateFmt) / sizeof(dateFmt[0])); 1700 FileTimeToSystemTime(time, &sysTime); 1701 GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date, 1702 sizeof(date) / sizeof(date[0])); 1703 return wine_dbg_sprintf("%s", date); 1704 } 1705 1706 static void dump_element(PCCERT_CONTEXT cert) 1707 { 1708 LPWSTR name = NULL; 1709 DWORD len, i; 1710 1711 TRACE_(chain)("%p: version %d\n", cert, cert->pCertInfo->dwVersion); 1712 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1713 CERT_NAME_ISSUER_FLAG, NULL, NULL, 0); 1714 name = CryptMemAlloc(len * sizeof(WCHAR)); 1715 if (name) 1716 { 1717 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 1718 CERT_NAME_ISSUER_FLAG, NULL, name, len); 1719 TRACE_(chain)("issued by %s\n", debugstr_w(name)); 1720 CryptMemFree(name); 1721 } 1722 len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, 1723 NULL, 0); 1724 name = CryptMemAlloc(len * sizeof(WCHAR)); 1725 if (name) 1726 { 1727 CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, 1728 name, len); 1729 TRACE_(chain)("issued to %s\n", debugstr_w(name)); 1730 CryptMemFree(name); 1731 } 1732 TRACE_(chain)("valid from %s to %s\n", 1733 filetime_to_str(&cert->pCertInfo->NotBefore), 1734 filetime_to_str(&cert->pCertInfo->NotAfter)); 1735 TRACE_(chain)("%d extensions\n", cert->pCertInfo->cExtension); 1736 for (i = 0; i < cert->pCertInfo->cExtension; i++) 1737 dump_extension(&cert->pCertInfo->rgExtension[i]); 1738 } 1739 1740 static BOOL CRYPT_KeyUsageValid(CertificateChainEngine *engine, 1741 PCCERT_CONTEXT cert, BOOL isRoot, BOOL isCA, DWORD index) 1742 { 1743 PCERT_EXTENSION ext; 1744 BOOL ret; 1745 BYTE usageBits = 0; 1746 1747 ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension, 1748 cert->pCertInfo->rgExtension); 1749 if (ext) 1750 { 1751 CRYPT_BIT_BLOB usage; 1752 DWORD size = sizeof(usage); 1753 1754 ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS, 1755 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, 1756 &usage, &size); 1757 if (!ret) 1758 return FALSE; 1759 else if (usage.cbData > 2) 1760 { 1761 /* The key usage extension only defines 9 bits => no more than 2 1762 * bytes are needed to encode all known usages. 1763 */ 1764 return FALSE; 1765 } 1766 else 1767 { 1768 /* The only bit relevant to chain validation is the keyCertSign 1769 * bit, which is always in the least significant byte of the 1770 * key usage bits. 1771 */ 1772 usageBits = usage.pbData[usage.cbData - 1]; 1773 } 1774 } 1775 if (isCA) 1776 { 1777 if (!ext) 1778 { 1779 /* MS appears to violate RFC 5280, section 4.2.1.3 (Key Usage) 1780 * here. Quoting the RFC: 1781 * "This [key usage] extension MUST appear in certificates that 1782 * contain public keys that are used to validate digital signatures 1783 * on other public key certificates or CRLs." 1784 * MS appears to accept certs that do not contain key usage 1785 * extensions as CA certs. V1 and V2 certificates did not have 1786 * extensions, and many root certificates are V1 certificates, so 1787 * perhaps this is prudent. On the other hand, MS also accepts V3 1788 * certs without key usage extensions. Because some CAs, e.g. 1789 * Certum, also do not include key usage extensions in their 1790 * intermediate certificates, we are forced to accept V3 1791 * certificates without key usage extensions as well. 1792 */ 1793 ret = TRUE; 1794 } 1795 else 1796 { 1797 if (!(usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE)) 1798 { 1799 WARN_(chain)("keyCertSign not asserted on a CA cert\n"); 1800 ret = FALSE; 1801 } 1802 else 1803 ret = TRUE; 1804 } 1805 } 1806 else 1807 { 1808 if (ext && (usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE)) 1809 { 1810 WARN_(chain)("keyCertSign asserted on a non-CA cert\n"); 1811 ret = FALSE; 1812 } 1813 else 1814 ret = TRUE; 1815 } 1816 return ret; 1817 } 1818 1819 static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert) 1820 { 1821 BOOL ret = TRUE; 1822 DWORD i; 1823 1824 for (i = 0; ret && i < cert->pCertInfo->cExtension; i++) 1825 { 1826 if (cert->pCertInfo->rgExtension[i].fCritical) 1827 { 1828 LPCSTR oid = cert->pCertInfo->rgExtension[i].pszObjId; 1829 1830 if (!strcmp(oid, szOID_BASIC_CONSTRAINTS)) 1831 ret = TRUE; 1832 else if (!strcmp(oid, szOID_BASIC_CONSTRAINTS2)) 1833 ret = TRUE; 1834 else if (!strcmp(oid, szOID_NAME_CONSTRAINTS)) 1835 ret = TRUE; 1836 else if (!strcmp(oid, szOID_KEY_USAGE)) 1837 ret = TRUE; 1838 else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME)) 1839 ret = TRUE; 1840 else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME2)) 1841 ret = TRUE; 1842 else if (!strcmp(oid, szOID_CERT_POLICIES)) 1843 ret = TRUE; 1844 else if (!strcmp(oid, szOID_ENHANCED_KEY_USAGE)) 1845 ret = TRUE; 1846 else 1847 { 1848 FIXME("unsupported critical extension %s\n", 1849 debugstr_a(oid)); 1850 ret = FALSE; 1851 } 1852 } 1853 } 1854 return ret; 1855 } 1856 1857 static BOOL CRYPT_IsCertVersionValid(PCCERT_CONTEXT cert) 1858 { 1859 BOOL ret = TRUE; 1860 1861 /* Checks whether the contents of the cert match the cert's version. */ 1862 switch (cert->pCertInfo->dwVersion) 1863 { 1864 case CERT_V1: 1865 /* A V1 cert may not contain unique identifiers. See RFC 5280, 1866 * section 4.1.2.8: 1867 * "These fields MUST only appear if the version is 2 or 3 (Section 1868 * 4.1.2.1). These fields MUST NOT appear if the version is 1." 1869 */ 1870 if (cert->pCertInfo->IssuerUniqueId.cbData || 1871 cert->pCertInfo->SubjectUniqueId.cbData) 1872 ret = FALSE; 1873 /* A V1 cert may not contain extensions. See RFC 5280, section 4.1.2.9: 1874 * "This field MUST only appear if the version is 3 (Section 4.1.2.1)." 1875 */ 1876 if (cert->pCertInfo->cExtension) 1877 ret = FALSE; 1878 break; 1879 case CERT_V2: 1880 /* A V2 cert may not contain extensions. See RFC 5280, section 4.1.2.9: 1881 * "This field MUST only appear if the version is 3 (Section 4.1.2.1)." 1882 */ 1883 if (cert->pCertInfo->cExtension) 1884 ret = FALSE; 1885 break; 1886 case CERT_V3: 1887 /* Do nothing, all fields are allowed for V3 certs */ 1888 break; 1889 default: 1890 WARN_(chain)("invalid cert version %d\n", cert->pCertInfo->dwVersion); 1891 ret = FALSE; 1892 } 1893 return ret; 1894 } 1895 1896 static void CRYPT_CheckSimpleChain(CertificateChainEngine *engine, 1897 PCERT_SIMPLE_CHAIN chain, LPFILETIME time) 1898 { 1899 PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1]; 1900 int i; 1901 BOOL pathLengthConstraintViolated = FALSE; 1902 CERT_BASIC_CONSTRAINTS2_INFO constraints = { FALSE, FALSE, 0 }; 1903 DWORD type; 1904 1905 TRACE_(chain)("checking chain with %d elements for time %s\n", 1906 chain->cElement, filetime_to_str(time)); 1907 for (i = chain->cElement - 1; i >= 0; i--) 1908 { 1909 BOOL isRoot; 1910 1911 if (TRACE_ON(chain)) 1912 dump_element(chain->rgpElement[i]->pCertContext); 1913 if (i == chain->cElement - 1) 1914 isRoot = CRYPT_IsCertificateSelfSigned( 1915 chain->rgpElement[i]->pCertContext, NULL); 1916 else 1917 isRoot = FALSE; 1918 if (!CRYPT_IsCertVersionValid(chain->rgpElement[i]->pCertContext)) 1919 { 1920 /* MS appears to accept certs whose versions don't match their 1921 * contents, so there isn't an appropriate error code. 1922 */ 1923 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1924 CERT_TRUST_INVALID_EXTENSION; 1925 } 1926 if (CertVerifyTimeValidity(time, 1927 chain->rgpElement[i]->pCertContext->pCertInfo) != 0) 1928 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1929 CERT_TRUST_IS_NOT_TIME_VALID; 1930 if (i != 0) 1931 { 1932 /* Check the signature of the cert this issued */ 1933 if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING, 1934 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, 1935 (void *)chain->rgpElement[i - 1]->pCertContext, 1936 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, 1937 (void *)chain->rgpElement[i]->pCertContext, 0, NULL)) 1938 chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |= 1939 CERT_TRUST_IS_NOT_SIGNATURE_VALID; 1940 /* Once a path length constraint has been violated, every remaining 1941 * CA cert's basic constraints is considered invalid. 1942 */ 1943 if (pathLengthConstraintViolated) 1944 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1945 CERT_TRUST_INVALID_BASIC_CONSTRAINTS; 1946 else if (!CRYPT_CheckBasicConstraintsForCA(engine, 1947 chain->rgpElement[i]->pCertContext, &constraints, i - 1, isRoot, 1948 &pathLengthConstraintViolated)) 1949 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1950 CERT_TRUST_INVALID_BASIC_CONSTRAINTS; 1951 else if (constraints.fPathLenConstraint && 1952 constraints.dwPathLenConstraint) 1953 { 1954 /* This one's valid - decrement max length */ 1955 constraints.dwPathLenConstraint--; 1956 } 1957 } 1958 else 1959 { 1960 /* Check whether end cert has a basic constraints extension */ 1961 if (!CRYPT_DecodeBasicConstraints( 1962 chain->rgpElement[i]->pCertContext, &constraints, FALSE)) 1963 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1964 CERT_TRUST_INVALID_BASIC_CONSTRAINTS; 1965 } 1966 if (!CRYPT_KeyUsageValid(engine, chain->rgpElement[i]->pCertContext, 1967 isRoot, constraints.fCA, i)) 1968 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1969 CERT_TRUST_IS_NOT_VALID_FOR_USAGE; 1970 if (CRYPT_IsSimpleChainCyclic(chain)) 1971 { 1972 /* If the chain is cyclic, then the path length constraints 1973 * are violated, because the chain is infinitely long. 1974 */ 1975 pathLengthConstraintViolated = TRUE; 1976 chain->TrustStatus.dwErrorStatus |= 1977 CERT_TRUST_IS_PARTIAL_CHAIN | 1978 CERT_TRUST_INVALID_BASIC_CONSTRAINTS; 1979 } 1980 /* Check whether every critical extension is supported */ 1981 if (!CRYPT_CriticalExtensionsSupported( 1982 chain->rgpElement[i]->pCertContext)) 1983 chain->rgpElement[i]->TrustStatus.dwErrorStatus |= 1984 CERT_TRUST_INVALID_EXTENSION | 1985 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT; 1986 CRYPT_CombineTrustStatus(&chain->TrustStatus, 1987 &chain->rgpElement[i]->TrustStatus); 1988 } 1989 CRYPT_CheckChainNameConstraints(chain); 1990 CRYPT_CheckChainPolicies(chain); 1991 if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext, &type)) 1992 { 1993 rootElement->TrustStatus.dwInfoStatus |= 1994 CERT_TRUST_IS_SELF_SIGNED | type; 1995 CRYPT_CheckRootCert(engine->hRoot, rootElement); 1996 } 1997 CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus); 1998 } 1999 2000 static PCCERT_CONTEXT CRYPT_FindIssuer(const CertificateChainEngine *engine, const CERT_CONTEXT *cert, 2001 HCERTSTORE store, DWORD type, void *para, DWORD flags, PCCERT_CONTEXT prev_issuer) 2002 { 2003 CRYPT_URL_ARRAY *urls; 2004 PCCERT_CONTEXT issuer; 2005 DWORD size; 2006 BOOL res; 2007 2008 issuer = CertFindCertificateInStore(store, cert->dwCertEncodingType, 0, type, para, prev_issuer); 2009 if(issuer) { 2010 TRACE("Found in store %p\n", issuer); 2011 return issuer; 2012 } 2013 2014 /* FIXME: For alternate issuers, we don't search world store nor try to retrieve issuer from URL. 2015 * This needs more tests. 2016 */ 2017 if(prev_issuer) 2018 return NULL; 2019 2020 if(engine->hWorld) { 2021 issuer = CertFindCertificateInStore(engine->hWorld, cert->dwCertEncodingType, 0, type, para, NULL); 2022 if(issuer) { 2023 TRACE("Found in world %p\n", issuer); 2024 return issuer; 2025 } 2026 } 2027 2028 res = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void*)cert, 0, NULL, &size, NULL, NULL, NULL); 2029 if(!res) 2030 return NULL; 2031 2032 urls = HeapAlloc(GetProcessHeap(), 0, size); 2033 if(!urls) 2034 return NULL; 2035 2036 res = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void*)cert, 0, urls, &size, NULL, NULL, NULL); 2037 if(res) 2038 { 2039 CERT_CONTEXT *new_cert; 2040 HCERTSTORE new_store; 2041 unsigned i; 2042 2043 for(i=0; i < urls->cUrl; i++) 2044 { 2045 TRACE("Trying URL %s\n", debugstr_w(urls->rgwszUrl[i])); 2046 2047 res = CryptRetrieveObjectByUrlW(urls->rgwszUrl[i], CONTEXT_OID_CERTIFICATE, 2048 (flags & CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL) ? CRYPT_CACHE_ONLY_RETRIEVAL : CRYPT_AIA_RETRIEVAL, 2049 0, (void**)&new_cert, NULL, NULL, NULL, NULL); 2050 if(!res) 2051 { 2052 TRACE("CryptRetrieveObjectByUrlW failed: %u\n", GetLastError()); 2053 continue; 2054 } 2055 2056 /* FIXME: Use new_cert->hCertStore once cert ref count bug is fixed. */ 2057 new_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); 2058 CertAddCertificateContextToStore(new_store, new_cert, CERT_STORE_ADD_NEW, NULL); 2059 issuer = CertFindCertificateInStore(new_store, cert->dwCertEncodingType, 0, type, para, NULL); 2060 CertFreeCertificateContext(new_cert); 2061 CertCloseStore(new_store, 0); 2062 if(issuer) 2063 { 2064 TRACE("Found downloaded issuer %p\n", issuer); 2065 break; 2066 } 2067 } 2068 } 2069 2070 HeapFree(GetProcessHeap(), 0, urls); 2071 return issuer; 2072 } 2073 2074 static PCCERT_CONTEXT CRYPT_GetIssuer(const CertificateChainEngine *engine, 2075 HCERTSTORE store, PCCERT_CONTEXT subject, PCCERT_CONTEXT prevIssuer, 2076 DWORD flags, DWORD *infoStatus) 2077 { 2078 PCCERT_CONTEXT issuer = NULL; 2079 PCERT_EXTENSION ext; 2080 DWORD size; 2081 2082 *infoStatus = 0; 2083 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER, 2084 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) 2085 { 2086 CERT_AUTHORITY_KEY_ID_INFO *info; 2087 BOOL ret; 2088 2089 ret = CryptDecodeObjectEx(subject->dwCertEncodingType, 2090 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData, 2091 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 2092 &info, &size); 2093 if (ret) 2094 { 2095 CERT_ID id; 2096 2097 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData) 2098 { 2099 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; 2100 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer, 2101 sizeof(CERT_NAME_BLOB)); 2102 memcpy(&id.u.IssuerSerialNumber.SerialNumber, 2103 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB)); 2104 2105 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer); 2106 if (issuer) 2107 { 2108 TRACE_(chain)("issuer found by issuer/serial number\n"); 2109 *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER; 2110 } 2111 } 2112 else if (info->KeyId.cbData) 2113 { 2114 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; 2115 2116 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); 2117 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer); 2118 if (issuer) 2119 { 2120 TRACE_(chain)("issuer found by key id\n"); 2121 *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER; 2122 } 2123 } 2124 LocalFree(info); 2125 } 2126 } 2127 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, 2128 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension))) 2129 { 2130 CERT_AUTHORITY_KEY_ID2_INFO *info; 2131 BOOL ret; 2132 2133 ret = CryptDecodeObjectEx(subject->dwCertEncodingType, 2134 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData, 2135 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 2136 &info, &size); 2137 if (ret) 2138 { 2139 CERT_ID id; 2140 2141 if (info->AuthorityCertIssuer.cAltEntry && 2142 info->AuthorityCertSerialNumber.cbData) 2143 { 2144 PCERT_ALT_NAME_ENTRY directoryName = NULL; 2145 DWORD i; 2146 2147 for (i = 0; !directoryName && 2148 i < info->AuthorityCertIssuer.cAltEntry; i++) 2149 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice 2150 == CERT_ALT_NAME_DIRECTORY_NAME) 2151 directoryName = 2152 &info->AuthorityCertIssuer.rgAltEntry[i]; 2153 if (directoryName) 2154 { 2155 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; 2156 memcpy(&id.u.IssuerSerialNumber.Issuer, 2157 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB)); 2158 memcpy(&id.u.IssuerSerialNumber.SerialNumber, 2159 &info->AuthorityCertSerialNumber, 2160 sizeof(CRYPT_INTEGER_BLOB)); 2161 2162 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer); 2163 if (issuer) 2164 { 2165 TRACE_(chain)("issuer found by directory name\n"); 2166 *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER; 2167 } 2168 } 2169 else 2170 FIXME("no supported name type in authority key id2\n"); 2171 } 2172 else if (info->KeyId.cbData) 2173 { 2174 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER; 2175 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB)); 2176 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer); 2177 if (issuer) 2178 { 2179 TRACE_(chain)("issuer found by key id\n"); 2180 *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER; 2181 } 2182 } 2183 LocalFree(info); 2184 } 2185 } 2186 else 2187 { 2188 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_SUBJECT_NAME, 2189 &subject->pCertInfo->Issuer, flags, prevIssuer); 2190 TRACE_(chain)("issuer found by name\n"); 2191 *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER; 2192 } 2193 return issuer; 2194 } 2195 2196 /* Builds a simple chain by finding an issuer for the last cert in the chain, 2197 * until reaching a self-signed cert, or until no issuer can be found. 2198 */ 2199 static BOOL CRYPT_BuildSimpleChain(const CertificateChainEngine *engine, 2200 HCERTSTORE world, DWORD flags, PCERT_SIMPLE_CHAIN chain) 2201 { 2202 BOOL ret = TRUE; 2203 PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext; 2204 2205 while (ret && !CRYPT_IsSimpleChainCyclic(chain) && 2206 !CRYPT_IsCertificateSelfSigned(cert, NULL)) 2207 { 2208 PCCERT_CONTEXT issuer = CRYPT_GetIssuer(engine, world, cert, NULL, flags, 2209 &chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus); 2210 2211 if (issuer) 2212 { 2213 ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, 2214 chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus); 2215 /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to 2216 * close the enumeration that found it 2217 */ 2218 CertFreeCertificateContext(issuer); 2219 cert = issuer; 2220 } 2221 else 2222 { 2223 TRACE_(chain)("Couldn't find issuer, halting chain creation\n"); 2224 chain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN; 2225 break; 2226 } 2227 } 2228 return ret; 2229 } 2230 2231 static LPCSTR debugstr_filetime(LPFILETIME pTime) 2232 { 2233 if (!pTime) 2234 return "(nil)"; 2235 return wine_dbg_sprintf("%p (%s)", pTime, filetime_to_str(pTime)); 2236 } 2237 2238 static BOOL CRYPT_GetSimpleChainForCert(CertificateChainEngine *engine, 2239 HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime, DWORD flags, 2240 PCERT_SIMPLE_CHAIN *ppChain) 2241 { 2242 BOOL ret = FALSE; 2243 PCERT_SIMPLE_CHAIN chain; 2244 2245 TRACE("(%p, %p, %p, %s)\n", engine, world, cert, debugstr_filetime(pTime)); 2246 2247 chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN)); 2248 if (chain) 2249 { 2250 memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN)); 2251 chain->cbSize = sizeof(CERT_SIMPLE_CHAIN); 2252 ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0); 2253 if (ret) 2254 { 2255 ret = CRYPT_BuildSimpleChain(engine, world, flags, chain); 2256 if (ret) 2257 CRYPT_CheckSimpleChain(engine, chain, pTime); 2258 } 2259 if (!ret) 2260 { 2261 CRYPT_FreeSimpleChain(chain); 2262 chain = NULL; 2263 } 2264 *ppChain = chain; 2265 } 2266 return ret; 2267 } 2268 2269 static BOOL CRYPT_BuildCandidateChainFromCert(CertificateChainEngine *engine, 2270 PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore, DWORD flags, 2271 CertificateChain **ppChain) 2272 { 2273 PCERT_SIMPLE_CHAIN simpleChain = NULL; 2274 HCERTSTORE world; 2275 BOOL ret; 2276 2277 world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 2278 CERT_STORE_CREATE_NEW_FLAG, NULL); 2279 CertAddStoreToCollection(world, engine->hWorld, 0, 0); 2280 if (hAdditionalStore) 2281 CertAddStoreToCollection(world, hAdditionalStore, 0, 0); 2282 /* FIXME: only simple chains are supported for now, as CTLs aren't 2283 * supported yet. 2284 */ 2285 if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime, flags, &simpleChain))) 2286 { 2287 CertificateChain *chain = CryptMemAlloc(sizeof(CertificateChain)); 2288 2289 if (chain) 2290 { 2291 chain->ref = 1; 2292 chain->world = world; 2293 chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT); 2294 chain->context.TrustStatus = simpleChain->TrustStatus; 2295 chain->context.cChain = 1; 2296 chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN)); 2297 chain->context.rgpChain[0] = simpleChain; 2298 chain->context.cLowerQualityChainContext = 0; 2299 chain->context.rgpLowerQualityChainContext = NULL; 2300 chain->context.fHasRevocationFreshnessTime = FALSE; 2301 chain->context.dwRevocationFreshnessTime = 0; 2302 } 2303 else 2304 { 2305 CRYPT_FreeSimpleChain(simpleChain); 2306 ret = FALSE; 2307 } 2308 *ppChain = chain; 2309 } 2310 return ret; 2311 } 2312 2313 /* Makes and returns a copy of chain, up to and including element iElement. */ 2314 static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement( 2315 const CERT_SIMPLE_CHAIN *chain, DWORD iElement) 2316 { 2317 PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN)); 2318 2319 if (copy) 2320 { 2321 memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN)); 2322 copy->cbSize = sizeof(CERT_SIMPLE_CHAIN); 2323 copy->rgpElement = 2324 CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT)); 2325 if (copy->rgpElement) 2326 { 2327 DWORD i; 2328 BOOL ret = TRUE; 2329 2330 memset(copy->rgpElement, 0, 2331 (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT)); 2332 for (i = 0; ret && i <= iElement; i++) 2333 { 2334 PCERT_CHAIN_ELEMENT element = 2335 CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT)); 2336 2337 if (element) 2338 { 2339 *element = *chain->rgpElement[i]; 2340 element->pCertContext = CertDuplicateCertificateContext( 2341 chain->rgpElement[i]->pCertContext); 2342 /* Reset the trust status of the copied element, it'll get 2343 * rechecked after the new chain is done. 2344 */ 2345 memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS)); 2346 copy->rgpElement[copy->cElement++] = element; 2347 } 2348 else 2349 ret = FALSE; 2350 } 2351 if (!ret) 2352 { 2353 for (i = 0; i <= iElement; i++) 2354 CryptMemFree(copy->rgpElement[i]); 2355 CryptMemFree(copy->rgpElement); 2356 CryptMemFree(copy); 2357 copy = NULL; 2358 } 2359 } 2360 else 2361 { 2362 CryptMemFree(copy); 2363 copy = NULL; 2364 } 2365 } 2366 return copy; 2367 } 2368 2369 static void CRYPT_FreeLowerQualityChains(CertificateChain *chain) 2370 { 2371 DWORD i; 2372 2373 for (i = 0; i < chain->context.cLowerQualityChainContext; i++) 2374 CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]); 2375 CryptMemFree(chain->context.rgpLowerQualityChainContext); 2376 chain->context.cLowerQualityChainContext = 0; 2377 chain->context.rgpLowerQualityChainContext = NULL; 2378 } 2379 2380 static void CRYPT_FreeChainContext(CertificateChain *chain) 2381 { 2382 DWORD i; 2383 2384 CRYPT_FreeLowerQualityChains(chain); 2385 for (i = 0; i < chain->context.cChain; i++) 2386 CRYPT_FreeSimpleChain(chain->context.rgpChain[i]); 2387 CryptMemFree(chain->context.rgpChain); 2388 CertCloseStore(chain->world, 0); 2389 CryptMemFree(chain); 2390 } 2391 2392 /* Makes and returns a copy of chain, up to and including element iElement of 2393 * simple chain iChain. 2394 */ 2395 static CertificateChain *CRYPT_CopyChainToElement(CertificateChain *chain, 2396 DWORD iChain, DWORD iElement) 2397 { 2398 CertificateChain *copy = CryptMemAlloc(sizeof(CertificateChain)); 2399 2400 if (copy) 2401 { 2402 copy->ref = 1; 2403 copy->world = CertDuplicateStore(chain->world); 2404 copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT); 2405 /* Leave the trust status of the copied chain unset, it'll get 2406 * rechecked after the new chain is done. 2407 */ 2408 memset(©->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS)); 2409 copy->context.cLowerQualityChainContext = 0; 2410 copy->context.rgpLowerQualityChainContext = NULL; 2411 copy->context.fHasRevocationFreshnessTime = FALSE; 2412 copy->context.dwRevocationFreshnessTime = 0; 2413 copy->context.rgpChain = CryptMemAlloc( 2414 (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN)); 2415 if (copy->context.rgpChain) 2416 { 2417 BOOL ret = TRUE; 2418 DWORD i; 2419 2420 memset(copy->context.rgpChain, 0, 2421 (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN)); 2422 if (iChain) 2423 { 2424 for (i = 0; ret && iChain && i < iChain - 1; i++) 2425 { 2426 copy->context.rgpChain[i] = 2427 CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i], 2428 chain->context.rgpChain[i]->cElement - 1); 2429 if (!copy->context.rgpChain[i]) 2430 ret = FALSE; 2431 } 2432 } 2433 else 2434 i = 0; 2435 if (ret) 2436 { 2437 copy->context.rgpChain[i] = 2438 CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i], 2439 iElement); 2440 if (!copy->context.rgpChain[i]) 2441 ret = FALSE; 2442 } 2443 if (!ret) 2444 { 2445 CRYPT_FreeChainContext(copy); 2446 copy = NULL; 2447 } 2448 else 2449 copy->context.cChain = iChain + 1; 2450 } 2451 else 2452 { 2453 CryptMemFree(copy); 2454 copy = NULL; 2455 } 2456 } 2457 return copy; 2458 } 2459 2460 static CertificateChain *CRYPT_BuildAlternateContextFromChain( 2461 CertificateChainEngine *engine, LPFILETIME pTime, HCERTSTORE hAdditionalStore, 2462 DWORD flags, CertificateChain *chain) 2463 { 2464 CertificateChain *alternate; 2465 2466 TRACE("(%p, %s, %p, %p)\n", engine, debugstr_filetime(pTime), 2467 hAdditionalStore, chain); 2468 2469 /* Always start with the last "lower quality" chain to ensure a consistent 2470 * order of alternate creation: 2471 */ 2472 if (chain->context.cLowerQualityChainContext) 2473 chain = (CertificateChain*)chain->context.rgpLowerQualityChainContext[ 2474 chain->context.cLowerQualityChainContext - 1]; 2475 /* A chain with only one element can't have any alternates */ 2476 if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1) 2477 alternate = NULL; 2478 else 2479 { 2480 DWORD i, j, infoStatus; 2481 PCCERT_CONTEXT alternateIssuer = NULL; 2482 2483 alternate = NULL; 2484 for (i = 0; !alternateIssuer && i < chain->context.cChain; i++) 2485 for (j = 0; !alternateIssuer && 2486 j < chain->context.rgpChain[i]->cElement - 1; j++) 2487 { 2488 PCCERT_CONTEXT subject = 2489 chain->context.rgpChain[i]->rgpElement[j]->pCertContext; 2490 PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext( 2491 chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext); 2492 2493 alternateIssuer = CRYPT_GetIssuer(engine, prevIssuer->hCertStore, 2494 subject, prevIssuer, flags, &infoStatus); 2495 } 2496 if (alternateIssuer) 2497 { 2498 i--; 2499 j--; 2500 alternate = CRYPT_CopyChainToElement(chain, i, j); 2501 if (alternate) 2502 { 2503 BOOL ret = CRYPT_AddCertToSimpleChain(engine, 2504 alternate->context.rgpChain[i], alternateIssuer, infoStatus); 2505 2506 /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it 2507 * to close the enumeration that found it 2508 */ 2509 CertFreeCertificateContext(alternateIssuer); 2510 if (ret) 2511 { 2512 ret = CRYPT_BuildSimpleChain(engine, alternate->world, 2513 flags, alternate->context.rgpChain[i]); 2514 if (ret) 2515 CRYPT_CheckSimpleChain(engine, 2516 alternate->context.rgpChain[i], pTime); 2517 CRYPT_CombineTrustStatus(&alternate->context.TrustStatus, 2518 &alternate->context.rgpChain[i]->TrustStatus); 2519 } 2520 if (!ret) 2521 { 2522 CRYPT_FreeChainContext(alternate); 2523 alternate = NULL; 2524 } 2525 } 2526 } 2527 } 2528 TRACE("%p\n", alternate); 2529 return alternate; 2530 } 2531 2532 #define CHAIN_QUALITY_SIGNATURE_VALID 0x16 2533 #define CHAIN_QUALITY_TIME_VALID 8 2534 #define CHAIN_QUALITY_COMPLETE_CHAIN 4 2535 #define CHAIN_QUALITY_BASIC_CONSTRAINTS 2 2536 #define CHAIN_QUALITY_TRUSTED_ROOT 1 2537 2538 #define CHAIN_QUALITY_HIGHEST \ 2539 CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \ 2540 CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_BASIC_CONSTRAINTS | \ 2541 CHAIN_QUALITY_TRUSTED_ROOT 2542 2543 #define IS_TRUST_ERROR_SET(TrustStatus, bits) \ 2544 (TrustStatus)->dwErrorStatus & (bits) 2545 2546 static DWORD CRYPT_ChainQuality(const CertificateChain *chain) 2547 { 2548 DWORD quality = CHAIN_QUALITY_HIGHEST; 2549 2550 if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, 2551 CERT_TRUST_IS_UNTRUSTED_ROOT)) 2552 quality &= ~CHAIN_QUALITY_TRUSTED_ROOT; 2553 if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, 2554 CERT_TRUST_INVALID_BASIC_CONSTRAINTS)) 2555 quality &= ~CHAIN_QUALITY_BASIC_CONSTRAINTS; 2556 if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, 2557 CERT_TRUST_IS_PARTIAL_CHAIN)) 2558 quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN; 2559 if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, 2560 CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED)) 2561 quality &= ~CHAIN_QUALITY_TIME_VALID; 2562 if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus, 2563 CERT_TRUST_IS_NOT_SIGNATURE_VALID)) 2564 quality &= ~CHAIN_QUALITY_SIGNATURE_VALID; 2565 return quality; 2566 } 2567 2568 /* Chooses the highest quality chain among chain and its "lower quality" 2569 * alternate chains. Returns the highest quality chain, with all other 2570 * chains as lower quality chains of it. 2571 */ 2572 static CertificateChain *CRYPT_ChooseHighestQualityChain( 2573 CertificateChain *chain) 2574 { 2575 DWORD i; 2576 2577 /* There are always only two chains being considered: chain, and an 2578 * alternate at chain->rgpLowerQualityChainContext[i]. If the alternate 2579 * has a higher quality than chain, the alternate gets assigned the lower 2580 * quality contexts, with chain taking the alternate's place among the 2581 * lower quality contexts. 2582 */ 2583 for (i = 0; i < chain->context.cLowerQualityChainContext; i++) 2584 { 2585 CertificateChain *alternate = 2586 (CertificateChain*)chain->context.rgpLowerQualityChainContext[i]; 2587 2588 if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain)) 2589 { 2590 alternate->context.cLowerQualityChainContext = 2591 chain->context.cLowerQualityChainContext; 2592 alternate->context.rgpLowerQualityChainContext = 2593 chain->context.rgpLowerQualityChainContext; 2594 alternate->context.rgpLowerQualityChainContext[i] = 2595 (PCCERT_CHAIN_CONTEXT)chain; 2596 chain->context.cLowerQualityChainContext = 0; 2597 chain->context.rgpLowerQualityChainContext = NULL; 2598 chain = alternate; 2599 } 2600 } 2601 return chain; 2602 } 2603 2604 static BOOL CRYPT_AddAlternateChainToChain(CertificateChain *chain, 2605 const CertificateChain *alternate) 2606 { 2607 BOOL ret; 2608 2609 if (chain->context.cLowerQualityChainContext) 2610 chain->context.rgpLowerQualityChainContext = 2611 CryptMemRealloc(chain->context.rgpLowerQualityChainContext, 2612 (chain->context.cLowerQualityChainContext + 1) * 2613 sizeof(PCCERT_CHAIN_CONTEXT)); 2614 else 2615 chain->context.rgpLowerQualityChainContext = 2616 CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT)); 2617 if (chain->context.rgpLowerQualityChainContext) 2618 { 2619 chain->context.rgpLowerQualityChainContext[ 2620 chain->context.cLowerQualityChainContext++] = 2621 (PCCERT_CHAIN_CONTEXT)alternate; 2622 ret = TRUE; 2623 } 2624 else 2625 ret = FALSE; 2626 return ret; 2627 } 2628 2629 static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain( 2630 const CERT_CHAIN_CONTEXT *chain, DWORD i) 2631 { 2632 DWORD j, iElement; 2633 PCERT_CHAIN_ELEMENT element = NULL; 2634 2635 for (j = 0, iElement = 0; !element && j < chain->cChain; j++) 2636 { 2637 if (iElement + chain->rgpChain[j]->cElement < i) 2638 iElement += chain->rgpChain[j]->cElement; 2639 else 2640 element = chain->rgpChain[j]->rgpElement[i - iElement]; 2641 } 2642 return element; 2643 } 2644 2645 typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS { 2646 DWORD cbSize; 2647 CERT_USAGE_MATCH RequestedUsage; 2648 } CERT_CHAIN_PARA_NO_EXTRA_FIELDS; 2649 2650 static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, 2651 LPFILETIME pTime, HCERTSTORE hAdditionalStore, 2652 const CERT_CHAIN_PARA *pChainPara, DWORD chainFlags) 2653 { 2654 DWORD cContext; 2655 2656 if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT) 2657 cContext = 1; 2658 else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) || 2659 (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)) 2660 { 2661 DWORD i; 2662 2663 for (i = 0, cContext = 0; i < chain->cChain; i++) 2664 { 2665 if (i < chain->cChain - 1 || 2666 chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) 2667 cContext += chain->rgpChain[i]->cElement; 2668 else 2669 cContext += chain->rgpChain[i]->cElement - 1; 2670 } 2671 } 2672 else 2673 cContext = 0; 2674 if (cContext) 2675 { 2676 DWORD i, j, iContext, revocationFlags; 2677 CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 }; 2678 CERT_REVOCATION_STATUS revocationStatus = 2679 { sizeof(revocationStatus), 0 }; 2680 BOOL ret; 2681 2682 revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG; 2683 if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY) 2684 revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION; 2685 if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT) 2686 revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG; 2687 revocationPara.pftTimeToUse = pTime; 2688 if (hAdditionalStore) 2689 { 2690 revocationPara.cCertStore = 1; 2691 revocationPara.rgCertStore = &hAdditionalStore; 2692 revocationPara.hCrlStore = hAdditionalStore; 2693 } 2694 if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA)) 2695 { 2696 revocationPara.dwUrlRetrievalTimeout = 2697 pChainPara->dwUrlRetrievalTimeout; 2698 revocationPara.fCheckFreshnessTime = 2699 pChainPara->fCheckRevocationFreshnessTime; 2700 revocationPara.dwFreshnessTime = 2701 pChainPara->dwRevocationFreshnessTime; 2702 } 2703 for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain; i++) 2704 { 2705 for (j = 0; iContext < cContext && 2706 j < chain->rgpChain[i]->cElement; j++, iContext++) 2707 { 2708 PCCERT_CONTEXT certToCheck = 2709 chain->rgpChain[i]->rgpElement[j]->pCertContext; 2710 2711 if (j < chain->rgpChain[i]->cElement - 1) 2712 revocationPara.pIssuerCert = 2713 chain->rgpChain[i]->rgpElement[j + 1]->pCertContext; 2714 else 2715 revocationPara.pIssuerCert = certToCheck; 2716 2717 ret = CertVerifyRevocation(X509_ASN_ENCODING, 2718 CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certToCheck, 2719 revocationFlags, &revocationPara, &revocationStatus); 2720 2721 if (!ret && revocationStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK && 2722 revocationPara.pIssuerCert == certToCheck) 2723 { 2724 FIXME("Unable to find CRL for CA certificate\n"); 2725 ret = TRUE; 2726 revocationStatus.dwError = 0; 2727 } 2728 2729 if (!ret) 2730 { 2731 PCERT_CHAIN_ELEMENT element = CRYPT_FindIthElementInChain( 2732 chain, iContext); 2733 DWORD error; 2734 2735 switch (revocationStatus.dwError) 2736 { 2737 case CRYPT_E_NO_REVOCATION_CHECK: 2738 case CRYPT_E_NO_REVOCATION_DLL: 2739 case CRYPT_E_NOT_IN_REVOCATION_DATABASE: 2740 /* If the revocation status is unknown, it's assumed 2741 * to be offline too. 2742 */ 2743 error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN | 2744 CERT_TRUST_IS_OFFLINE_REVOCATION; 2745 break; 2746 case CRYPT_E_REVOCATION_OFFLINE: 2747 error = CERT_TRUST_IS_OFFLINE_REVOCATION; 2748 break; 2749 case CRYPT_E_REVOKED: 2750 error = CERT_TRUST_IS_REVOKED; 2751 break; 2752 default: 2753 WARN("unmapped error %08x\n", revocationStatus.dwError); 2754 error = 0; 2755 } 2756 if (element) 2757 { 2758 /* FIXME: set element's pRevocationInfo member */ 2759 element->TrustStatus.dwErrorStatus |= error; 2760 } 2761 chain->TrustStatus.dwErrorStatus |= error; 2762 } 2763 } 2764 } 2765 } 2766 } 2767 2768 static void CRYPT_CheckUsages(PCERT_CHAIN_CONTEXT chain, 2769 const CERT_CHAIN_PARA *pChainPara) 2770 { 2771 if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) && 2772 pChainPara->RequestedUsage.Usage.cUsageIdentifier) 2773 { 2774 PCCERT_CONTEXT endCert; 2775 PCERT_EXTENSION ext; 2776 BOOL validForUsage; 2777 2778 /* A chain, if created, always includes the end certificate */ 2779 endCert = chain->rgpChain[0]->rgpElement[0]->pCertContext; 2780 /* The extended key usage extension specifies how a certificate's 2781 * public key may be used. From RFC 5280, section 4.2.1.12: 2782 * "This extension indicates one or more purposes for which the 2783 * certified public key may be used, in addition to or in place of the 2784 * basic purposes indicated in the key usage extension." 2785 * If the extension is present, it only satisfies the requested usage 2786 * if that usage is included in the extension: 2787 * "If the extension is present, then the certificate MUST only be used 2788 * for one of the purposes indicated." 2789 * There is also the special anyExtendedKeyUsage OID, but it doesn't 2790 * have to be respected: 2791 * "Applications that require the presence of a particular purpose 2792 * MAY reject certificates that include the anyExtendedKeyUsage OID 2793 * but not the particular OID expected for the application." 2794 * For now, I'm being more conservative and ignoring the presence of 2795 * the anyExtendedKeyUsage OID. 2796 */ 2797 if ((ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE, 2798 endCert->pCertInfo->cExtension, endCert->pCertInfo->rgExtension))) 2799 { 2800 const CERT_ENHKEY_USAGE *requestedUsage = 2801 &pChainPara->RequestedUsage.Usage; 2802 CERT_ENHKEY_USAGE *usage; 2803 DWORD size; 2804 2805 if (CryptDecodeObjectEx(X509_ASN_ENCODING, 2806 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData, 2807 CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)) 2808 { 2809 if (pChainPara->RequestedUsage.dwType == USAGE_MATCH_TYPE_AND) 2810 { 2811 DWORD i, j; 2812 2813 /* For AND matches, all usages must be present */ 2814 validForUsage = TRUE; 2815 for (i = 0; validForUsage && 2816 i < requestedUsage->cUsageIdentifier; i++) 2817 { 2818 BOOL match = FALSE; 2819 2820 for (j = 0; !match && j < usage->cUsageIdentifier; j++) 2821 match = !strcmp(usage->rgpszUsageIdentifier[j], 2822 requestedUsage->rgpszUsageIdentifier[i]); 2823 if (!match) 2824 validForUsage = FALSE; 2825 } 2826 } 2827 else 2828 { 2829 DWORD i, j; 2830 2831 /* For OR matches, any matching usage suffices */ 2832 validForUsage = FALSE; 2833 for (i = 0; !validForUsage && 2834 i < requestedUsage->cUsageIdentifier; i++) 2835 { 2836 for (j = 0; !validForUsage && 2837 j < usage->cUsageIdentifier; j++) 2838 validForUsage = 2839 !strcmp(usage->rgpszUsageIdentifier[j], 2840 requestedUsage->rgpszUsageIdentifier[i]); 2841 } 2842 } 2843 LocalFree(usage); 2844 } 2845 else 2846 validForUsage = FALSE; 2847 } 2848 else 2849 { 2850 /* If the extension isn't present, any interpretation is valid: 2851 * "Certificate using applications MAY require that the extended 2852 * key usage extension be present and that a particular purpose 2853 * be indicated in order for the certificate to be acceptable to 2854 * that application." 2855 * Not all web sites include the extended key usage extension, so 2856 * accept chains without it. 2857 */ 2858 TRACE_(chain)("requested usage from certificate with no usages\n"); 2859 validForUsage = TRUE; 2860 } 2861 if (!validForUsage) 2862 { 2863 chain->TrustStatus.dwErrorStatus |= 2864 CERT_TRUST_IS_NOT_VALID_FOR_USAGE; 2865 chain->rgpChain[0]->rgpElement[0]->TrustStatus.dwErrorStatus |= 2866 CERT_TRUST_IS_NOT_VALID_FOR_USAGE; 2867 } 2868 } 2869 if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA) && 2870 pChainPara->RequestedIssuancePolicy.Usage.cUsageIdentifier) 2871 FIXME("unimplemented for RequestedIssuancePolicy\n"); 2872 } 2873 2874 static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch) 2875 { 2876 if (usageMatch->Usage.cUsageIdentifier) 2877 { 2878 DWORD i; 2879 2880 TRACE_(chain)("%s: %s\n", name, 2881 usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR"); 2882 for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++) 2883 TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]); 2884 } 2885 } 2886 2887 static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara) 2888 { 2889 TRACE_(chain)("%d\n", pChainPara->cbSize); 2890 if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS)) 2891 dump_usage_match("RequestedUsage", &pChainPara->RequestedUsage); 2892 if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA)) 2893 { 2894 dump_usage_match("RequestedIssuancePolicy", 2895 &pChainPara->RequestedIssuancePolicy); 2896 TRACE_(chain)("%d\n", pChainPara->dwUrlRetrievalTimeout); 2897 TRACE_(chain)("%d\n", pChainPara->fCheckRevocationFreshnessTime); 2898 TRACE_(chain)("%d\n", pChainPara->dwRevocationFreshnessTime); 2899 } 2900 } 2901 2902 BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine, 2903 PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, 2904 PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved, 2905 PCCERT_CHAIN_CONTEXT* ppChainContext) 2906 { 2907 CertificateChainEngine *engine; 2908 BOOL ret; 2909 CertificateChain *chain = NULL; 2910 2911 TRACE("(%p, %p, %s, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext, 2912 debugstr_filetime(pTime), hAdditionalStore, pChainPara, dwFlags, 2913 pvReserved, ppChainContext); 2914 2915 engine = get_chain_engine(hChainEngine, TRUE); 2916 if (!engine) 2917 return FALSE; 2918 2919 if (ppChainContext) 2920 *ppChainContext = NULL; 2921 if (!pChainPara) 2922 { 2923 SetLastError(E_INVALIDARG); 2924 return FALSE; 2925 } 2926 if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId) 2927 { 2928 SetLastError(ERROR_INVALID_DATA); 2929 return FALSE; 2930 } 2931 2932 if (TRACE_ON(chain)) 2933 dump_chain_para(pChainPara); 2934 /* FIXME: what about HCCE_LOCAL_MACHINE? */ 2935 ret = CRYPT_BuildCandidateChainFromCert(engine, pCertContext, pTime, 2936 hAdditionalStore, dwFlags, &chain); 2937 if (ret) 2938 { 2939 CertificateChain *alternate = NULL; 2940 PCERT_CHAIN_CONTEXT pChain; 2941 2942 do { 2943 alternate = CRYPT_BuildAlternateContextFromChain(engine, 2944 pTime, hAdditionalStore, dwFlags, chain); 2945 2946 /* Alternate contexts are added as "lower quality" contexts of 2947 * chain, to avoid loops in alternate chain creation. 2948 * The highest-quality chain is chosen at the end. 2949 */ 2950 if (alternate) 2951 ret = CRYPT_AddAlternateChainToChain(chain, alternate); 2952 } while (ret && alternate); 2953 chain = CRYPT_ChooseHighestQualityChain(chain); 2954 if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS)) 2955 CRYPT_FreeLowerQualityChains(chain); 2956 pChain = (PCERT_CHAIN_CONTEXT)chain; 2957 CRYPT_VerifyChainRevocation(pChain, pTime, hAdditionalStore, 2958 pChainPara, dwFlags); 2959 CRYPT_CheckUsages(pChain, pChainPara); 2960 TRACE_(chain)("error status: %08x\n", 2961 pChain->TrustStatus.dwErrorStatus); 2962 if (ppChainContext) 2963 *ppChainContext = pChain; 2964 else 2965 CertFreeCertificateChain(pChain); 2966 } 2967 TRACE("returning %d\n", ret); 2968 return ret; 2969 } 2970 2971 PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain( 2972 PCCERT_CHAIN_CONTEXT pChainContext) 2973 { 2974 CertificateChain *chain = (CertificateChain*)pChainContext; 2975 2976 TRACE("(%p)\n", pChainContext); 2977 2978 if (chain) 2979 InterlockedIncrement(&chain->ref); 2980 return pChainContext; 2981 } 2982 2983 VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext) 2984 { 2985 CertificateChain *chain = (CertificateChain*)pChainContext; 2986 2987 TRACE("(%p)\n", pChainContext); 2988 2989 if (chain) 2990 { 2991 if (InterlockedDecrement(&chain->ref) == 0) 2992 CRYPT_FreeChainContext(chain); 2993 } 2994 } 2995 2996 PCCERT_CHAIN_CONTEXT WINAPI CertFindChainInStore(HCERTSTORE store, 2997 DWORD certEncodingType, DWORD findFlags, DWORD findType, 2998 const void *findPara, PCCERT_CHAIN_CONTEXT prevChainContext) 2999 { 3000 FIXME("(%p, %08x, %08x, %d, %p, %p): stub\n", store, certEncodingType, 3001 findFlags, findType, findPara, prevChainContext); 3002 return NULL; 3003 } 3004 3005 static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error, 3006 LONG *iChain, LONG *iElement) 3007 { 3008 DWORD i, j; 3009 3010 for (i = 0; i < chain->cChain; i++) 3011 for (j = 0; j < chain->rgpChain[i]->cElement; j++) 3012 if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus & 3013 error) 3014 { 3015 *iChain = i; 3016 *iElement = j; 3017 return; 3018 } 3019 } 3020 3021 static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID, 3022 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3023 PCERT_CHAIN_POLICY_STATUS pPolicyStatus) 3024 { 3025 DWORD checks = 0; 3026 3027 if (pPolicyPara) 3028 checks = pPolicyPara->dwFlags; 3029 pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1; 3030 pPolicyStatus->dwError = NO_ERROR; 3031 if (pChainContext->TrustStatus.dwErrorStatus & 3032 CERT_TRUST_IS_NOT_SIGNATURE_VALID) 3033 { 3034 pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE; 3035 find_element_with_error(pChainContext, 3036 CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex, 3037 &pPolicyStatus->lElementIndex); 3038 } 3039 else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC) 3040 { 3041 pPolicyStatus->dwError = CERT_E_CHAINING; 3042 find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC, 3043 &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex); 3044 /* For a cyclic chain, which element is a cycle isn't meaningful */ 3045 pPolicyStatus->lElementIndex = -1; 3046 } 3047 if (!pPolicyStatus->dwError && 3048 pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT && 3049 !(checks & CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG)) 3050 { 3051 pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT; 3052 find_element_with_error(pChainContext, 3053 CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex, 3054 &pPolicyStatus->lElementIndex); 3055 } 3056 if (!pPolicyStatus->dwError && 3057 pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) 3058 { 3059 pPolicyStatus->dwError = CERT_E_EXPIRED; 3060 find_element_with_error(pChainContext, 3061 CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex, 3062 &pPolicyStatus->lElementIndex); 3063 } 3064 if (!pPolicyStatus->dwError && 3065 pChainContext->TrustStatus.dwErrorStatus & 3066 CERT_TRUST_IS_NOT_VALID_FOR_USAGE && 3067 !(checks & CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG)) 3068 { 3069 pPolicyStatus->dwError = CERT_E_WRONG_USAGE; 3070 find_element_with_error(pChainContext, 3071 CERT_TRUST_IS_NOT_VALID_FOR_USAGE, &pPolicyStatus->lChainIndex, 3072 &pPolicyStatus->lElementIndex); 3073 } 3074 if (!pPolicyStatus->dwError && 3075 pChainContext->TrustStatus.dwErrorStatus & 3076 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT && 3077 !(checks & CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG)) 3078 { 3079 pPolicyStatus->dwError = CERT_E_CRITICAL; 3080 find_element_with_error(pChainContext, 3081 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, &pPolicyStatus->lChainIndex, 3082 &pPolicyStatus->lElementIndex); 3083 } 3084 return TRUE; 3085 } 3086 3087 static BYTE msTestPubKey1[] = { 3088 0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9, 3089 0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7, 3090 0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f, 3091 0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10, 3092 0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 }; 3093 static BYTE msTestPubKey2[] = { 3094 0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5, 3095 0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8, 3096 0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6, 3097 0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18, 3098 0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 }; 3099 3100 static void dump_authenticode_extra_chain_policy_para( 3101 AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA *extraPara) 3102 { 3103 if (extraPara) 3104 { 3105 TRACE_(chain)("cbSize = %d\n", extraPara->cbSize); 3106 TRACE_(chain)("dwRegPolicySettings = %08x\n", 3107 extraPara->dwRegPolicySettings); 3108 TRACE_(chain)("pSignerInfo = %p\n", extraPara->pSignerInfo); 3109 } 3110 } 3111 3112 static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID, 3113 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3114 PCERT_CHAIN_POLICY_STATUS pPolicyStatus) 3115 { 3116 BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara, 3117 pPolicyStatus); 3118 AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA *extraPara = NULL; 3119 3120 if (pPolicyPara) 3121 extraPara = pPolicyPara->pvExtraPolicyPara; 3122 if (TRACE_ON(chain)) 3123 dump_authenticode_extra_chain_policy_para(extraPara); 3124 if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT) 3125 { 3126 CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } }; 3127 BOOL isMSTestRoot = FALSE; 3128 PCCERT_CONTEXT failingCert = 3129 pChainContext->rgpChain[pPolicyStatus->lChainIndex]-> 3130 rgpElement[pPolicyStatus->lElementIndex]->pCertContext; 3131 DWORD i; 3132 CRYPT_DATA_BLOB keyBlobs[] = { 3133 { sizeof(msTestPubKey1), msTestPubKey1 }, 3134 { sizeof(msTestPubKey2), msTestPubKey2 }, 3135 }; 3136 3137 /* Check whether the root is an MS test root */ 3138 for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]); 3139 i++) 3140 { 3141 msPubKey.PublicKey.cbData = keyBlobs[i].cbData; 3142 msPubKey.PublicKey.pbData = keyBlobs[i].pbData; 3143 if (CertComparePublicKeyInfo( 3144 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 3145 &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey)) 3146 isMSTestRoot = TRUE; 3147 } 3148 if (isMSTestRoot) 3149 pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT; 3150 } 3151 return ret; 3152 } 3153 3154 static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID, 3155 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3156 PCERT_CHAIN_POLICY_STATUS pPolicyStatus) 3157 { 3158 pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1; 3159 if (pChainContext->TrustStatus.dwErrorStatus & 3160 CERT_TRUST_INVALID_BASIC_CONSTRAINTS) 3161 { 3162 pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS; 3163 find_element_with_error(pChainContext, 3164 CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex, 3165 &pPolicyStatus->lElementIndex); 3166 } 3167 else 3168 pPolicyStatus->dwError = NO_ERROR; 3169 return TRUE; 3170 } 3171 3172 static BOOL match_dns_to_subject_alt_name(const CERT_EXTENSION *ext, 3173 LPCWSTR server_name) 3174 { 3175 BOOL matches = FALSE; 3176 CERT_ALT_NAME_INFO *subjectName; 3177 DWORD size; 3178 3179 TRACE_(chain)("%s\n", debugstr_w(server_name)); 3180 /* This could be spoofed by the embedded NULL vulnerability, since the 3181 * returned CERT_ALT_NAME_INFO doesn't have a way to indicate the 3182 * encoded length of a name. Fortunately CryptDecodeObjectEx fails if 3183 * the encoded form of the name contains a NULL. 3184 */ 3185 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, 3186 ext->Value.pbData, ext->Value.cbData, 3187 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 3188 &subjectName, &size)) 3189 { 3190 DWORD i; 3191 3192 /* RFC 5280 states that multiple instances of each name type may exist, 3193 * in section 4.2.1.6: 3194 * "Multiple name forms, and multiple instances of each name form, 3195 * MAY be included." 3196 * It doesn't specify the behavior in such cases, but both RFC 2818 3197 * and RFC 2595 explicitly accept a certificate if any name matches. 3198 */ 3199 for (i = 0; !matches && i < subjectName->cAltEntry; i++) 3200 { 3201 if (subjectName->rgAltEntry[i].dwAltNameChoice == 3202 CERT_ALT_NAME_DNS_NAME) 3203 { 3204 TRACE_(chain)("dNSName: %s\n", debugstr_w( 3205 subjectName->rgAltEntry[i].u.pwszDNSName)); 3206 if (subjectName->rgAltEntry[i].u.pwszDNSName[0] == '*') 3207 { 3208 LPCWSTR server_name_dot; 3209 3210 /* Matching a wildcard: a wildcard matches a single name 3211 * component, which is terminated by a dot. RFC 1034 3212 * doesn't define whether multiple wildcards are allowed, 3213 * but I will assume that they are not until proven 3214 * otherwise. RFC 1034 also states that 'the "*" label 3215 * always matches at least one whole label and sometimes 3216 * more, but always whole labels.' Native crypt32 does not 3217 * match more than one label with a wildcard, so I do the 3218 * same here. Thus, a wildcard only accepts the first 3219 * label, then requires an exact match of the remaining 3220 * string. 3221 */ 3222 server_name_dot = strchrW(server_name, '.'); 3223 if (server_name_dot) 3224 { 3225 if (!strcmpiW(server_name_dot, 3226 subjectName->rgAltEntry[i].u.pwszDNSName + 1)) 3227 matches = TRUE; 3228 } 3229 } 3230 else if (!strcmpiW(server_name, 3231 subjectName->rgAltEntry[i].u.pwszDNSName)) 3232 matches = TRUE; 3233 } 3234 } 3235 LocalFree(subjectName); 3236 } 3237 return matches; 3238 } 3239 3240 static BOOL find_matching_domain_component(const CERT_NAME_INFO *name, 3241 LPCWSTR component) 3242 { 3243 BOOL matches = FALSE; 3244 DWORD i, j; 3245 3246 for (i = 0; !matches && i < name->cRDN; i++) 3247 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++) 3248 if (!strcmp(szOID_DOMAIN_COMPONENT, 3249 name->rgRDN[i].rgRDNAttr[j].pszObjId)) 3250 { 3251 const CERT_RDN_ATTR *attr; 3252 3253 attr = &name->rgRDN[i].rgRDNAttr[j]; 3254 /* Compare with memicmpW rather than strcmpiW in order to avoid 3255 * a match with a string with an embedded NULL. The component 3256 * must match one domain component attribute's entire string 3257 * value with a case-insensitive match. 3258 */ 3259 matches = !memicmpW(component, (LPCWSTR)attr->Value.pbData, 3260 attr->Value.cbData / sizeof(WCHAR)); 3261 } 3262 return matches; 3263 } 3264 3265 static BOOL match_domain_component(LPCWSTR allowed_component, DWORD allowed_len, 3266 LPCWSTR server_component, DWORD server_len, BOOL allow_wildcards, 3267 BOOL *see_wildcard) 3268 { 3269 LPCWSTR allowed_ptr, server_ptr; 3270 BOOL matches = TRUE; 3271 3272 *see_wildcard = FALSE; 3273 3274 if (server_len < allowed_len) 3275 { 3276 WARN_(chain)("domain component %s too short for %s\n", 3277 debugstr_wn(server_component, server_len), 3278 debugstr_wn(allowed_component, allowed_len)); 3279 /* A domain component can't contain a wildcard character, so a domain 3280 * component shorter than the allowed string can't produce a match. 3281 */ 3282 return FALSE; 3283 } 3284 for (allowed_ptr = allowed_component, server_ptr = server_component; 3285 matches && allowed_ptr - allowed_component < allowed_len; 3286 allowed_ptr++, server_ptr++) 3287 { 3288 if (*allowed_ptr == '*') 3289 { 3290 if (allowed_ptr - allowed_component < allowed_len - 1) 3291 { 3292 WARN_(chain)("non-wildcard characters after wildcard not supported\n"); 3293 matches = FALSE; 3294 } 3295 else if (!allow_wildcards) 3296 { 3297 WARN_(chain)("wildcard after non-wildcard component\n"); 3298 matches = FALSE; 3299 } 3300 else 3301 { 3302 /* the preceding characters must have matched, so the rest of 3303 * the component also matches. 3304 */ 3305 *see_wildcard = TRUE; 3306 break; 3307 } 3308 } 3309 if (matches) 3310 matches = tolowerW(*allowed_ptr) == tolowerW(*server_ptr); 3311 } 3312 if (matches && server_ptr - server_component < server_len) 3313 { 3314 /* If there are unmatched characters in the server domain component, 3315 * the server domain only matches if the allowed string ended in a '*'. 3316 */ 3317 matches = *allowed_ptr == '*'; 3318 } 3319 return matches; 3320 } 3321 3322 static BOOL match_common_name(LPCWSTR server_name, const CERT_RDN_ATTR *nameAttr) 3323 { 3324 LPCWSTR allowed = (LPCWSTR)nameAttr->Value.pbData; 3325 LPCWSTR allowed_component = allowed; 3326 DWORD allowed_len = nameAttr->Value.cbData / sizeof(WCHAR); 3327 LPCWSTR server_component = server_name; 3328 DWORD server_len = strlenW(server_name); 3329 BOOL matches = TRUE, allow_wildcards = TRUE; 3330 3331 TRACE_(chain)("CN = %s\n", debugstr_wn(allowed_component, allowed_len)); 3332 3333 /* Remove trailing NULLs from the allowed name; while they shouldn't appear 3334 * in a certificate in the first place, they sometimes do, and they should 3335 * be ignored. 3336 */ 3337 while (allowed_len && allowed_component[allowed_len - 1] == 0) 3338 allowed_len--; 3339 3340 /* From RFC 2818 (HTTP over TLS), section 3.1: 3341 * "Names may contain the wildcard character * which is considered to match 3342 * any single domain name component or component fragment. E.g., 3343 * *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com 3344 * but not bar.com." 3345 * 3346 * And from RFC 2595 (Using TLS with IMAP, POP3 and ACAP), section 2.4: 3347 * "A "*" wildcard character MAY be used as the left-most name component in 3348 * the certificate. For example, *.example.com would match a.example.com, 3349 * foo.example.com, etc. but would not match example.com." 3350 * 3351 * There are other protocols which use TLS, and none of them is 3352 * authoritative. This accepts certificates in common usage, e.g. 3353 * *.domain.com matches www.domain.com but not domain.com, and 3354 * www*.domain.com matches www1.domain.com but not mail.domain.com. 3355 */ 3356 do { 3357 LPCWSTR allowed_dot, server_dot; 3358 3359 allowed_dot = memchrW(allowed_component, '.', 3360 allowed_len - (allowed_component - allowed)); 3361 server_dot = memchrW(server_component, '.', 3362 server_len - (server_component - server_name)); 3363 /* The number of components must match */ 3364 if ((!allowed_dot && server_dot) || (allowed_dot && !server_dot)) 3365 { 3366 if (!allowed_dot) 3367 WARN_(chain)("%s: too many components for CN=%s\n", 3368 debugstr_w(server_name), debugstr_wn(allowed, allowed_len)); 3369 else 3370 WARN_(chain)("%s: not enough components for CN=%s\n", 3371 debugstr_w(server_name), debugstr_wn(allowed, allowed_len)); 3372 matches = FALSE; 3373 } 3374 else 3375 { 3376 LPCWSTR allowed_end, server_end; 3377 BOOL has_wildcard; 3378 3379 allowed_end = allowed_dot ? allowed_dot : allowed + allowed_len; 3380 server_end = server_dot ? server_dot : server_name + server_len; 3381 matches = match_domain_component(allowed_component, 3382 allowed_end - allowed_component, server_component, 3383 server_end - server_component, allow_wildcards, &has_wildcard); 3384 /* Once a non-wildcard component is seen, no wildcard components 3385 * may follow 3386 */ 3387 if (!has_wildcard) 3388 allow_wildcards = FALSE; 3389 if (matches) 3390 { 3391 allowed_component = allowed_dot ? allowed_dot + 1 : allowed_end; 3392 server_component = server_dot ? server_dot + 1 : server_end; 3393 } 3394 } 3395 } while (matches && allowed_component && 3396 allowed_component - allowed < allowed_len && 3397 server_component && server_component - server_name < server_len); 3398 TRACE_(chain)("returning %d\n", matches); 3399 return matches; 3400 } 3401 3402 static BOOL match_dns_to_subject_dn(PCCERT_CONTEXT cert, LPCWSTR server_name) 3403 { 3404 BOOL matches = FALSE; 3405 CERT_NAME_INFO *name; 3406 DWORD size; 3407 3408 TRACE_(chain)("%s\n", debugstr_w(server_name)); 3409 if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME, 3410 cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData, 3411 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, 3412 &name, &size)) 3413 { 3414 /* If the subject distinguished name contains any name components, 3415 * make sure all of them are present. 3416 */ 3417 if (CertFindRDNAttr(szOID_DOMAIN_COMPONENT, name)) 3418 { 3419 LPCWSTR ptr = server_name; 3420 3421 do { 3422 LPCWSTR dot = strchrW(ptr, '.'), end; 3423 /* 254 is the maximum DNS label length, see RFC 1035 */ 3424 WCHAR component[255]; 3425 DWORD len; 3426 3427 end = dot ? dot : ptr + strlenW(ptr); 3428 len = end - ptr; 3429 if (len >= sizeof(component) / sizeof(component[0])) 3430 { 3431 WARN_(chain)("domain component %s too long\n", 3432 debugstr_wn(ptr, len)); 3433 matches = FALSE; 3434 } 3435 else 3436 { 3437 memcpy(component, ptr, len * sizeof(WCHAR)); 3438 component[len] = 0; 3439 matches = find_matching_domain_component(name, component); 3440 } 3441 ptr = dot ? dot + 1 : end; 3442 } while (matches && ptr && *ptr); 3443 } 3444 else 3445 { 3446 DWORD i, j; 3447 3448 /* If the certificate isn't using a DN attribute in the name, make 3449 * make sure at least one common name matches. From RFC 2818, 3450 * section 3.1: 3451 * "If more than one identity of a given type is present in the 3452 * certificate (e.g., more than one dNSName name, a match in any 3453 * one of the set is considered acceptable.)" 3454 */ 3455 for (i = 0; !matches && i < name->cRDN; i++) 3456 for (j = 0; !matches && j < name->rgRDN[i].cRDNAttr; j++) 3457 { 3458 PCERT_RDN_ATTR attr = &name->rgRDN[i].rgRDNAttr[j]; 3459 3460 if (attr->pszObjId && !strcmp(szOID_COMMON_NAME, 3461 attr->pszObjId)) 3462 matches = match_common_name(server_name, attr); 3463 } 3464 } 3465 LocalFree(name); 3466 } 3467 return matches; 3468 } 3469 3470 static void dump_ssl_extra_chain_policy_para(HTTPSPolicyCallbackData *sslPara) 3471 { 3472 if (sslPara) 3473 { 3474 TRACE_(chain)("cbSize = %d\n", sslPara->u.cbSize); 3475 TRACE_(chain)("dwAuthType = %d\n", sslPara->dwAuthType); 3476 TRACE_(chain)("fdwChecks = %08x\n", sslPara->fdwChecks); 3477 TRACE_(chain)("pwszServerName = %s\n", 3478 debugstr_w(sslPara->pwszServerName)); 3479 } 3480 } 3481 3482 static BOOL WINAPI verify_ssl_policy(LPCSTR szPolicyOID, 3483 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3484 PCERT_CHAIN_POLICY_STATUS pPolicyStatus) 3485 { 3486 HTTPSPolicyCallbackData *sslPara = NULL; 3487 DWORD checks = 0; 3488 3489 if (pPolicyPara) 3490 sslPara = pPolicyPara->pvExtraPolicyPara; 3491 if (TRACE_ON(chain)) 3492 dump_ssl_extra_chain_policy_para(sslPara); 3493 if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData)) 3494 checks = sslPara->fdwChecks; 3495 pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1; 3496 if (pChainContext->TrustStatus.dwErrorStatus & 3497 CERT_TRUST_IS_NOT_SIGNATURE_VALID) 3498 { 3499 pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE; 3500 find_element_with_error(pChainContext, 3501 CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex, 3502 &pPolicyStatus->lElementIndex); 3503 } 3504 else if (pChainContext->TrustStatus.dwErrorStatus & 3505 CERT_TRUST_IS_UNTRUSTED_ROOT && 3506 !(checks & SECURITY_FLAG_IGNORE_UNKNOWN_CA)) 3507 { 3508 pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT; 3509 find_element_with_error(pChainContext, 3510 CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex, 3511 &pPolicyStatus->lElementIndex); 3512 } 3513 else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC) 3514 { 3515 pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT; 3516 find_element_with_error(pChainContext, 3517 CERT_TRUST_IS_CYCLIC, &pPolicyStatus->lChainIndex, 3518 &pPolicyStatus->lElementIndex); 3519 /* For a cyclic chain, which element is a cycle isn't meaningful */ 3520 pPolicyStatus->lElementIndex = -1; 3521 } 3522 else if (pChainContext->TrustStatus.dwErrorStatus & 3523 CERT_TRUST_IS_NOT_TIME_VALID && 3524 !(checks & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)) 3525 { 3526 pPolicyStatus->dwError = CERT_E_EXPIRED; 3527 find_element_with_error(pChainContext, 3528 CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex, 3529 &pPolicyStatus->lElementIndex); 3530 } 3531 else if (pChainContext->TrustStatus.dwErrorStatus & 3532 CERT_TRUST_IS_NOT_VALID_FOR_USAGE && 3533 !(checks & SECURITY_FLAG_IGNORE_WRONG_USAGE)) 3534 { 3535 pPolicyStatus->dwError = CERT_E_WRONG_USAGE; 3536 find_element_with_error(pChainContext, 3537 CERT_TRUST_IS_NOT_VALID_FOR_USAGE, &pPolicyStatus->lChainIndex, 3538 &pPolicyStatus->lElementIndex); 3539 } 3540 else if (pChainContext->TrustStatus.dwErrorStatus & 3541 CERT_TRUST_IS_REVOKED && !(checks & SECURITY_FLAG_IGNORE_REVOCATION)) 3542 { 3543 pPolicyStatus->dwError = CERT_E_REVOKED; 3544 find_element_with_error(pChainContext, 3545 CERT_TRUST_IS_REVOKED, &pPolicyStatus->lChainIndex, 3546 &pPolicyStatus->lElementIndex); 3547 } 3548 else if (pChainContext->TrustStatus.dwErrorStatus & 3549 CERT_TRUST_IS_OFFLINE_REVOCATION && 3550 !(checks & SECURITY_FLAG_IGNORE_REVOCATION)) 3551 { 3552 pPolicyStatus->dwError = CERT_E_REVOCATION_FAILURE; 3553 find_element_with_error(pChainContext, 3554 CERT_TRUST_IS_OFFLINE_REVOCATION, &pPolicyStatus->lChainIndex, 3555 &pPolicyStatus->lElementIndex); 3556 } 3557 else if (pChainContext->TrustStatus.dwErrorStatus & 3558 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT) 3559 { 3560 pPolicyStatus->dwError = CERT_E_CRITICAL; 3561 find_element_with_error(pChainContext, 3562 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, &pPolicyStatus->lChainIndex, 3563 &pPolicyStatus->lElementIndex); 3564 } 3565 else 3566 pPolicyStatus->dwError = NO_ERROR; 3567 /* We only need bother checking whether the name in the end certificate 3568 * matches if the chain is otherwise okay. 3569 */ 3570 if (!pPolicyStatus->dwError && pPolicyPara && 3571 pPolicyPara->cbSize >= sizeof(CERT_CHAIN_POLICY_PARA)) 3572 { 3573 if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData)) 3574 { 3575 if (sslPara->dwAuthType == AUTHTYPE_SERVER && 3576 sslPara->pwszServerName && 3577 !(checks & SECURITY_FLAG_IGNORE_CERT_CN_INVALID)) 3578 { 3579 PCCERT_CONTEXT cert; 3580 PCERT_EXTENSION altNameExt; 3581 BOOL matches; 3582 3583 cert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext; 3584 altNameExt = get_subject_alt_name_ext(cert->pCertInfo); 3585 /* If the alternate name extension exists, the name it contains 3586 * is bound to the certificate, so make sure the name matches 3587 * it. Otherwise, look for the server name in the subject 3588 * distinguished name. RFC5280, section 4.2.1.6: 3589 * "Whenever such identities are to be bound into a 3590 * certificate, the subject alternative name (or issuer 3591 * alternative name) extension MUST be used; however, a DNS 3592 * name MAY also be represented in the subject field using the 3593 * domainComponent attribute." 3594 */ 3595 if (altNameExt) 3596 matches = match_dns_to_subject_alt_name(altNameExt, 3597 sslPara->pwszServerName); 3598 else 3599 matches = match_dns_to_subject_dn(cert, 3600 sslPara->pwszServerName); 3601 if (!matches) 3602 { 3603 pPolicyStatus->dwError = CERT_E_CN_NO_MATCH; 3604 pPolicyStatus->lChainIndex = 0; 3605 pPolicyStatus->lElementIndex = 0; 3606 } 3607 } 3608 } 3609 } 3610 return TRUE; 3611 } 3612 3613 static BYTE msPubKey1[] = { 3614 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e, 3615 0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d, 3616 0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29, 3617 0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16, 3618 0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60, 3619 0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5, 3620 0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d, 3621 0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61, 3622 0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e, 3623 0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94, 3624 0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb, 3625 0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a, 3626 0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d, 3627 0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb, 3628 0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08, 3629 0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43, 3630 0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf, 3631 0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 }; 3632 static BYTE msPubKey2[] = { 3633 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6, 3634 0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25, 3635 0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2, 3636 0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54, 3637 0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62, 3638 0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a, 3639 0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7, 3640 0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84, 3641 0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9, 3642 0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91, 3643 0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52, 3644 0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80, 3645 0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18, 3646 0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07, 3647 0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef, 3648 0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0, 3649 0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30, 3650 0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 }; 3651 static BYTE msPubKey3[] = { 3652 0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4, 3653 0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7, 3654 0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94, 3655 0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04, 3656 0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d, 3657 0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09, 3658 0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae, 3659 0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7, 3660 0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f, 3661 0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94, 3662 0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d, 3663 0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05, 3664 0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e, 3665 0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d, 3666 0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b, 3667 0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67, 3668 0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08, 3669 0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5, 3670 0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64, 3671 0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38, 3672 0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0, 3673 0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9, 3674 0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28, 3675 0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc, 3676 0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45, 3677 0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde, 3678 0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04, 3679 0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89, 3680 0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11, 3681 0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32, 3682 0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40, 3683 0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41, 3684 0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1, 3685 0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5, 3686 0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00, 3687 0x01 }; 3688 3689 static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID, 3690 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3691 PCERT_CHAIN_POLICY_STATUS pPolicyStatus) 3692 { 3693 BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara, 3694 pPolicyStatus); 3695 3696 if (ret && !pPolicyStatus->dwError) 3697 { 3698 CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } }; 3699 BOOL isMSRoot = FALSE; 3700 DWORD i; 3701 CRYPT_DATA_BLOB keyBlobs[] = { 3702 { sizeof(msPubKey1), msPubKey1 }, 3703 { sizeof(msPubKey2), msPubKey2 }, 3704 { sizeof(msPubKey3), msPubKey3 }, 3705 }; 3706 PCERT_SIMPLE_CHAIN rootChain = 3707 pChainContext->rgpChain[pChainContext->cChain -1 ]; 3708 PCCERT_CONTEXT root = 3709 rootChain->rgpElement[rootChain->cElement - 1]->pCertContext; 3710 3711 for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]); 3712 i++) 3713 { 3714 msPubKey.PublicKey.cbData = keyBlobs[i].cbData; 3715 msPubKey.PublicKey.pbData = keyBlobs[i].pbData; 3716 if (CertComparePublicKeyInfo( 3717 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 3718 &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey)) 3719 isMSRoot = TRUE; 3720 } 3721 if (isMSRoot) 3722 pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0; 3723 } 3724 return ret; 3725 } 3726 3727 typedef BOOL (WINAPI *CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID, 3728 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3729 PCERT_CHAIN_POLICY_STATUS pPolicyStatus); 3730 3731 static void dump_policy_para(PCERT_CHAIN_POLICY_PARA para) 3732 { 3733 if (para) 3734 { 3735 TRACE_(chain)("cbSize = %d\n", para->cbSize); 3736 TRACE_(chain)("dwFlags = %08x\n", para->dwFlags); 3737 TRACE_(chain)("pvExtraPolicyPara = %p\n", para->pvExtraPolicyPara); 3738 } 3739 } 3740 3741 BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID, 3742 PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, 3743 PCERT_CHAIN_POLICY_STATUS pPolicyStatus) 3744 { 3745 static HCRYPTOIDFUNCSET set = NULL; 3746 BOOL ret = FALSE; 3747 CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL; 3748 HCRYPTOIDFUNCADDR hFunc = NULL; 3749 3750 TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext, 3751 pPolicyPara, pPolicyStatus); 3752 if (TRACE_ON(chain)) 3753 dump_policy_para(pPolicyPara); 3754 3755 if (IS_INTOID(szPolicyOID)) 3756 { 3757 switch (LOWORD(szPolicyOID)) 3758 { 3759 case LOWORD(CERT_CHAIN_POLICY_BASE): 3760 verifyPolicy = verify_base_policy; 3761 break; 3762 case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE): 3763 verifyPolicy = verify_authenticode_policy; 3764 break; 3765 case LOWORD(CERT_CHAIN_POLICY_SSL): 3766 verifyPolicy = verify_ssl_policy; 3767 break; 3768 case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS): 3769 verifyPolicy = verify_basic_constraints_policy; 3770 break; 3771 case LOWORD(CERT_CHAIN_POLICY_MICROSOFT_ROOT): 3772 verifyPolicy = verify_ms_root_policy; 3773 break; 3774 default: 3775 FIXME("unimplemented for %d\n", LOWORD(szPolicyOID)); 3776 } 3777 } 3778 if (!verifyPolicy) 3779 { 3780 if (!set) 3781 set = CryptInitOIDFunctionSet( 3782 CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0); 3783 CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0, 3784 (void **)&verifyPolicy, &hFunc); 3785 } 3786 if (verifyPolicy) 3787 ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara, 3788 pPolicyStatus); 3789 if (hFunc) 3790 CryptFreeOIDFunctionAddress(hFunc, 0); 3791 TRACE("returning %d (%08x)\n", ret, pPolicyStatus->dwError); 3792 return ret; 3793 } 3794