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 "components/security_state/security_state_model.h" | |
6 | |
7 #include <stdint.h> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/test/histogram_tester.h" | |
11 #include "components/security_state/security_state_model_client.h" | |
12 #include "components/security_state/switches.h" | |
13 #include "net/cert/x509_certificate.h" | |
14 #include "net/ssl/ssl_cipher_suite_names.h" | |
15 #include "net/ssl/ssl_connection_status_flags.h" | |
16 #include "net/test/cert_test_util.h" | |
17 #include "net/test/test_certificate_data.h" | |
18 #include "net/test/test_data_directory.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 namespace security_state { | |
22 | |
23 namespace { | |
24 | |
25 const char kHttpsUrl[] = "https://foo.test/"; | |
26 const char kHttpUrl[] = "http://foo.test/"; | |
27 | |
28 class TestSecurityStateModelClient : public SecurityStateModelClient { | |
29 public: | |
30 TestSecurityStateModelClient() | |
31 : url_(kHttpsUrl), | |
32 connection_status_(net::SSL_CONNECTION_VERSION_TLS1_2 | |
33 << net::SSL_CONNECTION_VERSION_SHIFT), | |
34 cert_status_(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT), | |
35 displayed_mixed_content_(false), | |
36 ran_mixed_content_(false), | |
37 malicious_content_status_( | |
38 SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE), | |
39 displayed_password_field_on_http_(false), | |
40 displayed_credit_card_field_on_http_(false) { | |
41 cert_ = | |
42 net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_2016.pem"); | |
43 } | |
44 ~TestSecurityStateModelClient() override {} | |
45 | |
46 void set_connection_status(int connection_status) { | |
47 connection_status_ = connection_status; | |
48 } | |
49 void SetCipherSuite(uint16_t ciphersuite) { | |
50 net::SSLConnectionStatusSetCipherSuite(ciphersuite, &connection_status_); | |
51 } | |
52 void AddCertStatus(net::CertStatus cert_status) { | |
53 cert_status_ |= cert_status; | |
54 } | |
55 void SetDisplayedMixedContent(bool displayed_mixed_content) { | |
56 displayed_mixed_content_ = displayed_mixed_content; | |
57 } | |
58 void SetRanMixedContent(bool ran_mixed_content) { | |
59 ran_mixed_content_ = ran_mixed_content; | |
60 } | |
61 void set_malicious_content_status( | |
62 SecurityStateModel::MaliciousContentStatus malicious_content_status) { | |
63 malicious_content_status_ = malicious_content_status; | |
64 } | |
65 void set_displayed_password_field_on_http( | |
66 bool displayed_password_field_on_http) { | |
67 displayed_password_field_on_http_ = displayed_password_field_on_http; | |
68 } | |
69 void set_displayed_credit_card_field_on_http( | |
70 bool displayed_credit_card_field_on_http) { | |
71 displayed_credit_card_field_on_http_ = displayed_credit_card_field_on_http; | |
72 } | |
73 | |
74 void UseHttpUrl() { url_ = GURL(kHttpUrl); } | |
75 | |
76 // SecurityStateModelClient: | |
77 void GetVisibleSecurityState( | |
78 SecurityStateModel::VisibleSecurityState* state) override { | |
79 state->connection_info_initialized = true; | |
80 state->url = url_; | |
81 state->certificate = cert_; | |
82 state->cert_status = cert_status_; | |
83 state->connection_status = connection_status_; | |
84 state->security_bits = 256; | |
85 state->displayed_mixed_content = displayed_mixed_content_; | |
86 state->ran_mixed_content = ran_mixed_content_; | |
87 state->malicious_content_status = malicious_content_status_; | |
88 state->displayed_password_field_on_http = displayed_password_field_on_http_; | |
89 state->displayed_credit_card_field_on_http = | |
90 displayed_credit_card_field_on_http_; | |
91 } | |
92 | |
93 bool UsedPolicyInstalledCertificate() override { return false; } | |
94 | |
95 bool IsOriginSecure(const GURL& url) override { | |
96 return url_ == kHttpsUrl; | |
97 } | |
98 | |
99 private: | |
100 GURL url_; | |
101 scoped_refptr<net::X509Certificate> cert_; | |
102 int connection_status_; | |
103 net::CertStatus cert_status_; | |
104 bool displayed_mixed_content_; | |
105 bool ran_mixed_content_; | |
106 SecurityStateModel::MaliciousContentStatus malicious_content_status_; | |
107 bool displayed_password_field_on_http_; | |
108 bool displayed_credit_card_field_on_http_; | |
109 }; | |
110 | |
111 // Tests that SHA1-signed certificates expiring in 2016 downgrade the | |
112 // security state of the page. | |
113 TEST(SecurityStateModelTest, SHA1Warning) { | |
114 TestSecurityStateModelClient client; | |
115 SecurityStateModel model; | |
116 model.SetClient(&client); | |
117 SecurityStateModel::SecurityInfo security_info; | |
118 model.GetSecurityInfo(&security_info); | |
119 EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR, | |
120 security_info.sha1_deprecation_status); | |
121 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
122 } | |
123 | |
124 // Tests that SHA1 warnings don't interfere with the handling of mixed | |
125 // content. | |
126 TEST(SecurityStateModelTest, SHA1WarningMixedContent) { | |
127 TestSecurityStateModelClient client; | |
128 SecurityStateModel model; | |
129 model.SetClient(&client); | |
130 client.SetDisplayedMixedContent(true); | |
131 SecurityStateModel::SecurityInfo security_info1; | |
132 model.GetSecurityInfo(&security_info1); | |
133 EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR, | |
134 security_info1.sha1_deprecation_status); | |
135 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_DISPLAYED, | |
136 security_info1.mixed_content_status); | |
137 EXPECT_EQ(SecurityStateModel::NONE, security_info1.security_level); | |
138 | |
139 client.SetDisplayedMixedContent(false); | |
140 client.SetRanMixedContent(true); | |
141 SecurityStateModel::SecurityInfo security_info2; | |
142 model.GetSecurityInfo(&security_info2); | |
143 EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR, | |
144 security_info2.sha1_deprecation_status); | |
145 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_RAN, | |
146 security_info2.mixed_content_status); | |
147 EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info2.security_level); | |
148 } | |
149 | |
150 // Tests that SHA1 warnings don't interfere with the handling of major | |
151 // cert errors. | |
152 TEST(SecurityStateModelTest, SHA1WarningBrokenHTTPS) { | |
153 TestSecurityStateModelClient client; | |
154 SecurityStateModel model; | |
155 model.SetClient(&client); | |
156 client.AddCertStatus(net::CERT_STATUS_DATE_INVALID); | |
157 SecurityStateModel::SecurityInfo security_info; | |
158 model.GetSecurityInfo(&security_info); | |
159 EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR, | |
160 security_info.sha1_deprecation_status); | |
161 EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level); | |
162 } | |
163 | |
164 // Tests that |security_info.is_secure_protocol_and_ciphersuite| is | |
165 // computed correctly. | |
166 TEST(SecurityStateModelTest, SecureProtocolAndCiphersuite) { | |
167 TestSecurityStateModelClient client; | |
168 SecurityStateModel model; | |
169 model.SetClient(&client); | |
170 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from | |
171 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-param
eters-4 | |
172 const uint16_t ciphersuite = 0xc02f; | |
173 client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2 | |
174 << net::SSL_CONNECTION_VERSION_SHIFT); | |
175 client.SetCipherSuite(ciphersuite); | |
176 SecurityStateModel::SecurityInfo security_info; | |
177 model.GetSecurityInfo(&security_info); | |
178 EXPECT_EQ(net::OBSOLETE_SSL_NONE, security_info.obsolete_ssl_status); | |
179 } | |
180 | |
181 TEST(SecurityStateModelTest, NonsecureProtocol) { | |
182 TestSecurityStateModelClient client; | |
183 SecurityStateModel model; | |
184 model.SetClient(&client); | |
185 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from | |
186 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-param
eters-4 | |
187 const uint16_t ciphersuite = 0xc02f; | |
188 client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_1 | |
189 << net::SSL_CONNECTION_VERSION_SHIFT); | |
190 client.SetCipherSuite(ciphersuite); | |
191 SecurityStateModel::SecurityInfo security_info; | |
192 model.GetSecurityInfo(&security_info); | |
193 EXPECT_EQ(net::OBSOLETE_SSL_MASK_PROTOCOL, security_info.obsolete_ssl_status); | |
194 } | |
195 | |
196 TEST(SecurityStateModelTest, NonsecureCiphersuite) { | |
197 TestSecurityStateModelClient client; | |
198 SecurityStateModel model; | |
199 model.SetClient(&client); | |
200 // TLS_RSA_WITH_AES_128_CCM_8 from | |
201 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-param
eters-4 | |
202 const uint16_t ciphersuite = 0xc0a0; | |
203 client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2 | |
204 << net::SSL_CONNECTION_VERSION_SHIFT); | |
205 client.SetCipherSuite(ciphersuite); | |
206 SecurityStateModel::SecurityInfo security_info; | |
207 model.GetSecurityInfo(&security_info); | |
208 EXPECT_EQ(net::OBSOLETE_SSL_MASK_KEY_EXCHANGE | net::OBSOLETE_SSL_MASK_CIPHER, | |
209 security_info.obsolete_ssl_status); | |
210 } | |
211 | |
212 // Tests that the malware/phishing status is set, and it overrides valid HTTPS. | |
213 TEST(SecurityStateModelTest, MalwareOverride) { | |
214 TestSecurityStateModelClient client; | |
215 SecurityStateModel model; | |
216 model.SetClient(&client); | |
217 // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from | |
218 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-param
eters-4 | |
219 const uint16_t ciphersuite = 0xc02f; | |
220 client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2 | |
221 << net::SSL_CONNECTION_VERSION_SHIFT); | |
222 client.SetCipherSuite(ciphersuite); | |
223 | |
224 SecurityStateModel::SecurityInfo security_info; | |
225 model.GetSecurityInfo(&security_info); | |
226 EXPECT_EQ(SecurityStateModel::MALICIOUS_CONTENT_STATUS_NONE, | |
227 security_info.malicious_content_status); | |
228 | |
229 client.set_malicious_content_status( | |
230 SecurityStateModel::MALICIOUS_CONTENT_STATUS_MALWARE); | |
231 model.GetSecurityInfo(&security_info); | |
232 | |
233 EXPECT_EQ(SecurityStateModel::MALICIOUS_CONTENT_STATUS_MALWARE, | |
234 security_info.malicious_content_status); | |
235 EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level); | |
236 } | |
237 | |
238 // Tests that the malware/phishing status is set, even if other connection info | |
239 // is not available. | |
240 TEST(SecurityStateModelTest, MalwareWithoutCOnnectionState) { | |
241 TestSecurityStateModelClient client; | |
242 SecurityStateModel model; | |
243 model.SetClient(&client); | |
244 client.set_malicious_content_status( | |
245 SecurityStateModel::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING); | |
246 SecurityStateModel::SecurityInfo security_info; | |
247 model.GetSecurityInfo(&security_info); | |
248 EXPECT_EQ(SecurityStateModel::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING, | |
249 security_info.malicious_content_status); | |
250 EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level); | |
251 } | |
252 | |
253 // Tests that password fields cause the security level to be downgraded | |
254 // to HTTP_SHOW_WARNING when the command-line switch is set. | |
255 TEST(SecurityStateModelTest, PasswordFieldWarning) { | |
256 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
257 switches::kMarkHttpAs, | |
258 switches::kMarkHttpWithPasswordsOrCcWithChip); | |
259 TestSecurityStateModelClient client; | |
260 client.UseHttpUrl(); | |
261 SecurityStateModel model; | |
262 model.SetClient(&client); | |
263 client.set_displayed_password_field_on_http(true); | |
264 SecurityStateModel::SecurityInfo security_info; | |
265 model.GetSecurityInfo(&security_info); | |
266 EXPECT_TRUE(security_info.displayed_password_field_on_http); | |
267 EXPECT_EQ(SecurityStateModel::HTTP_SHOW_WARNING, | |
268 security_info.security_level); | |
269 } | |
270 | |
271 // Tests that credit card fields cause the security level to be downgraded | |
272 // to HTTP_SHOW_WARNING when the command-line switch is set. | |
273 TEST(SecurityStateModelTest, CreditCardFieldWarning) { | |
274 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
275 switches::kMarkHttpAs, | |
276 switches::kMarkHttpWithPasswordsOrCcWithChip); | |
277 TestSecurityStateModelClient client; | |
278 client.UseHttpUrl(); | |
279 SecurityStateModel model; | |
280 model.SetClient(&client); | |
281 client.set_displayed_credit_card_field_on_http(true); | |
282 SecurityStateModel::SecurityInfo security_info; | |
283 model.GetSecurityInfo(&security_info); | |
284 EXPECT_TRUE(security_info.displayed_credit_card_field_on_http); | |
285 EXPECT_EQ(SecurityStateModel::HTTP_SHOW_WARNING, | |
286 security_info.security_level); | |
287 } | |
288 | |
289 // Tests that neither password nor credit fields cause the security | |
290 // level to be downgraded to HTTP_SHOW_WARNING when the command-line switch | |
291 // is NOT set. | |
292 TEST(SecurityStateModelTest, HttpWarningNotSetWithoutSwitch) { | |
293 TestSecurityStateModelClient client; | |
294 client.UseHttpUrl(); | |
295 SecurityStateModel model; | |
296 model.SetClient(&client); | |
297 client.set_displayed_password_field_on_http(true); | |
298 SecurityStateModel::SecurityInfo security_info; | |
299 model.GetSecurityInfo(&security_info); | |
300 EXPECT_TRUE(security_info.displayed_password_field_on_http); | |
301 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
302 | |
303 client.set_displayed_credit_card_field_on_http(true); | |
304 model.GetSecurityInfo(&security_info); | |
305 EXPECT_TRUE(security_info.displayed_credit_card_field_on_http); | |
306 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
307 } | |
308 | |
309 // Tests that neither |displayed_password_field_on_http| nor | |
310 // |displayed_credit_card_field_on_http| is set when the corresponding | |
311 // VisibleSecurityState flags are not set. | |
312 TEST(SecurityStateModelTest, PrivateUserDataNotSet) { | |
313 TestSecurityStateModelClient client; | |
314 client.UseHttpUrl(); | |
315 SecurityStateModel model; | |
316 model.SetClient(&client); | |
317 SecurityStateModel::SecurityInfo security_info; | |
318 model.GetSecurityInfo(&security_info); | |
319 EXPECT_FALSE(security_info.displayed_password_field_on_http); | |
320 EXPECT_FALSE(security_info.displayed_credit_card_field_on_http); | |
321 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
322 } | |
323 | |
324 // Tests that SSL.MarkHttpAsStatus histogram is updated when security state is | |
325 // computed for a page. | |
326 TEST(SecurityStateModelTest, MarkHttpAsStatusHistogram) { | |
327 const char* kHistogramName = "SSL.MarkHttpAsStatus"; | |
328 base::HistogramTester histograms; | |
329 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
330 switches::kMarkHttpAs, switches::kMarkHttpWithPasswordsOrCcWithChip); | |
331 TestSecurityStateModelClient client; | |
332 client.UseHttpUrl(); | |
333 SecurityStateModel model; | |
334 model.SetClient(&client); | |
335 | |
336 // Ensure histogram recorded correctly when a non-secure password input is | |
337 // found on the page. | |
338 client.set_displayed_password_field_on_http(true); | |
339 SecurityStateModel::SecurityInfo security_info; | |
340 histograms.ExpectTotalCount(kHistogramName, 0); | |
341 model.GetSecurityInfo(&security_info); | |
342 histograms.ExpectUniqueSample(kHistogramName, 2 /* HTTP_SHOW_WARNING */, 1); | |
343 | |
344 // Ensure histogram recorded correctly even without a password input. | |
345 client.set_displayed_password_field_on_http(false); | |
346 model.GetSecurityInfo(&security_info); | |
347 histograms.ExpectUniqueSample(kHistogramName, 2 /* HTTP_SHOW_WARNING */, 2); | |
348 } | |
349 | |
350 } // namespace | |
351 | |
352 } // namespace security_state | |
OLD | NEW |