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

Side by Side Diff: chrome/browser/ssl/chrome_ssl_host_state_delegate.cc

Issue 465133004: Remove DenyCertForHost from SSLHostStateDelegate API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on ToT Created 6 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/chrome_ssl_host_state_delegate.h" 5 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 23 matching lines...) Expand all
34 // the end of the current session. 34 // the end of the current session.
35 const int64 kForgetAtSessionEndSwitchValue = -1; 35 const int64 kForgetAtSessionEndSwitchValue = -1;
36 36
37 // Experiment information 37 // Experiment information
38 const char kRememberCertificateErrorDecisionsFieldTrialName[] = 38 const char kRememberCertificateErrorDecisionsFieldTrialName[] =
39 "RememberCertificateErrorDecisions"; 39 "RememberCertificateErrorDecisions";
40 const char kRememberCertificateErrorDecisionsFieldTrialDefaultGroup[] = 40 const char kRememberCertificateErrorDecisionsFieldTrialDefaultGroup[] =
41 "Default"; 41 "Default";
42 const char kRememberCertificateErrorDecisionsFieldTrialLengthParam[] = "length"; 42 const char kRememberCertificateErrorDecisionsFieldTrialLengthParam[] = "length";
43 43
44 // Keys for the per-site error + certificate finger to judgement content 44 // Keys for the per-site error + certificate finger to judgment content
45 // settings map. 45 // settings map.
46 const char kSSLCertDecisionCertErrorMapKey[] = "cert_exceptions_map"; 46 const char kSSLCertDecisionCertErrorMapKey[] = "cert_exceptions_map";
47 const char kSSLCertDecisionExpirationTimeKey[] = "decision_expiration_time"; 47 const char kSSLCertDecisionExpirationTimeKey[] = "decision_expiration_time";
48 const char kSSLCertDecisionVersionKey[] = "version"; 48 const char kSSLCertDecisionVersionKey[] = "version";
49 49
50 const int kDefaultSSLCertDecisionVersion = 1; 50 const int kDefaultSSLCertDecisionVersion = 1;
51 51
52 // Closes all idle network connections for the given URLRequestContext. This is
53 // a big hammer and should be wielded with extreme caution as it can have a big,
54 // negative impact on network performance. In this case, it is used by
55 // RevokeUserDecisionsHard, which should only be called by rare, user initiated
56 // events. See the comment before RevokeUserDecisionsHard implementation for
57 // more information.
58 void CloseIdleConnections( 52 void CloseIdleConnections(
59 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) { 53 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
60 url_request_context_getter-> 54 url_request_context_getter->
61 GetURLRequestContext()-> 55 GetURLRequestContext()->
62 http_transaction_factory()-> 56 http_transaction_factory()->
63 GetSession()-> 57 GetSession()->
64 CloseIdleConnections(); 58 CloseIdleConnections();
65 } 59 }
66 60
67 // All SSL decisions are per host (and are shared arcoss schemes), so this 61 // All SSL decisions are per host (and are shared arcoss schemes), so this
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 default_ssl_cert_decision_expiration_delta_ = 254 default_ssl_cert_decision_expiration_delta_ =
261 base::TimeDelta::FromSeconds(expiration_delta); 255 base::TimeDelta::FromSeconds(expiration_delta);
262 } 256 }
263 257
264 ChromeSSLHostStateDelegate::~ChromeSSLHostStateDelegate() { 258 ChromeSSLHostStateDelegate::~ChromeSSLHostStateDelegate() {
265 if (should_remember_ssl_decisions_ == 259 if (should_remember_ssl_decisions_ ==
266 FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END) 260 FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END)
267 Clear(); 261 Clear();
268 } 262 }
269 263
270 void ChromeSSLHostStateDelegate::DenyCert(const std::string& host,
271 const net::X509Certificate& cert,
272 net::CertStatus error) {
273 ChangeCertPolicy(host, cert, error, net::CertPolicy::DENIED);
274 }
275
276 void ChromeSSLHostStateDelegate::AllowCert(const std::string& host, 264 void ChromeSSLHostStateDelegate::AllowCert(const std::string& host,
277 const net::X509Certificate& cert, 265 const net::X509Certificate& cert,
278 net::CertStatus error) { 266 net::CertStatus error) {
279 ChangeCertPolicy(host, cert, error, net::CertPolicy::ALLOWED); 267 GURL url = GetSecureGURLForHost(host);
268 const ContentSettingsPattern pattern =
269 ContentSettingsPattern::FromURLNoWildcard(url);
270 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
271 scoped_ptr<base::Value> value(map->GetWebsiteSetting(
272 url, url, CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, std::string(), NULL));
273
274 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY))
275 value.reset(new base::DictionaryValue());
276
277 base::DictionaryValue* dict;
278 bool success = value->GetAsDictionary(&dict);
279 DCHECK(success);
280
281 bool expired_previous_decision; // unused value in this function
282 base::DictionaryValue* cert_dict = GetValidCertDecisionsDict(
283 dict, CREATE_DICTIONARY_ENTRIES, &expired_previous_decision);
284 // If a a valid certificate dictionary cannot be extracted from the content
285 // setting, that means it's in an unknown format. Unfortunately, there's
286 // nothing to be done in that case, so a silent fail is the only option.
287 if (!cert_dict)
288 return;
289
290 dict->SetIntegerWithoutPathExpansion(kSSLCertDecisionVersionKey,
291 kDefaultSSLCertDecisionVersion);
292 cert_dict->SetIntegerWithoutPathExpansion(GetKey(cert, error), ALLOWED);
293
294 // The map takes ownership of the value, so it is released in the call to
295 // SetWebsiteSetting.
296 map->SetWebsiteSetting(pattern,
297 pattern,
298 CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS,
299 std::string(),
300 value.release());
280 } 301 }
281 302
282 void ChromeSSLHostStateDelegate::Clear() { 303 void ChromeSSLHostStateDelegate::Clear() {
283 profile_->GetHostContentSettingsMap()->ClearSettingsForOneType( 304 profile_->GetHostContentSettingsMap()->ClearSettingsForOneType(
284 CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS); 305 CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS);
285 } 306 }
286 307
287 net::CertPolicy::Judgment ChromeSSLHostStateDelegate::QueryPolicy( 308 content::SSLHostStateDelegate::CertJudgment
288 const std::string& host, 309 ChromeSSLHostStateDelegate::QueryPolicy(const std::string& host,
289 const net::X509Certificate& cert, 310 const net::X509Certificate& cert,
290 net::CertStatus error, 311 net::CertStatus error,
291 bool* expired_previous_decision) { 312 bool* expired_previous_decision) {
292 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap(); 313 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
293 GURL url = GetSecureGURLForHost(host); 314 GURL url = GetSecureGURLForHost(host);
294 scoped_ptr<base::Value> value(map->GetWebsiteSetting( 315 scoped_ptr<base::Value> value(map->GetWebsiteSetting(
295 url, url, CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, std::string(), NULL)); 316 url, url, CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, std::string(), NULL));
296 317
297 // Set a default value in case this method is short circuited and doesn't do a 318 // Set a default value in case this method is short circuited and doesn't do a
298 // full query. 319 // full query.
299 *expired_previous_decision = false; 320 *expired_previous_decision = false;
300 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY)) 321 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY))
301 return net::CertPolicy::UNKNOWN; 322 return DENIED;
302 323
303 base::DictionaryValue* dict; // Owned by value 324 base::DictionaryValue* dict; // Owned by value
304 int policy_decision; 325 int policy_decision;
305 bool success = value->GetAsDictionary(&dict); 326 bool success = value->GetAsDictionary(&dict);
306 DCHECK(success); 327 DCHECK(success);
307 328
308 base::DictionaryValue* cert_error_dict; // Owned by value 329 base::DictionaryValue* cert_error_dict; // Owned by value
309 cert_error_dict = GetValidCertDecisionsDict( 330 cert_error_dict = GetValidCertDecisionsDict(
310 dict, DO_NOT_CREATE_DICTIONARY_ENTRIES, expired_previous_decision); 331 dict, DO_NOT_CREATE_DICTIONARY_ENTRIES, expired_previous_decision);
311 if (!cert_error_dict) { 332 if (!cert_error_dict) {
312 // This revoke is necessary to clear any old expired setting that may be 333 // This revoke is necessary to clear any old expired setting that may be
313 // lingering in the case that an old decision expried. 334 // lingering in the case that an old decision expried.
314 RevokeUserDecisions(host); 335 RevokeUserAllowExceptions(host);
315 return net::CertPolicy::UNKNOWN; 336 return DENIED;
316 } 337 }
317 338
318 success = cert_error_dict->GetIntegerWithoutPathExpansion(GetKey(cert, error), 339 success = cert_error_dict->GetIntegerWithoutPathExpansion(GetKey(cert, error),
319 &policy_decision); 340 &policy_decision);
320 341
321 // If a policy decision was successfully retrieved and it's a valid value of 342 // If a policy decision was successfully retrieved and it's a valid value of
322 // ALLOWED or DENIED, return the valid value. Otherwise, return UNKNOWN. 343 // ALLOWED, return the valid value. Otherwise, return DENIED.
323 if (success && policy_decision == net::CertPolicy::Judgment::ALLOWED) 344 if (success && policy_decision == ALLOWED)
324 return net::CertPolicy::Judgment::ALLOWED; 345 return ALLOWED;
325 else if (success && policy_decision == net::CertPolicy::Judgment::DENIED)
326 return net::CertPolicy::Judgment::DENIED;
327 346
328 return net::CertPolicy::Judgment::UNKNOWN; 347 return DENIED;
329 } 348 }
330 349
331 void ChromeSSLHostStateDelegate::RevokeUserDecisions(const std::string& host) { 350 void ChromeSSLHostStateDelegate::RevokeUserAllowExceptions(
351 const std::string& host) {
332 GURL url = GetSecureGURLForHost(host); 352 GURL url = GetSecureGURLForHost(host);
333 const ContentSettingsPattern pattern = 353 const ContentSettingsPattern pattern =
334 ContentSettingsPattern::FromURLNoWildcard(url); 354 ContentSettingsPattern::FromURLNoWildcard(url);
335 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap(); 355 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
336 356
337 map->SetWebsiteSetting(pattern, 357 map->SetWebsiteSetting(pattern,
338 pattern, 358 pattern,
339 CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, 359 CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS,
340 std::string(), 360 std::string(),
341 NULL); 361 NULL);
342 } 362 }
343 363
344 // TODO(jww): This will revoke all of the decisions in the browser context. 364 // TODO(jww): This will revoke all of the decisions in the browser context.
345 // However, the networking stack actually keeps track of its own list of 365 // However, the networking stack actually keeps track of its own list of
346 // exceptions per-HttpNetworkTransaction in the SSLConfig structure (see the 366 // exceptions per-HttpNetworkTransaction in the SSLConfig structure (see the
347 // allowed_bad_certs Vector in net/ssl/ssl_config.h). This dual-tracking of 367 // allowed_bad_certs Vector in net/ssl/ssl_config.h). This dual-tracking of
348 // exceptions introduces a problem where the browser context can revoke a 368 // exceptions introduces a problem where the browser context can revoke a
349 // certificate, but if a transaction reuses a cached version of the SSLConfig 369 // certificate, but if a transaction reuses a cached version of the SSLConfig
350 // (probably from a pooled socket), it may bypass the intestitial layer. 370 // (probably from a pooled socket), it may bypass the intestitial layer.
351 // 371 //
352 // Over time, the cached versions should expire and it should converge on 372 // Over time, the cached versions should expire and it should converge on
353 // showing the interstitial. We probably need to introduce into the networking 373 // showing the interstitial. We probably need to introduce into the networking
354 // stack a way revoke SSLConfig's allowed_bad_certs lists per socket. 374 // stack a way revoke SSLConfig's allowed_bad_certs lists per socket.
355 // 375 //
356 // For now, RevokeUserDecisionsHard is our solution for the rare case where it 376 // For now, RevokeUserAllowExceptionsHard is our solution for the rare case
357 // is necessary to revoke the preferences immediately. It does so by flushing 377 // where it is necessary to revoke the preferences immediately. It does so by
358 // idle sockets. 378 // flushing idle sockets, thus it is a big hammer and should be wielded with
359 void ChromeSSLHostStateDelegate::RevokeUserDecisionsHard( 379 // extreme caution as it can have a big, negative impact on network performance.
380 void ChromeSSLHostStateDelegate::RevokeUserAllowExceptionsHard(
360 const std::string& host) { 381 const std::string& host) {
361 RevokeUserDecisions(host); 382 RevokeUserAllowExceptions(host);
362 scoped_refptr<net::URLRequestContextGetter> getter( 383 scoped_refptr<net::URLRequestContextGetter> getter(
363 profile_->GetRequestContext()); 384 profile_->GetRequestContext());
364 getter->GetNetworkTaskRunner()->PostTask( 385 getter->GetNetworkTaskRunner()->PostTask(
365 FROM_HERE, base::Bind(&CloseIdleConnections, getter)); 386 FROM_HERE, base::Bind(&CloseIdleConnections, getter));
366 } 387 }
367 388
368 bool ChromeSSLHostStateDelegate::HasUserDecision( 389 bool ChromeSSLHostStateDelegate::HasAllowException(
369 const std::string& host) const { 390 const std::string& host) const {
370 GURL url = GetSecureGURLForHost(host); 391 GURL url = GetSecureGURLForHost(host);
371 const ContentSettingsPattern pattern = 392 const ContentSettingsPattern pattern =
372 ContentSettingsPattern::FromURLNoWildcard(url); 393 ContentSettingsPattern::FromURLNoWildcard(url);
373 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap(); 394 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
374 395
375 scoped_ptr<base::Value> value(map->GetWebsiteSetting( 396 scoped_ptr<base::Value> value(map->GetWebsiteSetting(
376 url, url, CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, std::string(), NULL)); 397 url, url, CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, std::string(), NULL));
377 398
378 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY)) 399 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY))
379 return false; 400 return false;
380 401
381 base::DictionaryValue* dict; // Owned by value 402 base::DictionaryValue* dict; // Owned by value
382 bool success = value->GetAsDictionary(&dict); 403 bool success = value->GetAsDictionary(&dict);
383 DCHECK(success); 404 DCHECK(success);
384 405
385 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { 406 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
386 int policy_decision; // Owned by dict 407 int policy_decision; // Owned by dict
387 success = it.value().GetAsInteger(&policy_decision); 408 success = it.value().GetAsInteger(&policy_decision);
388 if (success && (static_cast<net::CertPolicy::Judgment>(policy_decision) != 409 if (success && (static_cast<CertJudgment>(policy_decision) == ALLOWED))
389 net::CertPolicy::UNKNOWN))
390 return true; 410 return true;
391 } 411 }
392 412
393 return false; 413 return false;
394 } 414 }
395 415
396 void ChromeSSLHostStateDelegate::HostRanInsecureContent(const std::string& host, 416 void ChromeSSLHostStateDelegate::HostRanInsecureContent(const std::string& host,
397 int pid) { 417 int pid) {
398 ran_insecure_content_hosts_.insert(BrokenHostEntry(host, pid)); 418 ran_insecure_content_hosts_.insert(BrokenHostEntry(host, pid));
399 } 419 }
400 420
401 bool ChromeSSLHostStateDelegate::DidHostRunInsecureContent( 421 bool ChromeSSLHostStateDelegate::DidHostRunInsecureContent(
402 const std::string& host, 422 const std::string& host,
403 int pid) const { 423 int pid) const {
404 return !!ran_insecure_content_hosts_.count(BrokenHostEntry(host, pid)); 424 return !!ran_insecure_content_hosts_.count(BrokenHostEntry(host, pid));
405 } 425 }
406 void ChromeSSLHostStateDelegate::SetClock(scoped_ptr<base::Clock> clock) { 426 void ChromeSSLHostStateDelegate::SetClock(scoped_ptr<base::Clock> clock) {
407 clock_.reset(clock.release()); 427 clock_.reset(clock.release());
408 } 428 }
409
410 void ChromeSSLHostStateDelegate::ChangeCertPolicy(
411 const std::string& host,
412 const net::X509Certificate& cert,
413 net::CertStatus error,
414 const net::CertPolicy::Judgment judgment) {
415 GURL url = GetSecureGURLForHost(host);
416 const ContentSettingsPattern pattern =
417 ContentSettingsPattern::FromURLNoWildcard(url);
418 HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
419 scoped_ptr<base::Value> value(map->GetWebsiteSetting(
420 url, url, CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, std::string(), NULL));
421
422 if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY))
423 value.reset(new base::DictionaryValue());
424
425 base::DictionaryValue* dict;
426 bool success = value->GetAsDictionary(&dict);
427 DCHECK(success);
428
429 bool expired_previous_decision; // unused value in this function
430 base::DictionaryValue* cert_dict = GetValidCertDecisionsDict(
431 dict, CREATE_DICTIONARY_ENTRIES, &expired_previous_decision);
432 // If a a valid certificate dictionary cannot be extracted from the content
433 // setting, that means it's in an unknown format. Unfortunately, there's
434 // nothing to be done in that case, so a silent fail is the only option.
435 if (!cert_dict)
436 return;
437
438 dict->SetIntegerWithoutPathExpansion(kSSLCertDecisionVersionKey,
439 kDefaultSSLCertDecisionVersion);
440 cert_dict->SetIntegerWithoutPathExpansion(GetKey(cert, error), judgment);
441
442 // The map takes ownership of the value, so it is released in the call to
443 // SetWebsiteSetting.
444 map->SetWebsiteSetting(pattern,
445 pattern,
446 CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS,
447 std::string(),
448 value.release());
449 }
OLDNEW
« no previous file with comments | « chrome/browser/ssl/chrome_ssl_host_state_delegate.h ('k') | chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698