| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ssl/security_state_model.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include "base/command_line.h" | |
| 10 #include "base/metrics/field_trial.h" | |
| 11 #include "base/metrics/histogram_macros.h" | |
| 12 #include "chrome/browser/ssl/security_state_model_client.h" | |
| 13 #include "chrome/common/chrome_switches.h" | |
| 14 #include "net/ssl/ssl_cipher_suite_names.h" | |
| 15 #include "net/ssl/ssl_connection_status_flags.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 SecurityStateModel::SecurityLevel GetSecurityLevelForNonSecureFieldTrial() { | |
| 20 // TODO(estark): componentize switches::kMarkNonSecureAs. | |
| 21 // https://crbug.com/515071 | |
| 22 std::string choice = | |
| 23 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 24 switches::kMarkNonSecureAs); | |
| 25 std::string group = base::FieldTrialList::FindFullName("MarkNonSecureAs"); | |
| 26 | |
| 27 // Do not change this enum. It is used in the histogram. | |
| 28 enum MarkNonSecureStatus { NEUTRAL, DUBIOUS, NON_SECURE, LAST_STATUS }; | |
| 29 const char kEnumeration[] = "MarkNonSecureAs"; | |
| 30 | |
| 31 SecurityStateModel::SecurityLevel level = SecurityStateModel::NONE; | |
| 32 MarkNonSecureStatus status; | |
| 33 | |
| 34 if (choice == switches::kMarkNonSecureAsNeutral) { | |
| 35 status = NEUTRAL; | |
| 36 level = SecurityStateModel::NONE; | |
| 37 } else if (choice == switches::kMarkNonSecureAsNonSecure) { | |
| 38 status = NON_SECURE; | |
| 39 level = SecurityStateModel::SECURITY_ERROR; | |
| 40 } else if (group == switches::kMarkNonSecureAsNeutral) { | |
| 41 status = NEUTRAL; | |
| 42 level = SecurityStateModel::NONE; | |
| 43 } else if (group == switches::kMarkNonSecureAsNonSecure) { | |
| 44 status = NON_SECURE; | |
| 45 level = SecurityStateModel::SECURITY_ERROR; | |
| 46 } else { | |
| 47 status = NEUTRAL; | |
| 48 level = SecurityStateModel::NONE; | |
| 49 } | |
| 50 | |
| 51 UMA_HISTOGRAM_ENUMERATION(kEnumeration, status, LAST_STATUS); | |
| 52 return level; | |
| 53 } | |
| 54 | |
| 55 SecurityStateModel::SHA1DeprecationStatus GetSHA1DeprecationStatus( | |
| 56 scoped_refptr<net::X509Certificate> cert, | |
| 57 const SecurityStateModel::VisibleSecurityState& visible_security_state) { | |
| 58 if (!cert || | |
| 59 !(visible_security_state.cert_status & | |
| 60 net::CERT_STATUS_SHA1_SIGNATURE_PRESENT)) | |
| 61 return SecurityStateModel::NO_DEPRECATED_SHA1; | |
| 62 | |
| 63 // The internal representation of the dates for UI treatment of SHA-1. | |
| 64 // See http://crbug.com/401365 for details. | |
| 65 static const int64_t kJanuary2017 = INT64_C(13127702400000000); | |
| 66 if (cert->valid_expiry() >= base::Time::FromInternalValue(kJanuary2017)) | |
| 67 return SecurityStateModel::DEPRECATED_SHA1_MAJOR; | |
| 68 static const int64_t kJanuary2016 = INT64_C(13096080000000000); | |
| 69 if (cert->valid_expiry() >= base::Time::FromInternalValue(kJanuary2016)) | |
| 70 return SecurityStateModel::DEPRECATED_SHA1_MINOR; | |
| 71 | |
| 72 return SecurityStateModel::NO_DEPRECATED_SHA1; | |
| 73 } | |
| 74 | |
| 75 SecurityStateModel::MixedContentStatus GetMixedContentStatus( | |
| 76 const SecurityStateModel::VisibleSecurityState& visible_security_state) { | |
| 77 bool ran_insecure_content = visible_security_state.ran_mixed_content; | |
| 78 bool displayed_insecure_content = | |
| 79 visible_security_state.displayed_mixed_content; | |
| 80 if (ran_insecure_content && displayed_insecure_content) | |
| 81 return SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; | |
| 82 if (ran_insecure_content) | |
| 83 return SecurityStateModel::RAN_MIXED_CONTENT; | |
| 84 if (displayed_insecure_content) | |
| 85 return SecurityStateModel::DISPLAYED_MIXED_CONTENT; | |
| 86 | |
| 87 return SecurityStateModel::NO_MIXED_CONTENT; | |
| 88 } | |
| 89 | |
| 90 SecurityStateModel::SecurityLevel GetSecurityLevelForRequest( | |
| 91 const SecurityStateModel::VisibleSecurityState& visible_security_state, | |
| 92 SecurityStateModelClient* client, | |
| 93 const scoped_refptr<net::X509Certificate>& cert, | |
| 94 SecurityStateModel::SHA1DeprecationStatus sha1_status, | |
| 95 SecurityStateModel::MixedContentStatus mixed_content_status) { | |
| 96 DCHECK(visible_security_state.initialized); | |
| 97 GURL url = visible_security_state.url; | |
| 98 switch (visible_security_state.initial_security_level) { | |
| 99 case SecurityStateModel::NONE: { | |
| 100 if (!client->IsOriginSecure(url) && url.IsStandard()) | |
| 101 return GetSecurityLevelForNonSecureFieldTrial(); | |
| 102 return SecurityStateModel::NONE; | |
| 103 } | |
| 104 | |
| 105 case SecurityStateModel::SECURITY_ERROR: | |
| 106 return SecurityStateModel::SECURITY_ERROR; | |
| 107 | |
| 108 case SecurityStateModel::SECURITY_WARNING: | |
| 109 case SecurityStateModel::SECURITY_POLICY_WARNING: | |
| 110 return visible_security_state.initial_security_level; | |
| 111 | |
| 112 case SecurityStateModel::SECURE: | |
| 113 case SecurityStateModel::EV_SECURE: { | |
| 114 // Major cert errors and active mixed content will generally be | |
| 115 // downgraded by the embedder to SECURITY_ERROR and handled above, | |
| 116 // but downgrade here just in case. | |
| 117 net::CertStatus cert_status = visible_security_state.cert_status; | |
| 118 if (net::IsCertStatusError(cert_status) && | |
| 119 !net::IsCertStatusMinorError(cert_status)) { | |
| 120 return SecurityStateModel::SECURITY_ERROR; | |
| 121 } | |
| 122 if (mixed_content_status == SecurityStateModel::RAN_MIXED_CONTENT || | |
| 123 mixed_content_status == | |
| 124 SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT) { | |
| 125 return SecurityStateModel::kRanInsecureContentLevel; | |
| 126 } | |
| 127 | |
| 128 // Report if there is a policy cert first, before reporting any other | |
| 129 // authenticated-but-with-errors cases. A policy cert is a strong | |
| 130 // indicator of a MITM being present (the enterprise), while the | |
| 131 // other authenticated-but-with-errors indicate something may | |
| 132 // be wrong, or may be wrong in the future, but is unclear now. | |
| 133 if (client->UsedPolicyInstalledCertificate()) | |
| 134 return SecurityStateModel::SECURITY_POLICY_WARNING; | |
| 135 | |
| 136 if (sha1_status == SecurityStateModel::DEPRECATED_SHA1_MAJOR) | |
| 137 return SecurityStateModel::SECURITY_ERROR; | |
| 138 if (sha1_status == SecurityStateModel::DEPRECATED_SHA1_MINOR) | |
| 139 return SecurityStateModel::NONE; | |
| 140 | |
| 141 // Active mixed content is handled above. | |
| 142 DCHECK_NE(SecurityStateModel::RAN_MIXED_CONTENT, mixed_content_status); | |
| 143 DCHECK_NE(SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT, | |
| 144 mixed_content_status); | |
| 145 if (mixed_content_status == SecurityStateModel::DISPLAYED_MIXED_CONTENT) | |
| 146 return SecurityStateModel::kDisplayedInsecureContentLevel; | |
| 147 | |
| 148 if (net::IsCertStatusError(cert_status)) { | |
| 149 // Major cert errors are handled above. | |
| 150 DCHECK(net::IsCertStatusMinorError(cert_status)); | |
| 151 return SecurityStateModel::NONE; | |
| 152 } | |
| 153 if (net::SSLConnectionStatusToVersion( | |
| 154 visible_security_state.connection_status) == | |
| 155 net::SSL_CONNECTION_VERSION_SSL3) { | |
| 156 // SSLv3 will be removed in the future. | |
| 157 return SecurityStateModel::SECURITY_WARNING; | |
| 158 } | |
| 159 if ((cert_status & net::CERT_STATUS_IS_EV) && cert) | |
| 160 return SecurityStateModel::EV_SECURE; | |
| 161 return SecurityStateModel::SECURE; | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 return SecurityStateModel::NONE; | |
| 166 } | |
| 167 | |
| 168 void SecurityInfoForRequest( | |
| 169 SecurityStateModelClient* client, | |
| 170 const SecurityStateModel::VisibleSecurityState& visible_security_state, | |
| 171 const scoped_refptr<net::X509Certificate>& cert, | |
| 172 SecurityStateModel::SecurityInfo* security_info) { | |
| 173 if (!visible_security_state.initialized) { | |
| 174 *security_info = SecurityStateModel::SecurityInfo(); | |
| 175 return; | |
| 176 } | |
| 177 security_info->cert_id = visible_security_state.cert_id; | |
| 178 security_info->sha1_deprecation_status = | |
| 179 GetSHA1DeprecationStatus(cert, visible_security_state); | |
| 180 security_info->mixed_content_status = | |
| 181 GetMixedContentStatus(visible_security_state); | |
| 182 security_info->security_bits = visible_security_state.security_bits; | |
| 183 security_info->connection_status = visible_security_state.connection_status; | |
| 184 security_info->cert_status = visible_security_state.cert_status; | |
| 185 security_info->scheme_is_cryptographic = | |
| 186 visible_security_state.url.SchemeIsCryptographic(); | |
| 187 security_info->is_secure_protocol_and_ciphersuite = | |
| 188 (net::SSLConnectionStatusToVersion(security_info->connection_status) >= | |
| 189 net::SSL_CONNECTION_VERSION_TLS1_2 && | |
| 190 net::IsSecureTLSCipherSuite(net::SSLConnectionStatusToCipherSuite( | |
| 191 security_info->connection_status))); | |
| 192 | |
| 193 security_info->sct_verify_statuses = | |
| 194 visible_security_state.sct_verify_statuses; | |
| 195 | |
| 196 security_info->security_level = | |
| 197 GetSecurityLevelForRequest(visible_security_state, client, cert, | |
| 198 security_info->sha1_deprecation_status, | |
| 199 security_info->mixed_content_status); | |
| 200 } | |
| 201 | |
| 202 } // namespace | |
| 203 | |
| 204 const SecurityStateModel::SecurityLevel | |
| 205 SecurityStateModel::kDisplayedInsecureContentLevel = | |
| 206 SecurityStateModel::NONE; | |
| 207 const SecurityStateModel::SecurityLevel | |
| 208 SecurityStateModel::kRanInsecureContentLevel = | |
| 209 SecurityStateModel::SECURITY_ERROR; | |
| 210 | |
| 211 SecurityStateModel::SecurityInfo::SecurityInfo() | |
| 212 : security_level(SecurityStateModel::NONE), | |
| 213 sha1_deprecation_status(SecurityStateModel::NO_DEPRECATED_SHA1), | |
| 214 mixed_content_status(SecurityStateModel::NO_MIXED_CONTENT), | |
| 215 scheme_is_cryptographic(false), | |
| 216 cert_status(0), | |
| 217 cert_id(0), | |
| 218 security_bits(-1), | |
| 219 connection_status(0), | |
| 220 is_secure_protocol_and_ciphersuite(false) {} | |
| 221 | |
| 222 SecurityStateModel::SecurityInfo::~SecurityInfo() {} | |
| 223 | |
| 224 SecurityStateModel::SecurityStateModel() {} | |
| 225 | |
| 226 SecurityStateModel::~SecurityStateModel() {} | |
| 227 | |
| 228 const SecurityStateModel::SecurityInfo& SecurityStateModel::GetSecurityInfo() | |
| 229 const { | |
| 230 scoped_refptr<net::X509Certificate> cert = nullptr; | |
| 231 client_->RetrieveCert(&cert); | |
| 232 | |
| 233 // Check if the cached |security_info_| must be recomputed. | |
| 234 VisibleSecurityState new_visible_state; | |
| 235 client_->GetVisibleSecurityState(&new_visible_state); | |
| 236 bool visible_security_state_changed = | |
| 237 !(visible_security_state_ == new_visible_state); | |
| 238 if (!visible_security_state_changed) { | |
| 239 // A cert must be present in order for the site to be considered | |
| 240 // EV_SECURE, and the cert might have been removed since the | |
| 241 // security level was last computed. | |
| 242 if (security_info_.security_level == EV_SECURE && !cert) { | |
| 243 security_info_.security_level = SECURE; | |
| 244 } | |
| 245 return security_info_; | |
| 246 } | |
| 247 | |
| 248 visible_security_state_ = new_visible_state; | |
| 249 SecurityInfoForRequest(client_, visible_security_state_, cert, | |
| 250 &security_info_); | |
| 251 return security_info_; | |
| 252 } | |
| 253 | |
| 254 void SecurityStateModel::SetClient(SecurityStateModelClient* client) { | |
| 255 client_ = client; | |
| 256 } | |
| 257 | |
| 258 SecurityStateModel::VisibleSecurityState::VisibleSecurityState() | |
| 259 : initialized(false), | |
| 260 initial_security_level(SecurityStateModel::NONE), | |
| 261 cert_id(0), | |
| 262 cert_status(0), | |
| 263 connection_status(0), | |
| 264 security_bits(-1), | |
| 265 displayed_mixed_content(false), | |
| 266 ran_mixed_content(false) {} | |
| 267 | |
| 268 SecurityStateModel::VisibleSecurityState::~VisibleSecurityState() {} | |
| 269 | |
| 270 bool SecurityStateModel::VisibleSecurityState::operator==( | |
| 271 const SecurityStateModel::VisibleSecurityState& other) const { | |
| 272 return (url == other.url && | |
| 273 initial_security_level == other.initial_security_level && | |
| 274 cert_id == other.cert_id && cert_status == other.cert_status && | |
| 275 connection_status == other.connection_status && | |
| 276 security_bits == other.security_bits && | |
| 277 sct_verify_statuses == other.sct_verify_statuses && | |
| 278 displayed_mixed_content == other.displayed_mixed_content && | |
| 279 ran_mixed_content == other.ran_mixed_content); | |
| 280 } | |
| OLD | NEW |