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