| 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_policy.h" | 5 #include "chrome/browser/ssl/ssl_policy.h" |
| 6 | 6 |
| 7 #include "base/singleton.h" | 7 #include "base/singleton.h" |
| 8 #include "base/string_piece.h" | 8 #include "base/string_piece.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "chrome/browser/cert_store.h" | 10 #include "chrome/browser/cert_store.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 #if defined(OS_WIN) | 31 #if defined(OS_WIN) |
| 32 // TODO(port): port these files. | 32 // TODO(port): port these files. |
| 33 #include "chrome/browser/tab_contents/tab_contents.h" | 33 #include "chrome/browser/tab_contents/tab_contents.h" |
| 34 #elif defined(OS_POSIX) | 34 #elif defined(OS_POSIX) |
| 35 #include "chrome/common/temp_scaffolding_stubs.h" | 35 #include "chrome/common/temp_scaffolding_stubs.h" |
| 36 #endif | 36 #endif |
| 37 | 37 |
| 38 // Wrap all these helper classes in an anonymous namespace. | 38 // Wrap all these helper classes in an anonymous namespace. |
| 39 namespace { | 39 namespace { |
| 40 | 40 |
| 41 static void MarkOriginAsBroken(SSLManager* manager, const std::string& origin) { |
| 42 GURL parsed_origin(origin); |
| 43 if (!parsed_origin.SchemeIsSecure()) |
| 44 return; |
| 45 |
| 46 manager->MarkHostAsBroken(parsed_origin.host()); |
| 47 } |
| 48 |
| 49 static void AllowMixedContentForOrigin(SSLManager* manager, |
| 50 const std::string& origin) { |
| 51 GURL parsed_origin(origin); |
| 52 if (!parsed_origin.SchemeIsSecure()) |
| 53 return; |
| 54 |
| 55 manager->AllowMixedContentForHost(parsed_origin.host()); |
| 56 } |
| 57 |
| 58 static void UpdateStateForMixedContent(SSLManager::RequestInfo* info) { |
| 59 if (info->resource_type() != ResourceType::MAIN_FRAME || |
| 60 info->resource_type() != ResourceType::SUB_FRAME) { |
| 61 // The frame's origin now contains mixed content and therefore is broken. |
| 62 MarkOriginAsBroken(info->manager(), info->frame_origin()); |
| 63 } |
| 64 |
| 65 if (info->resource_type() != ResourceType::MAIN_FRAME) { |
| 66 // The user approved a mixed content exception for the main frame's origin. |
| 67 // That makes the main frame's origin broken too. |
| 68 MarkOriginAsBroken(info->manager(), info->main_frame_origin()); |
| 69 } |
| 70 } |
| 71 |
| 72 static void UpdateStateForUnsafeContent(SSLManager::RequestInfo* info) { |
| 73 // This request as a broken cert, which means its host is broken. |
| 74 info->manager()->MarkHostAsBroken(info->url().host()); |
| 75 |
| 76 UpdateStateForMixedContent(info); |
| 77 } |
| 78 |
| 41 class ShowMixedContentTask : public Task { | 79 class ShowMixedContentTask : public Task { |
| 42 public: | 80 public: |
| 43 ShowMixedContentTask(SSLManager::MixedContentHandler* handler); | 81 ShowMixedContentTask(SSLManager::MixedContentHandler* handler); |
| 44 virtual ~ShowMixedContentTask(); | 82 virtual ~ShowMixedContentTask(); |
| 45 | 83 |
| 46 virtual void Run(); | 84 virtual void Run(); |
| 47 | 85 |
| 48 private: | 86 private: |
| 49 scoped_refptr<SSLManager::MixedContentHandler> handler_; | 87 scoped_refptr<SSLManager::MixedContentHandler> handler_; |
| 50 | 88 |
| 51 DISALLOW_COPY_AND_ASSIGN(ShowMixedContentTask); | 89 DISALLOW_COPY_AND_ASSIGN(ShowMixedContentTask); |
| 52 }; | 90 }; |
| 53 | 91 |
| 54 ShowMixedContentTask::ShowMixedContentTask( | 92 ShowMixedContentTask::ShowMixedContentTask( |
| 55 SSLManager::MixedContentHandler* handler) | 93 SSLManager::MixedContentHandler* handler) |
| 56 : handler_(handler) { | 94 : handler_(handler) { |
| 57 } | 95 } |
| 58 | 96 |
| 59 ShowMixedContentTask::~ShowMixedContentTask() { | 97 ShowMixedContentTask::~ShowMixedContentTask() { |
| 60 } | 98 } |
| 61 | 99 |
| 62 void ShowMixedContentTask::Run() { | 100 void ShowMixedContentTask::Run() { |
| 63 handler_->manager()->AllowMixedContentForHost( | 101 AllowMixedContentForOrigin(handler_->manager(), handler_->frame_origin()); |
| 64 GURL(handler_->main_frame_origin()).host()); | 102 AllowMixedContentForOrigin(handler_->manager(), |
| 65 | 103 handler_->main_frame_origin()); |
| 66 // Reload the page. | |
| 67 handler_->manager()->controller()->Reload(true); | 104 handler_->manager()->controller()->Reload(true); |
| 68 } | 105 } |
| 69 | 106 |
| 70 static void ShowErrorPage(SSLPolicy* policy, SSLManager::CertError* error) { | 107 static void ShowErrorPage(SSLPolicy* policy, SSLManager::CertError* error) { |
| 71 SSLErrorInfo error_info = policy->GetSSLErrorInfo(error); | 108 SSLErrorInfo error_info = policy->GetSSLErrorInfo(error); |
| 72 | 109 |
| 73 // Let's build the html error page. | 110 // Let's build the html error page. |
| 74 DictionaryValue strings; | 111 DictionaryValue strings; |
| 75 strings.SetString(L"title", l10n_util::GetString(IDS_SSL_ERROR_PAGE_TITLE)); | 112 strings.SetString(L"title", l10n_util::GetString(IDS_SSL_ERROR_PAGE_TITLE)); |
| 76 strings.SetString(L"headLine", error_info.title()); | 113 strings.SetString(L"headLine", error_info.title()); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 105 security_info); | 142 security_info); |
| 106 tab->controller()->GetActiveEntry()->set_page_type( | 143 tab->controller()->GetActiveEntry()->set_page_type( |
| 107 NavigationEntry::ERROR_PAGE); | 144 NavigationEntry::ERROR_PAGE); |
| 108 } | 145 } |
| 109 | 146 |
| 110 static void ShowBlockingPage(SSLPolicy* policy, SSLManager::CertError* error) { | 147 static void ShowBlockingPage(SSLPolicy* policy, SSLManager::CertError* error) { |
| 111 SSLBlockingPage* blocking_page = new SSLBlockingPage(error, policy); | 148 SSLBlockingPage* blocking_page = new SSLBlockingPage(error, policy); |
| 112 blocking_page->Show(); | 149 blocking_page->Show(); |
| 113 } | 150 } |
| 114 | 151 |
| 152 static void InitializeEntryIfNeeded(NavigationEntry* entry) { |
| 153 if (entry->ssl().security_style() != SECURITY_STYLE_UNKNOWN) |
| 154 return; |
| 155 |
| 156 entry->ssl().set_security_style(entry->url().SchemeIsSecure() ? |
| 157 SECURITY_STYLE_AUTHENTICATED : SECURITY_STYLE_UNAUTHENTICATED); |
| 158 } |
| 159 |
| 160 static void AddMixedContentWarningToConsole( |
| 161 SSLManager::MixedContentHandler* handler) { |
| 162 const std::wstring& msg = l10n_util::GetStringF( |
| 163 IDS_MIXED_CONTENT_LOG_MESSAGE, |
| 164 UTF8ToWide(handler->frame_origin()), |
| 165 UTF8ToWide(handler->request_url().spec())); |
| 166 handler->manager()->AddMessageToConsole(msg, MESSAGE_LEVEL_WARNING); |
| 167 } |
| 168 |
| 115 } // namespace | 169 } // namespace |
| 116 | 170 |
| 117 SSLPolicy::SSLPolicy() { | 171 SSLPolicy::SSLPolicy() { |
| 118 } | 172 } |
| 119 | 173 |
| 120 SSLPolicy* SSLPolicy::GetDefaultPolicy() { | 174 SSLPolicy* SSLPolicy::GetDefaultPolicy() { |
| 121 return Singleton<SSLPolicy>::get(); | 175 return Singleton<SSLPolicy>::get(); |
| 122 } | 176 } |
| 123 | 177 |
| 124 void SSLPolicy::OnCertError(SSLManager::CertError* error) { | 178 void SSLPolicy::OnCertError(SSLManager::CertError* error) { |
| 125 // First we check if we know the policy for this error. | 179 // First we check if we know the policy for this error. |
| 126 net::X509Certificate::Policy::Judgment judgment = | 180 net::X509Certificate::Policy::Judgment judgment = |
| 127 error->manager()->QueryPolicy(error->ssl_info().cert, | 181 error->manager()->QueryPolicy(error->ssl_info().cert, |
| 128 error->request_url().host()); | 182 error->request_url().host()); |
| 129 | 183 |
| 130 if (judgment == net::X509Certificate::Policy::ALLOWED) { | 184 if (judgment == net::X509Certificate::Policy::ALLOWED) { |
| 131 // We've been told to allow this certificate. | |
| 132 if (error->manager()->SetMaxSecurityStyle( | |
| 133 SECURITY_STYLE_AUTHENTICATION_BROKEN)) { | |
| 134 NotificationService::current()->Notify( | |
| 135 NotificationType::SSL_VISIBLE_STATE_CHANGED, | |
| 136 Source<NavigationController>(error->manager()->controller()), | |
| 137 Details<NavigationEntry>( | |
| 138 error->manager()->controller()->GetActiveEntry())); | |
| 139 } | |
| 140 error->ContinueRequest(); | 185 error->ContinueRequest(); |
| 141 return; | 186 return; |
| 142 } | 187 } |
| 143 | 188 |
| 144 // The judgment is either DENIED or UNKNOWN. | 189 // The judgment is either DENIED or UNKNOWN. |
| 145 // For now we handle the DENIED as the UNKNOWN, which means a blocking | 190 // For now we handle the DENIED as the UNKNOWN, which means a blocking |
| 146 // page is shown to the user every time he comes back to the page. | 191 // page is shown to the user every time he comes back to the page. |
| 147 | 192 |
| 148 switch(error->cert_error()) { | 193 switch(error->cert_error()) { |
| 149 case net::ERR_CERT_COMMON_NAME_INVALID: | 194 case net::ERR_CERT_COMMON_NAME_INVALID: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 172 break; | 217 break; |
| 173 } | 218 } |
| 174 } | 219 } |
| 175 | 220 |
| 176 void SSLPolicy::OnMixedContent(SSLManager::MixedContentHandler* handler) { | 221 void SSLPolicy::OnMixedContent(SSLManager::MixedContentHandler* handler) { |
| 177 // Get the user's mixed content preference. | 222 // Get the user's mixed content preference. |
| 178 PrefService* prefs = handler->GetWebContents()->profile()->GetPrefs(); | 223 PrefService* prefs = handler->GetWebContents()->profile()->GetPrefs(); |
| 179 FilterPolicy::Type filter_policy = | 224 FilterPolicy::Type filter_policy = |
| 180 FilterPolicy::FromInt(prefs->GetInteger(prefs::kMixedContentFiltering)); | 225 FilterPolicy::FromInt(prefs->GetInteger(prefs::kMixedContentFiltering)); |
| 181 | 226 |
| 182 // If the user have added an exception, doctor the |filter_policy|. | 227 // If the user has added an exception, doctor the |filter_policy|. |
| 183 if (handler->manager()->DidAllowMixedContentForHost( | 228 std::string host = GURL(handler->main_frame_origin()).host(); |
| 184 GURL(handler->main_frame_origin()).host())) | 229 if (handler->manager()->DidAllowMixedContentForHost(host) || |
| 230 handler->manager()->DidMarkHostAsBroken(host)) |
| 185 filter_policy = FilterPolicy::DONT_FILTER; | 231 filter_policy = FilterPolicy::DONT_FILTER; |
| 186 | 232 |
| 187 if (filter_policy != FilterPolicy::DONT_FILTER) { | 233 if (filter_policy != FilterPolicy::DONT_FILTER) { |
| 188 handler->manager()->ShowMessageWithLink( | 234 handler->manager()->ShowMessageWithLink( |
| 189 l10n_util::GetString(IDS_SSL_INFO_BAR_FILTERED_CONTENT), | 235 l10n_util::GetString(IDS_SSL_INFO_BAR_FILTERED_CONTENT), |
| 190 l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT), | 236 l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT), |
| 191 new ShowMixedContentTask(handler)); | 237 new ShowMixedContentTask(handler)); |
| 192 } | 238 } |
| 239 |
| 193 handler->StartRequest(filter_policy); | 240 handler->StartRequest(filter_policy); |
| 194 | 241 AddMixedContentWarningToConsole(handler); |
| 195 NavigationEntry* entry = | |
| 196 handler->manager()->controller()->GetLastCommittedEntry(); | |
| 197 // We might not have a navigation entry in some cases (e.g. when a» | |
| 198 // HTTPS page opens a popup with no URL and then populate it with» | |
| 199 // document.write()). See bug http://crbug.com/3845. | |
| 200 if (!entry) | |
| 201 return; | |
| 202 | |
| 203 // Even though we are loading the mixed-content resource, it will not be | |
| 204 // included in the page when we set the policy to FILTER_ALL or | |
| 205 // FILTER_ALL_EXCEPT_IMAGES (only images and they are stamped with warning | |
| 206 // icons), so we don't set the mixed-content mode in these cases. | |
| 207 if (filter_policy == FilterPolicy::DONT_FILTER) | |
| 208 entry->ssl().set_has_mixed_content(); | |
| 209 | |
| 210 // Print a message indicating the mixed-contents resource in the console. | |
| 211 const std::wstring& msg = l10n_util::GetStringF( | |
| 212 IDS_MIXED_CONTENT_LOG_MESSAGE, | |
| 213 UTF8ToWide(entry->url().spec()), | |
| 214 UTF8ToWide(handler->request_url().spec())); | |
| 215 handler->manager()->AddMessageToConsole(msg, MESSAGE_LEVEL_WARNING); | |
| 216 | |
| 217 NotificationService::current()->Notify( | |
| 218 NotificationType::SSL_VISIBLE_STATE_CHANGED, | |
| 219 Source<NavigationController>(handler->manager()->controller()), | |
| 220 Details<NavigationEntry>(entry)); | |
| 221 } | 242 } |
| 222 | 243 |
| 223 void SSLPolicy::OnRequestStarted(SSLManager::RequestInfo* info) { | 244 void SSLPolicy::OnRequestStarted(SSLManager::RequestInfo* info) { |
| 224 // These schemes never leave the browser and don't require a warning. | 245 if (net::IsCertStatusError(info->ssl_cert_status())) |
| 225 if (info->url().SchemeIs(chrome::kDataScheme) || | 246 UpdateStateForUnsafeContent(info); |
| 226 info->url().SchemeIs(chrome::kJavaScriptScheme) || | 247 |
| 227 info->url().SchemeIs(chrome::kAboutScheme)) | 248 if (IsMixedContent(info->url(), |
| 249 info->resource_type(), |
| 250 info->filter_policy(), |
| 251 info->frame_origin())) |
| 252 UpdateStateForMixedContent(info); |
| 253 } |
| 254 |
| 255 void SSLPolicy::UpdateEntry(SSLManager* manager, NavigationEntry* entry) { |
| 256 DCHECK(entry); |
| 257 |
| 258 InitializeEntryIfNeeded(entry); |
| 259 |
| 260 if (!entry->url().SchemeIsSecure()) |
| 228 return; | 261 return; |
| 229 | 262 |
| 230 NavigationEntry* entry = info->manager()->controller()->GetActiveEntry(); | 263 // An HTTPS response may not have a certificate for some reason. When that |
| 231 if (!entry) { | 264 // happens, use the unauthenticated (HTTP) rather than the authentication |
| 232 // We may not have an entry for cases such as the inspector. | 265 // broken security style so that we can detect this error condition. |
| 266 if (!entry->ssl().cert_id()) { |
| 267 entry->ssl().set_security_style(SECURITY_STYLE_UNAUTHENTICATED); |
| 233 return; | 268 return; |
| 234 } | 269 } |
| 235 | 270 |
| 236 NavigationEntry::SSLStatus& ssl = entry->ssl(); | 271 if (net::IsCertStatusError(entry->ssl().cert_status())) { |
| 237 bool changed = false; | 272 entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN); |
| 238 if (!entry->url().SchemeIsSecure() || // Current page is not secure. | |
| 239 info->resource_type() == ResourceType::MAIN_FRAME || // Main frame load. | |
| 240 net::IsCertStatusError(ssl.cert_status())) { // There is already | |
| 241 // an error for the main page, don't report sub-resources as unsafe | |
| 242 // content. | |
| 243 // No mixed/unsafe content check necessary. | |
| 244 return; | 273 return; |
| 245 } | 274 } |
| 246 | 275 |
| 247 if (info->url().SchemeIsSecure()) { | 276 if (manager->DidMarkHostAsBroken(entry->url().host())) |
| 248 // Check for insecure content (anything served over intranet is considered | 277 entry->ssl().set_has_mixed_content(); |
| 249 // insecure). | |
| 250 | |
| 251 // TODO(jcampan): bug #1178228 Disabling the broken style for intranet | |
| 252 // hosts for beta as it is missing error strings (and cert status). | |
| 253 // if (IsIntranetHost(url.host()) || | |
| 254 // net::IsCertStatusError(info->ssl_cert_status())) { | |
| 255 if (net::IsCertStatusError(info->ssl_cert_status())) { | |
| 256 // The resource is unsafe. | |
| 257 if (!ssl.has_unsafe_content()) { | |
| 258 changed = true; | |
| 259 ssl.set_has_unsafe_content(); | |
| 260 info->manager()->SetMaxSecurityStyle( | |
| 261 SECURITY_STYLE_AUTHENTICATION_BROKEN); | |
| 262 } | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 if (changed) { | |
| 267 // Only send the notification when something actually changed. | |
| 268 NotificationService::current()->Notify( | |
| 269 NotificationType::SSL_VISIBLE_STATE_CHANGED, | |
| 270 Source<NavigationController>(info->manager()->controller()), | |
| 271 NotificationService::NoDetails()); | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 SecurityStyle SSLPolicy::GetDefaultStyle(const GURL& url) { | |
| 276 // Show the secure style for HTTPS. | |
| 277 if (url.SchemeIsSecure()) { | |
| 278 // TODO(jcampan): bug #1178228 Disabling the broken style for intranet | |
| 279 // hosts for beta as it is missing error strings (and cert status). | |
| 280 // CAs issue certs for intranet hosts to anyone. | |
| 281 // if (IsIntranetHost(url.host())) | |
| 282 // return SECURITY_STYLE_AUTHENTICATION_BROKEN; | |
| 283 | |
| 284 return SECURITY_STYLE_AUTHENTICATED; | |
| 285 } | |
| 286 | |
| 287 // Otherwise, show the unauthenticated style. | |
| 288 return SECURITY_STYLE_UNAUTHENTICATED; | |
| 289 } | 278 } |
| 290 | 279 |
| 291 // static | 280 // static |
| 292 bool SSLPolicy::IsMixedContent(const GURL& url, | 281 bool SSLPolicy::IsMixedContent(const GURL& url, |
| 293 ResourceType::Type resource_type, | 282 ResourceType::Type resource_type, |
| 294 const std::string& main_frame_origin) { | 283 FilterPolicy::Type filter_policy, |
| 284 const std::string& frame_origin) { |
| 295 //////////////////////////////////////////////////////////////////////////// | 285 //////////////////////////////////////////////////////////////////////////// |
| 296 // WARNING: This function is called from both the IO and UI threads. Do // | 286 // WARNING: This function is called from both the IO and UI threads. Do // |
| 297 // not touch any non-thread-safe objects! You have been warned. // | 287 // not touch any non-thread-safe objects! You have been warned. // |
| 298 //////////////////////////////////////////////////////////////////////////// | 288 //////////////////////////////////////////////////////////////////////////// |
| 299 | 289 |
| 300 // We can't possibly have mixed content when loading the main frame. | 290 // We can't possibly have mixed content when loading the main frame. |
| 301 if (resource_type == ResourceType::MAIN_FRAME) | 291 if (resource_type == ResourceType::MAIN_FRAME) |
| 302 return false; | 292 return false; |
| 303 | 293 |
| 304 // TODO(abarth): This is wrong, but it matches our current behavior. | 294 // If we've filtered the resource, then it's no longer dangerous. |
| 305 // I'll fix this in a subsequent step. | 295 if (filter_policy != FilterPolicy::DONT_FILTER) |
| 306 return GURL(main_frame_origin).SchemeIsSecure() && !url.SchemeIsSecure(); | 296 return false; |
| 297 |
| 298 // If the frame doing the loading is already insecure, then we must have |
| 299 // already dealt with whatever mixed content might be going on. |
| 300 if (!GURL(frame_origin).SchemeIsSecure()) |
| 301 return false; |
| 302 |
| 303 // We aren't worried about mixed content if we're loading an HTTPS URL. |
| 304 if (url.SchemeIsSecure()) |
| 305 return false; |
| 306 |
| 307 return true; |
| 307 } | 308 } |
| 308 | 309 |
| 309 //////////////////////////////////////////////////////////////////////////////// | 310 //////////////////////////////////////////////////////////////////////////////// |
| 310 // SSLBlockingPage::Delegate methods | 311 // SSLBlockingPage::Delegate methods |
| 311 | 312 |
| 312 SSLErrorInfo SSLPolicy::GetSSLErrorInfo(SSLManager::CertError* error) { | 313 SSLErrorInfo SSLPolicy::GetSSLErrorInfo(SSLManager::CertError* error) { |
| 313 return SSLErrorInfo::CreateError( | 314 return SSLErrorInfo::CreateError( |
| 314 SSLErrorInfo::NetErrorToErrorType(error->cert_error()), | 315 SSLErrorInfo::NetErrorToErrorType(error->cert_error()), |
| 315 error->ssl_info().cert, error->request_url()); | 316 error->ssl_info().cert, error->request_url()); |
| 316 } | 317 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 | 353 |
| 353 void SSLPolicy::OnFatalCertError(SSLManager::CertError* error) { | 354 void SSLPolicy::OnFatalCertError(SSLManager::CertError* error) { |
| 354 if (error->resource_type() != ResourceType::MAIN_FRAME) { | 355 if (error->resource_type() != ResourceType::MAIN_FRAME) { |
| 355 error->DenyRequest(); | 356 error->DenyRequest(); |
| 356 return; | 357 return; |
| 357 } | 358 } |
| 358 error->CancelRequest(); | 359 error->CancelRequest(); |
| 359 ShowErrorPage(this, error); | 360 ShowErrorPage(this, error); |
| 360 // No need to degrade our security indicators because we didn't continue. | 361 // No need to degrade our security indicators because we didn't continue. |
| 361 } | 362 } |
| OLD | NEW |