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

Side by Side Diff: content/browser/ssl/ssl_manager.cc

Issue 2395663002: Collapse SSLPolicy/SSLPolicyBackend into SSLManager (Closed)
Patch Set: remove accidentally added temp file... oops... Created 4 years, 2 months 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 | « content/browser/ssl/ssl_manager.h ('k') | content/browser/ssl/ssl_policy.h » ('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 "content/browser/ssl/ssl_manager.h" 5 #include "content/browser/ssl/ssl_manager.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
12 #include "base/supports_user_data.h" 13 #include "base/supports_user_data.h"
13 #include "content/browser/frame_host/navigation_entry_impl.h" 14 #include "content/browser/frame_host/navigation_entry_impl.h"
14 #include "content/browser/loader/resource_dispatcher_host_impl.h" 15 #include "content/browser/loader/resource_dispatcher_host_impl.h"
15 #include "content/browser/loader/resource_request_info_impl.h" 16 #include "content/browser/loader/resource_request_info_impl.h"
16 #include "content/browser/ssl/ssl_error_handler.h" 17 #include "content/browser/ssl/ssl_error_handler.h"
17 #include "content/browser/ssl/ssl_policy.h"
18 #include "content/browser/web_contents/web_contents_impl.h" 18 #include "content/browser/web_contents/web_contents_impl.h"
19 #include "content/common/security_style_util.h"
19 #include "content/public/browser/browser_context.h" 20 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/certificate_request_result_type.h"
23 #include "content/public/browser/content_browser_client.h"
21 #include "content/public/browser/navigation_details.h" 24 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/resource_request_details.h" 25 #include "content/public/browser/ssl_host_state_delegate.h"
23 #include "content/public/browser/ssl_status.h" 26 #include "content/public/browser/ssl_status.h"
24 #include "net/url_request/url_request.h" 27 #include "net/url_request/url_request.h"
25 28
26 namespace content { 29 namespace content {
27 30
28 namespace { 31 namespace {
29 32
30 const char kSSLManagerKeyName[] = "content_ssl_manager"; 33 const char kSSLManagerKeyName[] = "content_ssl_manager";
31 34
35 // Events for UMA. Do not reorder or change!
36 enum SSLGoodCertSeenEvent {
37 NO_PREVIOUS_EXCEPTION = 0,
38 HAD_PREVIOUS_EXCEPTION = 1,
39 SSL_GOOD_CERT_SEEN_EVENT_MAX = 2
40 };
41
42 void OnAllowCertificate(SSLErrorHandler* handler,
43 SSLHostStateDelegate* state_delegate,
44 CertificateRequestResultType decision) {
45 DCHECK(handler->ssl_info().is_valid());
46 switch (decision) {
47 case CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE:
48 // Note that we should not call SetMaxSecurityStyle here, because
49 // the active NavigationEntry has just been deleted (in
50 // HideInterstitialPage) and the new NavigationEntry will not be
51 // set until DidNavigate. This is ok, because the new
52 // NavigationEntry will have its max security style set within
53 // DidNavigate.
54 //
55 // While AllowCert() executes synchronously on this thread,
56 // ContinueRequest() gets posted to a different thread. Calling
57 // AllowCert() first ensures deterministic ordering.
58 if (state_delegate) {
59 state_delegate->AllowCert(handler->request_url().host(),
60 *handler->ssl_info().cert.get(),
61 handler->cert_error());
62 }
63 handler->ContinueRequest();
64 return;
65 case CERTIFICATE_REQUEST_RESULT_TYPE_DENY:
66 handler->DenyRequest();
67 return;
68 case CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL:
69 handler->CancelRequest();
70 return;
71 }
72 }
73
32 class SSLManagerSet : public base::SupportsUserData::Data { 74 class SSLManagerSet : public base::SupportsUserData::Data {
33 public: 75 public:
34 SSLManagerSet() { 76 SSLManagerSet() {
35 } 77 }
36 78
37 std::set<SSLManager*>& get() { return set_; } 79 std::set<SSLManager*>& get() { return set_; }
38 80
39 private: 81 private:
40 std::set<SSLManager*> set_; 82 std::set<SSLManager*> set_;
41 83
(...skipping 19 matching lines...) Expand all
61 handler->ContinueRequest(); 103 handler->ContinueRequest();
62 } else { 104 } else {
63 handler->CancelRequest(); 105 handler->CancelRequest();
64 } 106 }
65 return; 107 return;
66 } 108 }
67 109
68 SSLManager* manager = 110 SSLManager* manager =
69 static_cast<NavigationControllerImpl*>(&web_contents->GetController()) 111 static_cast<NavigationControllerImpl*>(&web_contents->GetController())
70 ->ssl_manager(); 112 ->ssl_manager();
71 manager->policy()->OnCertError(std::move(handler)); 113 manager->OnCertError(std::move(handler));
72 } 114 }
73 115
74 } // namespace 116 } // namespace
75 117
76 // static 118 // static
77 void SSLManager::OnSSLCertificateError( 119 void SSLManager::OnSSLCertificateError(
78 const base::WeakPtr<SSLErrorHandler::Delegate>& delegate, 120 const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
79 const ResourceType resource_type, 121 const ResourceType resource_type,
80 const GURL& url, 122 const GURL& url,
81 const base::Callback<WebContents*(void)>& web_contents_getter, 123 const base::Callback<WebContents*(void)>& web_contents_getter,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 SSLManagerSet* managers = static_cast<SSLManagerSet*>( 157 SSLManagerSet* managers = static_cast<SSLManagerSet*>(
116 context->GetUserData(kSSLManagerKeyName)); 158 context->GetUserData(kSSLManagerKeyName));
117 159
118 for (std::set<SSLManager*>::iterator i = managers->get().begin(); 160 for (std::set<SSLManager*>::iterator i = managers->get().begin();
119 i != managers->get().end(); ++i) { 161 i != managers->get().end(); ++i) {
120 (*i)->UpdateEntry((*i)->controller()->GetLastCommittedEntry()); 162 (*i)->UpdateEntry((*i)->controller()->GetLastCommittedEntry());
121 } 163 }
122 } 164 }
123 165
124 SSLManager::SSLManager(NavigationControllerImpl* controller) 166 SSLManager::SSLManager(NavigationControllerImpl* controller)
125 : backend_(controller), 167 : controller_(controller),
126 policy_(new SSLPolicy(&backend_)), 168 ssl_host_state_delegate_(
127 controller_(controller) { 169 controller->GetBrowserContext()->GetSSLHostStateDelegate()) {
128 DCHECK(controller_); 170 DCHECK(controller_);
129 171
130 SSLManagerSet* managers = static_cast<SSLManagerSet*>( 172 SSLManagerSet* managers = static_cast<SSLManagerSet*>(
131 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName)); 173 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName));
132 if (!managers) { 174 if (!managers) {
133 managers = new SSLManagerSet; 175 managers = new SSLManagerSet;
134 controller_->GetBrowserContext()->SetUserData(kSSLManagerKeyName, managers); 176 controller_->GetBrowserContext()->SetUserData(kSSLManagerKeyName, managers);
135 } 177 }
136 managers->get().insert(this); 178 managers->get().insert(this);
137 } 179 }
138 180
139 SSLManager::~SSLManager() { 181 SSLManager::~SSLManager() {
140 SSLManagerSet* managers = static_cast<SSLManagerSet*>( 182 SSLManagerSet* managers = static_cast<SSLManagerSet*>(
141 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName)); 183 controller_->GetBrowserContext()->GetUserData(kSSLManagerKeyName));
142 managers->get().erase(this); 184 managers->get().erase(this);
143 } 185 }
144 186
145 void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) { 187 void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) {
146 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry(); 188 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
147 policy()->UpdateEntry(entry, controller_->delegate()->GetWebContents()); 189 UpdateEntry(entry);
148 // Always notify the WebContents that the SSL state changed when a 190 // Always notify the WebContents that the SSL state changed when a
149 // load is committed, in case the active navigation entry has changed. 191 // load is committed, in case the active navigation entry has changed.
150 NotifyDidChangeVisibleSSLState(); 192 NotifyDidChangeVisibleSSLState();
151 } 193 }
152 194
153 void SSLManager::DidRunInsecureContent(const GURL& security_origin) { 195 void SSLManager::DidRunInsecureContent(const GURL& security_origin) {
154 NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry(); 196 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
155 policy()->DidRunInsecureContent(navigation_entry, security_origin); 197 if (!entry)
156 UpdateEntry(navigation_entry); 198 return;
199
200 SiteInstance* site_instance = entry->site_instance();
201 if (!site_instance)
202 return;
203
204 if (ssl_host_state_delegate_) {
205 ssl_host_state_delegate_->HostRanInsecureContent(
206 security_origin.host(), site_instance->GetProcess()->GetID(),
207 SSLHostStateDelegate::MIXED_CONTENT);
208 }
209 UpdateEntry(entry);
210 NotifySSLInternalStateChanged(controller_->GetBrowserContext());
157 } 211 }
158 212
159 void SSLManager::DidRunContentWithCertErrors(const GURL& security_origin) { 213 void SSLManager::DidRunContentWithCertErrors(const GURL& security_origin) {
160 NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry(); 214 NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
161 policy()->DidRunContentWithCertErrors(navigation_entry, security_origin); 215 if (!entry)
162 UpdateEntry(navigation_entry); 216 return;
217
218 SiteInstance* site_instance = entry->site_instance();
219 if (!site_instance)
220 return;
221
222 if (ssl_host_state_delegate_) {
223 ssl_host_state_delegate_->HostRanInsecureContent(
224 security_origin.host(), site_instance->GetProcess()->GetID(),
225 SSLHostStateDelegate::CERT_ERRORS_CONTENT);
226 }
227 UpdateEntry(entry);
228 NotifySSLInternalStateChanged(controller_->GetBrowserContext());
163 } 229 }
164 230
165 void SSLManager::DidStartResourceResponse( 231 void SSLManager::OnCertError(std::unique_ptr<SSLErrorHandler> handler) {
166 const ResourceRequestDetails& details) { 232 bool expired_previous_decision = false;
167 // Notify our policy that we started a resource request. Ideally, the 233 // First we check if we know the policy for this error.
168 // policy should have the ability to cancel the request, but we can't do 234 DCHECK(handler->ssl_info().is_valid());
169 // that yet. 235 SSLHostStateDelegate::CertJudgment judgment =
170 policy()->OnRequestStarted(details.url, details.has_certificate, 236 ssl_host_state_delegate_
171 details.ssl_cert_status); 237 ? ssl_host_state_delegate_->QueryPolicy(
238 handler->request_url().host(), *handler->ssl_info().cert.get(),
239 handler->cert_error(), &expired_previous_decision)
240 : SSLHostStateDelegate::DENIED;
241
242 if (judgment == SSLHostStateDelegate::ALLOWED) {
243 handler->ContinueRequest();
244 return;
245 }
246
247 // For all other hosts, which must be DENIED, a blocking page is shown to the
248 // user every time they come back to the page.
249 int options_mask = 0;
250 switch (handler->cert_error()) {
251 case net::ERR_CERT_COMMON_NAME_INVALID:
252 case net::ERR_CERT_DATE_INVALID:
253 case net::ERR_CERT_AUTHORITY_INVALID:
254 case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
255 case net::ERR_CERT_WEAK_KEY:
256 case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
257 case net::ERR_CERT_VALIDITY_TOO_LONG:
258 case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
259 if (!handler->fatal())
260 options_mask |= OVERRIDABLE;
261 else
262 options_mask |= STRICT_ENFORCEMENT;
263 if (expired_previous_decision)
264 options_mask |= EXPIRED_PREVIOUS_DECISION;
265 OnCertErrorInternal(std::move(handler), options_mask);
266 break;
267 case net::ERR_CERT_NO_REVOCATION_MECHANISM:
268 // Ignore this error.
269 handler->ContinueRequest();
270 break;
271 case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
272 // We ignore this error but will show a warning status in the location
273 // bar.
274 handler->ContinueRequest();
275 break;
276 case net::ERR_CERT_CONTAINS_ERRORS:
277 case net::ERR_CERT_REVOKED:
278 case net::ERR_CERT_INVALID:
279 case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
280 case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
281 if (handler->fatal())
282 options_mask |= STRICT_ENFORCEMENT;
283 if (expired_previous_decision)
284 options_mask |= EXPIRED_PREVIOUS_DECISION;
285 OnCertErrorInternal(std::move(handler), options_mask);
286 break;
287 default:
288 NOTREACHED();
289 handler->CancelRequest();
290 break;
291 }
172 } 292 }
173 293
174 void SSLManager::DidReceiveResourceRedirect( 294 void SSLManager::DidStartResourceResponse(const GURL& url,
175 const ResourceRedirectDetails& details) { 295 bool has_certificate,
176 // TODO(abarth): Make sure our redirect behavior is correct. If we ever see a 296 net::CertStatus ssl_cert_status) {
177 // non-HTTPS resource in the redirect chain, we want to trigger 297 if (has_certificate && url.SchemeIsCryptographic() &&
178 // insecure content, even if the redirect chain goes back to 298 !net::IsCertStatusError(ssl_cert_status)) {
179 // HTTPS. This is because the network attacker can redirect the 299 // If the scheme is https: or wss: *and* the security info for the
180 // HTTP request to https://attacker.com/payload.js. 300 // cert has been set (i.e. the cert id is not 0) and the cert did
301 // not have any errors, revoke any previous decisions that
302 // have occurred. If the cert info has not been set, do nothing since it
303 // isn't known if the connection was actually a valid connection or if it
304 // had a cert error.
305 SSLGoodCertSeenEvent event = NO_PREVIOUS_EXCEPTION;
306 if (ssl_host_state_delegate_ &&
307 ssl_host_state_delegate_->HasAllowException(url.host())) {
308 // If there's no certificate error, a good certificate has been seen, so
309 // clear out any exceptions that were made by the user for bad
310 // certificates. This intentionally does not apply to cached resources
311 // (see https://crbug.com/634553 for an explanation).
312 ssl_host_state_delegate_->RevokeUserAllowExceptions(url.host());
313 event = HAD_PREVIOUS_EXCEPTION;
314 }
315 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.good_cert_seen", event,
316 SSL_GOOD_CERT_SEEN_EVENT_MAX);
317 }
318 }
319
320 void SSLManager::OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler,
321 int options_mask) {
322 bool overridable = (options_mask & OVERRIDABLE) != 0;
323 bool strict_enforcement = (options_mask & STRICT_ENFORCEMENT) != 0;
324 bool expired_previous_decision =
325 (options_mask & EXPIRED_PREVIOUS_DECISION) != 0;
326
327 WebContents* web_contents = handler->web_contents();
328 int cert_error = handler->cert_error();
329 const net::SSLInfo& ssl_info = handler->ssl_info();
330 const GURL& request_url = handler->request_url();
331 ResourceType resource_type = handler->resource_type();
332 GetContentClient()->browser()->AllowCertificateError(
333 web_contents, cert_error, ssl_info, request_url, resource_type,
334 overridable, strict_enforcement, expired_previous_decision,
335 base::Bind(&OnAllowCertificate, base::Owned(handler.release()),
336 ssl_host_state_delegate_));
181 } 337 }
182 338
183 void SSLManager::UpdateEntry(NavigationEntryImpl* entry) { 339 void SSLManager::UpdateEntry(NavigationEntryImpl* entry) {
184 // We don't always have a navigation entry to update, for example in the 340 // We don't always have a navigation entry to update, for example in the
185 // case of the Web Inspector. 341 // case of the Web Inspector.
186 if (!entry) 342 if (!entry)
187 return; 343 return;
188 344
189 SSLStatus original_ssl_status = entry->GetSSL(); // Copy! 345 SSLStatus original_ssl_status = entry->GetSSL(); // Copy!
190 346
191 policy()->UpdateEntry(entry, controller_->delegate()->GetWebContents()); 347 // Initialize the entry with an initial SecurityStyle if needed.
348 if (entry->GetSSL().security_style == SECURITY_STYLE_UNKNOWN) {
349 entry->GetSSL().security_style = GetSecurityStyleForResource(
350 entry->GetURL(), !!entry->GetSSL().certificate,
351 entry->GetSSL().cert_status);
352 }
353
354 WebContentsImpl* web_contents_impl =
355 static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents());
356 if (entry->GetSSL().security_style == SECURITY_STYLE_UNAUTHENTICATED)
357 return;
358
359 // Update the entry's flags for insecure content.
360 if (!web_contents_impl->DisplayedInsecureContent())
361 entry->GetSSL().content_status &= ~SSLStatus::DISPLAYED_INSECURE_CONTENT;
362 if (web_contents_impl->DisplayedInsecureContent())
363 entry->GetSSL().content_status |= SSLStatus::DISPLAYED_INSECURE_CONTENT;
364 if (!web_contents_impl->DisplayedContentWithCertErrors())
365 entry->GetSSL().content_status &=
366 ~SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS;
367 if (web_contents_impl->DisplayedContentWithCertErrors())
368 entry->GetSSL().content_status |=
369 SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS;
370
371 SiteInstance* site_instance = entry->site_instance();
372 // Note that |site_instance| can be NULL here because NavigationEntries don't
373 // necessarily have site instances. Without a process, the entry can't
374 // possibly have insecure content. See bug http://crbug.com/12423.
375 if (site_instance && ssl_host_state_delegate_ &&
376 ssl_host_state_delegate_->DidHostRunInsecureContent(
377 entry->GetURL().host(), site_instance->GetProcess()->GetID(),
378 SSLHostStateDelegate::MIXED_CONTENT)) {
379 entry->GetSSL().security_style = SECURITY_STYLE_AUTHENTICATION_BROKEN;
380 entry->GetSSL().content_status |= SSLStatus::RAN_INSECURE_CONTENT;
381 }
382
383 if (site_instance && ssl_host_state_delegate_ &&
384 ssl_host_state_delegate_->DidHostRunInsecureContent(
385 entry->GetURL().host(), site_instance->GetProcess()->GetID(),
386 SSLHostStateDelegate::CERT_ERRORS_CONTENT)) {
387 entry->GetSSL().security_style = SECURITY_STYLE_AUTHENTICATION_BROKEN;
388 entry->GetSSL().content_status |= SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS;
389 }
192 390
193 if (!entry->GetSSL().Equals(original_ssl_status)) 391 if (!entry->GetSSL().Equals(original_ssl_status))
194 NotifyDidChangeVisibleSSLState(); 392 NotifyDidChangeVisibleSSLState();
195 } 393 }
196 394
197 void SSLManager::NotifyDidChangeVisibleSSLState() { 395 void SSLManager::NotifyDidChangeVisibleSSLState() {
198 WebContentsImpl* contents = 396 WebContentsImpl* contents =
199 static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents()); 397 static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents());
200 contents->DidChangeVisibleSSLState(); 398 contents->DidChangeVisibleSSLState();
201 } 399 }
202 400
203 } // namespace content 401 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/ssl/ssl_manager.h ('k') | content/browser/ssl/ssl_policy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698