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

Side by Side Diff: components/security_state/security_state_model.cc

Issue 2448943002: Refactor SecurityStateModel/Clients for simplicity and reusability. (Closed)
Patch Set: sync. Created 4 years, 1 month 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
OLDNEW
(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 "components/security_state/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 "components/security_state/security_state_model_client.h"
13 #include "components/security_state/switches.h"
14 #include "net/ssl/ssl_cipher_suite_names.h"
15 #include "net/ssl/ssl_connection_status_flags.h"
16
17 namespace security_state {
18
19 namespace {
20
21 // Do not change or reorder this enum, and add new values at the end. It is used
22 // in the MarkHttpAs histogram.
23 enum MarkHttpStatus { NEUTRAL, NON_SECURE, HTTP_SHOW_WARNING, LAST_STATUS };
24
25 // If |switch_or_field_trial_group| corresponds to a valid
26 // MarkHttpAs group, sets |*level| and |*histogram_status| to the
27 // appropriate values and returns true. Otherwise, returns false.
28 bool GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
29 std::string switch_or_field_trial_group,
30 bool displayed_sensitive_input_on_http,
31 SecurityStateModel::SecurityLevel* level,
32 MarkHttpStatus* histogram_status) {
33 if (switch_or_field_trial_group == switches::kMarkHttpAsNeutral) {
34 *level = SecurityStateModel::NONE;
35 *histogram_status = NEUTRAL;
36 return true;
37 }
38
39 if (switch_or_field_trial_group == switches::kMarkHttpAsDangerous) {
40 *level = SecurityStateModel::DANGEROUS;
41 *histogram_status = NON_SECURE;
42 return true;
43 }
44
45 if (switch_or_field_trial_group ==
46 switches::kMarkHttpWithPasswordsOrCcWithChip ||
47 switch_or_field_trial_group ==
48 switches::kMarkHttpWithPasswordsOrCcWithChipAndFormWarning) {
49 if (displayed_sensitive_input_on_http) {
50 *level = SecurityStateModel::HTTP_SHOW_WARNING;
51 } else {
52 *level = SecurityStateModel::NONE;
53 }
54 *histogram_status = HTTP_SHOW_WARNING;
55 return true;
56 }
57
58 return false;
59 }
60
61 SecurityStateModel::SecurityLevel GetSecurityLevelForNonSecureFieldTrial(
62 bool displayed_sensitive_input_on_http) {
63 std::string choice =
64 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
65 switches::kMarkHttpAs);
66 std::string group = base::FieldTrialList::FindFullName("MarkNonSecureAs");
67
68 const char kEnumeration[] = "SSL.MarkHttpAsStatus";
69
70 SecurityStateModel::SecurityLevel level = SecurityStateModel::NONE;
71 MarkHttpStatus status;
72
73 // If the command-line switch is set, then it takes precedence over
74 // the field trial group.
75 if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
76 choice, displayed_sensitive_input_on_http, &level, &status)) {
77 if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
78 group, displayed_sensitive_input_on_http, &level, &status)) {
79 // If neither the command-line switch nor field trial group is set, then
80 // nonsecure defaults to neutral.
81 status = NEUTRAL;
82 level = SecurityStateModel::NONE;
83 }
84 }
85
86 UMA_HISTOGRAM_ENUMERATION(kEnumeration, status, LAST_STATUS);
87 return level;
88 }
89
90 SecurityStateModel::SHA1DeprecationStatus GetSHA1DeprecationStatus(
91 const SecurityStateModel::VisibleSecurityState& visible_security_state) {
92 if (!visible_security_state.certificate ||
93 !(visible_security_state.cert_status &
94 net::CERT_STATUS_SHA1_SIGNATURE_PRESENT))
95 return SecurityStateModel::NO_DEPRECATED_SHA1;
96
97 // The internal representation of the dates for UI treatment of SHA-1.
98 // See http://crbug.com/401365 for details.
99 static const int64_t kJanuary2017 = INT64_C(13127702400000000);
100 if (visible_security_state.certificate->valid_expiry() >=
101 base::Time::FromInternalValue(kJanuary2017))
102 return SecurityStateModel::DEPRECATED_SHA1_MAJOR;
103 static const int64_t kJanuary2016 = INT64_C(13096080000000000);
104 if (visible_security_state.certificate->valid_expiry() >=
105 base::Time::FromInternalValue(kJanuary2016))
106 return SecurityStateModel::DEPRECATED_SHA1_MINOR;
107
108 return SecurityStateModel::NO_DEPRECATED_SHA1;
109 }
110
111 SecurityStateModel::ContentStatus GetContentStatus(bool displayed, bool ran) {
112 if (ran && displayed)
113 return SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN;
114 if (ran)
115 return SecurityStateModel::CONTENT_STATUS_RAN;
116 if (displayed)
117 return SecurityStateModel::CONTENT_STATUS_DISPLAYED;
118 return SecurityStateModel::CONTENT_STATUS_NONE;
119 }
120
121 SecurityStateModel::SecurityLevel GetSecurityLevelForRequest(
122 const SecurityStateModel::VisibleSecurityState& visible_security_state,
123 SecurityStateModelClient* client,
124 SecurityStateModel::SHA1DeprecationStatus sha1_status,
125 SecurityStateModel::ContentStatus mixed_content_status,
126 SecurityStateModel::ContentStatus content_with_cert_errors_status) {
127 DCHECK(visible_security_state.connection_info_initialized ||
128 visible_security_state.malicious_content_status !=
129 SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE);
130
131 // Override the connection security information if the website failed the
132 // browser's malware checks.
133 if (visible_security_state.malicious_content_status !=
134 SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE) {
135 return SecurityStateModel::DANGEROUS;
136 }
137
138 GURL url = visible_security_state.url;
139
140 bool is_cryptographic_with_certificate =
141 (url.SchemeIsCryptographic() && visible_security_state.certificate);
142
143 // Set the security level to DANGEROUS for major certificate errors.
144 if (is_cryptographic_with_certificate &&
145 net::IsCertStatusError(visible_security_state.cert_status) &&
146 !net::IsCertStatusMinorError(visible_security_state.cert_status)) {
147 return SecurityStateModel::DANGEROUS;
148 }
149
150 // Choose the appropriate security level for HTTP requests.
151 if (!is_cryptographic_with_certificate) {
152 if (!client->IsOriginSecure(url) && url.IsStandard()) {
153 return GetSecurityLevelForNonSecureFieldTrial(
154 visible_security_state.displayed_password_field_on_http ||
155 visible_security_state.displayed_credit_card_field_on_http);
156 }
157 return SecurityStateModel::NONE;
158 }
159
160 // Downgrade the security level for active insecure subresources.
161 if (mixed_content_status == SecurityStateModel::CONTENT_STATUS_RAN ||
162 mixed_content_status ==
163 SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN ||
164 content_with_cert_errors_status ==
165 SecurityStateModel::CONTENT_STATUS_RAN ||
166 content_with_cert_errors_status ==
167 SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN) {
168 return SecurityStateModel::kRanInsecureContentLevel;
169 }
170
171 // Report if there is a policy cert first, before reporting any other
172 // authenticated-but-with-errors cases. A policy cert is a strong
173 // indicator of a MITM being present (the enterprise), while the
174 // other authenticated-but-with-errors indicate something may
175 // be wrong, or may be wrong in the future, but is unclear now.
176 if (client->UsedPolicyInstalledCertificate())
177 return SecurityStateModel::SECURE_WITH_POLICY_INSTALLED_CERT;
178
179 if (sha1_status == SecurityStateModel::DEPRECATED_SHA1_MAJOR)
180 return SecurityStateModel::DANGEROUS;
181 if (sha1_status == SecurityStateModel::DEPRECATED_SHA1_MINOR)
182 return SecurityStateModel::NONE;
183
184 // Active mixed content is handled above.
185 DCHECK_NE(SecurityStateModel::CONTENT_STATUS_RAN, mixed_content_status);
186 DCHECK_NE(SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN,
187 mixed_content_status);
188
189 if (mixed_content_status == SecurityStateModel::CONTENT_STATUS_DISPLAYED ||
190 content_with_cert_errors_status ==
191 SecurityStateModel::CONTENT_STATUS_DISPLAYED) {
192 return SecurityStateModel::kDisplayedInsecureContentLevel;
193 }
194
195 if (net::IsCertStatusError(visible_security_state.cert_status)) {
196 // Major cert errors are handled above.
197 DCHECK(net::IsCertStatusMinorError(visible_security_state.cert_status));
198 return SecurityStateModel::NONE;
199 }
200
201 if ((visible_security_state.cert_status & net::CERT_STATUS_IS_EV) &&
202 visible_security_state.certificate) {
203 return SecurityStateModel::EV_SECURE;
204 }
205 return SecurityStateModel::SECURE;
206 }
207
208 void SecurityInfoForRequest(
209 SecurityStateModelClient* client,
210 const SecurityStateModel::VisibleSecurityState& visible_security_state,
211 SecurityStateModel::SecurityInfo* security_info) {
212 if (!visible_security_state.connection_info_initialized) {
213 *security_info = SecurityStateModel::SecurityInfo();
214 security_info->malicious_content_status =
215 visible_security_state.malicious_content_status;
216 if (security_info->malicious_content_status !=
217 SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE) {
218 security_info->security_level = GetSecurityLevelForRequest(
219 visible_security_state, client, SecurityStateModel::UNKNOWN_SHA1,
220 SecurityStateModel::CONTENT_STATUS_UNKNOWN,
221 SecurityStateModel::CONTENT_STATUS_UNKNOWN);
222 }
223 return;
224 }
225 security_info->certificate = visible_security_state.certificate;
226 security_info->sha1_deprecation_status =
227 GetSHA1DeprecationStatus(visible_security_state);
228 security_info->mixed_content_status =
229 GetContentStatus(visible_security_state.displayed_mixed_content,
230 visible_security_state.ran_mixed_content);
231 security_info->content_with_cert_errors_status = GetContentStatus(
232 visible_security_state.displayed_content_with_cert_errors,
233 visible_security_state.ran_content_with_cert_errors);
234 security_info->security_bits = visible_security_state.security_bits;
235 security_info->connection_status = visible_security_state.connection_status;
236 security_info->key_exchange_group = visible_security_state.key_exchange_group;
237 security_info->cert_status = visible_security_state.cert_status;
238 security_info->scheme_is_cryptographic =
239 visible_security_state.url.SchemeIsCryptographic();
240 security_info->obsolete_ssl_status =
241 net::ObsoleteSSLStatus(security_info->connection_status);
242 security_info->pkp_bypassed = visible_security_state.pkp_bypassed;
243 security_info->sct_verify_statuses =
244 visible_security_state.sct_verify_statuses;
245
246 security_info->malicious_content_status =
247 visible_security_state.malicious_content_status;
248
249 security_info->displayed_password_field_on_http =
250 visible_security_state.displayed_password_field_on_http;
251 security_info->displayed_credit_card_field_on_http =
252 visible_security_state.displayed_credit_card_field_on_http;
253
254 security_info->security_level = GetSecurityLevelForRequest(
255 visible_security_state, client, security_info->sha1_deprecation_status,
256 security_info->mixed_content_status,
257 security_info->content_with_cert_errors_status);
258 }
259
260 } // namespace
261
262 const SecurityStateModel::SecurityLevel
263 SecurityStateModel::kDisplayedInsecureContentLevel =
264 SecurityStateModel::NONE;
265 const SecurityStateModel::SecurityLevel
266 SecurityStateModel::kRanInsecureContentLevel =
267 SecurityStateModel::DANGEROUS;
268
269 SecurityStateModel::SecurityInfo::SecurityInfo()
270 : security_level(SecurityStateModel::NONE),
271 malicious_content_status(
272 SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE),
273 sha1_deprecation_status(SecurityStateModel::NO_DEPRECATED_SHA1),
274 mixed_content_status(SecurityStateModel::CONTENT_STATUS_NONE),
275 content_with_cert_errors_status(SecurityStateModel::CONTENT_STATUS_NONE),
276 scheme_is_cryptographic(false),
277 cert_status(0),
278 security_bits(-1),
279 connection_status(0),
280 key_exchange_group(0),
281 obsolete_ssl_status(net::OBSOLETE_SSL_NONE),
282 pkp_bypassed(false),
283 displayed_password_field_on_http(false),
284 displayed_credit_card_field_on_http(false) {}
285
286 SecurityStateModel::SecurityInfo::~SecurityInfo() {}
287
288 SecurityStateModel::SecurityStateModel() {}
289
290 SecurityStateModel::~SecurityStateModel() {}
291
292 void SecurityStateModel::GetSecurityInfo(
293 SecurityStateModel::SecurityInfo* result) const {
294 VisibleSecurityState new_visible_state;
295 client_->GetVisibleSecurityState(&new_visible_state);
296 SecurityInfoForRequest(client_, new_visible_state, result);
297 }
298
299 void SecurityStateModel::SetClient(SecurityStateModelClient* client) {
300 client_ = client;
301 }
302
303 SecurityStateModel::VisibleSecurityState::VisibleSecurityState()
304 : malicious_content_status(
305 SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE),
306 connection_info_initialized(false),
307 cert_status(0),
308 connection_status(0),
309 key_exchange_group(0),
310 security_bits(-1),
311 displayed_mixed_content(false),
312 ran_mixed_content(false),
313 displayed_content_with_cert_errors(false),
314 ran_content_with_cert_errors(false),
315 pkp_bypassed(false),
316 displayed_password_field_on_http(false),
317 displayed_credit_card_field_on_http(false) {}
318
319 SecurityStateModel::VisibleSecurityState::~VisibleSecurityState() {}
320
321 bool SecurityStateModel::VisibleSecurityState::operator==(
322 const SecurityStateModel::VisibleSecurityState& other) const {
323 return (url == other.url &&
324 malicious_content_status == other.malicious_content_status &&
325 !!certificate == !!other.certificate &&
326 (certificate ? certificate->Equals(other.certificate.get()) : true) &&
327 connection_status == other.connection_status &&
328 key_exchange_group == other.key_exchange_group &&
329 security_bits == other.security_bits &&
330 sct_verify_statuses == other.sct_verify_statuses &&
331 displayed_mixed_content == other.displayed_mixed_content &&
332 ran_mixed_content == other.ran_mixed_content &&
333 displayed_content_with_cert_errors ==
334 other.displayed_content_with_cert_errors &&
335 ran_content_with_cert_errors == other.ran_content_with_cert_errors &&
336 pkp_bypassed == other.pkp_bypassed &&
337 displayed_password_field_on_http ==
338 other.displayed_password_field_on_http &&
339 displayed_credit_card_field_on_http ==
340 other.displayed_credit_card_field_on_http);
341 }
342
343 } // namespace security_state
OLDNEW
« no previous file with comments | « components/security_state/security_state_model.h ('k') | components/security_state/security_state_model_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698