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

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

Powered by Google App Engine
This is Rietveld 408576698