Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/cert_verify_proc_mac.h" | 5 #include "net/cert/cert_verify_proc_mac.h" |
| 6 | 6 |
| 7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
| 8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
| 9 #include <Security/Security.h> | 9 #include <Security/Security.h> |
| 10 | 10 |
| 11 #include <set> | 11 #include <set> |
| 12 #include <string> | 12 #include <string> |
| 13 #include <vector> | 13 #include <vector> |
| 14 | 14 |
| 15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/mac/mac_logging.h" | 17 #include "base/mac/mac_logging.h" |
| 18 #include "base/mac/mac_util.h" | |
| 18 #include "base/mac/scoped_cftyperef.h" | 19 #include "base/mac/scoped_cftyperef.h" |
| 19 #include "base/sha1.h" | 20 #include "base/sha1.h" |
| 20 #include "base/strings/string_piece.h" | 21 #include "base/strings/string_piece.h" |
| 21 #include "base/synchronization/lock.h" | 22 #include "base/synchronization/lock.h" |
| 22 #include "crypto/mac_security_services_lock.h" | 23 #include "crypto/mac_security_services_lock.h" |
| 23 #include "crypto/sha2.h" | 24 #include "crypto/sha2.h" |
| 24 #include "net/base/hash_value.h" | 25 #include "net/base/hash_value.h" |
| 25 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 26 #include "net/cert/asn1_util.h" | 27 #include "net/cert/asn1_util.h" |
| 27 #include "net/cert/cert_status_flags.h" | 28 #include "net/cert/cert_status_flags.h" |
| 28 #include "net/cert/cert_verifier.h" | 29 #include "net/cert/cert_verifier.h" |
| 29 #include "net/cert/cert_verify_result.h" | 30 #include "net/cert/cert_verify_result.h" |
| 30 #include "net/cert/crl_set.h" | 31 #include "net/cert/crl_set.h" |
| 32 #include "net/cert/ev_root_ca_metadata.h" | |
| 33 #include "net/cert/internal/certificate_policies.h" | |
| 34 #include "net/cert/internal/parsed_certificate.h" | |
| 31 #include "net/cert/test_keychain_search_list_mac.h" | 35 #include "net/cert/test_keychain_search_list_mac.h" |
| 32 #include "net/cert/test_root_certs.h" | 36 #include "net/cert/test_root_certs.h" |
| 33 #include "net/cert/x509_certificate.h" | 37 #include "net/cert/x509_certificate.h" |
| 34 #include "net/cert/x509_util_mac.h" | 38 #include "net/cert/x509_util_mac.h" |
| 35 | 39 |
| 36 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. | 40 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. |
| 37 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 | 41 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 |
| 38 #pragma clang diagnostic push | 42 #pragma clang diagnostic push |
| 39 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 43 #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| 40 | 44 |
| 41 // From 10.7.2 libsecurity_keychain-55035/lib/SecTrustPriv.h, for use with | |
| 42 // SecTrustCopyExtendedResult. | |
| 43 #ifndef kSecEVOrganizationName | |
| 44 #define kSecEVOrganizationName CFSTR("Organization") | |
| 45 #endif | |
| 46 | |
| 47 using base::ScopedCFTypeRef; | 45 using base::ScopedCFTypeRef; |
| 48 | 46 |
| 49 namespace net { | 47 namespace net { |
| 50 | 48 |
| 51 namespace { | 49 namespace { |
| 52 | 50 |
| 53 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | 51 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, |
| 54 CFDictionaryRef*); | 52 CFDictionaryRef*); |
| 55 | 53 |
| 56 int NetErrorFromOSStatus(OSStatus status) { | 54 int NetErrorFromOSStatus(OSStatus status) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 x509_util::CreateSSLServerPolicy(std::string(), &ssl_policy); | 162 x509_util::CreateSSLServerPolicy(std::string(), &ssl_policy); |
| 165 if (status) | 163 if (status) |
| 166 return status; | 164 return status; |
| 167 CFArrayAppendValue(local_policies, ssl_policy); | 165 CFArrayAppendValue(local_policies, ssl_policy); |
| 168 CFRelease(ssl_policy); | 166 CFRelease(ssl_policy); |
| 169 | 167 |
| 170 // Explicitly add revocation policies, in order to override system | 168 // Explicitly add revocation policies, in order to override system |
| 171 // revocation checking policies and instead respect the application-level | 169 // revocation checking policies and instead respect the application-level |
| 172 // revocation preference. | 170 // revocation preference. |
| 173 status = x509_util::CreateRevocationPolicies( | 171 status = x509_util::CreateRevocationPolicies( |
| 174 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), | 172 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), local_policies); |
| 175 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY), | |
| 176 local_policies); | |
| 177 if (status) | 173 if (status) |
| 178 return status; | 174 return status; |
| 179 | 175 |
| 180 policies->reset(local_policies.release()); | 176 policies->reset(local_policies.release()); |
| 181 return noErr; | 177 return noErr; |
| 182 } | 178 } |
| 183 | 179 |
| 184 // Stores the constructed certificate chain |cert_chain| and information about | 180 // Stores the constructed certificate chain |cert_chain| and information about |
| 185 // the signature algorithms used into |*verify_result|. If the leaf cert in | 181 // the signature algorithms used into |*verify_result|. If the leaf cert in |
| 186 // |cert_chain| contains a weak (MD2, MD4, MD5, SHA-1) signature, stores that | 182 // |cert_chain| contains a weak (MD2, MD4, MD5, SHA-1) signature, stores that |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 } | 261 } |
| 266 if (!verified_cert) { | 262 if (!verified_cert) { |
| 267 NOTREACHED(); | 263 NOTREACHED(); |
| 268 return; | 264 return; |
| 269 } | 265 } |
| 270 | 266 |
| 271 verify_result->verified_cert = | 267 verify_result->verified_cert = |
| 272 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | 268 X509Certificate::CreateFromHandle(verified_cert, verified_chain); |
| 273 } | 269 } |
| 274 | 270 |
| 271 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; | |
| 272 | |
| 273 // Helper that looks up an extension by OID given a map of extensions. | |
| 274 bool GetExtensionValue(const ExtensionsMap& extensions, | |
| 275 const net::der::Input& oid, | |
| 276 net::der::Input* value) { | |
| 277 auto it = extensions.find(oid); | |
| 278 if (it == extensions.end()) | |
| 279 return false; | |
| 280 *value = it->second.value; | |
| 281 return true; | |
| 282 } | |
| 283 | |
| 284 // Checks if |*cert| has a Certificate Policies extension containing either | |
| 285 // of |ev_policy_oid| or anyPolicy. | |
| 286 bool HasPolicyOrAnyPolicy(const ParsedCertificate* cert, | |
| 287 const der::Input& ev_policy_oid) { | |
| 288 der::Input extension_value; | |
| 289 if (!GetExtensionValue(cert->unparsed_extensions(), CertificatePoliciesOid(), | |
| 290 &extension_value)) | |
| 291 return false; | |
| 292 | |
| 293 std::vector<der::Input> policies; | |
| 294 if (!ParseCertificatePoliciesExtension(extension_value, &policies)) | |
| 295 return false; | |
| 296 | |
| 297 for (const der::Input& policy_oid : policies) { | |
| 298 if (policy_oid == ev_policy_oid || policy_oid == AnyPolicy()) | |
| 299 return true; | |
| 300 } | |
| 301 return false; | |
| 302 } | |
| 303 | |
| 304 // Looks for known EV policy OIDs in |cert_input|, if one is found it will be | |
| 305 // stored in |*ev_policy_oid| as a DER-encoded OID value (no tag or length). | |
| 306 void GetCandidateEVPolicy(const X509Certificate* cert_input, | |
| 307 std::string* ev_policy_oid) { | |
| 308 *ev_policy_oid = std::string(); | |
|
Ryan Sleevi
2016/11/08 23:54:09
ev_policy_oid->clear(); is slightly more efficient
mattm
2016/11/10 05:40:40
Done.
| |
| 309 | |
| 310 std::string der_cert; | |
| 311 if (!X509Certificate::GetDEREncoded(cert_input->os_cert_handle(), | |
| 312 &der_cert)) { | |
| 313 return; | |
| 314 } | |
| 315 | |
| 316 scoped_refptr<ParsedCertificate> cert( | |
| 317 ParsedCertificate::Create(der_cert, {}, nullptr)); | |
| 318 if (!cert) | |
| 319 return; | |
| 320 | |
| 321 der::Input extension_value; | |
| 322 if (!GetExtensionValue(cert->unparsed_extensions(), CertificatePoliciesOid(), | |
| 323 &extension_value)) { | |
|
Ryan Sleevi
2016/11/08 23:54:09
Since you braced here, should you brace 289-291 fo
mattm
2016/11/10 05:40:40
Done.
| |
| 324 return; | |
| 325 } | |
| 326 | |
| 327 std::vector<der::Input> policies; | |
| 328 if (!ParseCertificatePoliciesExtension(extension_value, &policies)) | |
| 329 return; | |
| 330 | |
| 331 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); | |
| 332 for (const der::Input& policy_oid : policies) { | |
| 333 if (metadata->IsEVPolicyOID(policy_oid)) { | |
| 334 *ev_policy_oid = policy_oid.AsString(); | |
| 335 return; | |
| 336 } | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 // Checks that the certificate chain of |cert| has policies consistent with | |
| 341 // |ev_policy_oid_string|. The leaf is not checked, as it is assumed that is | |
| 342 // where the policy came from. | |
| 343 bool CheckCertChainEV(const X509Certificate* cert, | |
| 344 const std::string& ev_policy_oid_string) { | |
| 345 der::Input ev_policy_oid(&ev_policy_oid_string); | |
| 346 X509Certificate::OSCertHandles os_cert_chain = | |
| 347 cert->GetIntermediateCertificates(); | |
| 348 | |
| 349 // Intermediates should have Certificate Policies extension with the EV policy | |
| 350 // or AnyPolicy. | |
| 351 for (size_t i = 0; i < os_cert_chain.size() - 1; ++i) { | |
| 352 std::string der_cert; | |
| 353 if (!X509Certificate::GetDEREncoded(os_cert_chain[i], &der_cert)) | |
| 354 return false; | |
| 355 scoped_refptr<ParsedCertificate> intermediate_cert( | |
| 356 ParsedCertificate::Create(der_cert, {}, nullptr)); | |
| 357 if (!intermediate_cert) | |
| 358 return false; | |
| 359 if (!HasPolicyOrAnyPolicy(intermediate_cert.get(), ev_policy_oid)) | |
| 360 return false; | |
| 361 } | |
| 362 | |
| 363 // Root should have matching policy in EVRootCAMetadata. | |
| 364 std::string der_cert; | |
| 365 if (!X509Certificate::GetDEREncoded(os_cert_chain.back(), &der_cert)) | |
| 366 return false; | |
| 367 SHA1HashValue weak_fingerprint; | |
| 368 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(der_cert.data()), | |
| 369 der_cert.size(), weak_fingerprint.data); | |
| 370 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); | |
| 371 return metadata->HasEVPolicyOID(weak_fingerprint, ev_policy_oid); | |
|
Ryan Sleevi
2016/11/08 23:54:09
It seems like this check would be faster/a quicker
mattm
2016/11/10 05:40:40
Done.
| |
| 372 } | |
| 373 | |
| 275 void AppendPublicKeyHashes(CFArrayRef chain, | 374 void AppendPublicKeyHashes(CFArrayRef chain, |
| 276 HashValueVector* hashes) { | 375 HashValueVector* hashes) { |
| 277 const CFIndex n = CFArrayGetCount(chain); | 376 const CFIndex n = CFArrayGetCount(chain); |
| 278 for (CFIndex i = 0; i < n; i++) { | 377 for (CFIndex i = 0; i < n; i++) { |
| 279 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( | 378 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( |
| 280 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); | 379 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); |
| 281 | 380 |
| 282 CSSM_DATA cert_data; | 381 CSSM_DATA cert_data; |
| 283 OSStatus err = SecCertificateGetData(cert, &cert_data); | 382 OSStatus err = SecCertificateGetData(cert, &cert_data); |
| 284 DCHECK_EQ(err, noErr); | 383 DCHECK_EQ(err, noErr); |
| 285 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), | 384 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), |
| 286 cert_data.Length); | 385 cert_data.Length); |
| 287 base::StringPiece spki_bytes; | 386 base::StringPiece spki_bytes; |
| 288 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | 387 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) |
| 289 continue; | 388 continue; |
| 290 | 389 |
| 291 HashValue sha1(HASH_VALUE_SHA1); | 390 HashValue sha1(HASH_VALUE_SHA1); |
| 292 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); | 391 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); |
| 293 hashes->push_back(sha1); | 392 hashes->push_back(sha1); |
| 294 | 393 |
| 295 HashValue sha256(HASH_VALUE_SHA256); | 394 HashValue sha256(HASH_VALUE_SHA256); |
| 296 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); | 395 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); |
| 297 hashes->push_back(sha256); | 396 hashes->push_back(sha256); |
| 298 } | 397 } |
| 299 } | 398 } |
| 300 | 399 |
| 301 bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) { | 400 enum CRLSetResult { |
| 401 kCRLSetOk, | |
| 402 kCRLSetRevoked, | |
| 403 kCRLSetUnknown, | |
| 404 }; | |
| 405 | |
| 406 // CheckRevocationWithCRLSet attempts to check each element of |cert_list| | |
| 407 // against |crl_set|. It returns: | |
| 408 // kCRLSetRevoked: if any element of the chain is known to have been revoked. | |
| 409 // kCRLSetUnknown: if there is no fresh information about the leaf | |
| 410 // certificate in the chain or if the CRLSet has expired. | |
| 411 // | |
| 412 // Only the leaf certificate is considered for coverage because some | |
| 413 // intermediates have CRLs with no revocations (after filtering) and | |
| 414 // those CRLs are pruned from the CRLSet at generation time. This means | |
| 415 // that some EV sites would otherwise take the hit of an OCSP lookup for | |
| 416 // no reason. | |
| 417 // kCRLSetOk: otherwise. | |
| 418 CRLSetResult CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) { | |
| 302 if (CFArrayGetCount(chain) == 0) | 419 if (CFArrayGetCount(chain) == 0) |
| 303 return true; | 420 return kCRLSetOk; |
| 421 | |
| 422 // error is set to true if any errors are found. It causes such chains to be | |
| 423 // considered as not covered. | |
| 424 bool error = false; | |
| 425 // last_covered is set to the coverage state of the previous certificate. The | |
| 426 // certificates are iterated over backwards thus, after the iteration, | |
| 427 // |last_covered| contains the coverage state of the leaf certificate. | |
|
Ryan Sleevi
2016/11/08 23:54:09
Inconsistency with respect to || vs no ||. I'd dro
mattm
2016/11/10 05:40:41
Done.
| |
| 428 bool last_covered = false; | |
| 304 | 429 |
| 305 // We iterate from the root certificate down to the leaf, keeping track of | 430 // We iterate from the root certificate down to the leaf, keeping track of |
| 306 // the issuer's SPKI at each step. | 431 // the issuer's SPKI at each step. |
| 307 std::string issuer_spki_hash; | 432 std::string issuer_spki_hash; |
| 308 for (CFIndex i = CFArrayGetCount(chain) - 1; i >= 0; i--) { | 433 for (CFIndex i = CFArrayGetCount(chain) - 1; i >= 0; i--) { |
| 309 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( | 434 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( |
| 310 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); | 435 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); |
| 311 | 436 |
| 312 CSSM_DATA cert_data; | 437 CSSM_DATA cert_data; |
| 313 OSStatus err = SecCertificateGetData(cert, &cert_data); | 438 OSStatus err = SecCertificateGetData(cert, &cert_data); |
| 314 if (err != noErr) { | 439 if (err != noErr) { |
| 315 NOTREACHED(); | 440 NOTREACHED(); |
| 441 error = true; | |
| 316 continue; | 442 continue; |
| 317 } | 443 } |
| 318 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), | 444 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), |
| 319 cert_data.Length); | 445 cert_data.Length); |
| 320 base::StringPiece spki; | 446 base::StringPiece spki; |
| 321 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) { | 447 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) { |
| 322 NOTREACHED(); | 448 NOTREACHED(); |
| 449 error = true; | |
| 323 continue; | 450 continue; |
| 324 } | 451 } |
| 325 | 452 |
| 326 const std::string spki_hash = crypto::SHA256HashString(spki); | 453 const std::string spki_hash = crypto::SHA256HashString(spki); |
| 327 x509_util::CSSMCachedCertificate cached_cert; | 454 x509_util::CSSMCachedCertificate cached_cert; |
| 328 if (cached_cert.Init(cert) != CSSM_OK) { | 455 if (cached_cert.Init(cert) != CSSM_OK) { |
| 329 NOTREACHED(); | 456 NOTREACHED(); |
| 457 error = true; | |
| 330 continue; | 458 continue; |
| 331 } | 459 } |
| 332 x509_util::CSSMFieldValue serial_number; | 460 x509_util::CSSMFieldValue serial_number; |
| 333 err = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, &serial_number); | 461 err = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, &serial_number); |
| 334 if (err || !serial_number.field()) { | 462 if (err || !serial_number.field()) { |
| 335 NOTREACHED(); | 463 NOTREACHED(); |
| 464 error = true; | |
| 336 continue; | 465 continue; |
| 337 } | 466 } |
| 338 | 467 |
| 339 base::StringPiece serial( | 468 base::StringPiece serial( |
| 340 reinterpret_cast<const char*>(serial_number.field()->Data), | 469 reinterpret_cast<const char*>(serial_number.field()->Data), |
| 341 serial_number.field()->Length); | 470 serial_number.field()->Length); |
| 342 | 471 |
| 343 CRLSet::Result result = crl_set->CheckSPKI(spki_hash); | 472 CRLSet::Result result = crl_set->CheckSPKI(spki_hash); |
| 344 | 473 |
| 345 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) | 474 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) |
| 346 result = crl_set->CheckSerial(serial, issuer_spki_hash); | 475 result = crl_set->CheckSerial(serial, issuer_spki_hash); |
| 347 | 476 |
| 348 issuer_spki_hash = spki_hash; | 477 issuer_spki_hash = spki_hash; |
| 349 | 478 |
| 350 switch (result) { | 479 switch (result) { |
| 351 case CRLSet::REVOKED: | 480 case CRLSet::REVOKED: |
| 352 return false; | 481 return kCRLSetRevoked; |
| 353 case CRLSet::UNKNOWN: | 482 case CRLSet::UNKNOWN: |
| 483 last_covered = false; | |
| 484 continue; | |
| 354 case CRLSet::GOOD: | 485 case CRLSet::GOOD: |
| 486 last_covered = true; | |
| 355 continue; | 487 continue; |
| 356 default: | 488 default: |
| 357 NOTREACHED(); | 489 NOTREACHED(); |
| 358 return false; | 490 error = true; |
| 491 continue; | |
| 359 } | 492 } |
| 360 } | 493 } |
| 361 | 494 |
| 362 return true; | 495 if (error || !last_covered || crl_set->IsExpired()) |
| 496 return kCRLSetUnknown; | |
| 497 return kCRLSetOk; | |
| 363 } | 498 } |
| 364 | 499 |
| 365 // Builds and evaluates a SecTrustRef for the certificate chain contained | 500 // Builds and evaluates a SecTrustRef for the certificate chain contained |
| 366 // in |cert_array|, using the verification policies in |trust_policies|. On | 501 // in |cert_array|, using the verification policies in |trust_policies|. On |
| 367 // success, returns OK, and updates |trust_ref|, |trust_result|, | 502 // success, returns OK, and updates |trust_ref|, |trust_result|, |
| 368 // |verified_chain|, and |chain_info| with the verification results. On | 503 // |verified_chain|, and |chain_info| with the verification results. On |
| 369 // failure, no output parameters are modified. | 504 // failure, no output parameters are modified. |
| 370 // | 505 // |
| 371 // Note: An OK return does not mean that |cert_array| is trusted, merely that | 506 // Note: An OK return does not mean that |cert_array| is trusted, merely that |
| 372 // verification was performed successfully. | 507 // verification was performed successfully. |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 } | 649 } |
| 515 | 650 |
| 516 ~OSXKnownRootHelper() {} | 651 ~OSXKnownRootHelper() {} |
| 517 | 652 |
| 518 std::set<SHA256HashValue, SHA256HashValueLessThan> known_roots_; | 653 std::set<SHA256HashValue, SHA256HashValueLessThan> known_roots_; |
| 519 }; | 654 }; |
| 520 | 655 |
| 521 base::LazyInstance<OSXKnownRootHelper>::Leaky g_known_roots = | 656 base::LazyInstance<OSXKnownRootHelper>::Leaky g_known_roots = |
| 522 LAZY_INSTANCE_INITIALIZER; | 657 LAZY_INSTANCE_INITIALIZER; |
| 523 | 658 |
| 524 } // namespace | 659 // Runs path building & verification loop for |cert|, given |flags|. This is |
| 525 | 660 // split into a separate function so verification can be repeated with different |
| 526 CertVerifyProcMac::CertVerifyProcMac() {} | 661 // flags. This function does not handle EV. |
| 527 | 662 int VerifyWithGivenFlags(X509Certificate* cert, |
| 528 CertVerifyProcMac::~CertVerifyProcMac() {} | 663 const std::string& hostname, |
| 529 | 664 const int flags, |
| 530 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const { | 665 CRLSet* crl_set, |
| 531 return false; | 666 CertVerifyResult* verify_result, |
| 532 } | 667 CRLSetResult* completed_chain_crl_result) { |
| 533 | |
| 534 bool CertVerifyProcMac::SupportsOCSPStapling() const { | |
| 535 // TODO(rsleevi): Plumb an OCSP response into the Mac system library. | |
| 536 // https://crbug.com/430714 | |
| 537 return false; | |
| 538 } | |
| 539 | |
| 540 int CertVerifyProcMac::VerifyInternal( | |
| 541 X509Certificate* cert, | |
| 542 const std::string& hostname, | |
| 543 const std::string& ocsp_response, | |
| 544 int flags, | |
| 545 CRLSet* crl_set, | |
| 546 const CertificateList& additional_trust_anchors, | |
| 547 CertVerifyResult* verify_result) { | |
| 548 ScopedCFTypeRef<CFArrayRef> trust_policies; | 668 ScopedCFTypeRef<CFArrayRef> trust_policies; |
| 549 OSStatus status = CreateTrustPolicies(flags, &trust_policies); | 669 OSStatus status = CreateTrustPolicies(flags, &trust_policies); |
| 550 if (status) | 670 if (status) |
| 551 return NetErrorFromOSStatus(status); | 671 return NetErrorFromOSStatus(status); |
| 552 | 672 |
| 673 *completed_chain_crl_result = kCRLSetUnknown; | |
| 674 | |
| 553 // Serialize all calls that may use the Keychain, to work around various | 675 // Serialize all calls that may use the Keychain, to work around various |
| 554 // issues in OS X 10.6+ with multi-threaded access to Security.framework. | 676 // issues in OS X 10.6+ with multi-threaded access to Security.framework. |
| 555 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 677 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
| 556 | 678 |
| 557 ScopedCFTypeRef<SecTrustRef> trust_ref; | 679 ScopedCFTypeRef<SecTrustRef> trust_ref; |
| 558 SecTrustResultType trust_result = kSecTrustResultDeny; | 680 SecTrustResultType trust_result = kSecTrustResultDeny; |
| 559 ScopedCFTypeRef<CFArrayRef> completed_chain; | 681 ScopedCFTypeRef<CFArrayRef> completed_chain; |
| 560 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; | 682 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; |
| 561 bool candidate_untrusted = true; | 683 bool candidate_untrusted = true; |
| 562 bool candidate_weak = false; | 684 bool candidate_weak = false; |
| 563 bool completed_chain_revoked = false; | |
| 564 | 685 |
| 565 // OS X lacks proper path discovery; it will take the input certs and never | 686 // OS X lacks proper path discovery; it will take the input certs and never |
| 566 // backtrack the graph attempting to discover valid paths. | 687 // backtrack the graph attempting to discover valid paths. |
| 567 // This can create issues in some situations: | 688 // This can create issues in some situations: |
| 568 // - When OS X changes the trust store, there may be a chain | 689 // - When OS X changes the trust store, there may be a chain |
| 569 // A -> B -> C -> D | 690 // A -> B -> C -> D |
| 570 // where OS X trusts D (on some versions) and trusts C (on some versions). | 691 // where OS X trusts D (on some versions) and trusts C (on some versions). |
| 571 // If a server supplies a chain A, B, C (cross-signed by D), then this chain | 692 // If a server supplies a chain A, B, C (cross-signed by D), then this chain |
| 572 // will successfully validate on systems that trust D, but fail for systems | 693 // will successfully validate on systems that trust D, but fail for systems |
| 573 // that trust C. If the server supplies a chain of A -> B, then it forces | 694 // that trust C. If the server supplies a chain of A -> B, then it forces |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 697 // The CRLSet checking is performed inside the loop in the hope that if a | 818 // The CRLSet checking is performed inside the loop in the hope that if a |
| 698 // path is revoked, it's an older path, and the only reason it was built | 819 // path is revoked, it's an older path, and the only reason it was built |
| 699 // is because the server forced it (by supplying an older or less | 820 // is because the server forced it (by supplying an older or less |
| 700 // desirable intermediate) or because the user had installed a | 821 // desirable intermediate) or because the user had installed a |
| 701 // certificate in their Keychain forcing this path. However, this means | 822 // certificate in their Keychain forcing this path. However, this means |
| 702 // its still possible for a CRLSet block of an intermediate to prevent | 823 // its still possible for a CRLSet block of an intermediate to prevent |
| 703 // access, even when there is a 'good' chain. To fully remedy this, a | 824 // access, even when there is a 'good' chain. To fully remedy this, a |
| 704 // solution might be to have CRLSets contain enough knowledge about what | 825 // solution might be to have CRLSets contain enough knowledge about what |
| 705 // the 'desired' path might be, but for the time being, the | 826 // the 'desired' path might be, but for the time being, the |
| 706 // implementation is kept as 'simple' as it can be. | 827 // implementation is kept as 'simple' as it can be. |
| 707 bool revoked = | 828 CRLSetResult crl_result = kCRLSetUnknown; |
| 708 (crl_set && !CheckRevocationWithCRLSet(temp_chain, crl_set)); | 829 if (crl_set) |
| 830 crl_result = CheckRevocationWithCRLSet(temp_chain, crl_set); | |
| 709 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && | 831 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && |
| 710 temp_trust_result != kSecTrustResultProceed) || | 832 temp_trust_result != kSecTrustResultProceed) || |
| 711 revoked; | 833 crl_result == kCRLSetRevoked; |
| 712 bool weak_chain = false; | 834 bool weak_chain = false; |
| 713 if (CFArrayGetCount(temp_chain) == 0) { | 835 if (CFArrayGetCount(temp_chain) == 0) { |
| 714 // If the chain is empty, it cannot be trusted or have recoverable | 836 // If the chain is empty, it cannot be trusted or have recoverable |
| 715 // errors. | 837 // errors. |
| 716 DCHECK(untrusted); | 838 DCHECK(untrusted); |
| 717 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); | 839 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); |
| 718 } else { | 840 } else { |
| 719 CertVerifyResult temp_verify_result; | 841 CertVerifyResult temp_verify_result; |
| 720 bool leaf_is_weak = false; | 842 bool leaf_is_weak = false; |
| 721 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, | 843 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 738 // old chain. | 860 // old chain. |
| 739 // | 861 // |
| 740 // Note: If the leaf certificate itself is weak, then the only | 862 // Note: If the leaf certificate itself is weak, then the only |
| 741 // consideration is whether or not there is a trusted chain. That's | 863 // consideration is whether or not there is a trusted chain. That's |
| 742 // because no amount of path discovery will fix a weak leaf. | 864 // because no amount of path discovery will fix a weak leaf. |
| 743 if (!trust_ref || (!untrusted && (candidate_untrusted || | 865 if (!trust_ref || (!untrusted && (candidate_untrusted || |
| 744 (candidate_weak && !weak_chain)))) { | 866 (candidate_weak && !weak_chain)))) { |
| 745 trust_ref = temp_ref; | 867 trust_ref = temp_ref; |
| 746 trust_result = temp_trust_result; | 868 trust_result = temp_trust_result; |
| 747 completed_chain = temp_chain; | 869 completed_chain = temp_chain; |
| 748 completed_chain_revoked = revoked; | 870 *completed_chain_crl_result = crl_result; |
| 749 chain_info = temp_chain_info; | 871 chain_info = temp_chain_info; |
| 750 | 872 |
| 751 candidate_untrusted = untrusted; | 873 candidate_untrusted = untrusted; |
| 752 candidate_weak = weak_chain; | 874 candidate_weak = weak_chain; |
| 753 } | 875 } |
| 754 // Short-circuit when a current, trusted chain is found. | 876 // Short-circuit when a current, trusted chain is found. |
| 755 if (!untrusted && !weak_chain) | 877 if (!untrusted && !weak_chain) |
| 756 break; | 878 break; |
| 757 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); | 879 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); |
| 758 } | 880 } |
| 759 // Short-circuit when a current, trusted chain is found. | 881 // Short-circuit when a current, trusted chain is found. |
| 760 if (!candidate_untrusted && !candidate_weak) | 882 if (!candidate_untrusted && !candidate_weak) |
| 761 break; | 883 break; |
| 762 } | 884 } |
| 763 | 885 |
| 764 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) | 886 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) |
| 765 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 887 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 766 | 888 |
| 767 if (completed_chain_revoked) | 889 if (*completed_chain_crl_result == kCRLSetRevoked) |
| 768 verify_result->cert_status |= CERT_STATUS_REVOKED; | 890 verify_result->cert_status |= CERT_STATUS_REVOKED; |
| 769 | 891 |
| 770 if (CFArrayGetCount(completed_chain) > 0) { | 892 if (CFArrayGetCount(completed_chain) > 0) { |
| 771 bool leaf_is_weak_unused = false; | 893 bool leaf_is_weak_unused = false; |
| 772 GetCertChainInfo(completed_chain, chain_info, verify_result, | 894 GetCertChainInfo(completed_chain, chain_info, verify_result, |
| 773 &leaf_is_weak_unused); | 895 &leaf_is_weak_unused); |
| 774 } | 896 } |
| 775 | 897 |
| 776 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits | 898 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits |
| 777 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds | 899 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds |
| 778 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping | 900 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping |
| 779 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only | 901 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only |
| 780 // error was due to an unsupported key size. | 902 // error was due to an unsupported key size. |
| 781 bool policy_failed = false; | 903 bool policy_failed = false; |
| 904 bool policy_fail_already_mapped = false; | |
| 782 bool weak_key_or_signature_algorithm = false; | 905 bool weak_key_or_signature_algorithm = false; |
| 783 | 906 |
| 784 // Evaluate the results | 907 // Evaluate the results |
| 785 OSStatus cssm_result; | 908 OSStatus cssm_result; |
| 786 switch (trust_result) { | 909 switch (trust_result) { |
| 787 case kSecTrustResultUnspecified: | 910 case kSecTrustResultUnspecified: |
| 788 case kSecTrustResultProceed: | 911 case kSecTrustResultProceed: |
| 789 // Certificate chain is valid and trusted ("unspecified" indicates that | 912 // Certificate chain is valid and trusted ("unspecified" indicates that |
| 790 // the user has not explicitly set a trust setting) | 913 // the user has not explicitly set a trust setting) |
| 791 break; | 914 break; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 829 // failure, with the status code CSSMERR_TP_INVALID_CERTIFICATE | 952 // failure, with the status code CSSMERR_TP_INVALID_CERTIFICATE |
| 830 // added to the Status Codes. Don't treat this code as an invalid | 953 // added to the Status Codes. Don't treat this code as an invalid |
| 831 // certificate; instead, map it to a weak key. Any truly invalid | 954 // certificate; instead, map it to a weak key. Any truly invalid |
| 832 // certificates will have the major error (cssm_result) set to | 955 // certificates will have the major error (cssm_result) set to |
| 833 // CSSMERR_TP_INVALID_CERTIFICATE, rather than | 956 // CSSMERR_TP_INVALID_CERTIFICATE, rather than |
| 834 // CSSMERR_TP_VERIFY_ACTION_FAILED. | 957 // CSSMERR_TP_VERIFY_ACTION_FAILED. |
| 835 CertStatus mapped_status = 0; | 958 CertStatus mapped_status = 0; |
| 836 if (policy_failed && | 959 if (policy_failed && |
| 837 chain_info[index].StatusCodes[status_code_index] == | 960 chain_info[index].StatusCodes[status_code_index] == |
| 838 CSSMERR_TP_INVALID_CERTIFICATE) { | 961 CSSMERR_TP_INVALID_CERTIFICATE) { |
| 839 mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; | 962 mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; |
| 963 weak_key_or_signature_algorithm = true; | |
| 964 policy_fail_already_mapped = true; | |
| 965 } else if (policy_failed && | |
| 966 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) && | |
| 967 chain_info[index].StatusCodes[status_code_index] == | |
| 968 CSSMERR_TP_VERIFY_ACTION_FAILED && | |
| 969 base::mac::IsAtLeastOS10_12()) { | |
| 970 // On 10.12, using kSecRevocationRequirePositiveResponse flag | |
| 971 // causes a CSSMERR_TP_VERIFY_ACTION_FAILED status if revocation | |
| 972 // couldn't be checked. (Note: even if the cert had no | |
| 973 // crlDistributionPoints or OCSP AIA.) | |
| 974 mapped_status = CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 975 policy_fail_already_mapped = true; | |
| 976 } else { | |
| 977 mapped_status = CertStatusFromOSStatus( | |
| 978 chain_info[index].StatusCodes[status_code_index]); | |
| 979 if (mapped_status == CERT_STATUS_WEAK_KEY) { | |
| 840 weak_key_or_signature_algorithm = true; | 980 weak_key_or_signature_algorithm = true; |
| 841 } else { | 981 policy_fail_already_mapped = true; |
| 842 mapped_status = CertStatusFromOSStatus( | 982 } |
| 843 chain_info[index].StatusCodes[status_code_index]); | |
| 844 if (mapped_status == CERT_STATUS_WEAK_KEY) | |
| 845 weak_key_or_signature_algorithm = true; | |
| 846 } | 983 } |
| 847 verify_result->cert_status |= mapped_status; | 984 verify_result->cert_status |= mapped_status; |
| 848 } | 985 } |
| 849 } | 986 } |
| 850 if (policy_failed && !weak_key_or_signature_algorithm) { | 987 if (policy_failed && !policy_fail_already_mapped) { |
| 851 // If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak | 988 // If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak |
| 852 // key, map it back to an appropriate error code. | 989 // key or problem checking revocation, map it back to an appropriate |
| 990 // error code. | |
| 853 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | 991 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); |
| 854 } | 992 } |
| 855 if (!IsCertStatusError(verify_result->cert_status)) { | 993 if (!IsCertStatusError(verify_result->cert_status)) { |
| 856 LOG(ERROR) << "cssm_result=" << cssm_result; | 994 LOG(ERROR) << "cssm_result=" << cssm_result; |
| 857 verify_result->cert_status |= CERT_STATUS_INVALID; | 995 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 858 NOTREACHED(); | 996 NOTREACHED(); |
| 859 } | 997 } |
| 860 break; | 998 break; |
| 861 | 999 |
| 862 default: | 1000 default: |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 884 // compatible with WinHTTP, which doesn't report this error (bug 3004). | 1022 // compatible with WinHTTP, which doesn't report this error (bug 3004). |
| 885 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; | 1023 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; |
| 886 | 1024 |
| 887 AppendPublicKeyHashes(completed_chain, &verify_result->public_key_hashes); | 1025 AppendPublicKeyHashes(completed_chain, &verify_result->public_key_hashes); |
| 888 verify_result->is_issued_by_known_root = | 1026 verify_result->is_issued_by_known_root = |
| 889 g_known_roots.Get().IsIssuedByKnownRoot(completed_chain); | 1027 g_known_roots.Get().IsIssuedByKnownRoot(completed_chain); |
| 890 | 1028 |
| 891 if (IsCertStatusError(verify_result->cert_status)) | 1029 if (IsCertStatusError(verify_result->cert_status)) |
| 892 return MapCertStatusToNetError(verify_result->cert_status); | 1030 return MapCertStatusToNetError(verify_result->cert_status); |
| 893 | 1031 |
| 894 if (flags & CertVerifier::VERIFY_EV_CERT) { | 1032 return OK; |
| 895 // Determine the certificate's EV status using SecTrustCopyExtendedResult(), | 1033 } |
| 896 // which is an internal/private API function added in OS X 10.5.7. | 1034 |
| 897 // Note: "ExtendedResult" means extended validation results. | 1035 } // namespace |
| 898 CFBundleRef bundle = | 1036 |
| 899 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); | 1037 CertVerifyProcMac::CertVerifyProcMac() {} |
| 900 if (bundle) { | 1038 |
| 901 SecTrustCopyExtendedResultFuncPtr copy_extended_result = | 1039 CertVerifyProcMac::~CertVerifyProcMac() {} |
| 902 reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>( | 1040 |
| 903 CFBundleGetFunctionPointerForName(bundle, | 1041 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const { |
| 904 CFSTR("SecTrustCopyExtendedResult"))); | 1042 return false; |
| 905 if (copy_extended_result) { | 1043 } |
| 906 CFDictionaryRef ev_dict_temp = NULL; | 1044 |
| 907 status = copy_extended_result(trust_ref, &ev_dict_temp); | 1045 bool CertVerifyProcMac::SupportsOCSPStapling() const { |
| 908 ScopedCFTypeRef<CFDictionaryRef> ev_dict(ev_dict_temp); | 1046 // TODO(rsleevi): Plumb an OCSP response into the Mac system library. |
| 909 ev_dict_temp = NULL; | 1047 // https://crbug.com/430714 |
| 910 if (status == noErr && ev_dict) { | 1048 return false; |
| 911 // In 10.7.3, SecTrustCopyExtendedResult returns noErr and populates | 1049 } |
| 912 // ev_dict even for non-EV certificates, but only EV certificates | 1050 |
| 913 // will cause ev_dict to contain kSecEVOrganizationName. In previous | 1051 int CertVerifyProcMac::VerifyInternal( |
| 914 // releases, SecTrustCopyExtendedResult would only return noErr and | 1052 X509Certificate* cert, |
| 915 // populate ev_dict for EV certificates, but would always include | 1053 const std::string& hostname, |
| 916 // kSecEVOrganizationName in that case, so checking for this key is | 1054 const std::string& ocsp_response, |
| 917 // appropriate for all known versions of SecTrustCopyExtendedResult. | 1055 int flags, |
| 918 // The actual organization name is unneeded here and can be accessed | 1056 CRLSet* crl_set, |
| 919 // through other means. All that matters here is the OS' conception | 1057 const CertificateList& additional_trust_anchors, |
| 920 // of whether or not the certificate is EV. | 1058 CertVerifyResult* verify_result) { |
| 921 if (CFDictionaryContainsKey(ev_dict, | 1059 // Save the input state of |*verify_result|, which may be needed to re-do |
| 922 kSecEVOrganizationName)) { | 1060 // verification with different flags. |
| 923 verify_result->cert_status |= CERT_STATUS_IS_EV; | 1061 const CertVerifyResult input_verify_result(*verify_result); |
| 924 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) | 1062 |
| 925 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 1063 // If EV verification is enabled, check for EV policy in leaf cert. |
| 926 } | 1064 std::string candidate_ev_policy_oid; |
| 927 } | 1065 if (flags & CertVerifier::VERIFY_EV_CERT) |
| 928 } | 1066 GetCandidateEVPolicy(cert, &candidate_ev_policy_oid); |
| 1067 | |
| 1068 CRLSetResult completed_chain_crl_result; | |
| 1069 int rv = VerifyWithGivenFlags(cert, hostname, flags, crl_set, verify_result, | |
| 1070 &completed_chain_crl_result); | |
| 1071 if (rv != OK) | |
| 1072 return rv; | |
| 1073 | |
| 1074 if (!candidate_ev_policy_oid.empty() && | |
| 1075 CheckCertChainEV(verify_result->verified_cert.get(), | |
| 1076 candidate_ev_policy_oid)) { | |
| 1077 // EV policies check out and the verification succeeded. See if revocation | |
| 1078 // checking still needs to be done before it can be marked as EV. | |
| 1079 if (completed_chain_crl_result == kCRLSetUnknown && | |
| 1080 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) && | |
| 1081 !(flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)) { | |
| 1082 // If this is an EV cert and it wasn't covered by CRLSets and revocation | |
| 1083 // checking wasn't already on, try again with revocation forced on. | |
| 1084 // | |
| 1085 // Restore the input state of |*verify_result|, so that the | |
| 1086 // re-verification starts with a clean slate. | |
| 1087 *verify_result = input_verify_result; | |
| 1088 int tmp_rv = VerifyWithGivenFlags( | |
| 1089 verify_result->verified_cert.get(), hostname, | |
| 1090 flags | CertVerifier::VERIFY_REV_CHECKING_ENABLED, crl_set, | |
| 1091 verify_result, &completed_chain_crl_result); | |
| 1092 // If re-verification failed, return those results without setting EV | |
| 1093 // status. | |
| 1094 if (tmp_rv != OK) | |
| 1095 return tmp_rv; | |
| 1096 // Otherwise, fall through and add the EV status flag. | |
| 929 } | 1097 } |
| 1098 // EV cert and it was covered by CRLSets or revocation checking passed. | |
| 1099 verify_result->cert_status |= CERT_STATUS_IS_EV; | |
| 930 } | 1100 } |
| 931 | 1101 |
| 932 return OK; | 1102 return OK; |
| 933 } | 1103 } |
| 934 | 1104 |
| 935 } // namespace net | 1105 } // namespace net |
| 936 | 1106 |
| 937 #pragma clang diagnostic pop // "-Wdeprecated-declarations" | 1107 #pragma clang diagnostic pop // "-Wdeprecated-declarations" |
| OLD | NEW |