Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: net/cert/cert_verify_proc_mac.cc

Issue 2499083003: Mac EV verification using Chrome methods rather than OS methods. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/certificate_viewer_mac.mm ('k') | net/cert/cert_verify_proc_nss.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
294 std::vector<der::Input> policies;
295 if (!ParseCertificatePoliciesExtension(extension_value, &policies))
296 return false;
297
298 for (const der::Input& policy_oid : policies) {
299 if (policy_oid == ev_policy_oid || policy_oid == AnyPolicy())
300 return true;
301 }
302 return false;
303 }
304
305 // Looks for known EV policy OIDs in |cert_input|, if one is found it will be
306 // stored in |*ev_policy_oid| as a DER-encoded OID value (no tag or length).
307 void GetCandidateEVPolicy(const X509Certificate* cert_input,
308 std::string* ev_policy_oid) {
309 ev_policy_oid->clear();
310
311 std::string der_cert;
312 if (!X509Certificate::GetDEREncoded(cert_input->os_cert_handle(),
313 &der_cert)) {
314 return;
315 }
316
317 scoped_refptr<ParsedCertificate> cert(
318 ParsedCertificate::Create(der_cert, {}, nullptr));
319 if (!cert)
320 return;
321
322 der::Input extension_value;
323 if (!GetExtensionValue(cert->unparsed_extensions(), CertificatePoliciesOid(),
324 &extension_value)) {
325 return;
326 }
327
328 std::vector<der::Input> policies;
329 if (!ParseCertificatePoliciesExtension(extension_value, &policies))
330 return;
331
332 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
333 for (const der::Input& policy_oid : policies) {
334 if (metadata->IsEVPolicyOID(policy_oid)) {
335 *ev_policy_oid = policy_oid.AsString();
336 return;
337 }
338 }
339 }
340
341 // Checks that the certificate chain of |cert| has policies consistent with
342 // |ev_policy_oid_string|. The leaf is not checked, as it is assumed that is
343 // where the policy came from.
344 bool CheckCertChainEV(const X509Certificate* cert,
345 const std::string& ev_policy_oid_string) {
346 der::Input ev_policy_oid(&ev_policy_oid_string);
347 X509Certificate::OSCertHandles os_cert_chain =
348 cert->GetIntermediateCertificates();
349
350 // Root should have matching policy in EVRootCAMetadata.
351 std::string der_cert;
352 if (!X509Certificate::GetDEREncoded(os_cert_chain.back(), &der_cert))
353 return false;
354 SHA1HashValue weak_fingerprint;
355 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(der_cert.data()),
356 der_cert.size(), weak_fingerprint.data);
357 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
358 if (!metadata->HasEVPolicyOID(weak_fingerprint, ev_policy_oid))
359 return false;
360
361 // Intermediates should have Certificate Policies extension with the EV policy
362 // or AnyPolicy.
363 for (size_t i = 0; i < os_cert_chain.size() - 1; ++i) {
364 std::string der_cert;
365 if (!X509Certificate::GetDEREncoded(os_cert_chain[i], &der_cert))
366 return false;
367 scoped_refptr<ParsedCertificate> intermediate_cert(
368 ParsedCertificate::Create(der_cert, {}, nullptr));
369 if (!intermediate_cert)
370 return false;
371 if (!HasPolicyOrAnyPolicy(intermediate_cert.get(), ev_policy_oid))
372 return false;
373 }
374
375 return true;
376 }
377
275 void AppendPublicKeyHashes(CFArrayRef chain, 378 void AppendPublicKeyHashes(CFArrayRef chain,
276 HashValueVector* hashes) { 379 HashValueVector* hashes) {
277 const CFIndex n = CFArrayGetCount(chain); 380 const CFIndex n = CFArrayGetCount(chain);
278 for (CFIndex i = 0; i < n; i++) { 381 for (CFIndex i = 0; i < n; i++) {
279 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( 382 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
280 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); 383 const_cast<void*>(CFArrayGetValueAtIndex(chain, i)));
281 384
282 CSSM_DATA cert_data; 385 CSSM_DATA cert_data;
283 OSStatus err = SecCertificateGetData(cert, &cert_data); 386 OSStatus err = SecCertificateGetData(cert, &cert_data);
284 DCHECK_EQ(err, noErr); 387 DCHECK_EQ(err, noErr);
285 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), 388 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data),
286 cert_data.Length); 389 cert_data.Length);
287 base::StringPiece spki_bytes; 390 base::StringPiece spki_bytes;
288 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) 391 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
289 continue; 392 continue;
290 393
291 HashValue sha1(HASH_VALUE_SHA1); 394 HashValue sha1(HASH_VALUE_SHA1);
292 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); 395 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data());
293 hashes->push_back(sha1); 396 hashes->push_back(sha1);
294 397
295 HashValue sha256(HASH_VALUE_SHA256); 398 HashValue sha256(HASH_VALUE_SHA256);
296 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); 399 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data());
297 hashes->push_back(sha256); 400 hashes->push_back(sha256);
298 } 401 }
299 } 402 }
300 403
301 bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) { 404 enum CRLSetResult {
405 kCRLSetOk,
406 kCRLSetRevoked,
407 kCRLSetUnknown,
408 };
409
410 // CheckRevocationWithCRLSet attempts to check each element of |cert_list|
411 // against |crl_set|. It returns:
412 // kCRLSetRevoked: if any element of the chain is known to have been revoked.
413 // kCRLSetUnknown: if there is no fresh information about the leaf
414 // certificate in the chain or if the CRLSet has expired.
415 //
416 // Only the leaf certificate is considered for coverage because some
417 // intermediates have CRLs with no revocations (after filtering) and
418 // those CRLs are pruned from the CRLSet at generation time. This means
419 // that some EV sites would otherwise take the hit of an OCSP lookup for
420 // no reason.
421 // kCRLSetOk: otherwise.
422 CRLSetResult CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
302 if (CFArrayGetCount(chain) == 0) 423 if (CFArrayGetCount(chain) == 0)
303 return true; 424 return kCRLSetOk;
425
426 // error is set to true if any errors are found. It causes such chains to be
427 // considered as not covered.
428 bool error = false;
429 // last_covered is set to the coverage state of the previous certificate. The
430 // certificates are iterated over backwards thus, after the iteration,
431 // |last_covered| contains the coverage state of the leaf certificate.
432 bool last_covered = false;
304 433
305 // We iterate from the root certificate down to the leaf, keeping track of 434 // We iterate from the root certificate down to the leaf, keeping track of
306 // the issuer's SPKI at each step. 435 // the issuer's SPKI at each step.
307 std::string issuer_spki_hash; 436 std::string issuer_spki_hash;
308 for (CFIndex i = CFArrayGetCount(chain) - 1; i >= 0; i--) { 437 for (CFIndex i = CFArrayGetCount(chain) - 1; i >= 0; i--) {
309 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( 438 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
310 const_cast<void*>(CFArrayGetValueAtIndex(chain, i))); 439 const_cast<void*>(CFArrayGetValueAtIndex(chain, i)));
311 440
312 CSSM_DATA cert_data; 441 CSSM_DATA cert_data;
313 OSStatus err = SecCertificateGetData(cert, &cert_data); 442 OSStatus err = SecCertificateGetData(cert, &cert_data);
314 if (err != noErr) { 443 if (err != noErr) {
315 NOTREACHED(); 444 NOTREACHED();
445 error = true;
316 continue; 446 continue;
317 } 447 }
318 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data), 448 base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data),
319 cert_data.Length); 449 cert_data.Length);
320 base::StringPiece spki; 450 base::StringPiece spki;
321 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) { 451 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) {
322 NOTREACHED(); 452 NOTREACHED();
453 error = true;
323 continue; 454 continue;
324 } 455 }
325 456
326 const std::string spki_hash = crypto::SHA256HashString(spki); 457 const std::string spki_hash = crypto::SHA256HashString(spki);
327 x509_util::CSSMCachedCertificate cached_cert; 458 x509_util::CSSMCachedCertificate cached_cert;
328 if (cached_cert.Init(cert) != CSSM_OK) { 459 if (cached_cert.Init(cert) != CSSM_OK) {
329 NOTREACHED(); 460 NOTREACHED();
461 error = true;
330 continue; 462 continue;
331 } 463 }
332 x509_util::CSSMFieldValue serial_number; 464 x509_util::CSSMFieldValue serial_number;
333 err = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, &serial_number); 465 err = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, &serial_number);
334 if (err || !serial_number.field()) { 466 if (err || !serial_number.field()) {
335 NOTREACHED(); 467 NOTREACHED();
468 error = true;
336 continue; 469 continue;
337 } 470 }
338 471
339 base::StringPiece serial( 472 base::StringPiece serial(
340 reinterpret_cast<const char*>(serial_number.field()->Data), 473 reinterpret_cast<const char*>(serial_number.field()->Data),
341 serial_number.field()->Length); 474 serial_number.field()->Length);
342 475
343 CRLSet::Result result = crl_set->CheckSPKI(spki_hash); 476 CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
344 477
345 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) 478 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
346 result = crl_set->CheckSerial(serial, issuer_spki_hash); 479 result = crl_set->CheckSerial(serial, issuer_spki_hash);
347 480
348 issuer_spki_hash = spki_hash; 481 issuer_spki_hash = spki_hash;
349 482
350 switch (result) { 483 switch (result) {
351 case CRLSet::REVOKED: 484 case CRLSet::REVOKED:
352 return false; 485 return kCRLSetRevoked;
353 case CRLSet::UNKNOWN: 486 case CRLSet::UNKNOWN:
487 last_covered = false;
488 continue;
354 case CRLSet::GOOD: 489 case CRLSet::GOOD:
490 last_covered = true;
355 continue; 491 continue;
356 default: 492 default:
357 NOTREACHED(); 493 NOTREACHED();
358 return false; 494 error = true;
495 continue;
359 } 496 }
360 } 497 }
361 498
362 return true; 499 if (error || !last_covered || crl_set->IsExpired())
500 return kCRLSetUnknown;
501 return kCRLSetOk;
363 } 502 }
364 503
365 // Builds and evaluates a SecTrustRef for the certificate chain contained 504 // Builds and evaluates a SecTrustRef for the certificate chain contained
366 // in |cert_array|, using the verification policies in |trust_policies|. On 505 // in |cert_array|, using the verification policies in |trust_policies|. On
367 // success, returns OK, and updates |trust_ref|, |trust_result|, 506 // success, returns OK, and updates |trust_ref|, |trust_result|,
368 // |verified_chain|, and |chain_info| with the verification results. On 507 // |verified_chain|, and |chain_info| with the verification results. On
369 // failure, no output parameters are modified. 508 // failure, no output parameters are modified.
370 // 509 //
371 // Note: An OK return does not mean that |cert_array| is trusted, merely that 510 // Note: An OK return does not mean that |cert_array| is trusted, merely that
372 // verification was performed successfully. 511 // verification was performed successfully.
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 } 653 }
515 654
516 ~OSXKnownRootHelper() {} 655 ~OSXKnownRootHelper() {}
517 656
518 std::set<SHA256HashValue, SHA256HashValueLessThan> known_roots_; 657 std::set<SHA256HashValue, SHA256HashValueLessThan> known_roots_;
519 }; 658 };
520 659
521 base::LazyInstance<OSXKnownRootHelper>::Leaky g_known_roots = 660 base::LazyInstance<OSXKnownRootHelper>::Leaky g_known_roots =
522 LAZY_INSTANCE_INITIALIZER; 661 LAZY_INSTANCE_INITIALIZER;
523 662
524 } // namespace 663 // Runs path building & verification loop for |cert|, given |flags|. This is
525 664 // split into a separate function so verification can be repeated with different
526 CertVerifyProcMac::CertVerifyProcMac() {} 665 // flags. This function does not handle EV.
527 666 int VerifyWithGivenFlags(X509Certificate* cert,
528 CertVerifyProcMac::~CertVerifyProcMac() {} 667 const std::string& hostname,
529 668 const int flags,
530 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const { 669 CRLSet* crl_set,
531 return false; 670 CertVerifyResult* verify_result,
532 } 671 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; 672 ScopedCFTypeRef<CFArrayRef> trust_policies;
549 OSStatus status = CreateTrustPolicies(flags, &trust_policies); 673 OSStatus status = CreateTrustPolicies(flags, &trust_policies);
550 if (status) 674 if (status)
551 return NetErrorFromOSStatus(status); 675 return NetErrorFromOSStatus(status);
552 676
677 *completed_chain_crl_result = kCRLSetUnknown;
678
553 // Serialize all calls that may use the Keychain, to work around various 679 // 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. 680 // issues in OS X 10.6+ with multi-threaded access to Security.framework.
555 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 681 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
556 682
557 ScopedCFTypeRef<SecTrustRef> trust_ref; 683 ScopedCFTypeRef<SecTrustRef> trust_ref;
558 SecTrustResultType trust_result = kSecTrustResultDeny; 684 SecTrustResultType trust_result = kSecTrustResultDeny;
559 ScopedCFTypeRef<CFArrayRef> completed_chain; 685 ScopedCFTypeRef<CFArrayRef> completed_chain;
560 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; 686 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL;
561 bool candidate_untrusted = true; 687 bool candidate_untrusted = true;
562 bool candidate_weak = false; 688 bool candidate_weak = false;
563 bool completed_chain_revoked = false;
564 689
565 // OS X lacks proper path discovery; it will take the input certs and never 690 // OS X lacks proper path discovery; it will take the input certs and never
566 // backtrack the graph attempting to discover valid paths. 691 // backtrack the graph attempting to discover valid paths.
567 // This can create issues in some situations: 692 // This can create issues in some situations:
568 // - When OS X changes the trust store, there may be a chain 693 // - When OS X changes the trust store, there may be a chain
569 // A -> B -> C -> D 694 // A -> B -> C -> D
570 // where OS X trusts D (on some versions) and trusts C (on some versions). 695 // 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 696 // 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 697 // 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 698 // 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
697 // The CRLSet checking is performed inside the loop in the hope that if a 822 // 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 823 // 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 824 // is because the server forced it (by supplying an older or less
700 // desirable intermediate) or because the user had installed a 825 // desirable intermediate) or because the user had installed a
701 // certificate in their Keychain forcing this path. However, this means 826 // certificate in their Keychain forcing this path. However, this means
702 // its still possible for a CRLSet block of an intermediate to prevent 827 // 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 828 // 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 829 // solution might be to have CRLSets contain enough knowledge about what
705 // the 'desired' path might be, but for the time being, the 830 // the 'desired' path might be, but for the time being, the
706 // implementation is kept as 'simple' as it can be. 831 // implementation is kept as 'simple' as it can be.
707 bool revoked = 832 CRLSetResult crl_result = kCRLSetUnknown;
708 (crl_set && !CheckRevocationWithCRLSet(temp_chain, crl_set)); 833 if (crl_set)
834 crl_result = CheckRevocationWithCRLSet(temp_chain, crl_set);
709 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && 835 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified &&
710 temp_trust_result != kSecTrustResultProceed) || 836 temp_trust_result != kSecTrustResultProceed) ||
711 revoked; 837 crl_result == kCRLSetRevoked;
712 bool weak_chain = false; 838 bool weak_chain = false;
713 if (CFArrayGetCount(temp_chain) == 0) { 839 if (CFArrayGetCount(temp_chain) == 0) {
714 // If the chain is empty, it cannot be trusted or have recoverable 840 // If the chain is empty, it cannot be trusted or have recoverable
715 // errors. 841 // errors.
716 DCHECK(untrusted); 842 DCHECK(untrusted);
717 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); 843 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result);
718 } else { 844 } else {
719 CertVerifyResult temp_verify_result; 845 CertVerifyResult temp_verify_result;
720 bool leaf_is_weak = false; 846 bool leaf_is_weak = false;
721 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, 847 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result,
(...skipping 16 matching lines...) Expand all
738 // old chain. 864 // old chain.
739 // 865 //
740 // Note: If the leaf certificate itself is weak, then the only 866 // Note: If the leaf certificate itself is weak, then the only
741 // consideration is whether or not there is a trusted chain. That's 867 // consideration is whether or not there is a trusted chain. That's
742 // because no amount of path discovery will fix a weak leaf. 868 // because no amount of path discovery will fix a weak leaf.
743 if (!trust_ref || (!untrusted && (candidate_untrusted || 869 if (!trust_ref || (!untrusted && (candidate_untrusted ||
744 (candidate_weak && !weak_chain)))) { 870 (candidate_weak && !weak_chain)))) {
745 trust_ref = temp_ref; 871 trust_ref = temp_ref;
746 trust_result = temp_trust_result; 872 trust_result = temp_trust_result;
747 completed_chain = temp_chain; 873 completed_chain = temp_chain;
748 completed_chain_revoked = revoked; 874 *completed_chain_crl_result = crl_result;
749 chain_info = temp_chain_info; 875 chain_info = temp_chain_info;
750 876
751 candidate_untrusted = untrusted; 877 candidate_untrusted = untrusted;
752 candidate_weak = weak_chain; 878 candidate_weak = weak_chain;
753 } 879 }
754 // Short-circuit when a current, trusted chain is found. 880 // Short-circuit when a current, trusted chain is found.
755 if (!untrusted && !weak_chain) 881 if (!untrusted && !weak_chain)
756 break; 882 break;
757 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); 883 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1);
758 } 884 }
759 // Short-circuit when a current, trusted chain is found. 885 // Short-circuit when a current, trusted chain is found.
760 if (!candidate_untrusted && !candidate_weak) 886 if (!candidate_untrusted && !candidate_weak)
761 break; 887 break;
762 } 888 }
763 889
764 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) 890 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)
765 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 891 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
766 892
767 if (completed_chain_revoked) 893 if (*completed_chain_crl_result == kCRLSetRevoked)
768 verify_result->cert_status |= CERT_STATUS_REVOKED; 894 verify_result->cert_status |= CERT_STATUS_REVOKED;
769 895
770 if (CFArrayGetCount(completed_chain) > 0) { 896 if (CFArrayGetCount(completed_chain) > 0) {
771 bool leaf_is_weak_unused = false; 897 bool leaf_is_weak_unused = false;
772 GetCertChainInfo(completed_chain, chain_info, verify_result, 898 GetCertChainInfo(completed_chain, chain_info, verify_result,
773 &leaf_is_weak_unused); 899 &leaf_is_weak_unused);
774 } 900 }
775 901
776 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits 902 // 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 903 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds
778 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping 904 // 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 905 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only
780 // error was due to an unsupported key size. 906 // error was due to an unsupported key size.
781 bool policy_failed = false; 907 bool policy_failed = false;
908 bool policy_fail_already_mapped = false;
782 bool weak_key_or_signature_algorithm = false; 909 bool weak_key_or_signature_algorithm = false;
783 910
784 // Evaluate the results 911 // Evaluate the results
785 OSStatus cssm_result; 912 OSStatus cssm_result;
786 switch (trust_result) { 913 switch (trust_result) {
787 case kSecTrustResultUnspecified: 914 case kSecTrustResultUnspecified:
788 case kSecTrustResultProceed: 915 case kSecTrustResultProceed:
789 // Certificate chain is valid and trusted ("unspecified" indicates that 916 // Certificate chain is valid and trusted ("unspecified" indicates that
790 // the user has not explicitly set a trust setting) 917 // the user has not explicitly set a trust setting)
791 break; 918 break;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 // failure, with the status code CSSMERR_TP_INVALID_CERTIFICATE 956 // failure, with the status code CSSMERR_TP_INVALID_CERTIFICATE
830 // added to the Status Codes. Don't treat this code as an invalid 957 // 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 958 // certificate; instead, map it to a weak key. Any truly invalid
832 // certificates will have the major error (cssm_result) set to 959 // certificates will have the major error (cssm_result) set to
833 // CSSMERR_TP_INVALID_CERTIFICATE, rather than 960 // CSSMERR_TP_INVALID_CERTIFICATE, rather than
834 // CSSMERR_TP_VERIFY_ACTION_FAILED. 961 // CSSMERR_TP_VERIFY_ACTION_FAILED.
835 CertStatus mapped_status = 0; 962 CertStatus mapped_status = 0;
836 if (policy_failed && 963 if (policy_failed &&
837 chain_info[index].StatusCodes[status_code_index] == 964 chain_info[index].StatusCodes[status_code_index] ==
838 CSSMERR_TP_INVALID_CERTIFICATE) { 965 CSSMERR_TP_INVALID_CERTIFICATE) {
839 mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; 966 mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
967 weak_key_or_signature_algorithm = true;
968 policy_fail_already_mapped = true;
969 } else if (policy_failed &&
970 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) &&
971 chain_info[index].StatusCodes[status_code_index] ==
972 CSSMERR_TP_VERIFY_ACTION_FAILED &&
973 base::mac::IsAtLeastOS10_12()) {
974 // On 10.12, using kSecRevocationRequirePositiveResponse flag
975 // causes a CSSMERR_TP_VERIFY_ACTION_FAILED status if revocation
976 // couldn't be checked. (Note: even if the cert had no
977 // crlDistributionPoints or OCSP AIA.)
978 mapped_status = CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
979 policy_fail_already_mapped = true;
980 } else {
981 mapped_status = CertStatusFromOSStatus(
982 chain_info[index].StatusCodes[status_code_index]);
983 if (mapped_status == CERT_STATUS_WEAK_KEY) {
840 weak_key_or_signature_algorithm = true; 984 weak_key_or_signature_algorithm = true;
841 } else { 985 policy_fail_already_mapped = true;
842 mapped_status = CertStatusFromOSStatus( 986 }
843 chain_info[index].StatusCodes[status_code_index]);
844 if (mapped_status == CERT_STATUS_WEAK_KEY)
845 weak_key_or_signature_algorithm = true;
846 } 987 }
847 verify_result->cert_status |= mapped_status; 988 verify_result->cert_status |= mapped_status;
848 } 989 }
849 } 990 }
850 if (policy_failed && !weak_key_or_signature_algorithm) { 991 if (policy_failed && !policy_fail_already_mapped) {
851 // If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak 992 // If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak
852 // key, map it back to an appropriate error code. 993 // key or problem checking revocation, map it back to an appropriate
994 // error code.
853 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); 995 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result);
854 } 996 }
855 if (!IsCertStatusError(verify_result->cert_status)) { 997 if (!IsCertStatusError(verify_result->cert_status)) {
856 LOG(ERROR) << "cssm_result=" << cssm_result; 998 LOG(ERROR) << "cssm_result=" << cssm_result;
857 verify_result->cert_status |= CERT_STATUS_INVALID; 999 verify_result->cert_status |= CERT_STATUS_INVALID;
858 NOTREACHED(); 1000 NOTREACHED();
859 } 1001 }
860 break; 1002 break;
861 1003
862 default: 1004 default:
(...skipping 21 matching lines...) Expand all
884 // compatible with WinHTTP, which doesn't report this error (bug 3004). 1026 // compatible with WinHTTP, which doesn't report this error (bug 3004).
885 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; 1027 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM;
886 1028
887 AppendPublicKeyHashes(completed_chain, &verify_result->public_key_hashes); 1029 AppendPublicKeyHashes(completed_chain, &verify_result->public_key_hashes);
888 verify_result->is_issued_by_known_root = 1030 verify_result->is_issued_by_known_root =
889 g_known_roots.Get().IsIssuedByKnownRoot(completed_chain); 1031 g_known_roots.Get().IsIssuedByKnownRoot(completed_chain);
890 1032
891 if (IsCertStatusError(verify_result->cert_status)) 1033 if (IsCertStatusError(verify_result->cert_status))
892 return MapCertStatusToNetError(verify_result->cert_status); 1034 return MapCertStatusToNetError(verify_result->cert_status);
893 1035
894 if (flags & CertVerifier::VERIFY_EV_CERT) { 1036 return OK;
895 // Determine the certificate's EV status using SecTrustCopyExtendedResult(), 1037 }
896 // which is an internal/private API function added in OS X 10.5.7. 1038
897 // Note: "ExtendedResult" means extended validation results. 1039 } // namespace
898 CFBundleRef bundle = 1040
899 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); 1041 CertVerifyProcMac::CertVerifyProcMac() {}
900 if (bundle) { 1042
901 SecTrustCopyExtendedResultFuncPtr copy_extended_result = 1043 CertVerifyProcMac::~CertVerifyProcMac() {}
902 reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>( 1044
903 CFBundleGetFunctionPointerForName(bundle, 1045 bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const {
904 CFSTR("SecTrustCopyExtendedResult"))); 1046 return false;
905 if (copy_extended_result) { 1047 }
906 CFDictionaryRef ev_dict_temp = NULL; 1048
907 status = copy_extended_result(trust_ref, &ev_dict_temp); 1049 bool CertVerifyProcMac::SupportsOCSPStapling() const {
908 ScopedCFTypeRef<CFDictionaryRef> ev_dict(ev_dict_temp); 1050 // TODO(rsleevi): Plumb an OCSP response into the Mac system library.
909 ev_dict_temp = NULL; 1051 // https://crbug.com/430714
910 if (status == noErr && ev_dict) { 1052 return false;
911 // In 10.7.3, SecTrustCopyExtendedResult returns noErr and populates 1053 }
912 // ev_dict even for non-EV certificates, but only EV certificates 1054
913 // will cause ev_dict to contain kSecEVOrganizationName. In previous 1055 int CertVerifyProcMac::VerifyInternal(
914 // releases, SecTrustCopyExtendedResult would only return noErr and 1056 X509Certificate* cert,
915 // populate ev_dict for EV certificates, but would always include 1057 const std::string& hostname,
916 // kSecEVOrganizationName in that case, so checking for this key is 1058 const std::string& ocsp_response,
917 // appropriate for all known versions of SecTrustCopyExtendedResult. 1059 int flags,
918 // The actual organization name is unneeded here and can be accessed 1060 CRLSet* crl_set,
919 // through other means. All that matters here is the OS' conception 1061 const CertificateList& additional_trust_anchors,
920 // of whether or not the certificate is EV. 1062 CertVerifyResult* verify_result) {
921 if (CFDictionaryContainsKey(ev_dict, 1063 // Save the input state of |*verify_result|, which may be needed to re-do
922 kSecEVOrganizationName)) { 1064 // verification with different flags.
923 verify_result->cert_status |= CERT_STATUS_IS_EV; 1065 const CertVerifyResult input_verify_result(*verify_result);
924 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) 1066
925 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 1067 // If EV verification is enabled, check for EV policy in leaf cert.
926 } 1068 std::string candidate_ev_policy_oid;
927 } 1069 if (flags & CertVerifier::VERIFY_EV_CERT)
928 } 1070 GetCandidateEVPolicy(cert, &candidate_ev_policy_oid);
1071
1072 CRLSetResult completed_chain_crl_result;
1073 int rv = VerifyWithGivenFlags(cert, hostname, flags, crl_set, verify_result,
1074 &completed_chain_crl_result);
1075 if (rv != OK)
1076 return rv;
1077
1078 if (!candidate_ev_policy_oid.empty() &&
1079 CheckCertChainEV(verify_result->verified_cert.get(),
1080 candidate_ev_policy_oid)) {
1081 // EV policies check out and the verification succeeded. See if revocation
1082 // checking still needs to be done before it can be marked as EV.
1083 if (completed_chain_crl_result == kCRLSetUnknown &&
1084 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
1085 !(flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)) {
1086 // If this is an EV cert and it wasn't covered by CRLSets and revocation
1087 // checking wasn't already on, try again with revocation forced on.
1088 //
1089 // Restore the input state of |*verify_result|, so that the
1090 // re-verification starts with a clean slate.
1091 *verify_result = input_verify_result;
1092 int tmp_rv = VerifyWithGivenFlags(
1093 verify_result->verified_cert.get(), hostname,
1094 flags | CertVerifier::VERIFY_REV_CHECKING_ENABLED, crl_set,
1095 verify_result, &completed_chain_crl_result);
1096 // If re-verification failed, return those results without setting EV
1097 // status.
1098 if (tmp_rv != OK)
1099 return tmp_rv;
1100 // Otherwise, fall through and add the EV status flag.
929 } 1101 }
1102 // EV cert and it was covered by CRLSets or revocation checking passed.
1103 verify_result->cert_status |= CERT_STATUS_IS_EV;
930 } 1104 }
931 1105
932 return OK; 1106 return OK;
933 } 1107 }
934 1108
935 } // namespace net 1109 } // namespace net
936 1110
937 #pragma clang diagnostic pop // "-Wdeprecated-declarations" 1111 #pragma clang diagnostic pop // "-Wdeprecated-declarations"
OLDNEW
« no previous file with comments | « chrome/browser/ui/certificate_viewer_mac.mm ('k') | net/cert/cert_verify_proc_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698