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

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

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

Powered by Google App Engine
This is Rietveld 408576698