| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "chrome/browser/ssl/ssl_manager.h" | 5 #include "chrome/browser/ssl/ssl_manager.h" |
| 6 | 6 |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "chrome/browser/browser_process.h" | 9 #include "chrome/browser/browser_process.h" |
| 10 #include "chrome/browser/load_from_memory_cache_details.h" | 10 #include "chrome/browser/load_from_memory_cache_details.h" |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 // Delegate API method. | 199 // Delegate API method. |
| 200 bool SSLManager::DidMarkHostAsBroken(const std::string& host) const { | 200 bool SSLManager::DidMarkHostAsBroken(const std::string& host) const { |
| 201 return ssl_host_state_->DidMarkHostAsBroken(host); | 201 return ssl_host_state_->DidMarkHostAsBroken(host); |
| 202 } | 202 } |
| 203 | 203 |
| 204 // Delegate API method. | 204 // Delegate API method. |
| 205 void SSLManager::DenyCertForHost(net::X509Certificate* cert, | 205 void SSLManager::DenyCertForHost(net::X509Certificate* cert, |
| 206 const std::string& host) { | 206 const std::string& host) { |
| 207 // Remember that we don't like this cert for this host. | 207 // Remember that we don't like this cert for this host. |
| 208 ssl_host_state_->DenyCertForHost(cert, host); | 208 ssl_host_state_->DenyCertForHost(cert, host); |
| 209 DispatchSSLInternalStateChanged(); | |
| 210 } | 209 } |
| 211 | 210 |
| 212 // Delegate API method. | 211 // Delegate API method. |
| 213 void SSLManager::AllowCertForHost(net::X509Certificate* cert, | 212 void SSLManager::AllowCertForHost(net::X509Certificate* cert, |
| 214 const std::string& host) { | 213 const std::string& host) { |
| 215 ssl_host_state_->AllowCertForHost(cert, host); | 214 ssl_host_state_->AllowCertForHost(cert, host); |
| 216 DispatchSSLInternalStateChanged(); | |
| 217 } | 215 } |
| 218 | 216 |
| 219 // Delegate API method. | 217 // Delegate API method. |
| 220 net::X509Certificate::Policy::Judgment SSLManager::QueryPolicy( | 218 net::X509Certificate::Policy::Judgment SSLManager::QueryPolicy( |
| 221 net::X509Certificate* cert, const std::string& host) { | 219 net::X509Certificate* cert, const std::string& host) { |
| 222 return ssl_host_state_->QueryPolicy(cert, host); | 220 return ssl_host_state_->QueryPolicy(cert, host); |
| 223 } | 221 } |
| 224 | 222 |
| 225 // Delegate API method. | 223 // Delegate API method. |
| 226 void SSLManager::AllowMixedContentForHost(const std::string& host) { | 224 void SSLManager::AllowMixedContentForHost(const std::string& host) { |
| 227 ssl_host_state_->AllowMixedContentForHost(host); | 225 ssl_host_state_->AllowMixedContentForHost(host); |
| 228 DispatchSSLInternalStateChanged(); | |
| 229 } | 226 } |
| 230 | 227 |
| 231 // Delegate API method. | 228 // Delegate API method. |
| 232 bool SSLManager::DidAllowMixedContentForHost(const std::string& host) const { | 229 bool SSLManager::DidAllowMixedContentForHost(const std::string& host) const { |
| 233 return ssl_host_state_->DidAllowMixedContentForHost(host); | 230 return ssl_host_state_->DidAllowMixedContentForHost(host); |
| 234 } | 231 } |
| 235 | 232 |
| 236 bool SSLManager::ProcessedSSLErrorFromRequest() const { | 233 bool SSLManager::ProcessedSSLErrorFromRequest() const { |
| 237 NavigationEntry* entry = controller_->GetActiveEntry(); | 234 NavigationEntry* entry = controller_->GetActiveEntry(); |
| 238 if (!entry) { | 235 if (!entry) { |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 URLRequest* request, | 496 URLRequest* request, |
| 500 MessageLoop* ui_loop) { | 497 MessageLoop* ui_loop) { |
| 501 ResourceDispatcherHost::ExtraRequestInfo* info = | 498 ResourceDispatcherHost::ExtraRequestInfo* info = |
| 502 ResourceDispatcherHost::ExtraInfoForRequest(request); | 499 ResourceDispatcherHost::ExtraInfoForRequest(request); |
| 503 DCHECK(info); | 500 DCHECK(info); |
| 504 | 501 |
| 505 // We cheat here and talk to the SSLPolicy on the IO thread because we need | 502 // We cheat here and talk to the SSLPolicy on the IO thread because we need |
| 506 // to respond synchronously to avoid delaying all network requests... | 503 // to respond synchronously to avoid delaying all network requests... |
| 507 if (!SSLPolicy::IsMixedContent(request->url(), | 504 if (!SSLPolicy::IsMixedContent(request->url(), |
| 508 info->resource_type, | 505 info->resource_type, |
| 509 info->main_frame_origin)) | 506 info->filter_policy, |
| 507 info->frame_origin)) |
| 510 return true; | 508 return true; |
| 511 | 509 |
| 512 | 510 |
| 513 ui_loop->PostTask(FROM_HERE, | 511 ui_loop->PostTask(FROM_HERE, |
| 514 NewRunnableMethod(new MixedContentHandler(rdh, request, | 512 NewRunnableMethod(new MixedContentHandler(rdh, request, |
| 515 info->resource_type, | 513 info->resource_type, |
| 516 info->frame_origin, | 514 info->frame_origin, |
| 517 info->main_frame_origin, | 515 info->main_frame_origin, |
| 518 ui_loop), | 516 ui_loop), |
| 519 &MixedContentHandler::Dispatch)); | 517 &MixedContentHandler::Dispatch)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 NotificationService::NoDetails()); | 564 NotificationService::NoDetails()); |
| 567 } | 565 } |
| 568 | 566 |
| 569 void SSLManager::DispatchSSLVisibleStateChanged() { | 567 void SSLManager::DispatchSSLVisibleStateChanged() { |
| 570 NotificationService::current()->Notify( | 568 NotificationService::current()->Notify( |
| 571 NotificationType::SSL_VISIBLE_STATE_CHANGED, | 569 NotificationType::SSL_VISIBLE_STATE_CHANGED, |
| 572 Source<NavigationController>(controller_), | 570 Source<NavigationController>(controller_), |
| 573 NotificationService::NoDetails()); | 571 NotificationService::NoDetails()); |
| 574 } | 572 } |
| 575 | 573 |
| 576 void SSLManager::InitializeEntryIfNeeded(NavigationEntry* entry) { | 574 void SSLManager::UpdateEntry(NavigationEntry* entry) { |
| 577 DCHECK(entry); | 575 // We don't always have a navigation entry to update, for example in the |
| 576 // case of the Web Inspector. |
| 577 if (!entry) |
| 578 return; |
| 578 | 579 |
| 579 // If the security style of the entry is SECURITY_STYLE_UNKNOWN, then it is a | 580 NavigationEntry::SSLStatus original_ssl_status = entry->ssl(); // Copy! |
| 580 // fresh entry and should get the default style. | |
| 581 if (entry->ssl().security_style() == SECURITY_STYLE_UNKNOWN) { | |
| 582 entry->ssl().set_security_style( | |
| 583 delegate()->GetDefaultStyle(entry->url())); | |
| 584 } | |
| 585 } | |
| 586 | 581 |
| 587 void SSLManager::NavigationStateChanged() { | 582 delegate()->UpdateEntry(this, entry); |
| 588 NavigationEntry* active_entry = controller_->GetActiveEntry(); | |
| 589 if (!active_entry) | |
| 590 return; // Nothing showing yet. | |
| 591 | 583 |
| 592 // This might be a new entry we've never seen before. | 584 if (!entry->ssl().Equals(original_ssl_status)) |
| 593 InitializeEntryIfNeeded(active_entry); | 585 DispatchSSLVisibleStateChanged(); |
| 594 } | 586 } |
| 595 | 587 |
| 596 void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) { | 588 void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) { |
| 597 DCHECK(details); | 589 DCHECK(details); |
| 598 | 590 |
| 599 // Simulate loading this resource through the usual path. | 591 // Simulate loading this resource through the usual path. |
| 600 // Note that we specify SUB_RESOURCE as the resource type as WebCore only | 592 // Note that we specify SUB_RESOURCE as the resource type as WebCore only |
| 601 // caches sub-resources. | 593 // caches sub-resources. |
| 594 // This resource must have been loaded with FilterPolicy::DONT_FILTER because |
| 595 // filtered resouces aren't cachable. |
| 602 scoped_refptr<RequestInfo> info = new RequestInfo( | 596 scoped_refptr<RequestInfo> info = new RequestInfo( |
| 603 this, | 597 this, |
| 604 details->url(), | 598 details->url(), |
| 605 ResourceType::SUB_RESOURCE, | 599 ResourceType::SUB_RESOURCE, |
| 606 details->frame_origin(), | 600 details->frame_origin(), |
| 607 details->main_frame_origin(), | 601 details->main_frame_origin(), |
| 602 FilterPolicy::DONT_FILTER, |
| 608 details->ssl_cert_id(), | 603 details->ssl_cert_id(), |
| 609 details->ssl_cert_status()); | 604 details->ssl_cert_status()); |
| 610 | 605 |
| 611 // Simulate loading this resource through the usual path. | 606 // Simulate loading this resource through the usual path. |
| 612 delegate()->OnRequestStarted(info.get()); | 607 delegate()->OnRequestStarted(info.get()); |
| 613 } | 608 } |
| 614 | 609 |
| 615 void SSLManager::DidCommitProvisionalLoad( | 610 void SSLManager::DidCommitProvisionalLoad( |
| 616 const NotificationDetails& in_details) { | 611 const NotificationDetails& in_details) { |
| 617 NavigationController::LoadCommittedDetails* details = | 612 NavigationController::LoadCommittedDetails* details = |
| 618 Details<NavigationController::LoadCommittedDetails>(in_details).ptr(); | 613 Details<NavigationController::LoadCommittedDetails>(in_details).ptr(); |
| 619 | 614 |
| 620 // Ignore in-page navigations, they should not change the security style or | 615 // Ignore in-page navigations, they should not change the security style or |
| 621 // the info-bars. | 616 // the info-bars. |
| 622 if (details->is_in_page) | 617 if (details->is_in_page) |
| 623 return; | 618 return; |
| 624 | 619 |
| 625 // Decode the security details. | 620 NavigationEntry* entry = controller_->GetActiveEntry(); |
| 626 int ssl_cert_id, ssl_cert_status, ssl_security_bits; | |
| 627 DeserializeSecurityInfo(details->serialized_security_info, | |
| 628 &ssl_cert_id, &ssl_cert_status, &ssl_security_bits); | |
| 629 | 621 |
| 630 bool changed = false; | |
| 631 if (details->is_main_frame) { | 622 if (details->is_main_frame) { |
| 632 // Update the SSL states of the pending entry. | |
| 633 NavigationEntry* entry = controller_->GetActiveEntry(); | |
| 634 if (entry) { | 623 if (entry) { |
| 624 // Decode the security details. |
| 625 int ssl_cert_id, ssl_cert_status, ssl_security_bits; |
| 626 DeserializeSecurityInfo(details->serialized_security_info, |
| 627 &ssl_cert_id, |
| 628 &ssl_cert_status, |
| 629 &ssl_security_bits); |
| 630 |
| 635 // We may not have an entry if this is a navigation to an initial blank | 631 // We may not have an entry if this is a navigation to an initial blank |
| 636 // page. Reset the SSL information and add the new data we have. | 632 // page. Reset the SSL information and add the new data we have. |
| 637 entry->ssl() = NavigationEntry::SSLStatus(); | 633 entry->ssl() = NavigationEntry::SSLStatus(); |
| 638 InitializeEntryIfNeeded(entry); // For security_style. | |
| 639 entry->ssl().set_cert_id(ssl_cert_id); | 634 entry->ssl().set_cert_id(ssl_cert_id); |
| 640 entry->ssl().set_cert_status(ssl_cert_status); | 635 entry->ssl().set_cert_status(ssl_cert_status); |
| 641 entry->ssl().set_security_bits(ssl_security_bits); | 636 entry->ssl().set_security_bits(ssl_security_bits); |
| 642 changed = true; | |
| 643 } | 637 } |
| 644 | |
| 645 ShowPendingMessages(); | 638 ShowPendingMessages(); |
| 646 } | 639 } |
| 647 | 640 |
| 648 // An HTTPS response may not have a certificate for some reason. When that | 641 UpdateEntry(entry); |
| 649 // happens, use the unauthenticated (HTTP) rather than the authentication | |
| 650 // broken security style so that we can detect this error condition. | |
| 651 if (net::IsCertStatusError(ssl_cert_status) && | |
| 652 !details->is_content_filtered) { | |
| 653 changed |= SetMaxSecurityStyle(SECURITY_STYLE_AUTHENTICATION_BROKEN); | |
| 654 if (!details->is_main_frame && | |
| 655 !details->entry->ssl().has_unsafe_content()) { | |
| 656 details->entry->ssl().set_has_unsafe_content(); | |
| 657 changed = true; | |
| 658 } | |
| 659 } else if (details->entry->url().SchemeIsSecure() && !ssl_cert_id) { | |
| 660 if (details->is_main_frame) { | |
| 661 changed |= SetMaxSecurityStyle(SECURITY_STYLE_UNAUTHENTICATED); | |
| 662 } else { | |
| 663 // If the frame has been blocked we keep our security style as | |
| 664 // authenticated in that case as nothing insecure is actually showing or | |
| 665 // loaded. | |
| 666 if (!details->is_content_filtered && | |
| 667 !details->entry->ssl().has_mixed_content()) { | |
| 668 details->entry->ssl().set_has_mixed_content(); | |
| 669 changed = true; | |
| 670 } | |
| 671 } | |
| 672 } | |
| 673 | |
| 674 if (changed) { | |
| 675 // Only send the notification when something actually changed. | |
| 676 NotificationService::current()->Notify( | |
| 677 NotificationType::SSL_VISIBLE_STATE_CHANGED, | |
| 678 Source<NavigationController>(controller_), | |
| 679 NotificationService::NoDetails()); | |
| 680 } | |
| 681 } | 642 } |
| 682 | 643 |
| 683 void SSLManager::DidFailProvisionalLoadWithError( | 644 void SSLManager::DidFailProvisionalLoadWithError( |
| 684 ProvisionalLoadDetails* details) { | 645 ProvisionalLoadDetails* details) { |
| 685 DCHECK(details); | 646 DCHECK(details); |
| 686 | 647 |
| 687 // Ignore in-page navigations. | 648 // Ignore in-page navigations. |
| 688 if (details->in_page_navigation()) | 649 if (details->in_page_navigation()) |
| 689 return; | 650 return; |
| 690 | 651 |
| 691 if (details->main_frame()) | 652 if (details->main_frame()) |
| 692 ClearPendingMessages(); | 653 ClearPendingMessages(); |
| 693 } | 654 } |
| 694 | 655 |
| 695 void SSLManager::DidStartResourceResponse(ResourceRequestDetails* details) { | 656 void SSLManager::DidStartResourceResponse(ResourceRequestDetails* details) { |
| 696 DCHECK(details); | 657 DCHECK(details); |
| 697 | 658 |
| 698 scoped_refptr<RequestInfo> info = new RequestInfo( | 659 scoped_refptr<RequestInfo> info = new RequestInfo( |
| 699 this, | 660 this, |
| 700 details->url(), | 661 details->url(), |
| 701 details->resource_type(), | 662 details->resource_type(), |
| 702 details->frame_origin(), | 663 details->frame_origin(), |
| 703 details->main_frame_origin(), | 664 details->main_frame_origin(), |
| 665 details->filter_policy(), |
| 704 details->ssl_cert_id(), | 666 details->ssl_cert_id(), |
| 705 details->ssl_cert_status()); | 667 details->ssl_cert_status()); |
| 706 | 668 |
| 707 // Notify our delegate that we started a resource request. Ideally, the | 669 // Notify our delegate that we started a resource request. Ideally, the |
| 708 // delegate should have the ability to cancel the request, but we can't do | 670 // delegate should have the ability to cancel the request, but we can't do |
| 709 // that yet. | 671 // that yet. |
| 710 delegate()->OnRequestStarted(info.get()); | 672 delegate()->OnRequestStarted(info.get()); |
| 711 } | 673 } |
| 712 | 674 |
| 713 void SSLManager::DidReceiveResourceRedirect(ResourceRedirectDetails* details) { | 675 void SSLManager::DidReceiveResourceRedirect(ResourceRedirectDetails* details) { |
| 714 // TODO(abarth): Make sure our redirect behavior is correct. If we ever see | 676 // TODO(abarth): Make sure our redirect behavior is correct. If we ever see |
| 715 // a non-HTTPS resource in the redirect chain, we want to | 677 // a non-HTTPS resource in the redirect chain, we want to |
| 716 // trigger mixed content, even if the redirect chain goes back | 678 // trigger mixed content, even if the redirect chain goes back |
| 717 // to HTTPS. This is because the network attacker can redirect | 679 // to HTTPS. This is because the network attacker can redirect |
| 718 // the HTTP request to https://attacker.com/payload.js. | 680 // the HTTP request to https://attacker.com/payload.js. |
| 719 } | 681 } |
| 720 | 682 |
| 721 void SSLManager::ShowPendingMessages() { | 683 void SSLManager::ShowPendingMessages() { |
| 722 std::vector<SSLMessageInfo>::const_iterator iter; | 684 std::vector<SSLMessageInfo>::const_iterator iter; |
| 723 for (iter = pending_messages_.begin(); | 685 for (iter = pending_messages_.begin(); |
| 724 iter != pending_messages_.end(); ++iter) { | 686 iter != pending_messages_.end(); ++iter) { |
| 725 ShowMessageWithLink(iter->message, iter->link_text, iter->action); | 687 ShowMessageWithLink(iter->message, iter->link_text, iter->action); |
| 726 } | 688 } |
| 727 ClearPendingMessages(); | 689 ClearPendingMessages(); |
| 728 } | 690 } |
| 729 | 691 |
| 730 void SSLManager::DidChangeSSLInternalState() { | 692 void SSLManager::DidChangeSSLInternalState() { |
| 731 // TODO(abarth): We'll need to do something here in the next step. | 693 UpdateEntry(controller_->GetActiveEntry()); |
| 732 } | 694 } |
| 733 | 695 |
| 734 void SSLManager::ClearPendingMessages() { | 696 void SSLManager::ClearPendingMessages() { |
| 735 pending_messages_.clear(); | 697 pending_messages_.clear(); |
| 736 } | 698 } |
| 737 | 699 |
| 738 // static | 700 // static |
| 739 std::string SSLManager::SerializeSecurityInfo(int cert_id, | 701 std::string SSLManager::SerializeSecurityInfo(int cert_id, |
| 740 int cert_status, | 702 int cert_status, |
| 741 int security_bits) { | 703 int security_bits) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 } | 750 } |
| 789 | 751 |
| 790 if (ca_name) { | 752 if (ca_name) { |
| 791 // TODO(wtc): should we show the root CA's name instead? | 753 // TODO(wtc): should we show the root CA's name instead? |
| 792 *ca_name = l10n_util::GetStringF( | 754 *ca_name = l10n_util::GetStringF( |
| 793 IDS_SECURE_CONNECTION_EV_CA, | 755 IDS_SECURE_CONNECTION_EV_CA, |
| 794 UTF8ToWide(cert.issuer().organization_names[0])); | 756 UTF8ToWide(cert.issuer().organization_names[0])); |
| 795 } | 757 } |
| 796 return true; | 758 return true; |
| 797 } | 759 } |
| OLD | NEW |