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