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

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

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

Powered by Google App Engine
This is Rietveld 408576698